Animating Multiple Ellipses - matlab

sRMatTemp = [SENSORRANGE];
sRMat = repmat(sRMatTemp, size(obj.landmarks.sensed(:,1), 1));
ellipse(((2*pi*sRMat)/(360/obj.landmarks.sensed(:,4))), obj.landmarks.sensed(:,5) , obj.landmarks.sensed(:,3), obj.landmarks.apparentPositionsST(:,1), obj.landmarks.apparentPositionsST(:,2));
The above code works fine... ONCE. The problem is I need to animate it. Every time I plot the ellipses, they stay on my screen and the graph becomes unreadable instantly.
This is the code above that works fine as well, to animate a scatter plot. Is there a way I can use this with ellipses somehow?
I'm using ellipse.m that's on the Mathworks community site.
fig=figure;
axes('NextPlot','add');
set(fig, 'name', 'Animated Graph')
l.st=scatter([0],[0],'g.');
set(l.st,'XData',obj.landmarks.apparentPositionsST(:,1),'YData',obj.landmarks.apparentPositionsST(:,2));
drawnow

You need to set the EraseMode property to xor so that when you update its X/Y data, it will delete its old location then redraw. Make sure you read this animation guide.
I wrote a simple example to illustrate an animated ellipse. I am using the function calculateEllipse.m from a previous question here on SO.
step = linspace(50,200,100);
figure
hAx = axes('XLim',[-250 250], 'YLim',[-250 250], ...
'Drawmode','fast', 'NextPlot','add');
axis(hAx, 'equal')
p = calculateEllipse(0, 0, step(1), step(end), step(1));
hLine = line('XData',p(:,1), 'YData',p(:,2), 'EraseMode','xor', ...
'Color','r', 'LineWidth',3);
for i=1:numel(step)
p = calculateEllipse(0, 0, step(i), step(numel(step)-i+1), step(i));
set(hLine,'XData',p(:,1), 'YData',p(:,2)) %# update X/Y data
pause(.05) %# slow down animation
drawnow %# force refresh
if ~ishandle(hLine), return; end %# in case you close the figure
end

Related

Separate initialization and display of plot

