How can I write this animated figure as a movie?

This is a scaled-down model of a larger bit of code I have been trying to write to generate an animated plot of audio measurements taken in a matrix of 10 x 10 microphone positions - 10 simulatneous channels per each of the 10 positions (well, 11 channels were recorded at each position, but I only need 10 of them, hence the indexing in the example datacall format from the real code). Was unable to get it to work properly at "full-scale" (no errors, but an almost "jammed" figure, so probably wildly inefficient processing), so made a small model of it to demostrate what I'm trying to achieve. Further to saving the animated plot as a movie, if anyone has any other suggestions on how to improve the code, I'd be very grateful to hear them.
I've tried the things suggested in the documentation for writeAnimation and fanimator, but I don't think I'm giving those functions the correct type of figure/data to write.
Many thanks in advance!
% "SCALE MODEL" of 10x10 PLOTTING CODE
% Build random matrices for example purposes - i.e., 5 "channels" of audio, each
% 20 "samples" long. Each five channel signal "played" from five
% positions, resulting in a 5 x 5 matrix of microphones/measurements/audio
% vectors.
fs = 5; % Otherwise 48000 for audio measurements.
a = -1; % Generate values between -1 and 1 to simulate audio signals.
b = 1;
Position1 = a + (b - a) .* rand(20,5); % Would call audio data here.
Position2 = a + (b - a) .* rand(20,5); % Format: Pos01audio = Pos01audiodata.audio(:,1:10);
Position3 = a + (b - a) .* rand(20,5); % Should audio vectors be tranposed into rows?
Position4 = a + (b - a) .* rand(20,5);
Position5 = a + (b - a) .* rand(20,5);
[NumSamples] = size(Position1(:,1)); % Get length of audio vectors from any; all measurements are the same length; 4secs or 4*fs.
NumSamples = NumSamples(1,1);
for i = 1 : NumSamples % Length of audio file in samples.
PlotMatrix = [Position1(i,:); Position2(i,:); Position3(i,:); Position4(i,:); Position5(i,:)]; % Concatenate arrays into matrix to be rewritten in 'for' loop.
OutputPlot = surf(PlotMatrix);
grid on
pause(1/fs) % Make pause equivalent to sample rate.
drawnow
end

Answers (1)

10 Comments

