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.
Related
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
figure;
ax1 = axes;
figure;
ax2 = axes;
x = 0; y = 0;
while ishandle(ax1) && ishandle(ax2)
x = x + 1;
y = y + 1;
figure(1)
scatter(x,y, 'MarkerEdgeColor', 'red')
hold on
figure(2)
scatter(x,y, 'MarkerEdgeColor', 'blue')
hold on
end
In my script I have multiple figures, which are going to be updated in a loop. The figures have to be displayed, while the script is running. Unfortunately the currently updated figure is always popping in the foreground, which makes it impossible to monitor a certain figure. I understand that the calling of figure(1) and figure(2) causes this behaviour, but I how can I plot to these figures, without bringing the window into foreground?
As mikkola suggested in a comment, you can specify to which axes scatter or plot add data points. However, there is a better method: create a single line object, and update its xdata and ydata properties. This is both faster and more memory efficient. Your code would become:
x = 0; y = 0;
figure;
h1 = plot(x,y,'ro');
figure;
h2 = plot(x,y,'bo');
while ishandle(h1) && ishandle(h2)
x = x + 1;
y = y + 1;
h1.XData(end+1) = x;
h1.YData(end+1) = y;
h2.XData(end+1) = x;
h2.YData(end+1) = y;
drawnow
pause(0.1)
end
I keep a set of rules of thumb for when working with MATLAB handle graphics. These are relevant to this question:
Use figure only to create a new figure, or to bring an existing figure to the front (which you want to avoid in general, but sometimes is necessary).
Always specify with which figure or axes you want to work, by keeping and using their handles. I never rely on gcf or gca (not explicitly nor implicitly). Using the current figure is useful when typing on the command line, but in a script or a function there is the real danger than someone clicks randomly on windows while the function is executing. Creating a window then writing to gcf could end up writing to a different figure (really, I click on random things all the time).
Don't create more objects than necessary. Creating a new line object for every point you plot is wasteful.
Note also that plot(...'o') is equivalent to scatter(...) unless you specify a different color or size for each point. But using the dot size or color to specify additional information is not a good way to convey that information. Read Tufte's "The visual display of quantitative information" if you're interested in learning about effective communication through graphs.
The relevant part can be found in the part of the documentation of scatter that includes the input ax:
scatter(ax,___) plots into the axes specified by ax instead of into
the current axes.
This allows the user to specify an axis handle pointing to which axes should be used for drawing the scatter plot. Thus if you skip using figure in your code and use the ax input instead, you avoid the "bring to front" behavior associated with figure.
You can modify your code as follows:
figure;
ax1 = axes;
figure;
ax2 = axes;
x = 0; y = 0;
while ishandle(ax1) && ishandle(ax2)
x = x + 1;
y = y + 1;
scatter(ax1, x,y, 'MarkerEdgeColor', 'red')
hold on
scatter(ax2, x,y, 'MarkerEdgeColor', 'blue')
hold on
end
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
I am trying to plot both horizontal and vertical lines on a histogram that will be accurate to changing limits on both the x and y axes. I was using the line(X,Y) function, but cannot find a useful way to get the lines to be set depending on the parameters of the graph window.
I'm not entirely clear on what you want but here's the simplest answer to what I think you want:
Makes a sample histogram
y = randn(100,1);
hist(y,10)
Get the current limits of the x and y axes
xlimits = get(gca, 'XLim');
ylimits = get(gca, 'YLim');
Computes a single numeric value to plot a horizontal line.You'll want to replace this with your specific function of the axes limits
halfpt = ((ylimits(2)-ylimits(1))/2) + ylimits(1);
line(xlimits, [halfpt halfpt])
I'm not sure, but from your comment I'm suspecting that you aren't changing your axes programmatically, with say set(gca,'Xlim', [0 10]) but that you want to be able to drag the axes of your your figure with the mouse, say by using that hand/pointer button in the figure editor. In which case, one solution is to make your figure a GUI and write a callback function that handles line plotting that is a function of the xlim and ylim. Here's an example that always keeps the line in the middle of the axes regardless of how they are dragged:
function myGUI
figure('WindowButtonMotionFcn',#myCallback)
y = randn(100,1);
hist(y,10)
function myCallback(src,eventdata)
xlimits = get(gca, 'XLim');
ylimits = get(gca, 'YLim');
halfpt = ((ylimits(2)-ylimits(1))/2) + ylimits(1);
lh = findall(gcf,'Type','Line');
delete(lh);
myline = line(xlimits, [halfpt halfpt])
end
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.