Possible bug (?): AxisValFromPixel

Dear Igorians,

Consider the following snippet:

function thunk_do()
    make/o/n=100 a = gnoise(100)
    make/o/n=50  b = gnoise(100)
   
    string s_name = ("Graph" + hash( date()+time(),1 ))[0,30]
    display/k=1/n=$s_name b vs a
   
    setwindow $s_name, hook(modified)=thunk_hook_onmodify
end

function thunk_hook_onmodify(s)
    struct WMWinHookStruct &s
   
    strswitch(s.eventname)
           
        case "mousemoved":
            string s_pixel_y
            string s_pixel_x
           
            sprintf s_pixel_y, "%d.%d", s.mouseloc.v, s.mouseloc.h
            sprintf s_pixel_x, "%d.%d", s.mouseloc.h, s.mouseloc.v
                   
            variable v_y = AxisValFromPixel(s.winname, "left", str2num(s_pixel_y))
            variable v_x = AxisValFromPixel(s.winname, "bottom", str2num(s_pixel_x))
           
            printf "coords (y,x): (%3.3f,%3.3f)\r", v_y, v_x
            break
   
        case "kill":
            setwindow $s.winname, hook(modified)=$""
            break
    endswitch
end


and specifically, the following lines:

            sprintf s_pixel_y, "%d.%d", s.mouseloc.v, s.mouseloc.h
            sprintf s_pixel_x, "%d.%d", s.mouseloc.h, s.mouseloc.v
                   
            variable v_y = AxisValFromPixel(s.winname, "left", str2num(s_pixel_y))
            variable v_x = AxisValFromPixel(s.winname, "bottom", str2num(s_pixel_x))


While not the most elegant way of getting a pixel, both s_pixel_y and s_pixel_x are needed as AxisValFromPixel does not return the expected value for the "same" pixel applied to a different axis.

Put simply, is this a bug or "desired behaviour"™?

Btw, is this the best way of getting/representing a pixel? Seems rather odd if it is.

best,
_sk
You can use getMouse. For example:

getMouse/W=$(s.winname)
           
v_y = AxisValFromPixel(s.winname, "left", V_top)
v_x = AxisValFromPixel(s.winname, "bottom", V_left)
 
printf "mouse (y,x): (%3.3f,%3.3f)\r", v_y, v_x

KurtB wrote:
You can use getMouse. For example:

getMouse/W=$(s.winname)
           
v_y = AxisValFromPixel(s.winname, "left", V_top)
v_x = AxisValFromPixel(s.winname, "bottom", V_left)
 
printf "mouse (y,x): (%3.3f,%3.3f)\r", v_y, v_x


Thanks, but getmouse is unnecessary. The mouse location is already in the event structure as indicated above, namely:  s.mouseloc.v, s.mouseloc.h

I was asking why axisvalfrompixel doesn't use the same pixel as represented by:
sprintf s_pixel, "%d.%d", s.mouseloc.v, s.mouseloc.h
variable v_pixel = str2num(s_pixel)


to get the values from both axis? It is the same pixel whichever way it is "represented". To me, it seems like the logical thing to do. And the best thing to do would be for axisvalfrompixel to just use the struct of the event, s.mouseloc, thus:

variable v_y = axisvalfrompixel(s.winname, "left", s.mouseloc)
variable v_x = axisvalfrompixel(s.winname, "bottom", s.mouseloc)

When dealing with pixels or points I always try to divide or multiply with ScreenResolution/72 that fixes most of my problems. I have no idea if that will fix your problem.
Try this instead:
function thunk_hook_onmodify(s)
    struct WMWinHookStruct &s
 
    strswitch(s.eventname)
 
        case "mousemoved":
            variable v_y = AxisValFromPixel(s.winname, "left", s.mouseloc.v)
            variable v_x = AxisValFromPixel(s.winname, "bottom", s.mouseloc.h)
 
            printf "coords (y,x): (%3.3f,%3.3f)\r", v_y, v_x
            break
 
        case "kill":
            setwindow $s.winname, hook(modified)=$""
            break
    endswitch
end


If you're calling AxisValFromPixel with a vertical axis (left or right), you only need to pass the vertical value of the pixel. Likewise, with a horizontal axis (top or bottom) you only need to pass the horizontal value of the pixel.
aclight wrote:

If you're calling AxisValFromPixel with a vertical axis (left or right), you only need to pass the vertical value of the pixel. Likewise, with a horizontal axis (top or bottom) you only need to pass the horizontal value of the pixel.


Yes, of course this is going to work. My point is that the user of the AxisValFromPixel function shouldn't need to specify twice which value needs to be return: first time with the axis ("bottom", "left") and second time with the offset ("horizontal", "vertical"). If the function AxisValFromPixel knows that the user is passing the "bottom" axis (or axistype is bottom), I think only values with respect to this axis can be calculated. Respectively, only a particular value of the mouse position is needed, but this value is predetermined by the axis alone. Thus my suggestion for passing the struct, mouseloc.v, mouseloc.h. On top of that, a common consumer for AxisValFromPixel are event loops, and in this case mouseloc is already a substruct of the event.

A second point is that this is not a pixel, as suggested in the documentation, but the _offset distance_ of the mouse cursor (either horizontal or vertical) with respect to the window top-left corner.

Anyways, I hope somebody finds all of this helpful.

best,
_sk
Igor doesn't support global structures, so if AxisValFromPixel took a Point structure parameter instead of a variable, it wouldn't be possible to call it from the command line. Also, if your scenario, AxisValFromPixel would need to return two values. It could do so by returning a structure, but built-in functions don't return structures, partially because structures cannot be global. It could return a string list of values, but that's pretty clunky. It could return two actual values, but that's not supported in Igor 7 and below. So there's no good alternative other than returning a single value. If you want to know the value on both axes, you need to call the function twice.

I agree that the wording of the AxisValFromPixel help topic is a little vague.
aclight wrote:
Igor doesn't support global structures, so if AxisValFromPixel took a Point structure parameter instead of a variable, it wouldn't be possible to call it from the command line.

I didn't know. Anyways this is the least important thing.

aclight wrote:
Also, if your scenario, AxisValFromPixel would need to return two values.

Why do you say that? I think this isn't right. You pass the point struct and depending on the axis you selected you return the value for that axis. Simple as that. What you gain is that you don't need to memorize which value you pass as the offset, the proposed axisvalfrompixel does that for you.

aclight wrote:
... If you want to know the value on both axes, you need to call the function twice.

How is this different from the way it is now?

Anyways, the discussion is moot. Thanks again for the help.

best,
_sk