ginput and 'CurrentPoint' property do no match real axes coordinates

This is a very strange problem. I am creating a GUI with many overlapping patches objects. I also changed the XLim and YLim properties to make the axes square and to show all the patches. As the mouse moves over the axes, I use the CurrentPoint property to display the current mouse coordinates. But it seems the axes is offset to the right by a certain amount. If I plot a marker at 0,0, it is correclty plotted at the center of the axes. However, if I use ginput() at the center of the axes, it does not return (0,0), it instead returns (0.3185, 0).
I have noticed that the number 0.3185 is a multiple of 0.1593 and that ginput always returns multiples of 0.1593. So I believe 0.1593 is the axes maximum resoution, accordingly to the axes limits I am currently using.
Can someone explain why there is this offset of 0.3185 in the x-direction of my axes? And why is the data plotted correclty, while ginput and 'CurrentPoint' give wrong results?
Im using R2017b
Regards,
André

2 Kommentare

I'm getting something similar. The axes below has lines at x=0 and y=0 and you can see my ginput crosshairs overlap then well. But the small error could be real - my crosshairs may be 0.0023 units to the right of true-0.
axes()
xlim([-1 1])
ylim([-1 1])
xline(0)
ylin(0)
ginput(1)
% Results (on two indpendent tests)
ans =
0.0023041 0
However, when I zoom in and repeat the process, I get much smaller error.
xlim([-0.001, 0.001])
ylim([-0.001, 0.001])
André
André am 15 Jun. 2020
Bearbeitet: André am 15 Jun. 2020
Yeah, the ammount of error depends on the limits you are using. The wider the limits, the larger the error value.
Did you notice if the values you obatin using ginput() are common multiples of a base value?
Edit: I tried now with limits from [-1000, 1000]
Using ginput at the origin, I obtain
2.3041 -0.0000
I did some measurements around the origin and obtained the following:
2.3041 -0.0000
2.3041 -5.8309
6.9124 -5.8309
16.1290 -5.8309
11.5207 -11.6618
6.9124 -11.6618
If I divide by the first element, I obtain:
1.0000 -0.0000
1.0000 -2.5306
3.0000 -2.5306
7.0000 -2.5306
5.0000 -5.0612
3.0000 -5.0612
In the x-direction all values are multiples of 2.3041 (which is 1000 times the value you obtained, so the error is not yours).
I also tested the 'CurrentPoint' property of the axes (using a cross plotted at the origin to guide me) and obtained exacty the same results.
ans =
2.3041 -0.0000 1.0000
2.3041 -0.0000 -1.0000
This clearly demonstrates that there is a bias with ginput() and the 'CurrentPoint' property in the x-direction. On the other hand, the y-direction seems to be OK, despite the values seeming to be now multiples of 5.8309, which proves that the resolution of the axes is different for each direction.

Melden Sie sich an, um zu kommentieren.

 Akzeptierte Antwort

