ginput and 'CurrentPoint' property do no match real axes coordinates
12 ビュー (過去 30 日間)
古いコメントを表示
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 件のコメント
Adam Danz
2020 年 6 月 15 日
編集済み: Adam Danz
2020 年 6 月 15 日
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])
採用された回答
Adam Danz
2020 年 6 月 16 日
編集済み: Adam Danz
2020 年 10 月 14 日
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 件のコメント
Adam Danz
2020 年 6 月 19 日
"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.
その他の回答 (0 件)
参考
カテゴリ
Help Center および File Exchange で Data Exploration についてさらに検索
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!