I'd like to plot some points over an image in a dialog.

3 views (last 30 days)
I want to be able to select one point with a left-click, a second point with a right-click, but I'm running into all sorts of trouble.
This dialog calls nested function replot() on creation, and in the ButtonDownFcn() callback.
In this form, the image never shows up but the points do. If I un-comment the colormap line, everything looks right when the dialog is opened, but the image disappears again when the callback triggers.
To boot, I can't debug effectively because breakpoints inside replot() don't work.
The heck is going on? Alternatively, is there a better, lightweight way to accomplish this?
im = rgb2gray(imread('peppers.png'));
stats(1).Centroid = [260 260];
stats(2).Centroid = [350 260];
dHandle = cDialog(im,stats);
function d = cDialog(im, stats, d)
ddims = size(im).*1.5;
if nargin < 3
dp = [50 50 51+fliplr(ddims)];
else
dp = d.Position;
end
d = dialog('Units','pixels','Position', dp, ...
'Name','Confirm Selections');
ax = uiaxes('Parent',d,...
'Units','pixels',...
'Position',[25 10 dp([3,4])-25],...
'Visible','off');
ax.Title.String = 'Confirm or Select points (Left- & Right-click)';
% Show the current points
replot;
uiwait(d);
%%% Nested functions
function replot
hold(ax,"off")
image(im,'Parent',ax,'ButtonDownFcn',@clicked);
drawnow
hold(ax,"on")
% colormap(ax,parula);
pts = {stats(1).Centroid;stats(2).Centroid};
if ~isempty(pts{1})
scatter(ax,pts{1}(1),pts{1}(2),'bo','filled')
end
if ~isempty(pts{2})
scatter(ax,pts{2}(1),pts{2}(2),'ro','filled')
end
end
function clicked(~,event)
switch event.Button
case 1
stats(1).Centroid = event.IntersectionPoint([1 2]);
case 3
stats(2).Centroid = event.IntersectionPoint([1 2]);
otherwise
end
replot;
end
end
  3 Comments
Jan
Jan on 28 Jan 2023
@Chris: Please do not use notifications to attract specific users. I've read your question before and do not understand, what you want to achieve and have no idea, what I could answer. Now I got your notification, read the question again, found out, that it does not contain new information and still cannot help you. So this was a waste of time.
Imagine what will happen, if all users send notification to some preferred members: They will drown in a pile of messages and this reduces their time to post answers in the forum. So please don't do this. Thank you.
Today I got 4 of such notifications. I've disabled the possibility to contact me over my profile page already for these reasons.
Chris
Chris on 28 Jan 2023
Edited: Chris on 28 Jan 2023
My bad. I saw you had some know-how regarding axes stealing focus from an image, and this felt like it was in the same vein.
To perhaps word my question better for others:
I want this dialog to display an image and plot two point ROIs on top of the image. I want to allow the user to reposition the points using a left-click for the leftmost point, or a right-click for the right-most. However, the image fails to display. I can't use a breakpoint to figure out what's going on, because (I think) the dialog is interrupting the debugging process. I imagine that has something to do with how I have implemented the clicked callback.
The function as it sits is incomplete (for instance, it should probably return stats), but the script should be enough to reproduce the bug.

Sign in to comment.

Accepted Answer

Voss
Voss on 4 Feb 2023
Edited: Voss on 4 Feb 2023
The reason it doesn't work when the "colormap(ax,parula)" line is commented-out:
  • dialog() creates a figure with an empty Colormap.
  • The image you create from im is an indexed image, i.e., the values in im are interpreted as indices into the current colormap.
  • In this case (indexing into an empty colormap), MATLAB apparently just silently renders nothing.
The reason it doesn't work when the "colormap(ax,parula)" line is uncommented:
  • parula() called with no inputs uses the size of the current figure's Colormap to determine the size of the colormap it returns. If there is no current figure, then it uses the size of the root property DefaultFigureColormap. (You can open parula.m in the editor to see this logic in the first few lines of code; I'm using R2016b, but I imagine parula.m in R2022b is substantially similar and maybe exactly the same.)
  • The figure created by dialog() has its HandleVisibility set to 'callback' by default.
  • The first time parula() is called (during initialization, within replot when replot is called within cDialog), it's not being called from within a callback, so the dialog figure is not considered the current figure (i.e., not returned by gcf()), so parula returns a 64-by-3 colormap (assuming there are no other figures around that are the current figure, and assuming that the root DefaultFigureColormap is of size 64, which is the default).
  • The second time parula() is called (within replot when replot is called within clicked), it is being called from within a callback (clicked), so the dialog figure is considered the current figure (i.e., is returned by gcf()), so parula() uses the size of its colormap - which is empty - and returns an empty colormap as well.
  • I'm not 100% sure about this reasoning because if it were true, then setting the HandleVisibility of the dialog figure to 'off' should cause parula() to return a 64-by-3 colormap each time (i.e., never find the dialog figure as the current figure and always use the size of the root property DefaultFigureColormap), but in fact setting HandleVisibility to 'off' exhibits the same behavior as when HandleVisibility is 'callback'. (It's possible I misunderstand something about how the HandleVisibility of a figure determines under what conditions it is considered the root's CurrentFigure.)
In any case, the solution is to always make sure you are providing the correct colormap you want to use. In particular, you can bypass the behavior of parula() trying to use the size of the current figure's Colormap by specifying as an input the size of the colormap you want, i.e., use parula(N), either in specifying the figure's Colormap in the call to dialog():
  • d = dialog(___, 'Colormap',parula(64));
or in the command to set the axes colormap:
  • colormap(ax,parula(64))
  3 Comments

Sign in to comment.

More Answers (0)

Categories

Find more on Colormaps in Help Center and File Exchange

Products


Release

R2022b

Community Treasure Hunt

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

Start Hunting!