I have multiple 2D line plots in Matlab (they represent some wave moving through space). Each plot represents the wave at some time t. I want to animate through these plots (i.e. show the first plot for a fraction of a second, then show the next one, and the next, etc. I want to loop back to the beginning once it reaches the end time) to show the time evolution of the system. surf and mesh don't really do what I want since it is too difficult to see the changes with the number of time steps I have. Is there a way to do this in Matlab?
I assume with "2d-line" you mean a 2d-plot. This is done by the plot-function, so there is no need of surf or mesh. Sorry, when I got you wrong.
The following code does what I think you asked for:
% Generate some propagating wave
n = 20;
t = linspace(0,10,100);
x = cell(1,n);
for i = 1:n
x{i} = (1-abs(i/n-0.4))*sin(t+i*0.2);
end
% Create frames
figure;
for i = 1:length(x)
clf;
plot(t,x{i});
ylim([-1,1]);
myFrames(i) = getframe; %#ok<SAGROW>
end
% Show movie
figure;
movie(myFrames,2,2); % frames, repetitions, frames per second
Related
Does anyone know how to increase the size of the arrows in the Nyquist plot generated by MATLAB Control System Toolbox (while keeping the line width and everything else in the figure the same)?
I noticed that you also asked the same question in MATLAB
Central. Please make sure to refer other visitors to this answer if
you found it useful.
The Bad News first
MATLAB Control System Toolbox provides the functions nyquist and nyquistplot to draw a Nyquist plot of the frequency response of a dynamic system model.
Even though these functions allow a certain level of graphical customization (units, grids, labels and basic LineSpec), they don't allow to alter the size of the arrows that appear by default in the Nyquist plot (you can read more about this here and here).
The Good News (time to hack!)
I started exploring the object hierarchy of the Nyquist plot figure and realized that the arrows that are drawn are patch objects.
How did I notice that?
First I generated a sample Nyquist plot:
sys = tf([2 5 1],[1 2 3]); % System transfer function.
nyquist(sys); % Nyquist plot.
Then I ran a brute force test!
The following test iterates through every graphics object of the Nyquist plot figure window and blinks one element in every iteration. This way I was able to visually identify the objects that were linked to the arrows, when they started blinking.
h = findall(gcf); % Find all graphics objects including hidden ones.
t = 0.5; % Time interval.
for i = 1:length(h) % Loop through every object handle.
disp(i); % Display handle array index.
pause(t); % Pause for t seconds.
status = h(i).Visible; % Copy Visible property.
if strcmp(status, 'on') % If Visible = 'on' --> Visible = 'off'
h(i).Visible = 'off';
else % If Visible = 'off' --> Visible = 'on'
h(i).Visible = 'on';
end
pause(t); % Pause for t seconds.
h(i).Visible = status; % Restore original Visible property.
pause(t); % Pause for t seconds.
end
disp('Finished!'); % Display Finished!
After running this test, I found out that h(196) and h(197) were the two arrows of the Nyquist plot, and they were patch objects.
Changing the 'LineWidth' property was the next logical step. The following piece of code is really all you need to do in order to change the size of the arrows:
sys = tf([2 5 1],[1 2 3]); % System transfer function.
nyquist(sys); % Nyquist plot.
h = findall(gcf, 'Type', 'Patch'); % Find all patch objects.
for i = 1:length(h) % Loop through every patch object handle.
h(i).LineWidth = 4; % Set the new LineWidth value.
end
This is the result:
I hope that you enjoyed the adventure! :D
I'm trying to stitch together a bunch of plots I created within a loop into a single video file. I've been at this for several hours, but had no luck. Here is my minimum working example where I attempt to use the VideoWriter function to create a video. I always get an error saying my frame(s) can't be copied into the video objects. Grr.
Here is my minimum working example:
n=(1:50)*2*pi;
for t = 1:1000
Y = sin(n*50/t);
plot(Y); %plot shows a sine wave with decreasing frequency
F(t) = getframe; %I capture the plot here
end
writerObj = VideoWriter('test2.avi'); %Attempt to create an avi
open(writerObj);
for t= 1:time
writeVideo(writerObj,F(t))
end
close(writerObj);
Matheburg answer is correct and identified the part which was causing the error (at some point the scale of your axis was resized, which cause the frame size to change).
His solution works fine and if the usage of fplot works for you then follow his way.
In case you still want to use the traditional plot (2d lineserie object) method, then here's how I usually organize "animated" plots:
The plot function is high level. It means when it runs it plots the data (obviously) but also does a lot of other things. In any case it generate a completely new plot (erasing previous plot if hold on wasn't specified), but also readjust the axes limits and many other settings (color, style etc ...).
If in your animation you only want to update the plot data (the points/line position) but not change any other settings (axes limits, colors etc ...), it is better to define the plots and it's settings one time only, outside of the loop, then in the loop you only update the YData of the plot object (and/or the XData if relevant).
This is done by retrieving the plot object handle when you create it, then use the set method (which unlike plot will only modify the parameters you specify explicitly, and won't modify anything else).
In your case it looks like this:
n=(1:50)*2*pi ;
Y = sin(n*50) ;
hp = plot(Y) ; %// Generate the initial plot (and retrieve the handle of the graphic object)
ylim([-1,1]) ; %// Set the Y axes limits (once and for all)
writerObj = VideoWriter('test2.avi'); %// initialize the VideoWriter object
open(writerObj) ;
for t = 1:1000
Y = sin(n*50/t) ; %// calculate new Y values
set(hp,'YData',Y) ; %// update the plot data (this does not generate a "new" plot), nor resize the axes
F = getframe ; %// Capture the frame
writeVideo(writerObj,F) %// add the frame to the movie
end
close(writerObj);
Also, this method will usually runs faster, and save a significant amount of time if your loop has a great number of iterations.
Side note: As said above, Matheburg solution runs also fine. For such an application, the difference of speed will not be a major issue, but note that the plots (and movie) generated are slightly different (due to it's use of fplot instead of plot). So I encourage you to try both versions and choose which one suits you best.
You are missing a constant height of images. You can guarantee it by, e.g., ylim:
time = 100;
for t = 1:time
fplot(#(x) sin(x*50/t),[0,2*pi]); % plot
ylim([-1,1]); % guarantee consistent height
F(t) = getframe; % capture it
end
writerObj = VideoWriter('test2.avi');
open(writerObj);
writeVideo(writerObj, F)
close(writerObj);
I have further replaced your discrete plot by a "continuous" one (using fplot).
%free fall of a ball
clc
clear all
close all
v0=5; % initial velocity up
g=9.8; %free fall acceleration
v1=(0.7/0.9)*v0
% time of fly
tup=v0/9;
nsteps=10; %number of frames
dt=tup/nsteps; %time step
Hmax=v0*tup+(-g)*tup*tup/2; % maximum altitude
altitude(1:nsteps+1)=0; %define array for position Y
time=0:dt:tup;% define time array
%initilaise plot
figure(1)
axis([0,2*tup,0,2*Hmax]);
hold on
% loop
for i=1:nsteps
altitude(i)=v0*time(i)+(-g)*time(i)*time(i);
plot(time(i),altitude(i), 'ro')
grid on;
M(i)=getframe;
end
%loop bouncing
for i=1:nsteps
altitude(i)=v1*time(i)+(-g)*time(i)*time(i);
plot(time(i),altitude(i), 'ro')
grid on;
M(i)=getframe;
end
%make movie
movie(M);
movie2avi(M, 'C:\Users\Mehmet\Desktop\avi\mm','compression','none');
%extra plots
figure(2)
plot(time(1:nsteps),altitude(1:nsteps))
figure(3)
plot(time(1:nsteps),altitude(1:nsteps),'ro')
We have this ball bouncing simulation. What we want to do is, to continue loop 2 after loop 1 in graph.So, it will be continious bouncing simulation.2 bouncings are shown from 1:10 steps but we want second loop to be shown after 10 steps.
There are a couple of approaches, depending upon what effect you're going for. The simplest is to simply add hold on as a separate command after each of your plot commands. This will keep accumulating new lines/dots without erasing the old ones. To stop this effect, add a hold off command. The next plot command will then erase everything and plot on a clean graph.
Alternatively, if you only want to show a fixed number of the previous steps (and not all of them, as the hold on will do), you'll have to explicitly hold onto the previous values. Something like this:
% loop
max_history = 10; %plot this many symbols
for i=1:nsteps
altitude(i)=v0*time(i)+(-g)*time(i)*time(i);
%get the historical and current data points to plot
start_ind = i-max_history+1; %here's the oldest point that you'd like
start_ind = max([start_ind, 1]) %but you can't plot negative indices
inds = [start_ind:i]; %here are the ones to plot
%update the plot
plot(time(inds),altitude(inds), 'ro');
grid on;
%you might need a "drawnow" here
M(i)=getframe;
end
Copy this same idea into your other for loops and you should be good-to-go!
I'm trying to plot several signals in one graph and i would like to restrict them and sort of minimize it so all my signals will be clear (more or less).
I have no idea how to do it. I'm adding an image so what i need to do will be clearer.
My data changes but in general it's the mean intensity of each column of a certain area in an intensity image.I tried to do it like with the same idea as you but i don't get the right plot as i wanted. A is the relevant matrix,b is the matrix with shifted values:
for i=1:20
b(i,:)=A(i,:)+(100*i);
plot(b(i,:))
hold on
end
I will also add 2 images: one is the plot of all the 20 signals that i get and the other one is the plot of only the first signal. I don't understand why do they look so different.
You can try something like that :
x = [1:100]; %Distance 1 to 100
y = F(x) % Your first function (signal)
y2 = 0.5*G(x) % Your second function (signal)
plot(x,y,x,y2); % plot both function in a single plot.
hleg1 = legend('Intensity t1,'Intensity t27');
So you have your signal at intensity t27 half cut for each value ( 0.5 ), so it shift down.
So I have a plot of N points in the 2D plane (N can be very large). I am writing a script that is to show the workings of an algorithm. So I have for loops. At each step in the for loop I'd like to change the color of the current point (actually probably make a stem plot with just this point).
However, at the end of the step I'd like to remove the coloring of the current point so that I can color the next one. Currently I have to redraw the whole plot (incl. the 2D points). I'm not sure whether Matlab detects such things in the plotting commands but is there a way to do this without redrawing the whole plot?
For example:
plot(x,y, '*');
for j = 1:N-1
for i = j:N
hold on;
%Do stuff
plot(x,y, '*');
hold on;
stem(x(1), y(1), 'g*');
end
end
A quick example:
%# plot some data
x = 1:100;
y = cumsum(rand(size(x))-0.5);
plot(x,y,'*-')
%# animate by going through each point
hold on
h = stem(x(1),y(1),'g');
hold off
for i=1:numel(x)
%# update the stem x/y data
set(h, 'XData',x(i), 'YData',y(i));
%# slow down a bit, drawnow was too fast!
pause(.1)
end
Take a look at the documentation of handle graphics objects.
I'd recommend plotting the whole set of points as one object. Then, for each iteration, plot the point of interest. Save a handle to it (as in, h = plot(...);). When you're ready for the next iteration, delete the object using that handle (delete(h)), and create the next one in the same manner.
%# outside the for loop (do this once)
plot(x,y,'*');
for...
h = stem(x(i),y(i),'g*');
...
%# next iteration... i has been incremented
delete(h);
h = stem(x(i),y(i),'g*');
end