What is a proper way to separate the initialization and the display of plots in Matlab? (I mean plots in a wide sense here; could be plot, plot3, scatter etc.) To give a concrete example, I have a pretty complex 3D visualization that uses sphere and mesh to draw a static sphere mesh and then scatter3 to plot a moving trajectory on the sphere. To be able to do this in real time I have implemented some simple optimizations, such as only updating the scatter3 object each frame. But the code is a bit messy, making it hard to add additional features that I want, so I would like improve code separation.
I also feel like it might sometimes be useful to return some kind of plot object from a function without displaying it, for example to combine it with other plots in a nice modular way.
An example of what I have in mind would be something like this:
function frames = spherePlot(solution, options)
% Initialize sphere mesh and scatter objects, configure properties.
...
% Configure axes, maybe figure as well.
...
% Draw sphere.
...
if options.display
% Display figure.
end
for step = 1:solution.length
% Update scatter object, redraw, save frame.
% The frames are saved for use with 'movie' or 'VideoWriter'.
end
end
Each step might also be separated out as a function.
So, what is a neat and proper way to do stuff like this? All documentation seems to assume that one wants to display everything right away.
For example
% some sample data
N = 100;
phi = linspace(-pi, pi, N);
theta = linspace(-pi, pi, N);
f = #(phi, theta) [sin(phi).*cos(theta); sin(phi).*sin(theta); cos(phi)];
data = f(phi, theta);
% init plot
figure(1); clf
plot3(data(1,:), data(2,:), data(3,:)); % plot path, not updated
hold on
p = plot3([0 data(1,1)], [0 data(2,1)], [0 data(3,1)]); % save handle to graphics objects to update
s = scatter3(data(1,1), data(2,1), data(3,1), 'filled');
axis equal
xlabel('x'); ylabel('y'); zlabel('z');
t = title('first frame'); % also store handle for title or labels to update during animation
% now animate the figure
for k = 1:N
p.XData = [0 data(1,k)]; % update line data
p.YData = [0 data(2,k)];
p.ZData = [0 data(3,k)];
s.XData = data(1,k); % update scatter data
s.YData = data(2,k);
s.ZData = data(3,k);
t.String = sprintf('frame %i', k); % update title
drawnow % update figure
end
Basically you can update all values for a graphics handle, in this case 'p' and 's'. If you open the matlab doc for plot or plot3 you will find a link to all properties of that primitive: e.g. Line Properties. Similar documentation pages exist for scatter/imagesc etc.
So the general idea is to first create a figure with the first frame, save the handles to the objects you would like to update (p = plot(...), and then enter a loop in which you update the required property of that graphics object (e.g. p.Color = 'r', or p.XData = ...).

How to update / animate a complicated figure in MATLAB?

I need to animate a complex figure consisting of a chain of rectangles, forming an arm.
Here is an example of how this arm looks like when not animated :
To animate this figure, I made the following code :
function renderFrame(fig, data)
hold(ax, 'on'); % Need to hold so that new elements of the arm add themselves
showMembers(fig, data); % Create patches and rotate them to the right angle to create members
showJoints(fig, data); % Draw circles at the joints betwwen the members. Use the width of rectangle members
drawnow;
hold(ax, 'off'); % Next rendering will replace this one; No need to hold
end
function rotateMember(fig, data, iMember, rotAngle)
for iAngle = 1:rotAngle
updateMemberAngle(data, i, 1); % Change thew data so the i-th member rotates by 1
renderFrame(fig); % Show frame after the data was changed
end
end
function main()
fig = figure;
ax = gca;
axis(ax, 'equal');
setAxis(data); % Set axis limits and create axis arrows with totalLength of the arm
renderFrame(ax, data);
rotateMember(fig, data, 3, 90); % Rotate 3rd member by 90 degrees
end
main()
But the frames of my animation doesn't clear at all. It results in this figure :
What am I doing wrong ? Is there a way to plot complicated figures with multiple parts and to animate it, by clearing frame ?
I looked into using newplot and nextplot, but MATLAB's documentation on the subject is incomplete, as always. I also tried creating graphic objects and then setting the data at each iteration, but it rejects an exception every time the figure is deleted since "graphics objects are deleted".
It seems to me as if in your approach, you're not erasing the plot when drawing the next frame. Maybe calling cla() prior to drawing the next frame would make it work? However, this may produce a flickering behavior if the redrawing is done in the wrong order.
I suggest taking a look at animation techniques in Matlab to see three different ways to produce animations.
Found a way to clear the axis childrens, except the two axis quivers (arrows).
Here is a code that works properly:
function renderFrame(renderAxes, data)
% CHECK IF THERE ARE MORE GRAPHIC OBJECTS THAN ONLY THE QUIVERS
if ~(length(renderAxes.Children) == 2)
% DELETE EVERYTHING EXCEPT THE AXIS QUIVERS THAT WERE RENDERED AT THE BEGINNING
% MATLAB ADDS NEW GRAPHIC OBJECTS TO THE BEGINNING OF AX.CHILDREN
delete(renderAxes.Children(1:length(renderAxes.Children)-2))
end
showMembers(renderAxes, data); % Create patches and rotate them to the right angle to create members
showJoints(renderAxes, data); % Draw circles at the joints betwwen the members. Use the width of rectangle members
drawnow;
end
function rotateMember(ax, data, iMember, rotAngle)
for iAngle = 1:rotAngle
updateMemberAngle(data, i, 1); % Change thew data so the i-th member rotates by 1
renderFrame(ax, data); % Show frame after the data was changed
end
end
function main()
fig = figure;
ax = gca;
axis(ax, 'equal');
% HOLD AXES AT THE BEGINNING OF THE SCRIPT
hold(ax, 'on');
setAxis(data); % Set axis limits and create axis arrows with totalLength of the arm
renderFrame(ax, data);
rotateMember(ax, data, 3, 90); % Rotate 3rd member by 90 degrees
end
main()

Although I used 'drawnow' and 'hold on', last plot still appears in animation - MATLAB

I read a lot of answers here, but for some reason my animation still doesn't work as expected.
The axis range should vary from frame to frame. The 'Hurricane Center' caption should remain in the center all the time, but the captions from the previous frames must be erased. Also, I'm afraid that some of the data from previous parts remain.
I used hold on and draw now but it still happens.
The animation can be seen here:
Code:
v = VideoWriter('test_video.avi');
v.FrameRate = 4;
v.open()
hold on
for i=1:length(relevant(1,1,:))
if isempty(relevant) == 0
title('Lightning around Hurricane Jerry')
grid on
ylim([Interp_Jerry(i,2)-Radius Interp_Jerry(i,2)+Radius])
xlim([Interp_Jerry(i,3)-Radius Interp_Jerry(i,3)+Radius])
ylabel('latitude')
xlabel('longitude')
text(Interp_Jerry(i,3),Interp_Jerry(i,2),txt1);
scatter(relevant(:,3,i),relevant(:,2,i),'.');
drawnow
pause(0.1);
v.writeVideo(getframe(fig));
end
end
v.close()
The best of the two worlds:
v = VideoWriter('test_video.avi');
v.FrameRate = 4;
v.open()
hold on;
for i=1:length(relevant(1,1,:))
if ~isempty(relevant) % Corrected
if i == 1
% Prepare first plot and save handles of graphical objects
ht = text(Interp_Jerry(i,3),Interp_Jerry(i,2),txt1);
hold on;
hs = scatter(relevant(:,3,i),relevant(:,2,i),'.');
ylabel('latitude')
xlabel('longitude')
title('Lightning around Hurricane Jerry')
grid on
else
% Update graphical objects
set(ht, 'position', [Interp_Jerry(i,3), Interp_Jerry(i,2)]);
set(hs, 'XData', relevant(:,3,i) , 'YData' , relevant(:,2,i));
end
ylim([Interp_Jerry(i,2)-Radius Interp_Jerry(i,2)+Radius])
xlim([Interp_Jerry(i,3)-Radius Interp_Jerry(i,3)+Radius])
drawnow
pause(0.1);
v.writeVideo(getframe(fig));
end
end
v.close()
Instead of writing the text every time, just modify its position in the loop. Create a text object out side of the loop
t = text(position1, position2, txt);
in the loop change the position and if necessary the text
set(t, 'position', [new_position1, new_position2]);
If you don't want the previous data to remain, then you shouldn't use hold on... I think you should revise your code as follows:
v = VideoWriter('test_video.avi');
v.FrameRate = 4;
v.open();
fg = figure();
% Do not hold on, so that data is not retained frame-to-frame
for i=1:length(relevant(1,1,:))
% You don't need to test if 'relevant' is empty, since you're looping to its length!
% New plot
scatter(relevant(:,3,i),relevant(:,2,i),'.');
% Customise plot (labels / axes / text / ...)
title('Lightning around Hurricane Jerry')
ylabel('latitude')
xlabel('longitude')
ylim([Interp_Jerry(i,2)-Radius Interp_Jerry(i,2)+Radius]);
xlim([Interp_Jerry(i,3)-Radius Interp_Jerry(i,3)+Radius]);
text(Interp_Jerry(i,3),Interp_Jerry(i,2),txt1);
grid on;
drawnow;
% You don't need to pause whilst plotting, you already set the video framerate.
% pause(0.1);
v.writeVideo(getframe(fg));
end
v.close()

How to animate points on an image in MATLAB?

I have the pixel locations of P points on a -constant- image, for T iterations of an algorithm, so locations = [T x 2*P] double.
Now I want to create an animation where it plots the image, then plots the points, pauses for N seconds and updates their location to the next step. I don't know if there is a standard way to follow. I think I need something like:
figure;
imshow(img);
hold on;
for t=1:T
anim = updatePlot(locations(t,:), anim); % ?
end
How can I implement this updatePlot function?
Thanks for any help!
You can do this a couple of different ways. The first way would be to give the plotted points a handle so that you can delete them before the next iteration:
figure
imshow(img);
hold on;
for t = 1:T
% delete the previous points plotted (skip t = 1 since they won't exist)
if t > 1
delete(hPoints);
end
hPoints = plot(xLocations(t,:),yLocations(t,:),'.');
getframe;
pause(N);
end
(I am not exactly sure how you parse your locations along each row to separate the x and y components, so I've just used xLocations and yLocations to represent those values.)
The second way would be to re-draw the entire image at each iteration:
figure
for t = 1:T
clf;
imshow(img);
hold on;
plot(xLocations(t,:),yLocations(t,:),'.');
getframe;
pause(N);
end
Note that imshow might have its own getframe effect so that you'll see the image flicker before plotting the points -- if that happens just switch from imshow to image.

How to make a smooth rotation of a 3D plot in MATLAB?

If I try to rotate camera around my current figure with plot3 using
while true; camorbit(0.9,-0.1); drawnow; end
then the rotation periodically hangs for a while (example) even on 8-core MacPro.
Can I make it smooth?
EDIT1:
While there is no solution for my original question yet, I've managed to make a better movie with getframe function. It doesn't allow recording free-hand rotation, though, and is quite buggy in MATLAB2010b for Mac.
%# fix wrong figure position in MATLAB2010b for Mac - depends on your layout
correctedPosition = get(gcf,'Position') + [21 -125 0 0];
fps = 60; sec = 10;
vidObj = VideoWriter('newfile.avi');
vidObj.Quality = 100;
vidObj.FrameRate = fps;
open(vidObj);
for i=1:fps*sec
camorbit(0.9,-0.1);
writeVideo(vidObj,getframe(gcf, correctedPosition));
end
close(vidObj);
EDIT2:
I created a similar thread at MATLAB Central.
EDIT3:
You can try it yourself downloading one of my figures.
I would say it's the large number of points you are drawing that's causing the slowdown. One option is to downsample.. Also you could use lower-level functions to draw (check this related post for a comparison of plot3/scatter3/line performance).
Consider the animation below optimized for speed:
[X Y Z] = sphere(64);
X = X(:); Y = Y(:); Z = Z(:);
%# set-up figure
hFig = figure('Backingstore','off', 'renderer','zbuffer');
%# use lower-level function LINE
line(0.50*[X,X], 0.50*[Y,Y], 0.50*[Z,Z], 'LineStyle','none', 'Marker','.', 'MarkerSize',1, 'Color','r')
line(0.75*[X,X], 0.75*[Y,Y], 0.75*[Z,Z], 'LineStyle','none', 'Marker','.', 'MarkerSize',1, 'Color','g')
line(1.00*[X,X], 1.00*[Y,Y], 1.00*[Z,Z], 'LineStyle','none', 'Marker','.', 'MarkerSize',1, 'Color','b')
view(3)
%# freeze the aspect ratio to override stretch-to-fill behaviour
axis vis3d
%# fix the axes limits manually
%#set(gca, 'xlim',[-1 1], 'ylim',[-1 1], 'zlim',[-1 1])
axis manual
%# maybe even remove the tick labels
%set(gca, 'xticklabel',[], 'yticklabel',[], 'zticklabel',[])
%# animate (until figure is closed)
while ishandle(hFig); camorbit(0.9,-0.1); drawnow; end
Note how we are using the Z-buffer renderer, and turned off the Backingstore property.
EDIT:
If I understood correctly, what you are trying to do is to record a screencast (using a 3rd-party app), while you manually rotate the figure, but in your case these manual rotations are "jumpy". On the other animating your figure with CAMORBIT/VIEW in a while-loop is running smooth...
I propose an alternative solution: start by rotating the figure using the mouse and write these view configurations at each step (azimuth,elevation). Then you can replay them using the VIEW function while recording the video, something like:
v = [...]; %# matrix where each row specify Az/El of view
for i=1:size(v,1)
view( v(i,:) )
drawnow
end
The downside is that you will have to press/rotate/release using the mouse in small steps (the ROTATE3D object does not expose a mouse-motion event)
I wrote a simple function to help you in this process. It loads the saved figure, enable 3d-rotation, and keeps track of the intermediate position at each step. Once finished, press the "Done" button to return the list of views...
function v = rotationDemo(figFileName)
views = []; %# list of views (Az,El)
hFig = hgload(figFileName); %# load the saved figure
views(1,:) = get(gca,'View'); %# store initial view
%# add a button, used to terminate the process
hButton = uicontrol('Style','pushbutton', 'Position',[400 1 80 20], ...
'String','Done?', 'Callback',#buttonCallback);
set(hFig, 'Toolbar','figure') %# restore toolbar
%# start 3d rotation, and handle post-callback to record intermediate views
h = rotate3d(hFig); %# get rotation object
set(h, 'ActionPostCallback',#rotateCallback)
set(h, 'Enable','on') %# enable rotation
msgbox('Rotate the view step-by-step', 'rotate3d', 'warn', 'modal')
uiwait(hFig) %# wait for user to click button
delete(hButton) %# delete button on finish
set(h, 'Enable','off') %# disable rotation
v = round(views); %# return the list of views
%# callback functions
function rotateCallback(o,e)
views(end+1,:) = get(e.Axes,'View'); %# add current view to list
end
function buttonCallback(o,e)
uiresume(gcbf) %# uiresume(hFig)
end
end
You can call the above function, then replay the animation:
v = rotationDemo('smooth_rotation.fig');
for i=1:size(v,1)
view(v(i,:))
drawnow
end
We can smooth the transitions by simple interpolation:
v = rotationDemo('smooth_rotation.fig');
n = size(v,1);
nn = linspace(1,n,100)'; %'# use 100 steps
vv = round( [interp1(v(:,1),nn) interp1(v(:,2),nn)] );
for i=1:size(vv,1)
view(vv(i,:))
DRAWNOW %# or PAUSE(..) to slow it down
end
As a side note, I should mention that ROTATE3D and CAMORBIT have different effects. ROTATE3D changes the View property of the current axis, while CAMORBIT controls the camera properties CameraTarget/CameraPosition/CameraUpVector of the current axis.
I recognize the same jerking movements that you are talking about on a regular MATLAB Figure. But when I tried running the Amro's code, created a movie (*.AVI), it looks smooth on my Mac notebook also.
The movie making code that I used is the following:
% Added the 'Visible' property of the figure 'off' while making a movie (although I am not exactly certain if this will make the situation better) like so:
hFig = figure('Backingstore','off','visible','off','renderer','zbuffer');
% Then, I replaced Amro's while-loop with a simple AVI production loop, as follows:
aviobj=avifile('test.avi'); %creates AVI file
for I=1:360
camorbit(0.9,-0.1); drawnow;
aviobj=addframe(aviobj,hFig); %adds frames to the AVI file
end
aviobj=close(aviobj); %closes AVI file
close(hFig); %close hFig
Question:
Would it help to decimate some points or to create a density map before rendering the figure?
[Ref. on various Rendering Options: http://www.mathworks.com/support/tech-notes/1200/1201.html ]
I hope the comments above would be of any help.
I don't know if this will help your issue, but for some reason, I've had better success with pause(0.001) than drawnow to force an update of the graphics window
You might also see if rotate3d is faster.
The number of cores doesn't matter as much as you think, as many functions in matlab do not support multi-threading.
A workaround would be to proceed as you are now, but write the figure window to a movie file. Then you can play back the movie.