From a graph marquee, save a list of points, average, or NaN data
jcor
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
// Does simple tasks on the data within a marquee -- either prints avg or sets nan
function doWithinMarquee([doWhat, quiet])
// Note: if no changes are made, nothing is printed.
// Joel Corbin, 2016-09-22
string doWhat // == one of: "avg", "nan", "getPlist" (get str list of row indices for selection)
// (see below for what these mean)
variable quiet // if set, function doesn't print anything
if (ParamIsDefault(doWhat))
doWhat="avg"
endif
variable printStuff=0
if (ParamIsDefault(quiet) || quiet)
printStuff=1
endif
String graphName= WinName(0,1)
String traceList=TraceNameList(graphName,";",1+4) // 1+4 --> normal+visible traces
variable i, n_traces= itemsInList(traceList)
variable alertedAlready= 0
variable n_traces_used= 0
// search for & get traces for any subwindows. Expand graph names to match traces to allow this.
string graphsList= strmultiply(graphName, n_traces) // empty if n=0
string childWinList= ChildWindowList(graphName)
variable j, n_childs= itemsInList(childWinList)
for (j=0; j<n_childs; j+=1)
// [this doesn't execute if n_childs==0]
string nextSubGr= graphName + "#" + stringFromList(j, childWinList) // ParentGraph#Subwindow format
graphsList+= nextSubGr + ";"
traceList+= TraceNameList(nextSubGr,";",1+4) // 1+4 --> normal+visible traces
endfor
n_traces= itemsInList(traceList)
// for each trace...
for (i=0; i<n_traces; i+=1)
// prepare
graphName= stringFromList(i, graphsList)
string traceName= stringFromList(i, traceList)
Wave/Z yw= TraceNameToWaveRef(graphName,traceName)
Wave/Z xw= XWaveRefFromTrace(graphName,traceName)
if (!WaveExists(yw))
printf "\t//* Wave %s not found.\r", traceName
endif
// get axis and marquee properties
String hAxis= StringByKey("XAXIS", TraceInfo(graphName, traceName, 0))
String vAxis= StringByKey("YAXIS", TraceInfo(graphName, traceName, 0))
GetMarquee /W=$graphName $hAxis, $vAxis // removed /K (kill marquee) for the sake of the points version
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)
// get mask of selected items [code here inspired by http://www.igorexchange.com/node/1140]
make /free /n=(numpnts(yw)) mask
if( WaveExists(xw)) // y vs x
mask = (yw[p] > yMin) && (yw[p] < yMax) && (xw > xMin) && (xw < xMax) ? 1 : 0
else // just a waveform, use X scaling
mask = (yw[p] > yMin) && (yw[p] < yMax) && (pnt2x(yw,p) > xMin) && (pnt2x(yw,p) < xMax) ? 1 : 0
endif
// if trace is masked [some points not visible] the result is wrong.
if (0)
String maskName= StringByKey("mask(x)", TraceInfo(graphName, traceName, 0), "=", ";")
// But to mask a trace, I do a hack using zmarkersize... so very hard to work with]
print maskName // msizez ??
endif
strswitch (doWhat)
case "avg":
mask= yw*mask/mask
// get stats
WaveStats /Q mask
if (V_npnts > 2)
StatsQuantiles /iNaN /Q mask
else
V_Q25=nan; V_Median=nan; V_Q75=nan
endif
// print result
if (xMin > date2secs(2000, 1, 1)) // assume time:
string S_range= secs2dt(xMin) + ", " + secs2dt(xMax)
else
S_range= num2str(xMin) + ", " + num2str(xMax)
endif
if (V_npnts > 0)
if (printStuff)
printf "Wave %s(%s) {avg, SD, %%SD}\t= {%.4g, %.4g, %.1f %%}; {min, Q25, Q50, Q75, max} = {%.4g, %.4g, %.4g, %.4g, %.4g}\r", traceName, S_range, V_avg, V_sdev, V_sdev/V_avg*100, V_min, V_Q25, V_Median, V_Q75, V_Max
endif
n_traces_used+=1
endif
break
case "nan":
if (!alertedAlready)
alertedAlready=1
// warn
doAlert 1, "This will permanently remove data from the selected wave(s). Continue?"
if (V_flag==2)
abort "Abort -- no changes made. -- " + GetRTStackInfo(0)
endif
endif
WaveStats /Q yw
variable V_nansBefore= V_numNaNs
// do it
mask= !mask / !mask // maskOfKeepers[1,nan] <- maskOfMarqueeMembers[0,1]
yw *= mask
// print a report
WaveStats /Q yw
variable V_numDeleted= V_numNaNs - V_nansBefore
if (V_numDeleted)
if (printStuff)
printf "\t//* %s deleted %g points from wave %s according to a marquee selection [%s].\r", GetRTStackInfo(1), V_numDeleted, getwavesdatafolder(yw,2), secs2dt(datetime)
endif
n_traces_used+=1
endif
GetMarquee /W=$graphName /K // kill marquee
break
case "getPlist":
DFREF sdf= getDataFolderDFR()
cd root:; newdatafolder /o/s Packages; newdatafolder /o/s jTools
variable V_noList= 0
if (DimSize(xw, 1)>1 || DimSize(yw, 1)>1) // can't handle multidimensional inputs...
if (printStuff)
printf "\t//* doWithinMarquee() can't handle multidimensional inputs, returning nothing...\r"
endif
V_noList= 1
make /free /n=1 mask=nan
endif
// do it
mask= mask/mask * p
duplicate /free mask, mask_deletedNaNs
deleteNaNs(mask_deletedNaNs)
if (!numpnts(mask_deletedNaNs)) // no selection
cd sdf
continue
endif
// save result 1/2
duplicate /o mask, root:Packages:jTools:MarqueeMask /WAVE=MarqueeMask
n_traces_used+= 1
if (n_traces_used > 1)
printf "// (Multiple traces used, not saving selected points in MarqueeP / MarqueeMask... (to fix, remove all other traces first)"
// there is no mechanism for choosing which trace to save yet
endif
// save result 2/2
duplicate /o mask_deletedNaNs, root:Packages:jTools:MarqueePs /WAVE=MarqueePs
string wnote= "Saved from a marquee selection of wave %s \ron %s by doWithinMarquee(\"getPlist\")"
if (V_noList) // ensure no misleading info saved
xMin=nan; xMax=nan; yMin=nan; yMax=nan;
else
wnote+= "\rThe marquee was located at {left, right, top, bottom} = {%g, %g, %g, %g}\r on the axes %s\r and %s"
sprintf wnote, wnote, getwavesdatafolder(yw,2), secs2dt(datetime), xMin, xMax, yMin, yMax, getwavesdatafolder(yw,2), ifElseStr(WaveExists(xw), getwavesdatafolder(yw,2), "[none]")
endif
note /K MarqueePs, wnote
note /K MarqueeMask, wnote
PutScrapText getwavesdatafolder(MarqueePs,2)
// wrap up
if (numpnts(MarqueePs) < 100) // interact if just a few points
string output= wave2list(MarqueePs)
if (printStuff)
printf "The following indices of wave %s (trace %s) were selected:\r%s\rand are saved in %s and %s \r", getWaveFullPathStr(yw), traceName, output, getWaveFullPathStr(MarqueePs), getWaveFullPathStr(MarqueeMask)
endif
// doAlert 0, "A list of row indices has been copied to the clipboard and printed."
PutScrapText output
else
if (printStuff)
printf "// %g indices of wave %s (trace %s) were selected\r // and saved in %s and %s [the former wave ref copied to clipboard]\r", numpnts(mask), getWaveFullPathStr(yw), traceName, getWaveFullPathStr(MarqueePs), getWaveFullPathStr(MarqueeMask)
endif
endif
cd sdf
break
default:
cd sdf
abort "Argument not recognized -- " + GetRTStackInfo(0)
endswitch
endfor
if (n_traces_used==0)
print "No points were selected."
endif
end
// Given "item" and 3, returns "item;item;item"
function/s strmultiply(input, n)
string input
variable n
variable i=0
string output= ""
for (i=0; i<n; i+=1)
output += input + ";"
n -= 1
endfor
return output
end
function/s secs2dt(secs)
// Given a datetime in seconds, returns an ISO-8601--formatted datetime.
// e.g. secs2dt(date2secs(2012,1,31)) returns "2012-01-31 00:00:00"
variable secs
if (secs)
return secs2date(secs,-2) + " " + secs2time(secs,3)
endif
return ""
end
function deleteNaNs(w)
// Deletes points in w containing NaNs.
wave w
variable i, j, np= numpnts(w)
make /free /n=(np) onda
for (i=0; i<np; i+=1)
if (numtype(w[i])!=2)
onda[j]= w[i]
j+=1
endif
endfor
DeletePoints j, i-j, onda
duplicate /o onda, w
end
function/s ifelseStr(bool, iftrue, iffalse)
// if variable bool is true, return iftrue, else return iffalse.
// analogue to R's ifelse()
variable bool
string iftrue, iffalse
if (bool)
return iftrue
endif
return iffalse
end
// Given a wave reference, returns a string-list formatted version of the wave.
function/s wave2list(w[,noNaNs])
// printed using %g.
// e.g. make w={1,2,3}; print wave2list(w) returns "1;2;3"
// make w={1,nan,3}; print wave2list(w) returns "1;3"
wave w
variable noNaNs // optionally remove NaNs from the returned list
if (!WaveExists(w) || numpnts(w)==0)
return ""
endif
string str
wfprintf str, "%g;", w
if (noNaNs)
do
str = removeFromList("NaN", str)
while (findInList("NaN", str)>=0)
endif
return str
end
// returns "root:exampleDF:exampleWaveName"
function/s getWaveFullPathStr(w)
wave w
if (WaveExists(w))
return getwavesdatafolder(w,2)
else
return ""
endif
end
function findInList(findstr, liststr[, sep])
// Returns the list index in which findstr is found in ;-list liststr,
// else returns -1
string findstr, liststr, sep
if (ParamIsDefault(sep))
sep = ";"
endif
return WhichListItem(findstr, liststr, sep)
end
// Does simple tasks on the data within a marquee -- either prints avg or sets nan
function doWithinMarquee([doWhat, quiet])
// Note: if no changes are made, nothing is printed.
// Joel Corbin, 2016-09-22
string doWhat // == one of: "avg", "nan", "getPlist" (get str list of row indices for selection)
// (see below for what these mean)
variable quiet // if set, function doesn't print anything
if (ParamIsDefault(doWhat))
doWhat="avg"
endif
variable printStuff=0
if (ParamIsDefault(quiet) || quiet)
printStuff=1
endif
String graphName= WinName(0,1)
String traceList=TraceNameList(graphName,";",1+4) // 1+4 --> normal+visible traces
variable i, n_traces= itemsInList(traceList)
variable alertedAlready= 0
variable n_traces_used= 0
// search for & get traces for any subwindows. Expand graph names to match traces to allow this.
string graphsList= strmultiply(graphName, n_traces) // empty if n=0
string childWinList= ChildWindowList(graphName)
variable j, n_childs= itemsInList(childWinList)
for (j=0; j<n_childs; j+=1)
// [this doesn't execute if n_childs==0]
string nextSubGr= graphName + "#" + stringFromList(j, childWinList) // ParentGraph#Subwindow format
graphsList+= nextSubGr + ";"
traceList+= TraceNameList(nextSubGr,";",1+4) // 1+4 --> normal+visible traces
endfor
n_traces= itemsInList(traceList)
// for each trace...
for (i=0; i<n_traces; i+=1)
// prepare
graphName= stringFromList(i, graphsList)
string traceName= stringFromList(i, traceList)
Wave/Z yw= TraceNameToWaveRef(graphName,traceName)
Wave/Z xw= XWaveRefFromTrace(graphName,traceName)
if (!WaveExists(yw))
printf "\t//* Wave %s not found.\r", traceName
endif
// get axis and marquee properties
String hAxis= StringByKey("XAXIS", TraceInfo(graphName, traceName, 0))
String vAxis= StringByKey("YAXIS", TraceInfo(graphName, traceName, 0))
GetMarquee /W=$graphName $hAxis, $vAxis // removed /K (kill marquee) for the sake of the points version
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)
// get mask of selected items [code here inspired by http://www.igorexchange.com/node/1140]
make /free /n=(numpnts(yw)) mask
if( WaveExists(xw)) // y vs x
mask = (yw[p] > yMin) && (yw[p] < yMax) && (xw > xMin) && (xw < xMax) ? 1 : 0
else // just a waveform, use X scaling
mask = (yw[p] > yMin) && (yw[p] < yMax) && (pnt2x(yw,p) > xMin) && (pnt2x(yw,p) < xMax) ? 1 : 0
endif
// if trace is masked [some points not visible] the result is wrong.
if (0)
String maskName= StringByKey("mask(x)", TraceInfo(graphName, traceName, 0), "=", ";")
// But to mask a trace, I do a hack using zmarkersize... so very hard to work with]
print maskName // msizez ??
endif
strswitch (doWhat)
case "avg":
mask= yw*mask/mask
// get stats
WaveStats /Q mask
if (V_npnts > 2)
StatsQuantiles /iNaN /Q mask
else
V_Q25=nan; V_Median=nan; V_Q75=nan
endif
// print result
if (xMin > date2secs(2000, 1, 1)) // assume time:
string S_range= secs2dt(xMin) + ", " + secs2dt(xMax)
else
S_range= num2str(xMin) + ", " + num2str(xMax)
endif
if (V_npnts > 0)
if (printStuff)
printf "Wave %s(%s) {avg, SD, %%SD}\t= {%.4g, %.4g, %.1f %%}; {min, Q25, Q50, Q75, max} = {%.4g, %.4g, %.4g, %.4g, %.4g}\r", traceName, S_range, V_avg, V_sdev, V_sdev/V_avg*100, V_min, V_Q25, V_Median, V_Q75, V_Max
endif
n_traces_used+=1
endif
break
case "nan":
if (!alertedAlready)
alertedAlready=1
// warn
doAlert 1, "This will permanently remove data from the selected wave(s). Continue?"
if (V_flag==2)
abort "Abort -- no changes made. -- " + GetRTStackInfo(0)
endif
endif
WaveStats /Q yw
variable V_nansBefore= V_numNaNs
// do it
mask= !mask / !mask // maskOfKeepers[1,nan] <- maskOfMarqueeMembers[0,1]
yw *= mask
// print a report
WaveStats /Q yw
variable V_numDeleted= V_numNaNs - V_nansBefore
if (V_numDeleted)
if (printStuff)
printf "\t//* %s deleted %g points from wave %s according to a marquee selection [%s].\r", GetRTStackInfo(1), V_numDeleted, getwavesdatafolder(yw,2), secs2dt(datetime)
endif
n_traces_used+=1
endif
GetMarquee /W=$graphName /K // kill marquee
break
case "getPlist":
DFREF sdf= getDataFolderDFR()
cd root:; newdatafolder /o/s Packages; newdatafolder /o/s jTools
variable V_noList= 0
if (DimSize(xw, 1)>1 || DimSize(yw, 1)>1) // can't handle multidimensional inputs...
if (printStuff)
printf "\t//* doWithinMarquee() can't handle multidimensional inputs, returning nothing...\r"
endif
V_noList= 1
make /free /n=1 mask=nan
endif
// do it
mask= mask/mask * p
duplicate /free mask, mask_deletedNaNs
deleteNaNs(mask_deletedNaNs)
if (!numpnts(mask_deletedNaNs)) // no selection
cd sdf
continue
endif
// save result 1/2
duplicate /o mask, root:Packages:jTools:MarqueeMask /WAVE=MarqueeMask
n_traces_used+= 1
if (n_traces_used > 1)
printf "// (Multiple traces used, not saving selected points in MarqueeP / MarqueeMask... (to fix, remove all other traces first)"
// there is no mechanism for choosing which trace to save yet
endif
// save result 2/2
duplicate /o mask_deletedNaNs, root:Packages:jTools:MarqueePs /WAVE=MarqueePs
string wnote= "Saved from a marquee selection of wave %s \ron %s by doWithinMarquee(\"getPlist\")"
if (V_noList) // ensure no misleading info saved
xMin=nan; xMax=nan; yMin=nan; yMax=nan;
else
wnote+= "\rThe marquee was located at {left, right, top, bottom} = {%g, %g, %g, %g}\r on the axes %s\r and %s"
sprintf wnote, wnote, getwavesdatafolder(yw,2), secs2dt(datetime), xMin, xMax, yMin, yMax, getwavesdatafolder(yw,2), ifElseStr(WaveExists(xw), getwavesdatafolder(yw,2), "[none]")
endif
note /K MarqueePs, wnote
note /K MarqueeMask, wnote
PutScrapText getwavesdatafolder(MarqueePs,2)
// wrap up
if (numpnts(MarqueePs) < 100) // interact if just a few points
string output= wave2list(MarqueePs)
if (printStuff)
printf "The following indices of wave %s (trace %s) were selected:\r%s\rand are saved in %s and %s \r", getWaveFullPathStr(yw), traceName, output, getWaveFullPathStr(MarqueePs), getWaveFullPathStr(MarqueeMask)
endif
// doAlert 0, "A list of row indices has been copied to the clipboard and printed."
PutScrapText output
else
if (printStuff)
printf "// %g indices of wave %s (trace %s) were selected\r // and saved in %s and %s [the former wave ref copied to clipboard]\r", numpnts(mask), getWaveFullPathStr(yw), traceName, getWaveFullPathStr(MarqueePs), getWaveFullPathStr(MarqueeMask)
endif
endif
cd sdf
break
default:
cd sdf
abort "Argument not recognized -- " + GetRTStackInfo(0)
endswitch
endfor
if (n_traces_used==0)
print "No points were selected."
endif
end
// Given "item" and 3, returns "item;item;item"
function/s strmultiply(input, n)
string input
variable n
variable i=0
string output= ""
for (i=0; i<n; i+=1)
output += input + ";"
n -= 1
endfor
return output
end
function/s secs2dt(secs)
// Given a datetime in seconds, returns an ISO-8601--formatted datetime.
// e.g. secs2dt(date2secs(2012,1,31)) returns "2012-01-31 00:00:00"
variable secs
if (secs)
return secs2date(secs,-2) + " " + secs2time(secs,3)
endif
return ""
end
function deleteNaNs(w)
// Deletes points in w containing NaNs.
wave w
variable i, j, np= numpnts(w)
make /free /n=(np) onda
for (i=0; i<np; i+=1)
if (numtype(w[i])!=2)
onda[j]= w[i]
j+=1
endif
endfor
DeletePoints j, i-j, onda
duplicate /o onda, w
end
function/s ifelseStr(bool, iftrue, iffalse)
// if variable bool is true, return iftrue, else return iffalse.
// analogue to R's ifelse()
variable bool
string iftrue, iffalse
if (bool)
return iftrue
endif
return iffalse
end
// Given a wave reference, returns a string-list formatted version of the wave.
function/s wave2list(w[,noNaNs])
// printed using %g.
// e.g. make w={1,2,3}; print wave2list(w) returns "1;2;3"
// make w={1,nan,3}; print wave2list(w) returns "1;3"
wave w
variable noNaNs // optionally remove NaNs from the returned list
if (!WaveExists(w) || numpnts(w)==0)
return ""
endif
string str
wfprintf str, "%g;", w
if (noNaNs)
do
str = removeFromList("NaN", str)
while (findInList("NaN", str)>=0)
endif
return str
end
// returns "root:exampleDF:exampleWaveName"
function/s getWaveFullPathStr(w)
wave w
if (WaveExists(w))
return getwavesdatafolder(w,2)
else
return ""
endif
end
function findInList(findstr, liststr[, sep])
// Returns the list index in which findstr is found in ;-list liststr,
// else returns -1
string findstr, liststr, sep
if (ParamIsDefault(sep))
sep = ";"
endif
return WhichListItem(findstr, liststr, sep)
end
Forum
Support
Gallery
Igor Pro 9
Learn More
Igor XOP Toolkit
Learn More
Igor NIDAQ Tools MX
Learn More