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

guiguideimagetimer

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

Best Answer

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);
Related Question