Adapt to user zooming into axis
thomas_braun
I have a graph with some data, attached to it a free axis and an axis hook function. The axis hook function should run some code whenever a user zooms in or out of an trace/image.
Fuction Setup()
Make/O data = p
Make/O largedata = p + 100
End
Function AxisHook(s)
STRUCT WMAxisHookStruct &s
print "called with", s
End
Window Graph0() : Graph
PauseUpdate; Silent 1 // building window...
Display /W=(95.25,263,612,634.25) data
NewFreeAxis/O/L test
ModifyFreeAxis/Z test,master= bottom,hook= AxisHook
ModifyGraph nticks(test)=0
ModifyGraph axThick(test)=0
ModifyGraph lblPos(left)=47
ModifyGraph freePos(test)=-50
SetAxis left -7.63192488262911,144.768075117371
EndMacro
Make/O data = p
Make/O largedata = p + 100
End
Function AxisHook(s)
STRUCT WMAxisHookStruct &s
print "called with", s
End
Window Graph0() : Graph
PauseUpdate; Silent 1 // building window...
Display /W=(95.25,263,612,634.25) data
NewFreeAxis/O/L test
ModifyFreeAxis/Z test,master= bottom,hook= AxisHook
ModifyGraph nticks(test)=0
ModifyGraph axThick(test)=0
ModifyGraph lblPos(left)=47
ModifyGraph freePos(test)=-50
SetAxis left -7.63192488262911,144.768075117371
EndMacro
Now this works for my use case.
But when I add more data to it via
AppendToGraph largeData
my hook function get's also called. But I would like to distinguish the case of users zooming into the axis and code changing the axis limits. Or to rephrase I actually want to run the code *only* when the user zooms in/out interactively and not when doing it programmatically.
Is that possible? Am I doing it right?
Hmm, that is surprisingly difficult. There seems to be no way to tell from the axis hook what event called the hook function. I came up with a somewhat kludgy workaround which saves the latest axis scaling in the graph's user data and only calls code if the axis range has changed (which happens when zooming):
STRUCT WMAxisHookStruct &s
String putRange, lastZoom = GetUserData(s.win,"","axisRange")
sprintf putRange, "%f;%f;", s.min, s.max
SetWindow $(s.win), userdata(axisRange)=putRange
Variable zoomCall = 0
if (strlen(lastZoom) > 0)
Variable left = str2num(StringFromList(0,lastZoom))
Variable right = str2num(StringFromList(1,lastZoom))
if ( ((left - s.min) > 1e-6) || ((right - s.max) > 1e-6))
zoomCall = 1
endif
endif
if (zoomCall)
print "called with", s
endif
End
November 5, 2020 at 04:51 pm - Permalink
Unfortunately, the axis range changes when you add a trace with different range, and also when the user changes the axis range.
November 5, 2020 at 04:56 pm - Permalink
Oh, that's right! So my example was not very useful. That's really an uphill battle, but one could use the same method to store a list of displayed traces on the graph and compare if something has changed between calls. I don't see how one can distinguish user's zooming in from any other event which changes the axis range.
November 5, 2020 at 05:03 pm - Permalink
You may need to have a button to turn the zoom feature (your hook function) on/off.
You may need to lock out any ability to manually add data to the graph and instead force the user to run a function instead (e.g. myappendtograph).
Doesn't Igor give an option to know what the last issued command was? Can that be tested in the hook function to distinguish a command-line input appendtograph and thereby ignore break from the hook?
Of these three, I might find the first the easiest to do even as it adds the overhead for the UI on the user.
November 5, 2020 at 05:15 pm - Permalink
Thanks all for your input. I've now found a solution. I've ditched the axis hook approach and went with a normal window hook. The code is basically
STRUCT WMWinHookStruct &s
string traceGraph
switch(s.eventcode)
case 22: // mouse wheel
case 6: // resize
traceGraph = s.winName
Execute/P/Q "PA_UpdateScaleBars(\"" + traceGraph + "\", 0)"
break
case 10: // menu
if(!cmpstr(s.menuName, "Graph") && !cmpstr(s.menuItem, "Autoscale Axes"))
traceGraph = s.winName
Execute/P/Q "PA_UpdateScaleBars(\"" + traceGraph + "\", 1)"
endif
break
endswitch
return 0
End
where PA_UpdateScaleBars reacts to the user zooming into an axis via the mouse wheel, and the menu reset the scale bars on Ctrl+a. I had to use the operation queue here so that it is executed after the axis has been rescaled by IP.
November 15, 2020 at 07:43 am - Permalink