Adam Danz
Adam Danz am 16 Jun. 2020
Bearbeitet: Adam Danz am 14 Okt. 2020
Written in r2020a update 3
Symptoms of the problem
The current mouse position within an axes (ax.CurrentPoint) has a limit of precision such that the true (0,0) coordinate (and other specific coordinates) cannot be manually selected from the CurrentPoint property along the x axis.
Demonstrating the problem
The code below creates a square axes with axis limits from -1:1 and dashed crosshairs at x=0 and y=0 for reference. The figure contains a WindowButtonMotionFcn that updates text in the upper, left corner of the axes indicating the current mouse position within the axes. A second line of text ("delta") shows the distance between the previous and current mouse position. It also contains blue crosshairs that follow the current mouse position.
With a sensitive mouse and some patience, align the blue crosshairs with the reference lines at (0,0) and you'll notice that the current y-coordinates matches y=0 but the current x-coordinate cannot match x=0.
figure()
ax = axes('FontSize', 20, 'XTick', -1:.2:1, 'YTick',-1:.2:1);
axis equal
xlim([-1 1])
ylim([-1 1])
xline(0, 'k--')
yline(0, 'k--')
grid on
th = text(min(xlim), max(xlim), '', 'FontSize', 16, 'VerticalAlignment', 'top');
crosshairs(1) = xline(max(xlim),'b--');
crosshairs(2) = yline(max(ylim),'b--');
set (gcf, 'WindowButtonMotionFcn', {@mouseMove, th, ax, crosshairs});
hold on
drawnow
function mouseMove(~, ~, th, ax, crosshairs)
persistent cursorPos
if ~isempty(cursorPos)
delta = abs(cursorPos - ax.CurrentPoint(1,1:2));
else
delta = [nan, nan];
end
cursorPos = ax.CurrentPoint(1,1:2);
th.String = sprintf('(%.5f, %.5f)\n(%.5f, %.5f) delta', ax.CurrentPoint(1,1:2), delta);
crosshairs(1).Value = ax.CurrentPoint(1,1);
crosshairs(2).Value = ax.CurrentPoint(1,2);
end
In the example below, the cursor is as close as possible to (0,0) and the error between the perceived coordinate and the actual selected coordinate is at 0.00122.
Magnitude and direction of the error
The magnitude and direction of the error between the perceived selected coordinate and the actual selected coordinate depends on
  • Axis size
  • Figure size (when axes resize with the figure)
  • Axis limits
  • Axis aspect ratio
  • Monitor resolution
  • Location of the selected coordinate within the same axes.
Change any of those properties and the magnitude and direction of the error will likely change. Since the error changes with different coordinates within the exact same axes, the magnitude and direction of error cannot be corrected. However, zooming into an area of interest and reducing the range of axis limits will decrease the magnitude of the error.
The cause of the problem
The precision of coordinate selection is limited by the arrangement of pixels on your monitor. When you select a point, you are selecting a pixel. That pixel will often have a relatively small offet from the actual coordinate you intended to select. Zooming into the axes is equivalent to decreasing the pixel size relative to the axes which increases precision. The problem is analgous to roundoff error.
Going back to the demo figure above, the mouse is as close as possible to (0,0) but the current coordinate reads (0.0012, 0.0000). If we add a marker at that location and another marker at (0,0), the two coordinates are indistinguishable while holding the axis and figure properties constant.
plot(0.0012, 0.0000, 'rx','MarkerSize', 20)
plot(0.0000, 0.0000, 'bx','MarkerSize', 12)
You can see that blue x is directly on the red x even though they have slighly different coordinates. Then, zoom into that point and you will see that they separate. This demonstrates the limit or precision at different axis scales.
Zoom into the axes, the difference between the two coordinates becomes visible.
xlim([-.01, .01])
ylim([-.01, .01])
Solution to the problem
In short, there is no simple solution. I suppose MathWorks could recalibrate the bias such that (0,0) can always be selected, but that would only fix the error at that coordinate.
Since the error is different for different coordinates within the same identical axes, you cannot simply measure a constant bias and offset all selected coordinates by that bias.
The only way to increase precision is by zoom into the region of interest and selected the coordinate within a narrow range of axis limits.
If selecting specific targets such as (0,0) is important, you could compute the distance between the CurrentPoint and all targets and select the target closest to the point.
Lastly, buying a monitor with higher resolution will also decrease, but not eliminate, the error.

10 Kommentare

I reported this to MathWorks and they can decide whether this is something that needs addressed or not.
André
André am 16 Jun. 2020
Bearbeitet: André am 16 Jun. 2020
Thats exaclty what I did. I found out the bias and then used it to correct the problem. In my case tough I had to shift by 3 times the bias, not just one, This suggests there are other factors affecting the offset. For example, a similar GUI I made before seems to be almost ok, while the one I am working right now has a huge bias, despite the data plotted being practically the same. I tried to control factors such as the number of axes in the panel, the units of the panel, the presence of a background image, but nothing changed the bias.
The need to shift by 3x the bias sounds like either
  1. the minimal bias wasn't measured/estimated precisely or,
  2. the bias changed between the time it was measured and the time it was applied, by a factor of ~3. Note the short list of axis and figure properties I mentioned in my answer that affect the magnitude of the bias.
