Matlab - Initialize a script in every two seconds - matlab

I tried to write an animation code in Matlab that repeats itself in every two seconds. The core animation scheme is as below:
Please take care the gif is repeating the core animation, originally there is only one cycle.
Here is the code:
% Figure settings
h= figure(2);
set(h, 'Position', [100 50 1200 750])
set(h,'Toolbar','None','Menubar','None')
set(h,'Name','Animation')
set(gcf,'doublebuffer','off');
set(gca, 'xlimmode','manual','ylimmode','manual','zlimmode','manual',...
'climmode','manual','alimmode','manual');
xlim([-200 1350])
ylim([-250 800])
set(gca,'xtick',[],'ytick', [], 'Position', [0 0 1 1]);
%Parameters
diameter = 60; %spot çapı
RamanX = 350; %ölçüm noktssı x konumu
nOfSpots = 4; %spot sayısı
spotCount = 0; %toplam spot sayısı
initPos = [50 150;50 300; 50 450; 50 600]; %konum 1
posII = [350 150;350 300; 350 450; 350 600]; %konum 2
Choice = rand(1,4)<.5; %Ölçüm sonunda verilen karar
deltaY2 = 100; % spotlar arası mesafe
x11 = zeros(nOfSpots,2);
x22 = zeros(nOfSpots,2);
x22a = zeros(nOfSpots,2);
x22b = zeros(nOfSpots,2);
for i=1:nOfSpots
x11(i,:) = [RamanX 150*(i-1)];
x22(i,:) = [800 50+deltaY2*(i-1)];
end
for i=1:nOfSpots/2
x22a(2*i-1,:) = [1280 -270+250*(i-1)];
x22a(2*i,:) = [1075 -270+250*(i-1)];
x22b(2*i-1,:) = [1280 220+250*(i-1)];
x22b(2*i,:) = [1075 220+250*(i-1)];
end
%Add 4 Circles to initial position
for i=1:nOfSpots
% Drag & Drop elipsler yerleştiriliyor
spot(i) = imellipse(gca, [initPos(i,1),initPos(i,2),diameter,diameter]);
spotCount = spotCount+1;
%elips özellikleri
setFixedAspectRatioMode(spot(spotCount), 'TRUE');
setResizable(spot(spotCount),0);
posSpot(spotCount,:) = getPosition(spot(i));
end
%Move Circles to posII
r = sqrt(sum(bsxfun(#minus,posII(:,1),initPos(:,1)).^2,2));
v = 30;
stepsize = ceil(r/v);
xstep = (posII(:,1)-initPos(:,1))/stepsize;
for i=1:stepsize
for j=1:nOfSpots
setPosition(spot(j), [initPos(j,1)+xstep(j)*i, initPos(j,2), diameter, diameter] )
posSpot(spotCount,:) = getPosition(spot(j));
end
pause(0.15)
end
%Move Circles to posIII
velocity = 30;
r2a = sqrt(sum(bsxfun(#minus,x22a,x11).^2,2));
stepsize2a = max(ceil(r2a/velocity));
r2b = sqrt(sum(bsxfun(#minus,x22a,x11).^2,2));
stepsize2b = max(ceil(r2b/velocity));
% Eğer öllçüm seçimi 1 ise taşı
for i=1:nOfSpots
if(Choice(i))
xstep2(i) = (x22a(i,1)-x11(i,1))./stepsize2a;
ystep2(i) = (x22a(i,2)-x11(i,2))./stepsize2a;
else
xstep2(i) = (x22b(i,1)-x11(i,1))./stepsize2b;
ystep2(i) = (x22b(i,2)-x11(i,2))./stepsize2b;
end
end
stepsize2 = max([stepsize2a stepsize2b]);
% Eğer ölçüm seçimi 0 ise taşı
for i=1:stepsize2
for j=1:nOfSpots
if(Choice(j))
setPosition(spot(j), [posII(j,1)+xstep2(j)*i, posII(j,2)+ystep2(j)*i, diameter, diameter] )
posSpot(spotCount,:) = getPosition(spot(j));
end
end
pause(0.15)
end
for i=1:stepsize2
for j=1:nOfSpots
if(~Choice(j))
setPosition(spot(j), [posII(j,1)+xstep2(j)*i, posII(j,2)+ystep2(j)*i, diameter, diameter] )
posSpot(spotCount,:) = getPosition(spot(j));
end
end
pause(0.15)
end
if(spotCount > 0)
for i=1:4
delete(spot(i))
end
end
The code doing this is a script not a function, say "animation.m". Now I am trying repeat this code in every 2 seconds. I tried to use loops with tic - toc commands, but the loop does not go to other cycle before finishing "animation.m". I need to get it work in the background.
One of my friend suggested me to use trigger. But, honestly, I could not apply the trigger command for my code even when I functionalized it.
Any help?
Edit:
The graphical flow chart of the problem is below:

I created an example that shows how it could be done.
Modifying your code, to draw just "one animated step" was too much work.
I decided to used your code to create all frames from advance (for example purpose).
I guess you are going to realize, that implementing background animation in Matlab is more difficult than you thought (unless I missed some hidden Matlab feature).
Matlab has very limited threading support, so I used a periodic timer.
My code sample does the following:
Build animation - create a cell array of all animated images.
You should avoid it, because it takes to much time (and memory).
I used it instead of modifying your code to draw one animated image.
Setup a periodic timer object with 0.2 seconds period (0.2 as an example).
I added a loop that illustrates the foreground processing (calculating sin(x) as an example).
Notice: I added small pause in the "foreground processing" loop.
The timer invokes a callback function every 0.2 seconds.
In the callback function the next animated frame is shown.
The timer is used for simulating a background execution.
You should replace the imshow, with your "animation step" function, that draws the frame (instead of showing a frame created from advance).
Here is the code sample (with your modified code included):
function TimerAnimation()
%Build set of images for animation.
[h_figure, Frames] = BuildAnimation();
t = timer;
t.TimerFcn = #timerFcn_Callback; %Set timer callback function
t.ExecutionMode = 'fixedRate'; %Set mode to "singleShot" - execute TimerFcn only once.
t.StartDelay = 0.1; %Wait 0.1 second from start(t) to executing timerFcn_Callback.
t.Period = 0.2; %Set period to 0.2 seconds.
%Turn on figure visibility
set(h_figure, 'Visible', 'on');
frame_counter = 1;
start(t) %Start timer;
%Do some other job...
%The animation is executed in the background (kind of in the background).
for x = 1:20000
y = sin(x/10000); %Calculate somthing...
if (mod(x, 100) == 0)
disp(['sin(', num2str(x/10000), ') = ', num2str(y)]); %Display somthing...
end
if (~isvalid(h_figure))
%Break loop if user closed the animation figure.
break;
end
%Must insert pause to "tight loop", allowing animation to run.
pause(0.01);
end
stop(t) %Stop timer;
delete(t); %Delete timer object.
if (~isvalid(h_figure))
close(h_figure);
end
%Timer function is executed every period of 0.2 seconds.
function timerFcn_Callback(mTimer, ~)
%Increse animation frame counter.
%figure(h_figure); %Set fo h_figure to be active figure.
h_axes = get(h_figure, 'CurrentAxes'); %Get axes of h_figure
imshow(Frames{frame_counter}, 'Parent', h_axes); %Display frame number frame_counter.
drawnow; %Force refresh.
frame_counter = mod(frame_counter, length(Frames)) + 1; %Advance to next frame (cyclically).
end
end
function [h, Frames] = BuildAnimation()
%Build set of images for animation.
%h - return handle to figure
%Frames - return cell array of animation images.
counter = 1;
% Figure settings
%h = figure(2);
%Create invisible figure.
h = figure('Visible', 'off');
set(h, 'Position', [100 50 1200 750])
set(h,'Toolbar','None','Menubar','None')
set(h,'Name','Animation')
set(gcf,'doublebuffer','off');
set(gca, 'xlimmode','manual','ylimmode','manual','zlimmode','manual',...
'climmode','manual','alimmode','manual');
xlim([-200 1350])
ylim([-250 800])
set(gca,'xtick',[],'ytick', [], 'Position', [0 0 1 1]);
%Parameters
diameter = 60; %spot ?ap?
RamanX = 350; %?l??m noktss? x konumu
nOfSpots = 4; %spot say?s?
spotCount = 0; %toplam spot say?s?
initPos = [50 150;50 300; 50 450; 50 600]; %konum 1
posII = [350 150;350 300; 350 450; 350 600]; %konum 2
Choice = rand(1,4)<.5; %?l??m sonunda verilen karar
deltaY2 = 100; % spotlar aras? mesafe
x11 = zeros(nOfSpots,2);
x22 = zeros(nOfSpots,2);
x22a = zeros(nOfSpots,2);
x22b = zeros(nOfSpots,2);
for i=1:nOfSpots
x11(i,:) = [RamanX 150*(i-1)];
x22(i,:) = [800 50+deltaY2*(i-1)];
end
for i=1:nOfSpots/2
x22a(2*i-1,:) = [1280 -270+250*(i-1)];
x22a(2*i,:) = [1075 -270+250*(i-1)];
x22b(2*i-1,:) = [1280 220+250*(i-1)];
x22b(2*i,:) = [1075 220+250*(i-1)];
end
%Add 4 Circles to initial position
for i=1:nOfSpots
% Drag & Drop elipsler yerle?tiriliyor
spot(i) = imellipse(gca, [initPos(i,1),initPos(i,2),diameter,diameter]);
spotCount = spotCount+1;
%elips ?zellikleri
setFixedAspectRatioMode(spot(spotCount), 'TRUE');
setResizable(spot(spotCount),0);
posSpot(spotCount,:) = getPosition(spot(i));
end
%Move Circles to posII
r = sqrt(sum(bsxfun(#minus,posII(:,1),initPos(:,1)).^2,2));
v = 30;
stepsize = ceil(r/v);
xstep = (posII(:,1)-initPos(:,1))/stepsize;
for i=1:stepsize
for j=1:nOfSpots
setPosition(spot(j), [initPos(j,1)+xstep(j)*i, initPos(j,2), diameter, diameter] )
posSpot(spotCount,:) = getPosition(spot(j));
end
%pause(0.15)
%Get frame, convert frame to image, and store image in Frames
Frames{counter} = frame2im(getframe(h));counter = counter + 1;
end
%Move Circles to posIII
velocity = 30;
r2a = sqrt(sum(bsxfun(#minus,x22a,x11).^2,2));
stepsize2a = max(ceil(r2a/velocity));
r2b = sqrt(sum(bsxfun(#minus,x22a,x11).^2,2));
stepsize2b = max(ceil(r2b/velocity));
% E?er ?ll??m se?imi 1 ise ta??
for i=1:nOfSpots
if(Choice(i))
xstep2(i) = (x22a(i,1)-x11(i,1))./stepsize2a;
ystep2(i) = (x22a(i,2)-x11(i,2))./stepsize2a;
else
xstep2(i) = (x22b(i,1)-x11(i,1))./stepsize2b;
ystep2(i) = (x22b(i,2)-x11(i,2))./stepsize2b;
end
end
stepsize2 = max([stepsize2a stepsize2b]);
% E?er ?l??m se?imi 0 ise ta??
for i=1:stepsize2
for j=1:nOfSpots
if(Choice(j))
setPosition(spot(j), [posII(j,1)+xstep2(j)*i, posII(j,2)+ystep2(j)*i, diameter, diameter] )
posSpot(spotCount,:) = getPosition(spot(j));
end
end
% pause(0.15)
%Get frame, convert frame to image, and store image in Frames
Frames{counter} = frame2im(getframe(h));counter = counter + 1;
end
for i=1:stepsize2
for j=1:nOfSpots
if(~Choice(j))
setPosition(spot(j), [posII(j,1)+xstep2(j)*i, posII(j,2)+ystep2(j)*i, diameter, diameter] )
posSpot(spotCount,:) = getPosition(spot(j));
end
end
% pause(0.15)
%Get frame, convert frame to image, and store image in Frames
Frames{counter} = frame2im(getframe(h));counter = counter + 1;
end
if(spotCount > 0)
for i=1:4
delete(spot(i))
end
end
imshow(Frames{1})
end
Example for what I meant by "drawing just one animated step":
function TimerAnimation2()
%Initiazlie animation.
param = InitAnimation();
%Same code as in previous example.
t = timer;t.TimerFcn = #timerFcn_Callback;t.ExecutionMode = 'fixedRate';t.StartDelay = 0.1;t.Period = 0.2;start(t)
for x = 1:20000;if (~isvalid(param.h)), break;end;pause(0.01);end
stop(t);delete(t);if (isvalid(param.h)), close(param.h);end
%Timer function is executed every period of 0.2 seconds.
function timerFcn_Callback(mTimer, ~)
%Animation single step
param = StepAnimation(param);
end
end
function param = InitAnimation()
h = figure;
set(h, 'Position', [100 50 1200 750]);set(h,'Toolbar','None','Menubar','None');set(h,'Name','Animation');set(gcf,'doublebuffer','off');
set(gca, 'xlimmode','manual','ylimmode','manual','zlimmode','manual', 'climmode','manual','alimmode','manual');
xlim([-200 1350]);ylim([-250 800]);set(gca,'xtick',[],'ytick', [], 'Position', [0 0 1 1]);
%Initialize param struct (param struct keeps animation parameters).
param.h = h;
param.x = 10;
param.y = 10;
%Draw rectangle in position x, y
h_axes = get(param.h, 'CurrentAxes');
rectangle('Position', [param.x param.y 20 20], 'Parent', h_axes);
end
%Example fo single animation step
%Get exsiting animation param as input, and retuen updated param as output.
function param = StepAnimation(param)
h_axes = get(param.h, 'CurrentAxes');
%Update param (to be used in next StepAnimation).
param.x = param.x + 10;
param.y = param.y + 10;
if (param.x > 500), param.x = 10;end
if (param.y > 500), param.y = 10;end
%Draw rectangle in position x, y
rectangle('Position', [param.x param.y 20 20], 'Parent', h_axes)
drawnow; %Force refresh.
end

Related

Changing subplot data in MATLAB using slider function

I have been trying to plot two images side by side with two sliders using uicontrol. I am relatively new to uicontrol using matlab. Only the second subplot updates when I change the slider.
close all;
clear all;
clc;
set(0,'defaultAxesFontSize',14)
set(0,'DefaultFigureWindowStyle','docked')
data = rand(3,1024,64,20);
nslice = size(data,4);
nidx = size(data,1);
if nslice == 1
sampling = 1; % in some of my data nslice would be 1 so I would like my slider to not give me error in such a case
else
sampling = 5;
end
idx = 1;
slice = 1;
h.f = figure(1);
x_axis = linspace(0,0.5,size(data,3));
y_axis = linspace(0,70,size(data,2));
set(h.f,'doublebuffer','on')
h.data = data;
inst_data = squeeze(data(nidx,:,:,slice));
h.ax(1) = subplot(1,2,1,'Parent',h.f,'Units','Normalized');
imagesc(h.ax(1),x_axis,y_axis, inst_data)
colorbar;
colormap(h.ax(1),'gray')
caxis(h.ax(1),[min(abs(inst_data(:))),max(abs(inst_data(:)))])
xlabel('xaxis')
ylabel('yaxis')
title('figure 1')
h.ax(2) = subplot(1,2,2,'Parent',h.f,'Units','Normalized');
log_data = log(inst_data);
imagesc(h.ax(2),x_axis,y_axis, log_data)
colorbar;
colormap(h.ax(2),'jet')
caxis(h.ax(2),[-max(abs(log_data(:))),max(abs(log_data(:)))])
xlabel('xaxis')
ylabel('yaxis')
title('figure 2')
sgtitle({'Sample data ', ['Slice: ',num2str(slice),' index: ', num2str(idx)]},'FontSize',16,'FontWeight','Bold')
h.slider1=uicontrol('Parent',h.f,...
'Units','Normalized',...
'Position',[0.1 0.06 0.8 0.05],...
'Style','slider',...
'SliderStep',[1,sampling],...
'Min',1,'Max',nslice,'Value',1,...
'Callback',{#slider_Callback,data,x_axis,y_axis});
txt1 = 'Slice';
txt2 = 'Index';
annotation('textbox', [0.05 0.07 0.05 0.04], 'string', txt1);
annotation('textbox', [0.05 0.021 0.05 0.04], 'string', txt2);
h.slider2=uicontrol('Parent',h.f,...
'Units','Normalized',...
'Position',[0.1 0.02 0.8 0.05],...
'Style','slider',...
'SliderStep',[1,1],...
'Min',1,'Max',nidx,'Value',1,...
'Callback',{#slider_Callback,data,x_axis,y_axis});
guidata(h.f,h)
%%
function slider_Callback(hObject,eventdata,data,x_axis,y_axis)%#ok<INUSD>
h=guidata(hObject);%retrieve struct
slice_i = round(get(h.slider1, 'Value'));
idx_i = round(get(h.slider2,'Value'));
inst = squeeze(data(idx_i,:,slice_i));
colorbar;
colormap(h.ax(1),'gray')
caxis(h.ax(1),[min(abs(inst(:))),max(abs(inst(:)))])
h.ax(1) = imagesc(x_axis,y_axis,inst); colorbar
lg = log(inst);
colorbar;
colormap(h.ax(2),'jet')
caxis(h.ax(2),[-max(abs(lg(:))),max(abs(lg(:)))])
h.ax(2) = imagesc(x_axis,y_axis, lg ); colorbar;
sgtitle({'Sample data ', ['Slice: ',num2str(slice_i),' index: ', num2str(idx_i)]},'FontSize',16,'FontWeight','Bold')
drawnow
end
Other problems include:
The slider slides with a floating value which shouldnt be the case
When my data has only 1 slice, the slider moves to value zero which shouldn't happen. You can try the same example with data = rand(3,1024,64,1);

Line with NumericRuler-properties in Matlab

I want to create a relative axis in Matlab like the $\Delta I$-rulers in the following plot.
Before I start writing up a function that constructs it manually, I would like to know if there's way of creating an object with the NumericRuler-properties (like the default axes of a figure())
So I ended up using the link provided by Sardar Usama's comment as inspiration and wrote a function to create an axes-object relative to the values of a "parent"-axes:
function ax = create_value_axes(hAx, pos)
%% ax = create_value_axes(hAx, pos)
%
% Create axes at the value points of hAx.
%
% pos(1) = x-position
% pos(2) = y-position
% pos(3) = x-width
% pos(4) = y-width
%
% Get "parent" position and value limits
hAx_pos = hAx.Position;
hAx_xlm = hAx.XLim;
hAx_ylm = hAx.YLim;
% Get relative position increment pr value increment
x_step = hAx_pos(3) / (hAx_xlm(2) - hAx_xlm(1));
y_step = hAx_pos(4) / (hAx_ylm(2) - hAx_ylm(1));
% Set position
subaxes_abs_pos(1) = (pos(1)-hAx_xlm(1)) * x_step + hAx_pos(1);
subaxes_abs_pos(2) = (pos(2)-hAx_ylm(1)) * y_step + hAx_pos(2);
subaxes_abs_pos(3) = pos(3) * x_step;
subaxes_abs_pos(4) = pos(4) * y_step;
% Create axes
ax = axes('Position', subaxes_abs_pos);
% Remove background
ax.Color = 'none';
end
Sidenote: I found that I didn't need plotboxpos to get the correct positions of the "parent"-axes, using Matlab r2019b on macOS Mojave 10.14.6
Anyway, this is what I end up with:
Using the code:
% Just some random data
mockup_data_ild = [-10 -7 -4 0 4 7 10];
mockup_data_itd_45 = [-40 -20 -10 0 10 20 40];
mockup_data_itd_60 = [-30 -15 -5 0 5 15 30];
% Create figure
figure('Color', 'w')
x_axis_offset = [0 30];
hold on
% Plot 45 dB result
p1 = plot_markers(x_axis_offset(1) + mockup_data_ild, mockup_data_itd_45, ii);
% Plot 60 dB results
p2 = plot_markers(x_axis_offset(2) + mockup_data_ild, mockup_data_itd_60, ii);
p2.Color = p1.Color;
p2.HandleVisibility = 'off';
hold off
% Set axes properties
ax = gca;
ax.XAxis.TickValues = [x_axis_offset(1) x_axis_offset(2)];
ax.XAxis.TickLabels = {'45 dB' '60 dB'};
ax.XAxis.Limits = [x_axis_offset(1)-15 x_axis_offset(2)+15];
ax.XAxisLocation = 'top';
ax.YAxis.Limits = [-80 100];
ax.YAxis.Label.String = 'Interaural Time Difference, \Deltat, in samples';
ax.YGrid = 'on';
% Create 45 dB axis
ax2 = create_DeltaI_axis(ax, x_axis_offset(1));
% Create 60 dB axis
ax3 = create_DeltaI_axis(ax, x_axis_offset(2));
% Create legend
leg = legend(ax, {'P1'});
leg.Location = 'northwest';
%% Helpers
function ax = create_DeltaI_axis(hAx, x_pos)
y_pos = -70;
y_height = 170;
range = 20;
ax = create_value_axes(hAx, [x_pos-range/2 y_pos range y_height]);
ax.XAxis.TickValues = [0 .25 .5 .75 1];
ax.XAxis.TickLabels = {'-10'
'-5'
'0'
'5'
'10'};
ax.XAxis.Label.String = '\DeltaI';
ax.XGrid = 'on';
ax.XMinorGrid = 'on';
ax.YAxis.Visible = 'off';
end
function p = plot_markers(x, y, ii)
markers = {'square','^', 'v', 'o', 'd'};
p = plot(x, y);
p.LineWidth = 1.5;
p.LineStyle = 'none';
p.Marker = markers{ii};
end

How can i read and store mouse coordinates while the rest of the function does not do much, pretty much stall?

so i have a matlab function below that returns a matrix of [x y time_elapsed] coordinates from 'start' to 'target', and 'target' is reached when it is at distance of acc_length to it. the time_elapsed is to help me get the speed profile.
Currently, this works fine with sampling roughly every 0.01s and there is a 2-second pause when starting the motion from 'start'.
My question is how can i do the same thing - having the user to wait 2s once 'start' position is reached, but instead of pausing the program, how can I still read the mouse coordinates(within the 2s period) while nothing useful happens for 2s?
P.S. i want to get these coordinate to calculate the precision of user to the start.
function arr = pmove(start, target, acc_length)
uimenufcn(gcf,'WindowCommandWindow');
arr = [];
checkStart = 1;
checkEnd = 0;
while checkStart
pt = get(0,'PointerLocation');
pt = [pt(1) - 1920/2, pt(2) - 1080/2];
d = pdist( [start; pt] );
if ~checkEnd & d <= acc_length;
disp('Start moving to target after 2 seconds.')
pause(2);
pt = get(0, 'PointerLocation');
pt = [pt(1) - 1920/2, pt(2)-1080/2, 0];
arr = cat(1, arr, pt);
checkEnd = 1;
tic;
continue;
end
if checkEnd
d = pdist( [target; pt] );
t_elapsed = toc;
pt = [pt , t_elapsed];
arr = cat(1, arr, pt);
if d <= acc_length
checkStart = 0;
end
end
if ~isempty(arr)
figure(gcf)
hold on;
plot(arr(:,1), arr(:,2) );
%drawnow;
axis equal;
end
pause(0.01);
end
end
You can replace the pause(2) line with:
for i=1:200
pt2 = get(0, 'PointerLocation');
% do your calculation
pause(0.01);
end
i'm using another while-true loop and checking the time_elapsed, if it is longer than 2.1s (tolerance of 0.1s for the user) i break out of the loop. During which, i get the pointer cordinates about every 0.01s and run my calculations.
tic;
while 1
pt2 = get(0,'PointerLocation');
% calculation
time_elaps = toc;
if time_elaps > 2.1 % tolerance of 0.1s
break;
end
pause(0.01);
end

Matlab makes the loops run simultaneously

Unfortunately, I have two loops. that's why my code makes the first loop run and only when it is finished, it makes the second loop run.
But I want the gui to show the data simultaneously: in the hAxes and in the loading1.
How can I make it?
hFigure = figure('units','pixels','position',[300 300 424 470],'menubar','none',...
'name','start processing','numbertitle','off','resize','off');
hAxes = axes('Parent',hFigure,'Units','pixels','Position',[0 112 424 359]);
loading1 = uicontrol('style','text','unit','pix','position',[0 72 424 40],...
'backgroundcolor','r','fontsize',20);
%% shows the data on hAxes
for i = 5:100
if mod(i,2) == 0
set(hAxes,'Color','b');
else
set(hAxes,'Color','g');
end
drawnow;
end
%% shows the data on loading1
for i=1:200
image2 = horzcat('now processing ', 'image', num2str(i), '.jpg of 200 images');
set(loading1,'string',image2);
drawnow;
end
this code is of Peter:
function test1
hFigure = figure('units','pixels','position',[300 300 424 470],'menubar','none','name','start processing','numbertitle','off','resize','off');
% Your other setup calls
hAxes = axes('Parent',hFigure,'Units','pixels','Position',[0 112 424 359]);
loading1 = uicontrol('style','text','unit','pix','position',[0 72 424 40],'backgroundcolor','r','fontsize',20);
c = 1;
t = timer('TimerFcn', #color_change_fcn,'StartDelay',1.0);
start(t);
for i=1:200
image2 = horzcat('now processing ', 'image', num2str(i), '.jpg of 200 images');
set(loading1,'string',image2);
drawnow;
end
function color_change_fcn
if mod(c,2) == 0
set(hAxes,'Color','b');
else
set(hAxes,'Color','g');
end
drawnow;
c = c + 1;
end
end
It doesn't work (doesn't show the hAxes). I saw it doesn't make the color_change_fcn run (I tried to write: disp('test') in the first row of color_change_fcn function, but it prints nothing.
This seems to be related to your previous question, where you want the two loops to be running simultaneously (well at least appear to be that way).
Building on #Peter's answer, consider the following working example:
function timerDemo()
%# prepare GUI
hFig = figure('Menubar','none', 'Resize','off');
axes('XLim',[0 1], 'YLim',[0 1], 'Visible','off', ...
'Units','normalized', 'Position',[0.1 0.2 0.8 0.6])
hTxt = uicontrol('Style','text', 'FontSize',24, ...
'Units','normalized', 'Position',[0 0.9 1 0.1]);
hPatch = patch([0 0 1 1 0],[0 1 0 1 0],'k');
%# colors to cycle through
c = 1;
clr = lines(4);
%# create timer
delay = 0.5;
hTimer = timer('Period',delay, 'StartDelay',delay, ...
'ExecutionMode','FixedRate', 'TimerFcn',#timerCallback);
%# when figure is closed
set(hFig, 'CloseRequestFcn',#onClose);
%# process images
start(hTimer); %# start timer
for i=1:100
if ~ishandle(hFig), break; end
msg = sprintf('Processing image %d / %d', i, 100);
set(hTxt, 'String',msg)
%# some lengthy operation
pause(.1)
end
if isvalid(hTimer)
stop(hTimer) %# stop timer
delete(hTimer) %# delete timer
end
%# timer callback function
function timerCallback(src,evt)
if ~ishandle(hFig), return; end
%# incremenet counter circularly
c = rem(c,size(clr,1)) + 1;
%# update color of patch
set(hPatch, 'FaceColor',clr(c,:));
drawnow
end
%# on figure close
function onClose(src,evt)
%# stop and delete timer
if isvalid(hTimer)
stop(hTimer);
delete(hTimer);
end
%# call default close callback
feval(#closereq)
end
end
The code simulates running a lengthy processing step on a number of images, while at the same time showing an animation to keep the user entertained.
To keep the code simple, I am showing a patch that updates its color continuously (using a timer). This stands for the animated GIF image of "loading...".
Is this what you want? Just combine the loop bodies.
for i=1:200
if mod(i,2) == 0
set(hAxes,'Color','b');
else
set(hAxes,'Color','g');
end
image2 = horzcat('now processing ', 'image', num2str(i), '.jpg of 200 images');
set(loading1,'string',image2);
drawnow;
end
EDIT: OK, in that case, try a timer instead of the first loop
function output = main_function
% Your other setup calls
hAxes = axes('Parent',hFigure,'Units','pixels','Position',[0 112 424 359]);
c = 0;
t = timer('TimerFcn', #color_change_fcn, 'Period', 1.0);
start(t);
for i=1:200
image2 = horzcat('now processing ', 'image', num2str(i), '.jpg of 200 images');
set(loading1,'string',image2);
drawnow;
end
function color_change_fcn
if mod(c,2) == 0
set(hAxes,'Color','b');
else
set(hAxes,'Color','g');
end
drawnow;
c = c + 1;
end
end
Just remember that the MATLAB control flow is inherently single-threaded, so these callbacks won't run if MATLAB is busy working somewhere else.

Code for a multicolumn legend in Matlab

I have designed an application called CLegend, which allows to build a multicolumn legend, whose code is
function CLegend(hax,numcol,Ley)
%# Inputs
% hax : handle of the axes object to which belongs the legend
% numcol: number of columns for the legend
% Ley: text strings (labels) for the legend
set(hax,'Units','normalized','Position',[0.1 0.1 0.8 0.8]);
set(hax,'Units','characters');
posAx = get(hax,'Position');
insAx = get(hax,'TightInset');
[legend_h,object_h] = legend(hax,Ley,'Units','characters','Location',...
'South','Orientation','vertical');
posl = get(legend_h,'Position');
numlines = length(Ley);
if (numlines<numcol)
numcol = numlines;
end
numpercolumn = ceil(numlines/numcol);
if (mod(numlines,numpercolumn) == 0)
numcol = numlines/numpercolumn;
end
l = zeros(1,numlines);
a = zeros(1,numlines);
h = zeros(1,4);
for j=1:numlines
h = get(object_h(j),'Extent');
l(j) = h(3);
a(j) = h(4);
set(object_h(j),'Units','characters');
end
lmax = posl(3)*max(l);
hmax = posl(4)*max(a);
hLine = object_h(numlines+1);
xdata = get(hLine, 'xdata');
dx = xdata(2)-xdata(1);
di = 2;
sheight = hmax;
height = hmax*numpercolumn-sheight/2;
line_width = dx*posl(3);
spacer = xdata(1)*posl(3);
delta1 = spacer + line_width + spacer + lmax;
delta2 = line_width + spacer + lmax + spacer;
delta3 = lmax + spacer + line_width + spacer;
factx = 1/(posl(3)*numcol);
facty = 1/(hmax*numpercolumn);
width_l = numcol*delta1;
set(legend_h, 'Position', [posAx(1) + 0.5*(posAx(3)-width_l) posl(2) ...
width_l numpercolumn*hmax]);
col_ind = -1;
row_ind = -1;
j = 0;
for i=1:numlines,
if strcmpi(orient,'horizontal'),
if mod(i,numcol)==1,
row_ind = row_ind+1;
end
col_ind = mod(i,numcol)-1;
if col_ind == -1,
col_ind = numcol-1;
end
else
if numpercolumn==1 || mod(i,numpercolumn)==1,
col_ind = col_ind+1;
end
row_ind = mod(i,numpercolumn)-1;
if row_ind == -1,
row_ind = numpercolumn-1;
end
end
if (i==1)
linenum = i+numlines;
else
linenum = linenum+di;
end
labelnum = i;
set(object_h(linenum), 'ydata',facty*[height-row_ind*sheight ...
height-row_ind*sheight]);
set(object_h(linenum), 'xdata', factx*[spacer + j*delta2 ...
spacer + j*delta2 + line_width]);
set(object_h(linenum+1), 'ydata',facty*(height-row_ind*sheight));
set(object_h(linenum+1), 'xdata', factx*(spacer+line_width/2));
set(object_h(labelnum), 'Position', [j*delta3+spacer*2+line_width ...
height-row_ind*sheight]);
if (mod(i,numpercolumn)== 0)
j = j + 1;
end
end
opl = get(legend_h,'OuterPosition');
set(hax, 'Position',[posAx(1) posAx(2)+opl(4) posAx(3) posAx(4)-opl(4)]);
set(legend_h, 'OuterPosition',[opl(1) (posAx(2)-insAx(2))/2 opl(3) opl(4)]);
set([hax,legend_h],'Units','normalized');
end
I have problems with it. I have tried it with a more complicated code but similar to this one that appears below.
function qq
fh = figure('Units','characters');
GrapWin = uipanel ('Parent',fh,'Units','characters','title','Graphic',...
'Position',[135 5 120 40]);
haxes = axes('Parent',GrapWin,'Units','normalized','Position',[0.1 0.1 0.8 0.8]);
PanVD = uipanel('Parent',fh,'Units','characters','Position',[55 5 30 10],...
'title','Dependent Variable');
VDlh = uicontrol('Parent',PanVD,'Style','listbox','Units',...
'normalized','Position',[0 0 1 1],'String',{'X','Y','Z'},'Value',1,...
'Callback',#VDLhCallback);
T = 0:pi/100:2*pi;
X = sin(T);
xlabel(haxes,'Time');
title(haxes,'Sine Function');
plot(haxes,T,X);
CLegend(haxes,3,{'Var X'});
function VDLhCallback (src,evt)
value = get(VDlh,'Value');
switch value
case 1
title(haxes,'Sine Function');
plot(haxes,T,X);
CLegend(haxes,3,{'Var X'});
case 2
title(haxes,'Cosine Function');
Y = cos(T);
plot(haxes,T,Y);
CLegend(haxes,3,{'Var Y'});
case 3
Z = tan(T);
title(haxes,'Tangent Function');
plot(haxes,T,Z);
CLegend(haxes,3,{'Var Z'});
end
end
end
It happens something that I do not understand because the first time that CLegend is called the legend appears not centered (respect to axes) but the following callings through the listbox options it does is centered.
Other problem that occurs is that if I delete the command line
set(haxes,'Units','normalized')
then, although the legend is centered, the axes appear with a reduced size.
I also have found that the first time Clegend is calles, the position of the axes (variable posAx) is different from the following callings (in which posAx is always the same).
I have thought that when the units were changed, the position of the object was not changed but this problem arises doubts inside my mind.
In the Figure Properties documentation, it is said of Unit
This property affects the CurrentPoint and Position properties. If you
change the value of Units, it is good practice to return it to its
default value after completing your computation so as not to affect
other functions that assume Units is the default value.
Can it explain your problems?
After a lot of proofs, I have found that my problem was the resizing of the figure. The first time CLegend was called the figure window had its original size. The following calls of CLegend happened with the figure windows maximized.