[inf] to reference last trace added to graph
serrano
I often find myself trying to modify the appearance of a trace just after adding it to a graph. For this, I'd like an easy way to reference the last trace that was added to a graph.
Unless I'm missing something, the following doesn't work as expected:
Modifygraph lsize[inf] = 5
Right now, I'm using something like
Static Function/S LastAddedTraceName([win])
String win
win = selectstring(paramisdefault(win),win,"")
return stringfromlist(itemsinlist(TraceNameList(win, ";", 1))-1, TraceNameList(win, ";", 1))
End
String win
win = selectstring(paramisdefault(win),win,"")
return stringfromlist(itemsinlist(TraceNameList(win, ";", 1))-1, TraceNameList(win, ";", 1))
End
to call
Modifygraph lsize($lastaddedtracename())=5
but this is slow because of the string parsing.
Is there a better way? I understand that I could just extract the number of traces in the graph to save a bit of the string parsing, and use the [] syntax instead of the () syntax, but this is still tedious.
For the wishlist, I'd like to suggest: Have [inf] reference the last added trace.
A better way might be to simply right-click the trace and choose a new color from the popup menu.
April 5, 2019 at 04:12 pm - Permalink
This should bypass the need for a loop.
wave ww
variable ls, ...
string ...
string tname
appendtograph ww
tname = StringFromList(inf,TraceNameList(...))
modifygraph lsize($tname)=ls
return 0
end
We might also ask for the ability to change a trace name.
wave ww
variable ls, ...
string ...
string tname, tmpname = "recent"
tname = ... // set a name for the trace
appendtograph/TN=$tmpname ww
modifygraph lsize($tmpname)=ls
RenameTrace $tmpname, $tname // <-- DOES NOT EXIST (but may provide other useful options)
return 0
end
April 7, 2019 at 11:56 am - Permalink
Thanks for the suggestions, guys.
Unfortunately, right-clicking wouldn't work for me as I'm doing this in a script that sometimes adds >100 traces.
I was looking at JJ's suggestion and noticed that
print stringfromlist(inf,"one;two;three;")
didn't give me the last element of the list as I was hoping for. This means it would need the same clumsy
stringfromlist(itemsinlist(…)-1,…)
syntax that I was using.
I also realized that some of my issues came from the rather slow performance of stringfromlist and/or itemsinlist, which I had only tested on Igor 7. This improved quite a bit on Igor 8.
However, I still would argue that something
Modifygraph lsize[inf] = something
would be a lot easier and cleaner.
April 8, 2019 at 12:26 am - Permalink
This may not be the answer to your specific problem, but for anyone wondering why every new trace is plotted with the same appearance as the previous one, there are two useful ways to change this:
To set graph preferences so that newly added traces follow a pattern of styles:
displayHelpTopic "Graph Preferences"
To adjust trace styles after plotting many traces:
Graph > Packages > Make Traces Different
April 8, 2019 at 02:26 am - Permalink
It seems we might be in need of a few new features ...
* Problem: We have to invoke multiple steps to track the names of the traces that were just added to a graph as well as the last added trace name
Answer: The operations appendtograph and display should generate globals S_tracenames and S_lasttracename to document the list of traces generated and the last one added.
* Problem: We have to get invoke nested calls to multiple functions to get the last item in list functions.
Answer: StringFromList and other list functions accept "magic" token of lastitem in the index count (as well as lastitem - N to count backward when needed)
Additional Answer: ReverseList(...) -- function to reverse the order of a list (since index = 0 works but index = inf does not)
* Problem: We can name traces at the moment when they are added but we cannot rename them without removing them and re-adding them.
Answer: RenameTrace ... -- operation to rename a trace on a graph
April 8, 2019 at 01:34 pm - Permalink
You may find this of use:
String graphName
if (strlen(graphName) == 0)
graphName = WinName(0,1) // Top graph
endif
if (strlen(graphName) == 0)
return -1 // No such graph
endif
String list = TraceNameList(graphName, ";", -1)
Variable numItems = ItemsInList(list)
return numItems -1 // -1 if there are no traces in the graph
End
Function Demo()
Make/O jack=sin(x/8), joe=cos(x/8)
Display jack, joe
ModifyGraph lsize[LastTraceIndex("")] = 5
End
April 8, 2019 at 10:01 pm - Permalink
In reply to You may find this of use: … by hrodstein
I'll have to take back my statement that my code runs faster on Igor 8. I think the problem is mostly that TraceNameList is slow, especially if many traces are involved (as there are in my case), see the following example that uses hrodstein's code:
Function Demo()
Variable MaxWaves = 1000
ColorTab2Wave Rainbow
Wave M_colors
Setscale/I x, 0, MaxWaves-1, M_colors
Display/N=Win
Variable i
for(i=0;i<MaxWaves;i+=1)
Make/O/N=(100) $("Wave"+num2istr(i))/Wave=w
w=i
AppendToGraph/W=Win w
Modifygraph rgb[LastTraceIndex("Win")] = (M_colors(i)[0], M_colors(i)[1], M_colors(i)[2])
endfor
End
Function LastTraceIndex(graphName)
String graphName
if (strlen(graphName) == 0)
graphName = WinName(0,1) // Top graph
endif
if (strlen(graphName) == 0)
return -1 // No such graph
endif
String list = TraceNameList(graphName, ";", -1)
Variable numItems = ItemsInList(list)
return numItems -1 // -1 if there are no traces in the graph
End
FunctionProfiling of Demo() gives:
April 9, 2019 at 04:11 am - Permalink
Unfortunately, that long time is not surprising.
Finding a trace name is an n-squared problem due to need to determine the instance number. Any built-in routine to get the name of the last trace will also take pretty much the same time. This includes the idea of saving the name as traces are added.
So, the original idea of some syntax that specifies the last trace without needing a name, is a good idea. If traces could be accessed by numeric index, we could use -1 to access the last and -2 to access the next to last etc.
April 9, 2019 at 08:30 am - Permalink
The following two changes execute in about 0.1 s on my machine:
Variable MaxWaves = 1000
KillWindow/Z Win
ColorTab2Wave Rainbow
Wave M_colors
Setscale/I x, 0, MaxWaves-1, M_colors
Display/N=Win
Variable i
String thisName
for(i=0;i<MaxWaves;i+=1)
thisName = "Wave"+num2istr(i)
Make/O/N=(100) $(thisName)/Wave=w
w=i
AppendToGraph/W=Win w
Modifygraph rgb($thisName) = (M_colors(i)[0], M_colors(i)[1], M_colors(i)[2])
endfor
End
Function Demo2()
Variable MaxWaves = 1000
KillWindow/Z Win
ColorTab2Wave Rainbow
Wave M_colors
Setscale/I x, 0, MaxWaves-1, M_colors
Display/N=Win
Variable i
String thisName, thisTraceName
for(i=0;i<MaxWaves;i+=1)
thisName = "Wave"+num2istr(i)
thisTraceName = "trace_" + thisName
Make/O/N=(100) $(thisName)/Wave=w
w=i
AppendToGraph/W=Win w /TN=$(thisTraceName)
Modifygraph rgb($thisTraceName) = (M_colors(i)[0], M_colors(i)[1], M_colors(i)[2])
endfor
End
Both of these rely on the fact that at least in your example you know what the name of the trace will be when you append it to the graph (either because you specify it with /TN in Demo2 or you know the name of the wave and that there are no other instances of a trace with the same name in Demo1). Since you know the trace's name, you can pass that directly with ModifyGraph.
Another possibility would be to call TraceNameList before your loop to determine the number of traces already on the graph. Then after you append each trace, increment the value by 1. Then you can always use the correct trace number in the ModifyGraph command but you only need to call TraceNameList once.
April 9, 2019 at 09:06 am - Permalink
In reply to Unfortunately, that long… by Larry Hutchinson
Traces can be accessed by numeric index.
DisplayHelpTopic "ModifyGraph for Traces" // See "This syntax is used for style macros"
April 9, 2019 at 10:17 am - Permalink
Thanks guys. The /TN workaround did the job for me.
It would still be very convenient if the suggestion of being able to address indices "from the end" would be implemented in a future version of Igor.
April 12, 2019 at 01:10 am - Permalink