Carl Witthoft
Carl Witthoft

Reputation: 21502

How to force callback plot commands to go to desired figure window?

I have a working MATLAB function which plots data in response to GUI buttons in the figure window, including a callback which starts/stops a loop to plot movie-like frames of sequential data.
The problem I would like to solve is: how can I set up two such windows, running with different datasets but based on the same code (functions, callbacks etc) without having the active plotting loop jump to whichever figure window happens to have focus? That is, if I start one plot-movie, then click on the other window, the plotting takes place in this second window (and, only the GUI buttons in the original window can affect the plot).
What I'm hoping for is the equivalent of getting the figure window's Figure Number with, e.g., gcbf , and then adding a Property pair to my imagesc and plot commands to ensure the data are sent to the desired window. It isn't clear to me what (if any) Image Property or Chart Line Property would do this.
Is what I want to do possible, and if so do I have to retrieve the Axes property from the figure and use that property to assign my data plots? I don't require both plots to be actively updating simultaneously, but I do want to avoid the cross-window plotting that I'm dealing with now.

Upvotes: 1

Views: 33

Answers (1)

Suever
Suever

Reputation: 65440

You want to specify the Parent property when using plot or imagesc explicitly to ensure that the object is created in the appropriate place. You can do this using the 'Parent' parameter / value pair syntax or as the first input.

imagesc(data, 'Parent', hfigure)
imagesc(hfigure, data);

Personally I prefer the first option due to it being more explicit.

In general, you should always specify these parents to get a reliable result. While gca and gcf can be handy, they are also completely dependent on where the user happens to click and which figure is active, so a change in user selection during the execution of your callback can change their values and result in unexpected behavior.

It seems like you're trying to run two instances of the same GUI. If that's the case, then you should already have the handles to the axes objects so you should store them somewhere where they are accessible by the callbacks

handles.hfigure = figure();
handles.haxes = axes('Parent', hfigure);
handles.hbutton = uicontrol('Parent', hfigure, 'Callback', @callback)

% Store all of the handles within the main figure's guidata
guidata(handles.hfigure, handles)

function callback(src, evnt)
    % Retrieve the stored handles
    handles = guidata(src);

    imagesc(rand(10), 'Parent', handles.haxes)
end

Or you can explicitly pass them to your callbacks

hfigure = figure();
haxes = axes('Parent', hfigure);

hbutton = uicontrol('Parent', hfigure, 'Callback', @(s,e)callback(s, e, haxes));

function callback(src, evnt, haxes)
    imagesc(rand(10), 'Parent', haxes)
end 

I personally prefer the second approach because I pass around exactly what is needed.

Side Note

Rather than calling plot and imagesc continuously from within your callback, you're going to get better performance creating the image or plotobject in the intialization code of your GUI and then simply updating the CData or XData and YData properties from within the callback.

hfigure = figure();
haxes = axes('Parent', hfigure);
himage = imagesc(NaN, 'Parent', haxes);
hbutton = uicontrol('Parent', hfigure, 'Callback', @(s,e)callback(s,e,himage))

function callback(src, evnt, himage)
    set(himage, 'CData', rand(10))
    drawnow
end

Upvotes: 2

Related Questions