Updating multiple image axes with a timer - Images always load to new window not addressed one

3 views (last 30 days)
I am currently trying to run a program that shows a progressing series of blocks that are colored to indicate pressure level (this is for a user to see and respond to). The rate of increase is controlled by a timer and colored blocks are loaded images onto axes.
The program actually runs when in debug mode and a break point is placed in the case statement for the function "raisePressure", but when this code is run instead of loading the images into the referenced axes after the first image, the program retrieves a handle to an axis that doesn't exist and simply creates a new window for the output.
Here is the main code of this program, but if necessary I can upload the the rest of the program.
function varargout = PressureMonitor(varargin)
% PRESSUREMONITOR MATLAB code for PressureMonitor.fig
% PRESSUREMONITOR, by itself, creates a new PRESSUREMONITOR or raises the existing
% singleton*.
%
% H = PRESSUREMONITOR returns the handle to a new PRESSUREMONITOR or the handle to
% the existing singleton*.
%
% PRESSUREMONITOR('CALLBACK',hObject,eventData,handles,...) calls the local
% function named CALLBACK in PRESSUREMONITOR.M with the given input arguments.
%
% PRESSUREMONITOR('Property','Value',...) creates a new PRESSUREMONITOR or raises the
% existing singleton*. Starting from the left, property value pairs are
% applied to the GUI before PressureMonitor_OpeningFcn gets called. An
% unrecognized property name or invalid value makes property application
% stop. All inputs are passed to PressureMonitor_OpeningFcn via varargin.
%
% *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one
% instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES
% Edit the above text to modify the response to help PressureMonitor
% Last Modified by GUIDE v2.5 29-Oct-2012 17:23:51
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @PressureMonitor_OpeningFcn, ...
'gui_OutputFcn', @PressureMonitor_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
end
% --- Executes just before PressureMonitor is made visible.
function PressureMonitor_OpeningFcn(hObject, ~, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to PressureMonitor (see VARARGIN)
handles.white = imread('white.png');
handles.red = imread('red.png');
handles.green = imread('green.png');
handles.pressureLevel = 0;
% Choose default command line output for PressureMonitor
handles.output = hObject;
% Setup timer object
handles.guifig = gcf;
handles.timer = timer('Period', 1.0, 'ExecutionMode', 'FixedRate','TimerFcn', {@increment,handles.guifig});%.guifig
guidata(handles.guifig,handles);
% Update handles structure
guidata(hObject, handles);
releasePressure(7,handles);
% UIWAIT makes PressureMonitor wait for user response (see UIRESUME)
% uiwait(handles.figure1);
end
% --- Outputs from this function are returned to the command line.
function varargout = PressureMonitor_OutputFcn(hObject, ~, handles)
% varargout cell array for returning output args (see VARARGOUT);
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure
varargout{1} = handles.output;
% Update handles structure
guidata(hObject, handles);
end
% --- Executes on button press in start.
function start_Callback(hObject, ~, handles)
% hObject handle to start (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
start(handles.timer);
guidata(hObject, handles);
end
% --- Executes on button press in releasePressure.
function releasePressure_Callback(hObject, ~, handles)
% hObject handle to releasePressure (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
prevLevel = handles.pressureLevel;
handles.pressureLevel = releasePressure(handles.pressureLevel,handles);
if(handles.pressureLevel == 0 && prevLevel > 6)
tElapsed = toc(handles.tStart);
disp(tElapsed)
end
% Update handles
guidata(hObject, handles);
end
function nLevel = releasePressure(level,handles)
if(level > 6)
set(handles.guifig,'CurrentAxes',handles.axes1);
imshow(handles.white);
set(handles.guifig,'CurrentAxes',handles.axes2);
imshow(handles.white);
set(handles.guifig,'CurrentAxes',handles.axes3);
imshow(handles.white);
set(handles.guifig,'CurrentAxes',handles.axes4);
imshow(handles.white);
set(handles.guifig,'CurrentAxes',handles.axes5);
imshow(handles.white);
set(handles.guifig,'CurrentAxes',handles.axes6);
imshow(handles.white);
set(handles.guifig,'CurrentAxes',handles.axes7);
imshow(handles.white);
set(handles.guifig,'CurrentAxes',handles.axes8);
imshow(handles.white);
nLevel = 0;
else
nLevel = level;
end
end
function nLevel = raisePressure(level,handles)
switch level
case 0
axes(handles.axes1);
imshow(handles.green);
nLevel = level + 1;
case 1
axes(handles.axes2);
imshow(handles.green);
nLevel = level + 1;
case 2
axes(handles.axes3);
imshow(handles.green);
nLevel = level + 1;
case 3
axes(handles.axes4);
imshow(handles.green);
nLevel = level + 1;
case 4
axes(handles.axes5);
imshow(handles.green);
nLevel = level + 1;
case 5
axes(handles.axes6);
imshow(handles.green);
nLevel = level + 1;
case 6
axes(handles.axes7);
imshow(handles.red);
nLevel = level + 1;
case 7
set(handles.guifig,'CurrentAxes',handles.axes1);
imshow(handles.red);
set(handles.guifig,'CurrentAxes',handles.axes2);
imshow(handles.red);
set(handles.guifig,'CurrentAxes',handles.axes3);
imshow(handles.red);
set(handles.guifig,'CurrentAxes',handles.axes4);
imshow(handles.red);
set(handles.guifig,'CurrentAxes',handles.axes5);
imshow(handles.red);
set(handles.guifig,'CurrentAxes',handles.axes6);
imshow(handles.red);
set(handles.guifig,'CurrentAxes',handles.axes7);
imshow(handles.red);
set(handles.guifig,'CurrentAxes',handles.axes8);
imshow(handles.red);
nLevel = level + 1;
otherwise
nLevel = level;
end
gca
end
function increment(~,~,handles)
% handles structure with handles and user data (see GUIDATA)
handle = guidata(handles);
handle.pressureLevel = raisePressure(handle.pressureLevel,handle);
if(handle.pressureLevel == 7)
tic;
handle.tStart = tic;
end
guidata(handles, handle);
end
% --- Executes on button press in stop.
function stop_Callback(hObject, ~, handles)
% hObject handle to stop (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
stop(handles.timer);
guidata(hObject, handles);
end

Accepted Answer

Sean de Wolski
Sean de Wolski on 2 Nov 2012
Part 1
The problem is line 67:
% Setup timer object
handles.guifig = gcf; %ME!!!
handles.timer = timer('Period', 1.0, 'ExecutionMode', 'FixedRate','TimerFcn', {@increment,handles.guifig});%.guifig
guidata(handles.guifig,handles);
When you call gcf a new figure is poofed to become the current figure. The reason for this is the GUIDE GUI's Figure's 'HandleVisibility' is set to 'off'. This is the GUIDE default and can be changed in GUIDE->tools->GUI Options.
So now you have a new figure created and you set the GUIDATA to this figure. Axes will be poofed on this figure and the rest explains the behavior you are seeing.
The simplest way to fix this is to set handles.guifig to be handles.figure1'. 'figure1' is the default tag for the gui figure. Of course this is redundant since now you'll have handles.guifig and handles.figure1 both pointing to the same thing. Thus the easiest (and probably best) fix is to rename the figure's tag to guifig in the GUIDE Property inspector. Or you could just go through your code and replace guifig with figure1, both work.
Part 2
As far as what IA was mentioning above with using:
imshow(the_image,'Parent',handles.axes1)
This is definitely a requirement so that imshow does not poof a new axes.
Alternatively, and this is what IA was hinting at, you can just set the 'CData' of the image to be different. For a robust real time application, I would argue that this the right way to do it. The reason for this is that it is faster and cleaner to change the coloring of an image than to delete that image and make a new image. As long as all of the other properties remain the same, we can skip the delete&repeat steps.
To do this, store the image handles in and update the 'CData' as necessary.
Here is a small example that outlines the idea.
hImage = imshow(cat(3,ones(200,400),zeros(200,400,2)));
T = timer('Period',1,'TasksToExecute',10,...
'Timerfcn',@(~,~)set(hImage,'CData',circshift(get(hImage,'CData'),[0 0 1])),...
'StartDelay',1,'ExecutionMode','FixedRate');
start(T);

More Answers (2)

Image Analyst
Image Analyst on 30 Oct 2012
Edited: Image Analyst on 30 Oct 2012
When does it do that? Only for case 7? If so, try replacing all the
set(handles.guifig,'CurrentAxes',handles.axes1);
with an axes command:
axes(handles.axes1); % or whatever axes you want.
If that doesn't work, then pass the axes into all the imshow's as the 'Parent' property:
imshow(handles.green, 'Parent', handles.axes1);
If even that doesn't work, let us know. I'm working on showing images with a timer (though I've had to set it aside for a few weeks) and there was something bizarre, unexpected, and non intuitive about it. Sean de Wolski was helping me with it and for some reason you have to write to the CDdata property of the axes rather than use imshow() or something weird like that. Sean would know more - maybe he'll respond.
  2 Comments
Roy
Roy on 31 Oct 2012
Tried the suggestions you offered, and frankly everything I could find here at Mathworks, but I still end up with the case that the images are plotted to a new window after the first one has been successfully drawn in the embedded axis. I would be very interested in trying anything else that you can think of.

Sign in to comment.


Hannes
Hannes on 26 Aug 2014
Edited: Hannes on 26 Aug 2014
I had a very similar problem until a couple of minutes ago. I am working with timers to refresh multiple axes in my GUI. During the second call to the timer callback function a new figure was unintentionaly created. As usual, the devil is in the details. The specific code in the timer callback function was
ax1 = handles.axes1;
axes(ax1);
plot(ax1,rand,rand);
xTick = str2num(get(gca,'XTickLabel'));
That use of
gca
caused the problem. After I replaced gca by
ax1
the problem was no more. However, I don't understand why gca is not refering to my axes "ax1", since I explicitly called "axes(ax1)" before! Any explanation?
Returning to your problem. At the very end of your function
function nLevel = raisePressure(level,handles)
you are calling gca. Maybe this is causing your problem?

Categories

Find more on Migrate GUIDE Apps in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!