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 10

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More