Request a DuplicateGraph(...) Function

I'd like to petition for a DuplicateGraph(WinName,newWaves,[newWinName]) function to improve upon the methods that have to otherwise be used according to the discussion at this link.

https://www.wavemetrics.com/forum/general/duplicate-graph

WinName -- name of source window (following conventions)
newWaves -- 0 means duplicate just the graph keeping traces linked to original waves, 1 means generate new duplicates of waves used as well (functions as Save Graph Copy only internally)
[newWinName] -- optional new window name (default is to add suffix _N)

 

If you don't need to copy the waves in the graph, it's pretty simple to duplicate a graph programmatically. Here is an example:

Function test()
    Make/O ddd=sin(x)
    Display ddd
    DoIgorMenu "Edit", "Duplicate"
    // Get name of duplicate graph
    String duplicateName = WinName(0, 1)
    print "New graph is named ", duplicateName
End

 

It's possible to make such a function (see below), relying on WinRecreation, with info from DoWindow, and Execute. Nevertheless, I also think it would be useful to have a built in function, since functions like this will fail if the recreation macro syntax changes. (I'm also not sure the function below works for every possible recreation macro.)

EDIT: I hadn't realized that similar functions were linked in the earlier forum topic, so this is not much of an improvement.

function/S graph_duplicate(origWinName,appendStrForNewWaves,[newWinName,appendBefore])
    String origWinName      //original window name. Top graph is used in case of ""
    String appendStrForNewWaves //pass "" to make new plot with same waves, otherwise renames the waves as [origName]+appendStrForNewWaves and plots with those
    String newWinName       //optionally give the window a new name instead of its automatic name
    Variable appendBefore       //optionally specify to append appendStrForNewWaves before wave names
   
    Variable startSkipLines = 2     //skip "function ..." and "PauseUpdate ..." lines from beginning of recreation macro
    Variable endSkipLines = 1           //skip "PauseUpdate ..." line from recreation macro
   
    if (strlen(origWinName) < 1)    //default to top graph for ""
        origWinName = winname(0,1) 
    endif
   
    Variable i,newWaves = strlen(appendStrForNewWaves) > 0
    String recreationStr,createdWaves=""
    if (newWaves)       //use getWindow wavelist and winrecreation to replace unique ##(num)## in recreation macro with new wave names, after duplication
        recreationStr = winrecreation(origWinName,2)   
        getwindow $origWinName, waveList
        WAVE/T W_WaveList       //not sure what the difference betweens columns 0 and 1 is in this
        Variable numWaves = dimsize(W_WaveList,0)
        Variable doAppendBefore = !paramIsDefault(appendBefore) && appendBefore
       
        //set new wave names
        make/o/t/free/n=(numWaves) newWaveNames
        if (doAppendBefore)
            newWaveNames = appendStrForNewWaves + W_waveList[p][0]
        else
            newWaveNames = W_waveList[p][0] + appendStrForNewWaves
        endif
       
        //duplicate new waves and insert names into recreationStr
        String hashTagStr,newWaveName,origWaveName
        for (i=0;i<numWaves;i+=1)
            origWaveName = W_waveList[i][0]
            newWaveName = newWaveNames[i]
            hashTagStr = W_waveList[i][2]
            Duplicate/o $origWaveName,$newWaveName
            recreationStr=replacestring(hashTagStr,recreationStr,newWaveName)
            createdWaves += newWaveName + ";"
        endfor
    else
        recreationStr = winrecreation(origWinName,0)
    endif
   
    //window name handling
    String finalName
    if (ParamIsDefault(newWinName) || (strlen(newWinName) < 1) )        //use default window name
        finalName = stringfromlist(1,recreationStr," ") //get window name from recreation macro name.. (allows winStr="" for top window)
        finalName = replacestring("()",finalName,"")        //remove () from after recreation macro name
    else    //newWinName passed
        finalName = newWinName
    endif  
    recreationStr = replacestring("Display",recreationStr,"Display/N="+finalName,0,1)       //modify "Display..." line to include window name
   
    //run commands, line by line to avoid execute length limit
    Variable lines = itemsinlist(recreationStr,"\r"),lineLimit = lines - endSkipLines
    for (i=startSkipLines;i<lineLimit;i+=1)
        execute/q stringfromlist(i,recreationStr,"\r")
    endfor
   
    return createdWaves
end

 

Thanks Adam. I did not recognize DoIgorMenu in order to create what is needed. Unfortunately, that approach does not work for my main need, which is to duplicate sub-windows in panels to their own stand-alone window. So, what I want to achieve in one function call is this ...

DuplicateGraph("MainPanel#EmbeddedGraph",0,"StandAloneGraph")

@GSB ... I was not really concerned about changing the waves, just duplicating the graph entirely to go from an embedded graph in a panel to a stand alone graph. I ended up pulling the WinRec string, removing the Display/.../HOST= line, and executing the revised WinRec after my own Display statement.

In the meantime, I have decided to just run the entire set of commands to generate the graphics with a switch.

Function ShowGraphics(how)
     variable how

     switch(how)
          case 0: // embed in panel
          ....
          case 1: // stand alone
          ...
     endswitch
     ... // common changes to make to graph
return

So, my equivalent when needed to DuplicateGraph(...) is to call ShowGraphics(1).

As of Igor 7, WinRecreation() works on subwindows. But it doesn't excise the subwindow stuff like "/HOST", so here is some code to do that:

Function/S RemoveSlashW(String aLine)
    String newstr = ""
    if (StringMatch(aLine, "*/W=*"))
        Variable pos1 = StrSearch(aLine, "/W=", 0)
        Variable pos2 = StrSearch(aLine, ")", pos1)
        newstr = aLine[0,pos1-1]
        newstr += aLine[pos2+1,strlen(aLine)]
    endif
   
    return newstr
end

Function/S RemoveSlashHost(String aLine)
    String newstr = ""
    if (StringMatch(aLine, "*/HOST=*"))
        Variable pos1 = StrSearch(aLine, "/HOST=", 0)
        Variable pos2 = StrSearch(aLine, " ", pos1)     // This fails if there is another flag after /HOST=...
        newstr = aLine[0,pos1-1]
        newstr += aLine[pos2,strlen(aLine)]
    endif
   
    return newstr
end


Function DuplicateGraphSubwindow(String gname)
    String rec = WinRecreation(gname, 0)   
    Variable lines=ItemsInList(rec, "\r")
    Variable i
    String newrec=""
    for (i = 0; i < lines; i++)
        String oneline = StringFromList(i, rec, "\r")
        if (StringMatch(oneline, "*Display*"))
            oneline = RemoveSlashW(oneline)
            oneline = RemoveSlashHost(oneline)
        endif
        newrec += oneline+"\r"
    endfor
    Execute newrec
end

Caveats: no error checking! Feed it a proper string like "Graph0#G0". It worked on a really simple case with just one subwindow, not a bunch of nested subwindows.

Thanks. I have to suspect that grep could be used in a clever way to wipe out the /HOST=...  and /W=... flags regardless of whether they are or are not followed by another flag. This would eliminate the need for the iteration loop and two sub-functions.

 

Well, you're probably right about a cleverer way to deal with the subwindow cruft. But I'm not grep-clever. I subscribe to the rule of thumb: "I could solve this problem with grep. Oh, no- now I have two problems!"