Issues with CurrentPoint in R2021b

I am trying to track some user clicks within an axes that lives within a uifigure.
I was originally using CurrentPoint from the axes object, but I started to notice that in certain scenarios, the coordinates of CurrentPoint did not seem to be correct for where the mouse event happened. I did as much investigating as I could and found a possible solution in looking at the event IntersectionPoint property.
I can effectively use the IntersectionPoint property of the event for mouse down and up events and I get coordiantes that very closely match where I was trying to click.
I need something like IntersectionPoint that can be used withn mouse motion callbacks because CurrentPoint is off by a significant amount.
Here is what I have in all of my callbacks:
cp = get(obj.Axes,'CurrentPoint');
ip = evt.IntersectionPoint;
fprintf('Current Point: (%g,%g)\nIntersection Point: (%g,%g)\n\n',cp(1,1),cp(1,2),ip(1,1),ip(1,2));
Then when I execute clicks, attempting to click near (11,1200) on the axes, I get the follwing:
Current Point: (10.9365,1376.74)
Intersection Point: (10.9782,1196.9)

8 Comments

If you have a Minimum Working Example; it would be helpful to post it here.
I have an application using CurrentPoint and it works fine with R2021b.
May be your mouse is lagging for whatever reason, this might be another cause.
I added some more technicolor to what I have in my callbacks and what I am seeing. I can try to recreate this in a smaller example, but there is no way I could post the current implementation here.
Here is my code:
clc
close all
fig = figure;
ax = axes('Parent',fig);
set(ax,'ButtonDownFcn',@chekerrorcb);
text(ax,0.5,0.5,'click on the axes')
function chekerrorcb(ax, event)
p1 = event.IntersectionPoint(1,1:2);
p2 = ax.CurrentPoint(1,1:2);
d = p1-p2;
fprintf('%g\n',norm(d));
end
Run it then click randomly on the axes, I get this errors printed out
0.00362364
0.00362361
0.00362362
0.00362364
0.00362362
0.00362362
0.00362363
0.00362361
0.00362361
0.00362363
0.00362365
0.00362361
0.00362364
0.0036236
0.00362364
0.00362361
0.00362361
0.00362361
0.00362363
0.00362364
0.00362364
0.00362363
0.00158108
0.00362361
0.00362361
0.00362363
0.00362362
0.00362364
0.00362362
Consistently 3.6e-3 for a small windows of (0,1)x(0,1). That about one pixel.
I tried to create a simple example, but of course the problem doesn't replicate immediately so I need to work more on that. I did add this code to my callback and this is what I am getting.
Callback code:
function axesClick(obj,~,evt)
set(obj.Figure,'WindowButtonUpFcn','');
set(obj.Figure,'WindowButtonMotionFcn','');
cp = get(obj.Axes,'CurrentPoint');
ip = evt.IntersectionPoint;
fprintf('Current Point: (%g,%g)\nIntersection Point: (%g,%g)\nError: %g\n\n',cp(1,1),cp(1,2),ip(1,1),ip(1,2),norm(cp(1,1:2)-ip(1,1:2)));
end
With that as the callback and clicking in random spots, I get:
Current Point: (9.83083,1536.08)
Intersection Point: (9.92481,1191.75)
Error: 344.33
Current Point: (10.9211,1486.6)
Intersection Point: (11.015,1134.02)
Error: 352.577
Current Point: (11.7481,1412.37)
Intersection Point: (11.8421,1059.79)
Error: 352.577
Current Point: (12.1992,1173.2)
Intersection Point: (12.2932,820.619)
Error: 352.577
Current Point: (13.9286,1593.81)
Intersection Point: (14.0226,1241.24)
Error: 352.577
When watching where I click, I can say for certain that the InterserctionPoint is very close to where I am actually clicking.
Bruno Luong
Bruno Luong on 16 Dec 2021
Edited: Bruno Luong on 16 Dec 2021
What is obj in your case?
In my code the callback object is the axe handle. Your code doesn't clearly show that.
A snipet of code won't show exactly what you did.
This is all within a class. obj is my class object. obj.Axes is the handle to the axes within my uifigure, which is obj.Figure.
What if you call drawnow on top of your callback function? Also make sure the axes handle is the one you see on the screen, and not some hidden axes.
I tried sprinkling drawnows everywhere, including at the beginning of the callback and there were no differences.

