Copy of polygon created in matlab figure despite using same figure handle throughout - matlab

figure;
poly = fill(sq(:,1), sq(:,2), 'b');
%% create cell "p" consisting of 5600 arrays of same size as sq
for i=1:5600
hold on
set(poly, 'X', p{i}(:,1),...
'Y', p{i}(:,2));
hold off
drawnow;
end
%% again create cell "q" consisting of 8700 arrays of same size as sq
for i=1:8700
hold on
set(poly, 'X', q{i}(:,1),...
'Y', q{i}(:,2));
hold off
drawnow;
end
I create a blue-filled polygon in first line and then move it all over the figure. When i run the above code, first section moves a polygon as controlled by p from initial point x0 to x1. Then i make another cell q in second section of code and use it to move blue-filled polygon again from x1 to x2. But this time a copy of the polygon is created at x1 which moves so that the previous polygon is still at x1 while this new polygon is moving to x2. Why is this happening?

I tried to write what you describe, using a little different code (more efficient), and made up the parts you didn't add. It's working, so if this is what you look for you can either adopt this code or compare it with yours and look for the problem.
My code:
% define some parameters and auxilary function:
sq_size = 3;
makeSq = #(xy) [xy(1) xy(2)
xy(1)+sq_size xy(2)
xy(1)+sq_size xy(2)+sq_size
xy(1) xy(2)+sq_size];
% create the first object:
sq = makeSq([1 1]);
poly = fill(sq(:,1), sq(:,2), 'b');
% setting the limmits for a constant view:
xlim([0 50+sq_size])
ylim([0 50+sq_size])
% first loop:
p = randi(50,10,2); % no need for cell here...
for k = 1:size(p,1)
temp_sq = makeSq(p(k,:));
set(poly, 'X', temp_sq(:,1),'Y',temp_sq(:,2));
drawnow;
pause(0.1)
end
% second loop:
q = randi(50,20,2); % no need for cell here...
set(poly,'FaceColor','g') % change to green to see we are in the second loop
for k = 1:size(q,1)
temp_sq = makeSq(q(k,:));
set(poly,'X',temp_sq(:,1),'Y',temp_sq(:,2));
drawnow;
pause(0.1)
end
The pause is only so you see the animation, it's not really needed.

Related

Update plot using hold on inside a for loop

I'm combining two plots using this code
plot(x1,y1,'.','MarkerSize',20,'Color','r');
hold on; grid on;
plot(x2,y2,'x','MarkerSize',10,'Color','b');
xlim([-a a]);
ylim([-a a]);
Now I want to change the values of x1,y1 and x2,y2 in order to have more than one point and one cross inside my figure. I tried to use a for loop where I compute new values, but every iteration this code generates another figure - whereas I want just one figure with all the points in it.
I did something like this:
for i=1:1:8
% do things that compute x1,x2,y1,y2
figure; hold on
plot(x1,y1,'.','MarkerSize',20,'Color','r');
hold on; grid on;
plot(x2,y2,'x','MarkerSize',10,'Color','b');
xlim([-a a]);ylim([-a a]);
i=i+1;
end
I also tried to put the hold on just before i=i+1 but still give me a new figure.
There are several things you can do:
The simple solution would be to put the figure command outside the loop:
figure(); hold on;
for ...
plot(x1, ...);
plot(x2, ...);
end
A better solution would be to first compute all values and then plot them:
[x1,y1,x2,y2] = deal(NaN(8,1));
for ind1 = 1:8
% do some computations
x1(ind1) = ...
...
y2(ind1) = ...
end
figure(); plot(x1,y1,'.',x2,y2,'x');
The best solution (in my opinion) would be to update existing plot objects with new data points as they become available:
[x1,y1,x2,y2] = deal(NaN(8,1));
figure(); hP = plot(x1,y1,'.',x2,y2,'x');
for ind1 = 1:8
% do some computations
hP(1).XData(ind1) = <newly-computed x1>
hP(1).YData(ind1) = <newly-computed y1>
hP(2).XData(ind1) = <newly-computed x2>
hP(2).YData(ind1) = <newly-computed y2>
end

Handling and eliminating multiples entries in MatLab legend

