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

4 ビュー (過去 30 日間)
Chris 2023 年 1 月 26 日
コメント済み: Voss 2023 年 2 月 4 日
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)];
dp = d.Position;
d = dialog('Units','pixels','Position', dp, ...
'Name','Confirm Selections');
ax = uiaxes('Parent',d,...
'Position',[25 10 dp([3,4])-25],...
ax.Title.String = 'Confirm or Select points (Left- & Right-click)';
% Show the current points
%%% Nested functions
function replot
% colormap(ax,parula);
pts = {stats(1).Centroid;stats(2).Centroid};
if ~isempty(pts{1})
if ~isempty(pts{2})
function clicked(~,event)
switch event.Button
case 1
stats(1).Centroid = event.IntersectionPoint([1 2]);
case 3
stats(2).Centroid = event.IntersectionPoint([1 2]);
  3 件のコメント
Chris 2023 年 1 月 28 日
編集済み: Chris 2023 年 1 月 28 日
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.



Voss 2023 年 2 月 4 日
編集済み: Voss 2023 年 2 月 4 日
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 件のコメント
Voss 2023 年 2 月 4 日
You're welcome!


その他の回答 (0 件)




Community Treasure Hunt

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

Start Hunting!

Translated by