How to get pixel's position of an image in UIAxis in AppDesigner?

42 views (last 30 days)
I have to show a very large image(the size is about [230,1e4~1e5]) with AppDesigner. And I want to get any pixel's X/Y position for later code. After some times' test, it could be displayed successfully with image(app.modelObj.Image,'Parent',app.PictureUIAxes); But I found the UIAxis controller can't support the datatip or datacursor tool any more...
So I try to set a customized call_back for the UIAxis to get the pixel's position when I click on it, or try to set a call_back attribute just like 'ButtonDownFcn' to active someting. But I don't know how to write the code. What should I do then?

Accepted Answer

Adam Danz
Adam Danz on 24 Jun 2020
Edited: Adam Danz on 26 Jan 2022
Description of the problem
The data cursor does not work for image objects plotted in App Designer (or in any uifigure) prior to r2020B. AppDesigner features are still being rolled out with every release of Matlab. For example, data tips have been implemented in r2020a. But for image objects, the datacursor still does not work (prior to r2020B).
Here is a demo of the problem using a legacy figure and a uifigure.
% Create image data
imageData = randi(100,10,12);
% Show image in legacy figure and turn on datacursor
fig = figure();
ax = axes(fig);
image(ax,imageData);
ax.Colormap = jet(100);
dcm = datacursormode(fig);
dcm.Enable = 'on';
title(ax, 'Legacy figure')
% Show the same image in uifigure and turn on datacursor
uifig = uifigure();
uiax = uiaxes(uifig, 'Position', [10 10 500 410]);
image(uiax,imageData);
uiax.Colormap = jet(100);
axis(uiax,'tight')
dcm = datacursormode(uifig);
dcm.Enable = 'on';
title(uiax,'uifigure')
As you can see, the datacursor appears as exected in the legacy figure but in the uifigure, a message appears, Unrecognized method. property, or field 'ColorSpace' for class 'matlab.ui.control.UIAxes'
Solution
Create a custom update function for the datacursor object within the UIAxes/UIFigure. This demo shows how to recreate the datacursor text produced in the legacy figure using UIFigures anbd UIAxes.
Continuing from the example above,
% Step 1: Turn on datacursor mode in the UIFigure
% uifig is the figure handle to the uifigure or the app
dcm = datacursormode(uifig);
dcm.Enable = 'on';
% Step 2: Define a custom UpdateFcn function
% uiax is the handle to the UIAxes
dcm.UpdateFcn = @(hObj,event,ax)localDcmFcn(hObj,event,uiax);
% Step 3: Write the UpdateFcn
% This should be added as an independent function within the app
function txt = localDcmFcn(~,event,ax)
% Compute index
idx = event.Target.CData(event.Position(2),event.Position(1));
% Create output text
txt = sprintf('[X,Y] [%d %d]\nIndex %d\n[R,G,B] [%.4g %.4g %.4g]', ...
event.Position, idx, ax.Colormap(idx,:));
end
Now the datacursor should appear the same in the legacy figure and the uifigure/app. The only difference may be the number of decimal places shown in the RGB values.
Solution using scaled images
Scaled images (i.e. imagesc()) must use different indexing that scales the CData values to the colormap values. This demo shows how to achieve similar results to the demo above using scaled images. Note that I.CDataMapping is scaled in the image object. This demo added on Jan 2022.
% Create image using imagesc()
Z = peaks;
X = linspace(0,2*pi,size(Z,2)); % Important: number of cols of Z
Y = linspace(0,2*pi,size(Z,1)); % Important: number of rows of Z
uifig = uifigure();
uiax = uiaxes(uifig);
I = imagesc(uiax,X,Y,Z);
uiax.Colormap = jet(100); % Any number of colors should work
axis(uiax,'tight')
colorbar(uiax)
% Step 1: Turn on datacursor mode in the UIFigure
% uifig is the figure handle to the uifigure or the app
dcm = datacursormode(uifig);
dcm.Enable = 'on';
% Step 2: Define a custom UpdateFcn function
% uiax is the handle to the UIAxes
dcm.UpdateFcn = @(hObj,event,ax)localDcmFcn(hObj,event,uiax);
function txt = localDcmFcn(~,event,ax)
% find indices to closest x and y data values. This requires the
% number of values in XData and YData to agree with CData size.
[~, xidx] = min(abs(event.Target.XData - event.Position(1)));
[~, yidx] = min(abs(event.Target.YData - event.Position(2)));
colorbarValue = event.Target.CData(yidx, xidx);
colormapIdx = round((colorbarValue - ax.CLim(1))/(ax.CLim(2)-ax.CLim(1)) * (size(ax.Colormap,1)-1) +1);
txt = sprintf('[X,Y]: [%.2g, %.2g]\nCBar Value: %.2g\n[R,G,B]: [%.4g, %.4g, %.4g]', ...
event.Position, colorbarValue, ax.Colormap(colormapIdx,:));
end
  15 Comments
Adam Danz
Adam Danz on 24 Feb 2022
@Hamidreza Heydarian, turn on datacursormode for the figure.
% R2020b
uif = uifigure();
uiax = uiaxes(uif);
imagesc(uiax,magic(9))
datacursormode(uif,'on')
Now you can click on the image to see the datatip.
josh sol
josh sol on 1 May 2022
i am trying to do this on a greyscale image and i want only the [X Y] position.
how can i do that?

Sign in to comment.

More Answers (0)

Categories

Find more on Develop uifigure-Based Apps in Help Center and File Exchange

Products

Community Treasure Hunt

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

Start Hunting!