Some cautionary points to consider if applying a fixed constant offset (such as 3x the estimated bias)
  1. The magnitude of the bias seems to be quite sensitive to the plotting properties so running the code on a different monitor or any slight adjustments to axis limits etc will result in erroneous corrections.
  2. If this problem is ever fixed by MathWorks in the future, you may forget to un-fix the band aid.
Also keep in mind that mouse tracking precision is limited by the mouse itself and the user's ability to precisely selected a coordinate. So if the user should select from a set of key coordinates within the axes, it would be better to set a threshold distance between the CurrentPoint and the coordinate such that when the distance is less than the threshold, the selected coordinate is automatically change to the target coordinate. The threshold should be some value a little larger than the estimated precision limits.
Also, take note of the "Consistency across figure types and platforms" section I just added to my answer.
No need to select points. My plot is a 2D map of the retina which automatically displays each component of the solid angle of the visual field as the mouse moves over it. The only way to fix this is by knowing the bias a priori. Actually I saved the bias in a variable that is later loaded by the GUI. If something changes I will have to update it.
André, I fear that adjusting the selected coordinates by a fixed offset is a mistake. No matter what you do, there will always be a limit to the precision of coordinates selected by a mouse. If you zoom in, the precision increases but other than that, there's no easy way around it. If the user doesn't need to select pre-established coordinates such as (0,0), I wouldn't mess with any offsets. If you need higher precision, zoom into parts the axes. I have doubts that precision really matters in the first place if humans are selecting points by clicking on them with a mouse. Computers do a much better job at that than humans.
More importantly, the error between the perceived selected coordinate and the resultant coordinate seems to be non-linear. The two plots below show two different offset values within the same axes! At (0,0) the bias is +0.00122 but at (.2,0) it's -0.00098! Not only has the magnitude changed but the direction of the bias changed as well! If you offset all selected coordinates by a constant, you're likely adding external error, not reducing it.
My plot is static and no points need to be selected. After creating it, I won't change the limits anymore. As long as I do that the offset does not change.
Anyway thank you for the tips.
Lets hope this issue is solved soon.
Adam Danz
Adam Danz am 18 Jun. 2020
Bearbeitet: Adam Danz am 18 Jun. 2020
But I showed above that the offsets do change within the same exact plot when sampled at different areas of the plot. The offset at (0.2,0) had a different magnitude and was in the opposit direction to the offset at (0,0). Perhaps with large axis limits, the difference between the offsets is too small to see. Or maybe under certain conditions the offsets are constant. It's not clear to me.
In my case, the worst error I could find was 0.01 degrees, so it is fine. Anyway I will keep monitoring it.
@André , I heard back from the developers who confirmed my suspicions.
"The issue starts with rounding of the point to the nearest pixel, and there are inherent discretizations in the internal calculation of CurrentPoint which prevent the user from being able to select this [or any] specific point." I added the part in brackets.
This is related to the roundoff error which I referenced (and provided a link) in my answer.
That also explains why the error between the perceived selected point and the actual selected pixel will not be the same for each coordinate in the axes. If you are offsetting the values by a constant rate, you are adding error to the selected values.
I can't emphasize this enough. The only want to reduce the error is by zooming into the regon of interest. Subtracting (or adding) a constant to every selected point only minimizes error at the coordinate where the "bias" was measured.

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (0)

Kategorien

Mehr zu Data Exploration finden Sie in Hilfe-Center und File Exchange

Gefragt:

am 15 Jun. 2020

Bearbeitet:

am 14 Okt. 2020

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by