I currently want to have the legend of graph, however i'm plotting several lines that should be group in only 3 types.
My currently option is to use a dummy plot out of the boundaries, plotting the relevant data and calling the legend just at the end. It works but it is prone to errors. I wanted to update the legend and select just a few of the plots.
I tried to use the leg_handle.String, but then it comes two problems:
It still plot 5 handles instead of 3.
It does not have the proper line style & color.
Any ideas?
Bellow follow the code (with dummy plot commented) and the pictures of the current version giving the error and what i want to look.
clear
figure()
hold on
%using
%dummy plot
% leg_text={'a','b','c'};
% plot(100,100,'-r')
% plot(100,100,'-b')
% plot(100,100,'-k')
for ii=1:20,
plot(1:11,linspace(0,ii,11),'-r')
end
for ii=30:50,
plot(1:11,linspace(0,ii,11),'-b')
end
for ii=70:80,
plot(1:11,linspace(ii,25,11),'-k')
end
Yaxl=[-1 80];
Xaxl=[1 11];
set(gca, 'Visible','on', ...
'Box','on', ...
'Layer','top',...
'Xlim',Xaxl, ...
'Ylim',Yaxl);
%using
% legend(leg_text)
%want to use
leg_hand=legend(gca,'show');
leg_hand.String=leg_hand.String([1 21 42]);
%extra comand will give the things that i wanted above
% leg_hand.String=leg_hand.String([1 2 3]);
What it gives:
What I expect to have:
I have tried this method using [a,b,c,d]=legend, but this give only the a handle that i already using.
This little workaround should do the job:
clear();
figure();
hold on;
h = gobjects(3,1);
for ii = 1:20
h(1) = plot(1:11,linspace(0,ii,11),'-r');
end
for ii = 30:50
h(2) = plot(1:11,linspace(0,ii,11),'-b');
end
for ii = 70:80
h(3) = plot(1:11,linspace(ii,25,11),'-k');
end
set(gca,'Box','on','Layer','top','Visible','on','Xlim',[1 11],'Ylim',[-1 80]);
legend(h,'A','B','C');
hold off;
Actually, what I did is very simple. I created an array of graphical objects of size 3 (one for each iteration) using the gobjects function. Then, inside each iteration, I assigned the last plotted line to its respective array placeholder. Finally, I created the legend using the three graphical objects I previously stored.
Alternatively:
clear();
figure();
hold on;
h1 = gobjects(20,1);
for ii = 1:20
h1(ii) = plot(1:11,linspace(0,ii,11),'-r');
end
h2 = gobjects(21,1);
for ii = 30:50
h2(ii-29) = plot(1:11,linspace(0,ii,11),'-b');
end
h3 = gobjects(11,1);
for ii = 70:80
h3(ii-69) = plot(1:11,linspace(ii,25,11),'-k');
end
set(gca,'Box','on','Layer','top','Visible','on','Xlim',[1 11],'Ylim',[-1 80]);
legend([h1(1) h2(1) h3(1)],'A','B','C');
hold off;
You create an array of graphical objects for storing the plot handlers produced by every iteration. Then you create the legend using the first (basically, any) item of each array of graphical objects.

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()

Plotting on MATLAB

I am trying to plot a cobweb diagram using the following code:
function cobweb(f,a,b,x0,x1,N)
x(1)=0.2; % plot orbit starting at x0
for i=1:100
x(i+1)= 3*x(i)*(1-x(i));
plot([x(i),x(i)],[x(i),x(i+1)]);
hold on
plot([x(i),x(i+1)],[x(i+1),x(i+1)]);
hold on
end
hold on
r = 3;
x = 0:0.01:1; %// set some x
f = (r.*x.*(1-x));
hold on
plot(x,f,'k')
hold on
plot([x(1), 0], [x(1), 3*x(1)*(1-x(1))])
I want the first line to be drawn up from the x-axis, however it's currently starting from (x(1),x(1)), where x(1) is the initial point.
I understand that this is because of my loop so I tried adding an extra plot for the initial line by plot([x(1), 0], [x(1), 3*x(1)*(1-x(1))]), however I still get the same result.
The function I am plotting is f = 3x(1-x).
You probably want to move that line:
plot([x(1), 0], [x(1), 3*x(1)*(1-x(1))])
before the for loop and add a hold on after it before you enter the loop. You can then remove the other hold on inside the for loop and further down the code, as they are redundant.

How to do an animated plot in matlab

I was wondering if anyone knew how to do an animation plot of
x = (dataset of 1000 points)
y = (dataset of 1000 points)
plot(x,y)
big problem is these are datasets that i am trying to plot , or x,y coordinates as opposed to a function which I would know how to plot via an animation.
I tried to do frames in a for loop but it gave me dots and didn't join them in a line graph so I couldn't really watch the path being traced out.
code I used was
for i = 1:length(DATASET1)
pause(0.1)
plot(DATASET1(i),DATASET2(i))
draw on
end
If what you want is for the plot to "grow" point by point: the easiest way is to create an empty plot and then update its XData and YData properties at each iteration:
h = plot(NaN,NaN); %// initiallize plot. Get a handle to graphic object
axis([min(DATASET1) max(DATASET1) min(DATASET2) max(DATASET2)]); %// freeze axes
%// to their final size, to prevent Matlab from rescaling them dynamically
for ii = 1:length(DATASET1)
pause(0.01)
set(h, 'XData', DATASET1(1:ii), 'YData', DATASET2(1:ii));
drawnow %// you can probably remove this line, as pause already calls drawnow
end
Here's an example1 obtained with DATASET1 = 1:100; DATASET2 = sin((1:100)/6);
1 In case someone's interested, the figure is an animated gif which can be created by adding the following code (taken from here) within the loop, after the drawnow line:
frame = getframe(1);
im = frame2im(frame);
[imind,cm] = rgb2ind(im,256);
if ii == 1;
imwrite(imind,cm,filename,'gif','Loopcount',inf);
else
imwrite(imind,cm,filename,'gif','WriteMode','append');
end
Looks like you were close. Not sure draw on is any command though.
See if the code here inspires you to solve your case -
%// Sample x and y values assumed for demo.
x = 1:1000;
y = x.^2;
%// Plot starts here
figure,hold on
%// Set x and y limits of the plot
xlim([min(x(:)) max(x(:))])
ylim([min(y(:)) max(y(:))])
%// Plot point by point
for k = 1:numel(x)
plot(x(k),y(k),'-') %// Choose your own marker here
%// MATLAB pauses for 0.001 sec before moving on to execue the next
%%// instruction and thus creating animation effect
pause(0.001);
end
Since R2014b, you can work with annimatedline object (doc and how-to) that is meant to handle animated graphs pretty well. Basically, the annimatedline object has a addpoints function that adds new points to the line without having to redefine the existing points, along with a clearpoints function that clears lines for more complex animations.
Here is an example:
h = animatedline;
axis([0,4*pi,-1,1])
x = linspace(0,4*pi,1000);
y = sin(x);
for k = 1:length(x)
addpoints(h,x(k),y(k));
drawnow
end