Sign in to comment.

Answers (1)

We've seen issues in the past with CurrentPoint being slightly off, and we are investigating them. Can you provide a little more information about your particular setup and I'll add it to our internal report about this issue? Specifically:
  1. You said "CurrentPoint is off by a significant amount" but your reproduction steps show off by ~1 pixel. Have you experienced errors that are larger than 1 pixel before?
  2. In the code you posted you have an axes directly in a uifigure. Are you using anything else in the figure, like tabs, panels, uigridlayout, etc.? Is the axes always directly in the uifigure, or is it in another container inside the uifigure?
  3. Any reproduction code you have, with as much detail as you can include, will be helpful.
  4. Are you using the "Scrollable" feature of the uifigures?
  5. What platform are you using? Windows? Mac? Linux?
  6. What is the output from rendererinfo run on your axes?
  7. What is your screen resolution and pixel density?

7 Comments

I change my script to be able to display error for figure and uifigure, and obviously the problem lies on uifigure
function checkcperror(uiflag)
% uiflag: true to check uifigure; false old figure
close all
if uiflag
fig = uifigure('Name','uifigure');
ax = uiaxes('Parent',fig);
fprintf('Check for uifigure\n')
else
fig = figure('Name','figure');
ax = axes('Parent',fig);
fprintf('Check for figure\n')
end
set(ax, 'Units','normalize', 'innerposition',[0 0 1 1]);
set(ax,'ButtonDownFcn',@chekerrorcb);
text(ax,0.5,0.5,'click on the axes','HorizontalAlignment','center');
set(ax,'Unit','pixel');
end
function chekerrorcb(ax, event)
p1 = event.IntersectionPoint(1,1:2);
p2 = ax.CurrentPoint(1,1:2);
d = p1-p2;
ax.Units = 'pixel';
pos = get(ax,'Position');
dx = pos(3);
dy = pos(4);
fprintf('error = %g pixel\n',norm(d.*[dx dy]));
end
Results (R2021b, Windows 8 run on Remote Desktop):
>> checkcperror(false)
Check for figure
error = 0.58519 pixel
error = 0.585183 pixel
error = 0.585197 pixel
error = 0.5852 pixel
error = 0.585196 pixel
error = 0.585185 pixel
>> checkcperror(true)
Check for uifigure
error = 14.5491 pixel
error = 15.43 pixel
error = 14.549 pixel
error = 14.5491 pixel
error = 15.43 pixel
error = 16.3111 pixel
error = 15.43 pixel
error = 16.3111 pixel
error = 14.549 pixel
error = 14.5491 pixel
Also the error of 0.58 pixels seems odd even for figure. May be the rounding methods used or size of the axes are different for CurrentPoint and IntersectionPoint (not seems to be documented).
  1. In my testing, CurrentPoint is off by way more than 1 pixel. It seems to be off by about the size of any other rows in my uigridlayout, especially if I change the RowHeights dynamically (hiding/showing different rows that cause the axes to resize as well).
  2. In my actual code, I have the following tree: uifigure -> uigridlayout -> uigridlayout -> uipanel -> tiledlayout -> axes
  3. I have been unable to completely reproduce this is a smaller example. I am currently working with Mathworks Consulting for some related developments and I can demonstrate this behavior to them and have them pass it along.
  4. No
  5. Windows 10
  6. See below
  7. 2560x1080, 96 pixels per inch