Why bother? Do you seriously think I would ask if I hadn't tried examples in existing relevant answer threads and documentation?
Why is this forum full of so many goddamn condescending people refusing to accpet that not everyone was born knowing everything, so might need some ACTUAL assistance.
There is a differnce between images and figures.
Yes, there is a difference, and you can use functions like getframe to convert one to the other.
Sorry, I meant to say surface plots, not figures (it's been a rotten day). So, I mean can a surface plot be captured as an image in the same way as a 2d plot, as in the example, or does it require another step in processing? I wasn't able to modify it to work with a surf plot. Sorry for the confusion.
KSSV
KSSV on 13 Oct 2020
Edited: Rik on 13 Oct 2020
forum full of so many [] condescending people refusing to accpet that not everyone was born knowing everything
You got a very good opinion.....
When you ask a question, if the question is already answered, why to explain the same? What's wrong in showing the link? It is the user who has to try, not like people here write and give you entire code.
If you have tried what sowin in the link....tell us what error you have? So that we can futher help you. You have to show the error not pointing the users here who are helping you.
Sorry, I meant to say surface plots, not figures (it's been a rotten day). So, I mean can a surface plot be captured as an image in the same way as a 2d plot,
Yes...you can ..see this link:
I hope you will not point out that people here are [] CONDESCENDING ..as a link is given.
It is possible to capture a surface plot as an image in the same way as a 2-d plot. See as an example:
% Sample data
[x, y, z] = peaks;
h = surf(x, y, z);
% Capture the first frame
M = getframe(gca);
[~, EL] = view;
for k = 0:180
% Rotate the axes
view(k, EL);
% Capture the next frame
M(end+1) = getframe(gca);
end
% Show the movie
movie(M)
But nothing in the code you've posted does any capturing of image data. Can you show us that section of your code and explain what happens when you run it that you want to fix and/or change (error messages, part of the image cut off, excessive whitespace, etc.)?
I thought when posted someone a link it meant "it's been answered here, go there". So I tried to add to the thread there. But it was the code I tried from that page made me think it's different for surface plots is below. I'm yet to try to the above example, which looks more like what I would expect.
I got this error:
Error using getframe (line 52)
A valid figure or axes handle must be specified
Error in AniSurfSimple03 (line 31)
ImageFrames = getframe(OutputPlot);
From this code ...
% "SCALE MODEL" of 10x10 PLOTTING CODE
% Build random matrices for example purposes - 5 "channels" of audio, each
% 20 "samples" long. Each five channel signal "played" from five
% positions, resulting in a 5 x 5 matrix of microphones/measurements/audio
% vectors.
fs = 5; % Otherwise 48000 for audio measurements.
a = -1; % Generate values between -1 and 1 to simulate audio signals.
b = 1;
Position1 = a + (b - a) .* rand(20,5); % Would call audio data here.
Position2 = a + (b - a) .* rand(20,5); % Format: Pos01audio = Pos01audiodata.audio(:,1:10);
Position3 = a + (b - a) .* rand(20,5); % Should audio vectors be tranposed into rows?
Position4 = a + (b - a) .* rand(20,5);
Position5 = a + (b - a) .* rand(20,5);
[NumSamples] = size(Position1(:,1)); % Get length of audio vectors from any; all measurements are the same length; 4secs or 4*fs.
NumSamples = NumSamples(1,1);
for i = 1 : NumSamples % Length of audio file in samples.
PlotMatrix = [Position1(i,:); Position2(i,:); Position3(i,:); Position4(i,:); Position5(i,:)]; % Concatenate arrays into matrix to be rewritten in 'for' loop.
OutputPlot = surf(PlotMatrix);
grid on
pause(1/fs) % Make pause equivalent to sample rate.
drawnow
% Capture the plot as an image
ImageFrames = getframe(OutputPlot);
im = frame2im(ImageFrames);
[imind,cm] = rgb2ind(im,256);
% Write to the GIF File
if n == 1
imwrite(imind,cm,filename,'gif', 'Loopcount',inf);
else
imwrite(imind,cm,filename,'gif','WriteMode','append');
end
end
But capturing the animated plot matters somewhat less to a much more nuanced question about why that plotting code would not work as well with longer, "real" audio vectors. Doesn't seem to be much of that kind of help available here. Do you have any suggestions on where to look, or who to ask for some more specific help?
Tried your latest suggestion, but I'm sorry, I dont understand how these lines of code can be adapted to my needs. At what point should it call frames from the animated figure already generated in the 'for' loop? The surface plot is variable 'h', but isn't refferred to again, but from what I've read and looked at about it, getframe(gca) is acquiring frames from the plot 'h'. It seems this is to rotate and animate a static plot through 180 degrees, not capture an animated plot as a movie or GIF. When inserted and adpted to my script, it gets the first frame of the animated surf plot and rotates it by 180 degrees, but that's all. It would need to capture every redrawing of the plot as an image, so I thought the loop for 'getframe' would be 1 : NumSamples ... one frame per sample, etc.
Another way of putting it is that the figure is already animated, doesn't require animation, just capturing as image frames, to then be aseembled into an AVI or GIF, etc. using writeAnimation or similar.
I get this message after it runs ... which I think means it is coming up against the 'drawnow' function call refershing the figure, hence "invalid or deleted object".
Warning: The following error was caught while executing 'onCleanup' class destructor:
Error using matlab.ui.Figure/set
Invalid or deleted object.
Error in matlab.graphics.internal.getframeWithDecorations>doCleanup (line 57)
set(opts.fig, 'Visible', opts.Visible);
Error in matlab.graphics.internal.getframeWithDecorations>@()doCleanup(opts) (line 39)
cleanupHandler = onCleanup(@() doCleanup(opts));
Error in onCleanup/delete (line 81)
obj.task();
Error in matlab.graphics.internal.getframeWithDecorations (line 53)
end
Error in alternateGetframe
Error in getframe (line 138)
x = alternateGetframe(parentFig, offsetRect, scaledOffsetRect, includeDecorations);
Error in AniSurfSimple03 (line 36)
M(end+1) = getframe(gca);
> In matlab.graphics.internal.getframeWithDecorations (line 53)
In alternateGetframe
In getframe (line 138)
In AniSurfSimple03 (line 36)
Error using getpixelposition (line 30)
First argument must be a valid graphics object handle.
Error in alternateGetframe
Error in getframe (line 138)
x = alternateGetframe(parentFig, offsetRect, scaledOffsetRect, includeDecorations);
Error in AniSurfSimple03 (line 36)
M(end+1) = getframe(gca);
(Is there a "convention" on how to include and format error messages in a comment or answer?)
I'm terribly sorry that I haven't been able to make this work. This is the first time I've ever required an animated plot ... and hopefully the last. Thanks in advance for any help you may be able to provide. Cheers!
This is the code ...
% "SCALE MODEL" of 10x10 PLOTTING CODE
% Build random matrices for example purposes - 5 "channels" of audio, each
% 20 "samples" long. Each five channel signal "played" from five
% positions, resulting in a 5 x 5 matrix of microphones/measurements/audio
% vectors.
fs = 5; % Otherwise 48000 for audio measurements.
a = -1; % Generate values between -1 and 1 to simulate audio signals.
b = 1;
Position1 = a + (b - a) .* rand(20,5); % Would call audio data here.
Position2 = a + (b - a) .* rand(20,5); % Format: Pos01audio = Pos01audiodata.audio(:,1:10);
Position3 = a + (b - a) .* rand(20,5); % Should audio vectors be tranposed into rows?
Position4 = a + (b - a) .* rand(20,5);
Position5 = a + (b - a) .* rand(20,5);
[NumSamples] = size(Position1(:,1)); % Get length of audio vectors from any; all measurements are the same length; 4secs or 4*fs.
NumSamples = NumSamples(1,1);
for i = 1 : NumSamples % Length of audio file in samples.
PlotMatrix = [Position1(i,:); Position2(i,:); Position3(i,:); Position4(i,:); Position5(i,:)]; % Concatenate arrays into matrix to be rewritten in 'for' loop.
OutputPlot = surf(PlotMatrix);
grid on
pause(1/fs) % Make pause equivalent to sample rate.
drawnow
M = getframe(gca);
[~, EL] = view;
for k = 0:180
% Rotate the axes
view(k, EL);
% Capture the next frame
M(end+1) = getframe(gca);
end
end
Thanks a lot! It got me there in the end. I intend to save as AVI movie, but that looks simple enough to implement from where I am now. The main issue I was having was calling the "axes handle" of the figure being created by the 'for' loop. But now that I've got the image capture working fine, and AVI will be simple.
Looking at the code, I get the impression I have a few unnecesary (or misinterpreted) lines, possibly making it inefficient. Do you have any quick thoughts on that?
Thanks.
Here is the 'for' loop code updated to capture image frames ...
for i = 1 : NumSamples % Length of audio file in samples.
PlotMatrix = [Position1(i,:); Position2(i,:); Position3(i,:); Position4(i,:); Position5(i,:)]; % Concatenate arrays into matrix to be rewritten in 'for' loop.
OutputPlot = surf(PlotMatrix);
grid on
pause(1/fs) % Make pause equivalent to sample rate.
drawnow
PlotHandle = gcf;
ImageFrames = getframe(PlotHandle);
im = frame2im(ImageFrames);
[imind, cm] = rgb2ind(im,256);
% Write GIF file
if i == 1
imwrite(imind, cm, 'AnimatedFigure.gif', 'gif', 'Loopcount', inf);
else
imwrite(imind, cm, 'AnimatedFigure.gif', 'gif', 'WriteMode', 'append');
end
end

Sign in to comment.

Categories

Products

Release

R2019b

Asked:

on 12 Oct 2020

Commented:

on 14 Oct 2020

Community Treasure Hunt

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

Start Hunting!