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);
Related
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
I have a quite complex function that I plot using fsurf with a reasonably high MeshDensity (I cannot go much lower than the default, which is 35). Exporting this figure (saveas(gcf, 'file.pdf', 'pdf');) results in a 20-something MB pdf file of very nice quality, which nonetheless renders terribly slow. I would like to reduce the file size and, most importantly, the complexity of this pdf file, without exporting the whole plot (by which I mean the whole MATLAB figure) as a bitmap. How can I do that?
The perfect answer would explain how I can convert the surface plot (by which I mean, just the colored function surface on the white background) into a bitmap while maintaining the vectorized nature of axes and labels.
Update: Here's an example of such a plot.
This is my function BitmapRender, which Bitmap-renders part of the figure:
%% Test Code
clc;clf;
Objects = surf(-4-2*peaks);
hold('on');
Objects(2 : 50) = plot(peaks);
Objects(51) = imagesc([20 40], [0, 5], magic(100));
hold('off');
ylim([0 10]);
zlim([-10 15]);
Objects(1).Parent.GridLineStyle = 'none';
view(45, 45);
set(gcf, 'Color', 'white');
rotate3d on
saveas(gcf, 'pre.pdf');
BitmapRender(gca, Objects(2 : 3 : end));
% BitmapRender(gca, Objects(2 : 3 : end), [0.25 0.25 0.5 0.5], false);
saveas(gcf, 'post.pdf');
The function itself is pretty simple, except for the (re-)handling of visibility, as pressing the space key (after rotating, zooming etc) re-renders the figure.
function BitmapRender(Axes, KeepObjects, RelativePosition, Draft, Key)
if nargin < 2
KeepObjects = [];
end
if nargin < 3
RelativePosition = [0 0 1 1];
end
if nargin < 4
Draft = false;
end
if nargin < 5
Key = '';
end
Figure = Axes.Parent;
FigureInnerWH = Figure.InnerPosition([3 4 3 4]);
PixelPosition = round(RelativePosition .* FigureInnerWH);
if isempty(Key)
OverlayAxes = axes(Figure, 'Units', 'Normalized', 'Position', PixelPosition ./ FigureInnerWH);
if Draft
OverlayAxes.Box = 'on';
OverlayAxes.Color = 'none';
OverlayAxes.XTick = [];
OverlayAxes.YTick = [];
OverlayAxes.HitTest = 'off';
else
uistack(OverlayAxes, 'bottom');
OverlayAxes.Visible = 'off';
end
setappdata(Figure, 'BitmapRenderOriginalVisibility', get(Axes.Children, 'Visible'));
Axes.CLimMode = 'manual';
Axes.XLimMode = 'manual';
Axes.YLimMode = 'manual';
Axes.ZLimMode = 'manual';
hManager = uigetmodemanager(Figure);
[hManager.WindowListenerHandles.Enabled] = deal(false);
set(Figure, 'KeyPressFcn', #(f, e) BitmapRender(gca, KeepObjects, RelativePosition, Draft, e.Key));
elseif strcmpi(Key, 'space')
OverlayAxes = findobj(Figure, 'Tag', 'BitmapRenderOverlayAxes');
delete(get(OverlayAxes, 'Children'));
OriginalVisibility = getappdata(Figure, 'BitmapRenderOriginalVisibility');
[Axes.Children.Visible] = deal(OriginalVisibility{:});
else
return;
end
if Draft
return;
end
Axes.Visible = 'off';
KeepObjectsVisibility = get(KeepObjects, 'Visible');
[KeepObjects.Visible] = deal('off');
drawnow;
Frame = getframe(Figure, PixelPosition);
[Axes.Children.Visible] = deal('off');
Axes.Visible = 'on';
Axes.Color = 'none';
if numel(KeepObjects) == 1
KeepObjects.Visible = KeepObjectsVisibility;
else
[KeepObjects.Visible] = deal(KeepObjectsVisibility{:});
end
Image = imagesc(OverlayAxes, Frame.cdata);
uistack(Image, 'bottom');
OverlayAxes.Tag = 'BitmapRenderOverlayAxes';
OverlayAxes.Visible = 'off';
end
Obviously, the solution is pixel-perfect in terms of screen pixels. Two pdf files (pre and post) look like this. Note that surface, image and some plot lines are bitmap rendered, but some other plot lines, as well as axes and labels are still vectorized.
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
I have written the following code the plot the height of water in a tank vs. time.
A_t = 16;
[h1, t1] = update_plot(A_t);
f = figure;
h = plot(t1, h1);
b = uicontrol('Parent',f,'Style','slider','Position',[81,54,419,23], 'value',A_t, 'min',14, 'max',17);
bgcolor = f.Color;
set(b,'Callback',#(es,ed) updateSystem(h,update_plot((es.Value))))
The function to update the h (height of water) and t (time) vectors is:
function [h1, t1] = update_plot(A_t)
t = 0:0.01:100;
h = zeros(1, length(t));
h_init = 20;
t_0 = 0;
myeps = 1e-5;
i = 1;
h(1) = h_init;
while h(i) > myeps
i = i + 1;
h(i) = (sqrt(h_init) - (0.18/A_t)*sqrt(981/2)*(t(i) - t_0))^2;
h1 = h(1:i);
t1 = t(1:i);
end
The parameter A_t is the variable for which I want to use a slider.
I cannot get the callback function to work.
I want the plot to be updated as I move the slider.
You can try this:
set(b,'Callback', #slider_callback);
function slider_callback(hObject, callbackdata)
A_t = num2str(hObject.Value);
update_plot(A_t);
end
Then you would also have to clear your figure with cla and use plot with the update values.
I got it working. The modified code and functions are:
function[f] = update_plot(A_t)
t = 0:0.01:100;
h = zeros(1, length(t));
h_init = 20;
t_0 = 0;
myeps = 1e-5;
i = 1;
h(1) = h_init;
while h(i) > myeps
i = i + 1;
h(i) = (sqrt(h_init) - (0.18/A_t)*sqrt(981/2)*(t(i) - t_0))^2;
h1 = h(1:i);
t1 = t(1:i);
end
f = plot(t1, h1);
legend('Measured', 'Tuned')
grid on
The callback function is:
function change_plot(objHandle, ~)
slider_value = get(objHandle, 'Value');
new_A_t = slider_value;
update_plot(new_A_t);
And the main function is:
A_t = 15.5;
ff = figure;
axes('Parent',ff, 'units', 'normalized',...
'position',[0.05 0.15 0.9 0.8])
update_plot(A_t);
b = uicontrol('Parent',ff,'Style','slider',...
'value',A_t, 'min',14, 'max',17,...
'units', 'normalized',...
'position', [0.33 0 0.4 0.1],...
'SliderStep', [0.001 0.1],...
'callback', #change_plot);
disp_h = uicontrol('style', 'edit',...
'units', 'normalized',...
'position', [0.15 0.05 0.15 0.05]);
bgcolor = ff.Color;
Now I want to display the value of the slider in the 'edit' box I've created, but so far have been unable to get it to work.
I'm creating a tool for our engineering team to view data coming off our systems in the field. The underlying data isn't critical to it. Basically, it consists of vectors containing Y data at X time.
I'm plotting a series of vectors using subplot. Each plot has the ButtonDownFcn defined to launch a window that allows for deeper analysis. The problem is that when I click on the axes in the deployed application, nothing happens. There are no error messages or anything. When I click on the axes running it in Matlab, it works exactly as expected.
I'm not sure what's going on once the code is deployed that is preventing it from functioning properly. I'm a little lost on where to go. I've included my code and some sample data.
Test Data:
stats = struct('name','Car 54', ...
'date', '11-Aug-2014');
stats.SOC = struct('time', linspace(1,24,100)*3600', ...
'plugdata', [100*ones(20,1); NaN(70,1); (20:4:56)'], ...
'drivedata', [NaN(20,1); (100:-2:60)'; NaN(10,1); (40:-2:20)'; NaN(20,1); (30:-2:16)'; NaN(10,1)], ...
'eptodata', [NaN(41,1); (58:-2:40)'; NaN(11,1); (18:-2:5)'; NaN(13,1); NaN(7,1); NaN(11,1)], ...
'engchargedata', [NaN(69,1); (5:2:30)'; NaN(18,1)], ...
'otherdata', NaN(100,1));
Code:
function [output] = summarytablepopup(stats)
FH = figure('Name','Summary Table Popup', ...
'Units', 'normalized', ...
'Position', [0.05 0.05 0.9 0.8], ...
'Tag', 'sumTablePU', ...
'Toolbar', 'none', ...
'NumberTitle', 'off', ...
'WindowStyle', 'normal', ...
'Resize', 'on', ...
'CloseRequestFcn', #closereq, ...
'MenuBar', 'none', ...
'UserData', {});
movegui(FH,'onscreen')
noStats = numel(stats);
screensize = get(0,'ScreenSize');
mapIMG = imread([pwd '\icons\map.jpg']);
noGraphs = 5;
AH = NaN(noStats,1); % axes handles
TT = NaN(noStats,1); % name text handles
MB = NaN(noStats,1); % map button handles
TH = NaN(ceil(noStats/noGraphs),1); % tab handles
warning('off','all')
TGH = uitabgroup('Parent',FH); % tab group handle
for ii = 1:length(TH)
TH(ii) = uitab('parent',TGH,'title',sprintf('Page %d',ii));
end
warning('on','all')
for ii = 1:noStats
currentPage = ceil(ii/noGraphs);
vehiclename = stats(ii).name;
vehicledate = stats(ii).date;
if isfield(stats(ii),'SOC') && ~isempty(stats(ii).SOC) && isfield(stats(ii).SOC,'time') && ~isempty(stats(ii).SOC.time)
SOC = stats(ii).SOC;
time = SOC.time/3600;
subplot(5,1,mod(ii-1,noGraphs)+1,'Parent',TH(currentPage))
HH = plot(time, SOC.plugdata, 'g-x', ...
time, SOC.eptodata, 'b-x', ...
time, SOC.engchargedata, 'b-x', ...
time, SOC.drivedata, 'r-x', ...
time, SOC.otherdata, 'k-x');
AH(ii) = get(HH(1),'Parent');
set(HH,'Marker','.')
set(HH(3),'Color',[0 0.75 1])
set(HH(3),'MarkerFaceColor',[0 0.75 1])
else
subplot(5,1,mod(ii-1,noGraphs)+1,'Parent',TH(currentPage))
HH = plot([0 12 24],[NaN NaN NaN]);
AH(ii) = get(HH(1),'Parent');
%}
end
pos = get(AH(ii),'Position');
pos(1) = 0.25;
pos(3) = 0.72;
set(AH(ii),'Position',pos)
set(AH(ii),'UserData', ii)
set(AH(ii),'ButtonDownFcn', #divedeep)
set(AH(ii),'YLim',[0 100])
set(AH(ii),'YTick',[0 25 50 75 100])
set(AH(ii),'YTickLabel',{'0','25','50','75','100'})
set(AH(ii),'XLim',[0 24])
set(AH(ii),'XTick',[0 4 8 12 16 20 24])
set(AH(ii),'XTickLabel',{'0000','0400','0800','1200','1600','2000','2400'})
mapHeight = 0.1;
mappos = [0.18 pos(2)+pos(4)/2-mapHeight/2 mapHeight*screensize(4)/screensize(3) mapHeight];
MB(ii) = uicontrol('Parent', TH(currentPage), 'Style', 'pushbutton', ...
'Tag', sprintf('mapButton%d',ii), ...
'String', '', ...
'Units', 'normalized', ...
'Position', mappos, ...
'CData', mapIMG, ...
'Callback', #mapbutton);
if isfield(stats(ii),'location') && ~isempty(stats(ii).location) && isfield(stats(ii).location,'time') && ~isempty(stats(ii).location.time)
set(MB(ii),'Enable','on')
else
set(MB(ii),'Enable','off')
end
textHeight = 0.05;
textpos = [0.01 pos(2)+pos(4)/2-textHeight/2 0.15 textHeight];
TT(ii) = uicontrol('Parent', TH(currentPage), 'Style', 'text', ...
'Tag', sprintf('text%d',ii), ...
'String', vehiclename, ...
'FontSize', 12, ...
'Units', 'normalized', ...
'Position', textpos);
end
uiwait(FH)
function mapbutton(source, event)
tag = get(source,'Tag');
splittag = strsplit(tag,'n');
jj = str2num(splittag{2});
loc = stats(jj).location;
if ~isempty(loc)
len = numel(loc.time);
map = [linspace(1,0,len)', linspace(0,1,len)', zeros(len,1)];
MFH = figure;
MPH = plot(loc.lon, loc.lat, 'r:');
hold on;
MSH = scatter(loc.lon, loc.lat, 50, 'o', 'filled', 'CData', map);
plot_google_map
else
msgbox('No location information available for this vehicle. Really should disable this button.')
end
end
function electric(source, event)
ratio = get(SH,'Value')/100*(0.9-startheight)+0.05;
set(PH, 'Position', [panpos(1) ratio panpos(3) panpos(4)])
end
function divedeep(source, event)
HEDtimeplot([],stats(get(source,'UserData')));
end
function closereq(source,event)
uiresume(source)
delete(source)
end
end