Output of rendererinfo:
GraphicsRenderer: 'WebGL'
Vendor: 'Google Inc.'
Version: 'WebGL 2.0 (OpenGL ES 3.0 Chromium)'
RendererDevice: 'ANGLE (Intel(R) UHD Graphics 630 Direct3D11 vs_5_0 ps_5_0)'
Details: [1×1 struct]
Details:
HardwareSupportLevel: 'Full'
SupportsDepthPeelTransparency: 1
SupportsAlignVertexCenters: 1
SupportsGraphicsSmoothing: 1
MaxTextureSize: 16384
MaxFrameBufferSize: 16384
@Matt Butts: The issue with uigridlayout is a known bug in R2021b. Unfortunately, the only workaround I can suggest is to use IntersectionPoint (which is technically undocumented).
@Bruno Luong: You are correct, IntersectionPoint is undocumented, and your comment "Maybe the rounding methods used or size of the axes are different for CurrentPoint and IntersectionPoint" is exactly correct, but it is more than the rounding methods that are different, the method for calculating the CurrentPoint and IntersectionPoint are almost completely different.
At a very high level, CurrentPoint on the axes is derived by starting with the CurrentPoint on the figure (which may be rounded to the nearest pixel) and then applying transformations to the value to translate it into the axes data space. This is why it can sometimes have an error of roughly a pixel, due to rounding. In the case of uigridlayout, the wrong transformation is being applied in some cases, which can lead to the bigger errors that @Matt Butts is seeing. This is also why CurrentPoint works when you click outside the axes, and it is why the CurrentPoint doesn't know where you clicked in 3D space (for a 3D axes) but instead gives you the "front" and "back" coordinates.
IntersectionPoint on the other hand is being computed directly by the renderer based on where you clicked, which is why it doesn't work outside the axes, why it gives you a specific point in 3D, and why it can give different values from CurrentPoint (and why it isn't impacted by containers like uigridlayout).
Thanks Benjamin.
I ended up calculating an error for CurrentPoint in the ButtonDown callback based on the difference between IntersectionPoint and CurrentPoint and then using that difference to correct CurrentPoint in the motion callback (since we don't seem to get IntersectionPoint in the mouse movement callbacks). This seems to be working pretty well.
FWIW, I test to plot both coordinates returned by CurrentPoint and IntersectionPoint on the same axes and in all the cases CurrentPoint can correctly follow the mouse and IntersectionPoint cannnot. That is fine with me as I use CurrentPoint currently. I'm in the opposite situation than you Matt.
Here is the function with plot. In my case the difference is 3 pixels for uifigure and 0.7 pixel for figure. CurrentPoint returns correct values as stated ealier.
function checkcperror(uiflag)
% uiflag: true to check uifigure; false old figure
if nargin < 1
uiflag = true;
end
close all
if uiflag
name = 'uifigure';
fig = uifigure('Name', name);
ax = uiaxes('Parent',fig);
else
name = 'figure';
fig = figure('Name', name);
ax = axes('Parent',fig);
end
fprintf('*** Check for %s ***\n', name)
h = plot(ax,nan(3,2),nan(3,2));
legend(h, 'IntersectionPoint', 'CurrentPoint');
axis(ax,[0 1 0 1]);
set(ax, 'Units','normalize', 'innerposition',[0 0 1 1]);
set(ax,'ButtonDownFcn',@(ax,event) chekerrorcb(ax,event,h));
text(ax,0.5,0.5,sprintf('%s click on the axes', name), ...
'HorizontalAlignment','center');
end
function chekerrorcb(ax, event, h)
drawnow
ip = event.IntersectionPoint(1,1:2);
cp = ax.CurrentPoint(1,1:2);
d = ip-cp;
ax.Units = 'pixel';
pos = get(ax,'innerposition');
dx = pos(3);
dy = pos(4);
dpxl = d.*[dx dy];
fprintf('error = %g pixel\n',norm(dpxl));
set(h(1),'XData',[get(h(1),'XData') ip(1)]);
set(h(1),'YData',[get(h(1),'YData') ip(2)]);
set(h(2),'XData',[get(h(2),'XData') cp(1)]);
set(h(2),'YData',[get(h(2),'YData') cp(2)]);
set(ax, 'Units','normalize', 'innerposition', [0 0 1 1]);
axis(ax,[0 1 0 1]);
drawnow
end
Hello I have the same problem only when the uiaxes is in a couple nested gridlayouts

Sign in to comment.

Products

Release

R2021b

Asked:

on 15 Dec 2021

Commented:

on 12 Jul 2023

Community Treasure Hunt

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

Start Hunting!