Set Values in Marquee to NaN

// https://www.wavemetrics.com/code-snippet/set-values-marquee-nan
// Written 2009-07-23 by Jim Prouty
// Edited 2015-11-06 by Joel Corbin
// Revised 2018-07-19 by Jim Prouty, version 3, added undo, added ActiveGraphWindow() to support subwindows. Omits bar chart traces.

// Adds one menu item per trace to the GraphMarquee menu.
// Selecting one sets only that trace's values which lie inside the marquee to NaN.
// Both Y vs X and waveform traces are supported.
// One-level undo is implemented.

#pragma rtGlobals=1
#pragma version=3 // 2018-07-19, JP
 
Menu "GraphMarquee", dynamic
    Submenu "Set y-axis data within marquee to NaN..."
        CommandPerTrace(), /Q, SetMarqueedValuesToNaN()
        CommandUndoTrace(), /Q, UndoSetValuesToNaN()
    end
End

Function/S CommandPerTrace()
 
    String menuList=""
    String graphName=ActiveGraphWindow()
    String traceList=TraceNameList(graphName,";",1+4)  // only visible non-contour, non-box, non-violin traces
    Variable i, n= ItemsInList(traceList)
    for(i=0; i<n; i+= 1)
        String traceName= StringFromList(i,traceList)
        String info= TraceInfo(graphName, traceName, 0)
        // skip traces with text X waves (bar charts)
        String xWaveName= StringByKey("XWAVE", info)
        WAVE/Z wx = $xWaveName
        Variable wt= WaveType(wx,1)
        if( wt == 0 || wt == 1 )
            menuList += "Set "+traceName+" y-data to NaN;"
        endif
    endfor
 
    return menuList
End

Function/S CommandUndoTrace()

    String menuList=""
    String graphName=ActiveGraphWindow()

    String traceName
    WAVE/Z backupWave= HaveTraceBackupForGraph(graphName, traceName)

    if( WaveExists(backupWave) ) // see if the trace is still on the graph
        Wave/Z wy= TraceNameToWaveRef(graphName,traceName)
        CheckDisplayed/W=$graphName wy
        if( V_Flag )
            menuList += "Undo setting "+traceName+" y-data to NaN;"
        endif
    endif
    return menuList
End

static Function/S ActiveGraphWindow()
    String graphName=""
    String hostWindow=WinName(0,1+4+64) // top-level window, could be a panel or layout containing an embedded graph subwindow
    if( strlen(hostWindow) )
        GetWindow $hostWindow activeSW
        graphName= S_Value // Graph0:subWindow
    endif
    return graphName
End

Function SetMarqueedValuesToNaN()
 
    GetLastUserMenuInfo
    String traceName
    sscanf S_value, "Set %s y-data to NaN", traceName
    String graphName= ActiveGraphWindow()
    Wave/Z wy= TraceNameToWaveRef(graphName,traceName)
    if( !WaveExists(wy) )
        DoAlert 0, "Trace "+traceName+" could not be found"
        return -1
    endif
 
    String info= TraceInfo(graphName, traceName, 0)
    String hAxis= StringByKey("XAXIS", info)
    String vAxis= StringByKey("YAXIS", info)
    GetMarquee/W=$graphName/K $hAxis, $vAxis
    Variable xMin= min(V_right, V_left)
    Variable xMax= max(V_right, V_left)
    Variable yMin= min(V_top, V_bottom)
    Variable yMax= max(V_top, V_bottom)
 
    // Save backup of wy for Undo
    SaveTraceBackup(graphName, traceName, wy)
   
    // make a mask wave indicating points which lie within the marquee
    // then multiply it with the y (and possibly x) wave
    String maskName=UniqueName("mask",1,0)
    Duplicate/O wy, $maskName
    WAVE mask = $maskName
 
    Wave/Z wx = XWaveRefFromTrace(graphName,traceName)
    if( WaveExists(wx) )    // Y vs x
        mask = (wy > yMin) && (wy < yMax) && (wx > xMin) && (wx < xMax) ? NaN : 1
    else        // just a waveform, use X scaling
        mask = (wy > yMin) && (wy < yMax) && (pnt2x(wy,p) > xMin) && (pnt2x(wy,p) < xMax) ? NaN : 1
    endif
    wy *= mask
    KillWaves/Z mask
End

static Function SaveTraceBackup(graphName, traceName, wy)
    String graphName, traceName
    Wave wy
   
    NewDataFolder/O root:Packages
    NewDataFolder/O root:Packages:SetMarqueeValuesToNaN
    Duplicate/O wy, root:Packages:SetMarqueeValuesToNaN:backupForUndo
    String/G root:Packages:SetMarqueeValuesToNaN:graphName = graphName
    String/G root:Packages:SetMarqueeValuesToNaN:traceName = traceName
   
End

static Function/WAVE HaveTraceBackupForGraph(graphName, traceName)
    String graphName // input
    String &traceName // output
   
    WAVE backupWave // null
    DFREF dfr = root:Packages:SetMarqueeValuesToNaN
    if (DataFolderRefStatus(dfr) != 0)
        SVAR/Z backupGraphName= dfr:graphName
        SVAR/Z backupTraceName= dfr:traceName
        WAVE/Z backupYwave= dfr:backupForUndo
        Variable haveBackup = CmpStr(graphName, backupGraphName) == 0 && strlen(backupTraceName) && WaveExists(backupYwave)
        if( haveBackup )
            WAVE backupWave= backupYwave
            traceName= backupTraceName
        endif
    endif
   
    return backupWave // output
End

Function UndoSetValuesToNaN()

    String graphName= ActiveGraphWindow()
    GetMarquee/W=$graphName/K

    String traceName
    WAVE/Z backupWave= HaveTraceBackupForGraph(graphName, traceName)
    if( !WaveExists(backupWave) ) // see if the trace is still on the graph
        DoAlert 0, "Undo Wave for "+traceName+" could not be found"
        return -1
    endif

    WAVE/Z wy= TraceNameToWaveRef(graphName,traceName)
    if( !WaveExists(wy) )
        DoAlert 0, "Trace "+traceName+" wave could not be found"
        return -1
    endif

    // Undo
    wy= backupWave[p]
   
    // Remove Undo backup
    KillDataFolder/Z root:Packages:SetMarqueeValuesToNaN

    return 0 // success
End
Great Code. The only thing I would note is that to get it to work with subwindows graphs
change
    String graphName=WinName(0,1)
   

to
 
    GetMarquee
    String graphName= S_marqueeWin

Hello, the code works great. Do you know how to amend it to work for an image plot? 

I have a matrix that acts as the Z wave, and two 1D waves that act as the X and Y wave respectively. 

Forum

Support

Gallery

Igor Pro 9

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More