Question:
Write a function called point_cloud that takes one scalar as an input argument (the function does not have to check the format of the input) and has no output argument.
If it is called like this, point_cloud(100), then it plots 100 points. Each point has a random x coordinate and a random y coordinate, each of which is gotten by a call to randn, which uses a normal distribution with a standard deviation equal to 1. The range of the plot axes should be −5 to 5 in both the x and y dimensions. The grid should be turned off. The points should be plotted and displayed one at a time by calling plot with only one point specified and, following the call of plot, by a call of drawnow, which causes the point to be plotted immediately. The command hold on should be included so that all previous points are retained when a new point is plotted.
Figure 2.41 shows an example view of the plot after point_cloud(100000) has completed its point-by-point plotting on a Mac. (Note that on Windows the points are much larger. Also note that it takes a long time to plot this many points with drawnow. Finally, try zooming in the middle.)
Figure 2.41
My Code:
function point_cloud(N)
hold on
grid off
axis([-5,5,-5,5])
for ii = 1:N
plot(randn(ii));
drawnow;
end
I know this is wrong, but I'm not sure how to solve this problem. Can someone help?
Solved code:
function point_cloud(N)
figure
hold on
grid off
axis([-5,5,-5,5])
x = randn(N,1);
y = randn(N,1);
for ii = 1:N
plot(x(ii),y(ii),'b.');
drawnow;
end
You do not need the for loop at all. And drawing the plot each iteration is very time consuming. How about rather using the scatter function.
figure
hold on
grid off
axis([-5,5,-5,5])
x = randn(N,1);
y = randn(N,1);
scatter(x,y,'b.')
This will be a lot faster.
To add to the other answer, here is the code as a function, with the added functionality that the points are one pixel on Windows as well:
function point_cloud(N)
f = figure;
x = randn(N,1);
y = randn(N,1);
scatter(x,y,1/36,'b.');
f.GraphicsSmoothing = 'off';
grid off
axis([-5,5,-5,5])
axis equal
end
The size of the markers is set with the third parameter of scatter: 1/36. The graphics smoothing of the figure needs to be set to 'off' as well, to make sure that the pixels don't become blurry or lighter.
Here's a 3D version:
function point_cloud3D(N)
f = figure;
x = randn(N,1);
y = randn(N,1);
z = randn(N,1);
scatter3(x,y,z,1/36,'b.');
f.GraphicsSmoothing = 'off';
grid off
axis([-5,5,-5,5,-5,5])
axis square
view(3)
end
Related
I'm working on a script, where I need to show graph of Fixed Point Iteration and want to zoom in where lines are plotting. Graph is done, it is plotting lines on my graph, problem is that I want to see the values which are produced from function from f(x) and g(x). So I "zoom in" from the figure tools and see which values are produced in the graph right now I am doing it manually in the figure, is there any way to automatically zoom in by just giving the x, y axis? so it means when lines are plotting figure will be automatically zoomed like an animation.
clc;
clear all;
clf;
format short g
syms x;
f = #(x) x-cos(x);
g = #(x) cos(x);
dg = matlabFunction(diff(g(x),x));
figure(1)
z = -3:.001:3;
plot(z,z,'-k',z,g(z),'-k',z,0*z,'-r',0*z,g(z),'-r')
hold on;
x = 1.0;
tol =1.0e-15;
px = x;
x = g(x);
line([px,px],[px,x],'color','blue');
line([px,x,],[x,x],'color','blue');
i = 1;
while(abs(px-x)>tol)
px = x;
x = g(x);
line([px,px],[px,x],'color','blue');
line([px,x,],[x,x],'color','blue');
i = i+1;
data = [i x g(x) f(x)]
drawnow
end
This is what I want in my graph lines.
Link
I tested "zoom" function but it is not helping as per my requirement. Also I tried this one but I can't understand there code.
xlim will allow you to set the range of x-values that are shown. Link: xlim
ylim will allow you to set the range of y-values that are shown. Link: ylim
Together, these should allow you to 'zoom' to different parts of your plot. For example, after your first plot command you could include:
plot(z,z,'-k',z,g(z),'-k',z,0*z,'-r',0*z,g(z),'-r') % Already in your code
xlim([0 1.5]);
ylim([0 1.5]);
You could also include these commands in your for loop so that it gradually zooms in.
I'm trying to plot the gradient of the real part of a complex function, however what I get is a blank figure. I do not understand what I am doing wrong since the code works with other functions (such as the imaginary part)
% Set up
x = -3:0.2:3;
y1 = (-3:0.2:3);
y = (-3:0.2:3)*1i;
[X, Y]= meshgrid(x,y);
% Complex variable s
s = X + Y;
% Complex function f(z)
z = s + 1./s;
figure
subplot(1,2,1);
[Dx, Dy] = gradient(real(z),.2,.5);
quiver(x,y1,Dx,Dy)
title('u(x,y) gradient, vector field');
%%Imaginary part
subplot(1,2,2)
contour(x,y1,imag(z),linspace(-10,10,100)); title('Contour of Im(f)');
xlabel('x'); ylabel('y'); %clabel(C3);
title('Imaginary part');
Here below is the image I get
I tried to rescale and resize the picture, the domain etc... but couldn't get the gradient to display (the arrows). What am I doing wrong here?
EDIT:
I found out it displays blank perhaps because there are some Inf and -Inf values in the Dy and Dx variables, is there an option to ignore these values or set them to 0?
It looks to me like it works, but the line width of your arrows is too small for you to see.
You can increase it by assigning a handle to the quiver plot like so:
hQuiver = quiver(x,y1,Dx,Dy);
And then, after the plot is created, change any of its many properties like so:
set(hQuiver,'LineWidth',4)
or do it all in the call to quiver:
hQuiver = quiver(x,y1,Dx,Dy,'LineWidth',4);
In this case it gives the following:
EDIT:
To answer your secondary question, you can set elements that are equal to +Inf or -Inf to any value you want using isinf:
Dx(isinf(Dx)) = 0;
and
Dy(isinf(Dy)) = 0;
It is not blank. You've plotted the quiver diagram (usually used in optical flow diagrams). It is giving an inward pointing arrow at each of the locations formed by the grid with points in x and y1.
I am trying to simulate a network of mobile robots that uses artificial potential fields for movement planning to a shared destination xd. This is done by generating a series of m-files (one for each robot) from a symbolic expression, as this seems to be the best way in terms of computational time and accuracy. However, I can't figure out what is going wrong with my gradient computation: the analytical gradient that is being computed seems to be faulty, while the numerical gradient is calculated correctly (see the image posted below). I have written a MWE listed below, which also exhibits this problem. I have checked the file generating part of the code, and it does return a correct function file with a correct gradient. But I can't figure out why the analytic and numerical gradient are so different.
(A larger version of the image below can be found here)
% create symbolic variables
xd = sym('xd',[1 2]);
x = sym('x',[2 2]);
% create a potential function and a gradient function for both (x,y) pairs
% in x
for i=1:size(x,1)
phi = norm(x(i,:)-xd)/norm(x(1,:)-x(2,:)); % potential field function
xvector = reshape(x.',1,size(x,1)*size(x,2)); % reshape x to allow for gradient computation
grad = gradient(phi,xvector(2*i-1:2*i)); % compute the gradient
gradx = grad(1);grady=grad(2); % split the gradient in two components
% create function file names
gradfun = strcat('GradTester',int2str(i),'.m');
phifun = strcat('PotTester',int2str(i),'.m');
% generate two output files
matlabFunction(gradx, grady,'file',gradfun,'outputs',{'gradx','grady'},'vars',{xvector, xd});
matlabFunction(phi,'file',phifun,'vars',{xvector, xd});
end
clear all % make sure the workspace is empty: the functions are in the files
pause(0.1) % ensure the function file has been generated before it is called
% these are later overwritten by a specific case, but they can be used for
% debugging
x = 0.5*rand(2);
xd = 0.5*rand(1,2);
% values for the Stackoverflow case
x = [0.0533 0.0023;
0.4809 0.3875];
xd = [0.4087 0.4343];
xp = x; % dummy variable to keep x intact
% compute potential field and gradient for both (x,y) pairs
for i=1:size(x,1)
% create a grid centered on the selected (x,y) pair
xGrid = (x(i,1)-0.1):0.005:(x(i,1)+0.1);
yGrid = (x(i,2)-0.1):0.005:(x(i,2)+0.1);
% preallocate the gradient and potential matrices
gradx = zeros(length(xGrid),length(yGrid));
grady = zeros(length(xGrid),length(yGrid));
phi = zeros(length(xGrid),length(yGrid));
% generate appropriate function handles
fun = str2func(strcat('GradTester',int2str(i)));
fun2 = str2func(strcat('PotTester',int2str(i)));
% compute analytic gradient and potential for each position in the xGrid and
% yGrid vectors
for ii = 1:length(yGrid)
for jj = 1:length(xGrid)
xp(i,:) = [xGrid(ii) yGrid(jj)]; % select the position
Xvec = reshape(xp.',1,size(x,1)*size(x,2)); % turn the input into a vector
[gradx(ii,jj),grady(ii,jj)] = fun(Xvec,xd); % compute gradients
phi(jj,ii) = fun2(Xvec,xd); % compute potential value
end
end
[FX,FY] = gradient(phi); % compute the NUMERICAL gradient for comparison
%scale the numerical gradient
FX = FX/0.005;
FY = FY/0.005;
% plot analytic result
subplot(2,2,2*i-1)
hold all
xlim([xGrid(1) xGrid(end)]);
ylim([yGrid(1) yGrid(end)]);
quiver(xGrid,yGrid,-gradx,-grady)
contour(xGrid,yGrid,phi)
title(strcat('Analytic result for position ',int2str(i)));
xlabel('x');
ylabel('y');
subplot(2,2,2*i)
hold all
xlim([xGrid(1) xGrid(end)]);
ylim([yGrid(1) yGrid(end)]);
quiver(xGrid,yGrid,-FX,-FY)
contour(xGrid,yGrid,phi)
title(strcat('Numerical result for position ',int2str(i)));
xlabel('x');
ylabel('y');
end
The potential field I am trying to generate is defined by an (x,y) position, in my code called xd. x is the position matrix of dimension N x 2, where the first column represents x1, x2, and so on, and the second column represents y1, y2, and so on. Xvec is simply a reshaping of this vector to x1,y1,x2,y2,x3,y3 and so on, as the matlabfunction I am generating only accepts vector inputs.
The gradient for robot i is being calculated by taking the derivative w.r.t. x_i and y_i, these two components together yield a single derivative 'vector' shown in the quiver plots. The derivative should look like this, and I checked that the symbolic expression for [gradx,grady] indeed looks like that before an m-file is generated.
To fix the particular problem given in the question, you were actually calculating phi in such a way that meant you doing gradient(phi) was not giving the correct results compared to the symbolic gradient. I'll try and explain. Here is how you created xGrid and yGrid:
% create a grid centered on the selected (x,y) pair
xGrid = (x(i,1)-0.1):0.005:(x(i,1)+0.1);
yGrid = (x(i,2)-0.1):0.005:(x(i,2)+0.1);
But then in the for loop, ii and jj were used like phi(jj,ii) or gradx(ii,jj), but corresponding to the same physical position. This is why your results were different. Another problem you had was you used gradient incorrectly. Matlab assumes that [FX,FY]=gradient(phi) means that phi is calculated from phi=f(x,y) where x and y are matrices created using meshgrid. You effectively had the elements of phi arranged differently to that, an so gradient(phi) gave the wrong answer. Between reversing the jj and ii, and the incorrect gradient, the errors cancelled out (I suspect you tried doing phi(jj,ii) after trying phi(ii,jj) first and finding it didn't work).
Anyway, to sort it all out, on the line after you create xGrid and yGrid, put this in:
[X,Y]=meshgrid(xGrid,yGrid);
Then change the code after you load fun and fun2 to:
for ii = 1:length(xGrid) %// x loop
for jj = 1:length(yGrid) %// y loop
xp(i,:) = [X(ii,jj);Y(ii,jj)]; %// using X and Y not xGrid and yGrid
Xvec = reshape(xp.',1,size(x,1)*size(x,2));
[gradx(ii,jj),grady(ii,jj)] = fun(Xvec,xd);
phi(ii,jj) = fun2(Xvec,xd);
end
end
[FX,FY] = gradient(phi,0.005); %// use the second argument of gradient to set spacing
subplot(2,2,2*i-1)
hold all
axis([min(X(:)) max(X(:)) min(Y(:)) max(Y(:))]) %// use axis rather than xlim/ylim
quiver(X,Y,gradx,grady)
contour(X,Y,phi)
title(strcat('Analytic result for position ',int2str(i)));
xlabel('x');
ylabel('y');
subplot(2,2,2*i)
hold all
axis([min(X(:)) max(X(:)) min(Y(:)) max(Y(:))])
quiver(X,Y,FX,FY)
contour(X,Y,phi)
title(strcat('Numerical result for position ',int2str(i)));
xlabel('x');
ylabel('y');
I have some other comments about your code. I think your potential function is ill-defined, which is causing all sorts of problems. You say in the question that x is an Nx2 matrix, but you potential function is defined as
norm(x(i,:)-xd)/norm(x(1,:)-x(2,:));
which means if N was three, you'd have the following three potentials:
norm(x(1,:)-xd)/norm(x(1,:)-x(2,:));
norm(x(2,:)-xd)/norm(x(1,:)-x(2,:));
norm(x(3,:)-xd)/norm(x(1,:)-x(2,:));
and I don't think the third one makes sense. I think this could be causing some confusion with the gradients.
Also, I'm not sure if there is a reason to create the .m file functions in your real code, but they are not necessary for the code you posted.
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
So I have a simple loop in MATLAB that does the following:
for p = 1:100
x = 4.*randn(1,100);
y = 7.*randn(1,100);
figure(1)
plot(randn(1,100));
figure(2);
plot(randn(1,100));
end
The x and y are made up, but that is the jist of it. Anyway, when I run this code, not surprisingly, MATLAB will make two figures and plot accordingly. The problem is, I get a sort of 'blinking' between figures when I do this, and it makes the quality of seeing x and y evolve over time poorer.
I discovered a way to make one of the plots smoother like this:
figure(1);
for p = 1:100
x = 4.*randn(1,100);
y = 7.*randn(1,100);
plot(randn(1,100));
drawnow
end
If I do this, then of course figure(1) will plot very smoothly showing x nicely, without figure(1) 'blinking' between plots, but now I cant show figure(2) or y!
How can I plot both those quantities on different figures (not subplots) smoothly without 'blinking'?
EDIT:
Thanks Geodesic for your answer, the solution works, however there is a subtlety that I did not think would be an issue, however it is.
1) I am unable to use 'imagesc' with this solution.
For example,
figure(1);
aone = axes;
figure(2);
atwo = axes;
for p = 1:100
x = 4.*randn(1,100);
y = 7.*rand(10,100);
plot(aone,x);
drawnow;
imagesc(atwo,y);
drawnow;
end
In this case the part with imagesc(atwo, y) crashes.
Your flicker is because you're generating each figure window again and again through the loop, which is forcing the window to come to the foreground each time. Generate the figures first, attach some axes to them, and plot your data to each axis like so:
figure(1);
aone = axes;
figure(2);
atwo = axes;
for p = 1:100
x = 4.*randn(1,100);
y = 7.*randn(1,100);
plot(aone,randn(1,100));
drawnow;
imagesc(y,'Parent',atwo);
drawnow;
end
Edit: functions like plot take an axis argument directly, but imagesc does not. In this particular case you'll need to send a Property Name/Value pair in as an argument. The 'Parent' of the image generated will be our axis atwo (see above).
For p = 1, create the plots you need, using the plot command or the imagesc command. Keep the handle of the resulting graphics object by getting an output argument: for example h = plot(.... or h = imagesc(..... This will be a Handle Graphics lineseries or image object, or something else, depending on the particular plot type you create.
For p = 2:100, don't use the plotting commands directly, but instead update the relevant Data properties of the original Handle Graphics object h. For example, for a lineseries object resulting from a plot command, set its XData and YData properties to the new data. For an image object resulting from an imagesc command, set its CData property to the new image.
If necessary, call drawnow after updating to force a flush of the graphics queue.