Print names of traces in graph marquee
harneit
Print Traces In Marquee
in the graph marquee menu that lets you print the names of the traces in the marquee. To test, copy the code below in your procedure window and then execute this on the command line:
make/o w0=100-x, w1=x^2/128, w2=2*x+5, w3=3*x;Display w0, w1, w2, w3;Append w0,w2 vs w1;legend
Then, colorize the traces (menu Graph|Packages|Make Traces Different, press "Commonly-Used Colors") and drag a marquee on the graph, use the context-menu (right-click (windows) or ctrl-click (macintosh)).
Menu "GraphMarquee"
"Print Traces In Marquee", /Q, print GetTracesInMarquee()
End
function/S GetTracesInMarquee()
string tracesInMarquee = "" // result
// get marquee coordinates
// one may want to check whether these axes really exist since Igor throws an error otherwise
GetMarquee/K/Z left, bottom
if( V_Flag == 0 )
return "" // there was no marquee
endif
// print V_left, V_right, V_top, V_bottom
// convert marquee coordinates to polygon
Make/FREE/N=5 xPoly={V_Left, V_left, V_right, V_right, V_left}
Make/FREE/N=5 yPoly={V_Top, V_bottom, V_bottom, V_top, V_top}
// get info about traces
string traces = TraceNameList("", ";", 5) // omit hidden traces
string trace, traceX, info
variable n, lastInstanceChar, instance
// step through traces
for( n = 0; n < ItemsInList(traces); n += 1 )
// get y wave
trace = StringFromList(n, traces)
wave yWave = TraceNameToWaveRef("", trace)
// that was easy, now get x wave
if( WaveExists(XWaveRefFromTrace("", trace)) ) // has x wave?
wave xWave = XWaveRefFromTrace("", trace)
traceX = NameOfWave(xWave)
else
Make/FREE/N=(numpnts(yWave)) tmpXWave // make x wave, this could be costly
wave xWave = tmpXWave
xWave = leftx(yWave) + p*deltax(yWave)
traceX = ""
endif
// find out if its in the marquee
FindPointsInPoly xWave, yWave, xPoly, yPoly // probably costly
wave W_inPoly
W_inPoly = 1/W_inPoly // convert zeros to infs
WaveStats/Q W_inPoly
// if it's in there, V_npnts should be non-zero
if( V_npnts > 0 ) // only non-inf values are counted
if( strlen(traceX) > 0 )
trace += " vs "+traceX
endif
tracesInMarquee = AddListItem(trace, tracesInMarquee)
endif
endfor
return tracesInMarquee
end
"Print Traces In Marquee", /Q, print GetTracesInMarquee()
End
function/S GetTracesInMarquee()
string tracesInMarquee = "" // result
// get marquee coordinates
// one may want to check whether these axes really exist since Igor throws an error otherwise
GetMarquee/K/Z left, bottom
if( V_Flag == 0 )
return "" // there was no marquee
endif
// print V_left, V_right, V_top, V_bottom
// convert marquee coordinates to polygon
Make/FREE/N=5 xPoly={V_Left, V_left, V_right, V_right, V_left}
Make/FREE/N=5 yPoly={V_Top, V_bottom, V_bottom, V_top, V_top}
// get info about traces
string traces = TraceNameList("", ";", 5) // omit hidden traces
string trace, traceX, info
variable n, lastInstanceChar, instance
// step through traces
for( n = 0; n < ItemsInList(traces); n += 1 )
// get y wave
trace = StringFromList(n, traces)
wave yWave = TraceNameToWaveRef("", trace)
// that was easy, now get x wave
if( WaveExists(XWaveRefFromTrace("", trace)) ) // has x wave?
wave xWave = XWaveRefFromTrace("", trace)
traceX = NameOfWave(xWave)
else
Make/FREE/N=(numpnts(yWave)) tmpXWave // make x wave, this could be costly
wave xWave = tmpXWave
xWave = leftx(yWave) + p*deltax(yWave)
traceX = ""
endif
// find out if its in the marquee
FindPointsInPoly xWave, yWave, xPoly, yPoly // probably costly
wave W_inPoly
W_inPoly = 1/W_inPoly // convert zeros to infs
WaveStats/Q W_inPoly
// if it's in there, V_npnts should be non-zero
if( V_npnts > 0 ) // only non-inf values are counted
if( strlen(traceX) > 0 )
trace += " vs "+traceX
endif
tracesInMarquee = AddListItem(trace, tracesInMarquee)
endif
endfor
return tracesInMarquee
end
Forum
Support
Gallery
Igor Pro 9
Learn More
Igor XOP Toolkit
Learn More
Igor NIDAQ Tools MX
Learn More
I like your approach using
FindLevel
(that you suggested on the mailing list) better, because it can handle the case where no points lay inside the marquee, but the trace does (at least if visualized using 'lines between points'). See the attached image.Additionally your code does not take into account that a trace can be displayed versus other axes than left and bottom.
And lastly the trace can have an offset, which makes it move out of or into the marquee.
I propose the following:
string tracestr=tracenamelist("",";",5),tstr,infostr,tracesInMarquee=""
variable i,a,b,offsetx,offsety
for(i=0;i<itemsinlist(tracestr);i+=1)
tstr=stringfromlist(i,tracestr)
infostr=traceinfo("",tstr,0)
sscanf stringbykey("offset(x)",infostr,"="),"{%f,%f}",offsetx,offsety
getmarquee $stringbykey("XAXIS",infostr),$stringbykey("YAXIS",infostr)
if(strlen(stringbykey("XWAVE",infostr))==0) // trace is display vs internal scaling
wave yWave=tracenametowaveref("",tstr)
switch(0)
case 0:
findlevel/q/r=(V_left-offsetx,V_right-offsetx) yWave, V_bottom-offsety
if(V_flag==0)
tracesInMarquee=addlistitem(tstr,tracesInMarquee)
break
endif
case 1:
findlevel/q/r=(V_left-offsetx,V_right-offsetx) yWave, V_top-offsety
if(V_flag==0)
tracesInMarquee=addlistitem(tstr,tracesInMarquee)
break
endif
case 2:
wavestats/q/r=(V_left-offsetx,V_right-offsetx) yWave
if(V_avg>=V_bottom-offsety && V_avg<=V_top-offsety)
tracesInMarquee=addlistitem(tstr,tracesInMarquee)
break
endif
endswitch
else // trace is displayed vs xwave
wave yWave=tracenametowaveref("",tstr)
wave xwave=$stringbykey("XWAVE",infostr)
findlevel/q/p xwave,V_left
if(V_flag!=0)
break
endif
a=V_levelX
findlevel/q/p xwave,V_right
if(V_flag!=0)
break
endif
b=V_levelX
switch(0)
case 0:
findlevel/q/r=[a,b] yWave, V_bottom-offsety
if(V_flag==0)
tracesInMarquee=addlistitem(tstr,tracesInMarquee)
break
endif
case 1:
findlevel/q/r=[a,b] yWave, V_top-offsety
if(V_flag==0)
tracesInMarquee=addlistitem(tstr,tracesInMarquee)
break
endif
case 2:
wavestats/q/r=[a,b] yWave
if(V_avg>=V_bottom-offsety && V_avg<=V_top-offsety)
tracesInMarquee=addlistitem(tstr,tracesInMarquee)
break
endif
endswitch
endif
endfor
return tracesInMarquee
end
I don't know what happens if the xWave is not monotonic. Also a multiplier offset is not taken into consideration.
Andreas
August 12, 2010 at 02:31 am - Permalink
thanks for your snippet, it's always great to get new ideas. In all honesty, the credits for the FindLevel method you so nicely implemented should go to Holger Taschenberger who proposed it on the list (wasn't me!).
Although I did not try to implement a complete algorithm in the first place, your treatment of the axes (I noted that deficiency in my code) and inclusion of possible offsets (I did not even think of those) are marked improvements. I also liked your clever treatment of the case when there is no xWave. It took me some time to understand your cases-with-fall-through trick (you need that for the break to work, right?) -- devious!
As you say, the mulOffset could be included, probably by replacing
V_...-offset...
with(V_...-offset...)/mulOffset...
, where the mulOffset can be read from yourinfostr
in a similar way as the offsets.I tried to play around with your code to make it "watertight", but encountered some additional difficulties due to the fact that Igor graphs can be complicated beasts:
(1) The graph marquee coordinates can be reversed if the axis limits are inverted (i.e., V_left > V_right, etc.).
(2) If traces have been appended using the /VERT flag, or if the axes have been swapped globally (
ModifyGraph swapXY=1
is in effect), the graph marquee coordinates can have unexpected values (e.g., V_left is a y value instead of an x value).(3) Things get nasty for unequally spaced xWaves (as you already surmised), they get really nasty if the xWave is unsorted. The difficulties hidden in both cases are easily checked if you draw a wave with the DrawWave tool. I think that a general algorithm should cover these cases as well.
Issues (1) and (2) hold, of course, for any algorithm but they might more benign in Rick Gerkin's original TraceFromPixel-grid algorithm (see mailing list) or with mine. Issue (3) seems difficult, if not untractable, with the FindLevel method. I'd be interested if you found a way through that quagmire.
Finally, your worry about the case where a wave is "only passing through" -- would you expect that case to be treated differently depending on the drawing mode?
If the mode is 3 (markers only), I would be taken aback as a user if a function includes traces with points clearly outside the marquee!
Wolfgang
August 15, 2010 at 04:18 pm - Permalink
Oh I see, then thanks to Holger. I hope he follows igorexchange as well as the mailing list...
Right.
Mmh, I must admit I haven't foreseen all these pitfalls indeed. I think in that case, the TraceFromPixel approach is the most robust one, simply because it iterates through all the pixels of the marquee.
I totally agree.
Unfortunately I have not enough time to play around with this.
But in the end you could use one of the three algorithms even if it doesn't consider all the strangest cases as long as you're aware of the constraints.
August 16, 2010 at 04:02 am - Permalink