Using movie to record subplot frames in for loop

11 views (last 30 days)
Hi Mathworks,
I have the following code:
N1=rand(121,20e3);
X1=rand(1,121);
Y1=rand(1,121);
Z1=rand(1,121);
N2=rand(121,20e3);
X2=rand(1,121);
Y2=rand(1,121);
Z2=rand(1,121);
dt=100;
for i=1:dt:length(N1)
ax=gca
subplot(1,2,1);
ax=gca;
cmap=N1(:,i)';
hAxes=scatter3(X1,Y1,Z1,50,cmap,'filled');
title(strcat('Time = ',num2str(i*0.1),' ms'));
colorbar;
caxis(ax,[0 1]);
subplot(1,2,2)
ax2=gca
cmap2=N2(:,i)';
hAxes2=scatter3(X2,Y2,Z2,50,cmap2,'filled');
title(strcat('Time = ',num2str(i*0.1),' ms'));
colorbar;
caxis(ax2,[0 1]);
drawnow
end
It generates some subplots that update at each iteration of the FOR loop. Crucially the colorbars do not change their MIN and MAX on each iteration.
How do I record this into a movie?
I have tried creating a structure F and using movie(F) but it doesn't seem to work.
Thanks! Linford
PS also any clues on how better to have a "time = " updating during the movie would be really appreciated!
  1 Comment
Jan
Jan on 31 Jan 2017
Please post the code for teh creatrion of the struct F and explain, what "doesn't seem to work" exactly means. It is easier to suggest an improvement than to guess, what you have done and which problem occurred. :-)
Concerning a "better" way to display the time: What do you see as drawback currently?

Sign in to comment.

Accepted Answer

Jan
Jan on 31 Jan 2017
Edited: Jan on 2 Feb 2017
% [EDITED] Updated version, 31-Jan-2017 16:19:11 UTC]
FigH = figure;
ax1 = subplot(1, 2, 1, 'NextPlot', 'add'); % as: hold on
colorbar;
caxis(ax1,[0 1]);
t1 = title('dummy');
view(ax1, 3);
ax2 = subplot(1, 2, 2, 'NextPlot', 'add'); % as: hold on
colorbar;
caxis(ax2,[0 1]);
t2 = title('dummy');
view(ax2, 3);
dt = 100;
nFrame = numel(1:dt:length(N1)); % [EDITED]
F(nFrame) = struct('cdata',[],'colormap',[]);
ScatterH1 = [];
ScatterH2 = [];
iFrame = 0;
for i = 1:dt:length(N1)
if ~isempty(ScatterH1) % Clean up former objects
delete(ScatterH1); % Alternative: Update the 'CData' only
delete(ScatterH2);
end
cmap=N1(:,i)';
ScatterH1 = scatter3(X1,Y1,Z1,50,cmap,'filled', 'Parent', ax1);
set(t1, 'String', sprintf('Time = %.1f ms', i*0.1)); % [EDITED]
cmap2=N2(:,i)';
ScatterH2 = scatter3(X2,Y2,Z2,50,cmap2,'filled', 'Parent', ax2);
set(t2, 'String', sprintf('Time = %.1f ms', i*0.1)); % [EDITED]
drawnow
iFrame = iFrame + 1;
F(iFrame) = getframe(FigH); % Not i, because this steps in dt
end
figure;
MovieSize = [size(F(1).cdata, 2), size(F(1).cdata, 1)];
AxesH = axes('Visible', 'off', 'Units', 'pixels', ...
'Position', [10, 10, MovieSize]);
movie(AxesH, F);
I runtime matters, create the scatter3 objects once and only update the 'XData', 'YData' and 'ZData', or 'CData' in the loop.
If you speficy your problems, I will update this suggestion in the "..." line.
  12 Comments
Linford Briant
Linford Briant on 2 Feb 2017
Thanks Jan and Image Analyst, very useful material.
Here is my solution:
v = VideoWriter('example.avi');
open(v);
N1=rand(121,20e3);
X1=rand(1,121);
Y1=rand(1,121);
Z1=rand(1,121);
N2=rand(121,20e3);
X2=rand(1,121);
Y2=rand(1,121);
Z2=rand(1,121);
dt=100;
% [EDITED] Updated version, 31-Jan-2017 16:19:11 UTC]
FigH = figure;
hold on
ax1 = subplot(1, 2, 1, 'NextPlot', 'add'); % as: hold on
colorbar;
caxis(ax1,[0 1]);
t1 = title('dummy');
view(ax1, 3);
ax2 = subplot(1, 2, 2, 'NextPlot', 'add'); % as: hold on
colorbar;
caxis(ax2,[0 1]);
t2 = title('dummy');
view(ax2, 3);
dt = 1000;
nFrame = numel(1:dt:length(N1)); % [EDITED]
F(nFrame) = struct('cdata',[],'colormap',[]);
ScatterH1 = [];
ScatterH2 = [];
iFrame = 0;
for i = 1:dt:length(N1)
if ~isempty(ScatterH1) % Clean up former objects
delete(ScatterH1); % Alternative: Update the 'CData' only
delete(ScatterH2);
end
cmap=N1(:,i)';
ScatterH1 = scatter3(X1,Y1,Z1,50,cmap,'filled', 'Parent', ax1);
set(t1, 'String', sprintf('Time = %.1f ms', i*0.1)); % [EDITED]
cmap2=N2(:,i)';
ScatterH2 = scatter3(X2,Y2,Z2,50,cmap2,'filled', 'Parent', ax2);
set(t2, 'String', sprintf('Time = %.1f ms', i*0.1)); % [EDITED]
drawnow
iFrame = iFrame + 1;
F(iFrame) = getframe(FigH); % Not i, because this steps in dt
writeVideo(v,F(iFrame));
end
close(v);
I had to hold on to the figure because the frame changes size on every iteration... not sure why though because when the video is playing it doesn't seem to change size!

Sign in to comment.

More Answers (1)

Image Analyst
Image Analyst on 31 Jan 2017
  3 Comments
Linford Briant
Linford Briant on 2 Feb 2017
I actually opened these initially but it was above my station.
So I have to extract movie frames to make a video?
Image Analyst
Image Analyst on 3 Feb 2017
Well I didn't have the time, at that time, to adapt the demo for you - I was hoping you'd see how to do it. No, you don't have to write images or graphs to intermediate/temporary files. You can go right from the graph/axes to a video file and that's what my movie_made_from_surf.m demo shows. You can either make up the entire movie structure in memory, as I did, or if the movie would take up too much memory, you can skip that and go right from read() to writeVideo() without any intermediate complete movie being made. Something like this snippet
% Extract the frame from the movie.
thisFrame = read(videoObject, frame);
% Write this frame out to a new video file.
writeVideo(writerObj, thisFrame);
For what it's worth, I'm attaching another demo that I did for someone who wanted to convert an .avi format movie into a .mp4 format movie.

Sign in to comment.

Categories

Find more on Graphics Performance 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!