Let me start by saying that I suspect this is a very simple solution that I am somehow barely missing.
I'm trying to write a script that will plot one set of data in four separate subplots (each showing a different view of a 3D shape the points are being plot in), but I only want to show the current points - as in, I don't want to see every point, just one set of points as they progresses with time (I'm capturing video of the plot to visualize movement with time). However, for every instant in time, there are n points to plot simultaneously. I know this should be simple, but I can't manage to get all n points to plot at once - I can only seem to get it to plot one point at a time, which is pretty meaningless when you have n markers moving with time, all of which you'd like to see moving at the same time.
The following code works to plot every point in sequence, but does not plot all n points together, refreshing those points for every t:
n = 0;
for i = 1:length(data)
% every marker occurs in one row of a specific set of data, and is split
% into x, y, z, so I correct here for each marker being every 3rd column
for j = 1:(cind/3) % cycle through every marker
x = markerLoc(i, j*3 - 2);
y = markerLoc(i, j*3 - 1);
z = markerLoc(i, j*3);
if j == 1 && i == 1 % set up the initial plots for each subplot
% s1,2,3,4 are the handles for the subplots
h1 = scatter3(s1,x, y, z, 'MarkerFaceColor', [0 .75 .75],...
'MarkerEdgeColor','k');
h2 = scatter3(s2,x, y, z, 'MarkerFaceColor', [0 .75 .75],...
'MarkerEdgeColor','k');
h3 = scatter3(s3,x, y, z, 'MarkerFaceColor', [0 .75 .75],...
'MarkerEdgeColor','k');
h4 = scatter3(s4,x, y, z, 'MarkerFaceColor', [0 .75 .75],...
'MarkerEdgeColor','k');
else % update data
% this is probably insanely redundant
set(h1, 'XData', x, 'YData', y, 'ZData', z);
set(h2, 'XData', x, 'YData', y, 'ZData', z);
set(h3, 'XData', x, 'YData', y, 'ZData', z);
set(h4, 'XData', x, 'YData', y, 'ZData', z);
end
end
frames(n) = getframe(gcf); % capture frames
n = n + 1;
end
Can anyone help find what I need to change here to make it plot, instead of after every j (individual marker), after ever nth j?
As it is, you are currently only updating the XData, YData, and ZData for one marker at each instant at a time. Instead you want to get rid of the inner loop and get an array of x, y, and z variables. You can then use these for the scatter3 calls as well as to update the XData, YData, and ZData.
for i = 1:length(data)
%// Get XYZ coordinates for all markers at this time and reshape so X,Y,Z are rows
xyz = reshape(markerLoc(i,:), 3, []);
if i == 1
%// Put these in an array so we can update them easier
h(1) = scatter3(s1, xyz(1,:), xyz(2,:), xyz(3,:), ...
'MarkerFaceColor', [0 .75 .75],...
'MarkerEdgeColor','k');
%// Just use copyobj to make a copy of this plot to all axes
h(2:4) = copyobj(h(1), [s2, s3, s4]);
else
set(h, 'XData', xyz(1,:), 'YData', xyz(2,:), 'ZData', xyz(3,:))
end
end
Related
I created two scatter plots and then used lsline to add regression lines for each plot. I used this code:
for i=1:2
x = ..;
y = ..;
scatter(x, y, 50, 'MarkerFaceColor',myColours(i, :));
end
h_lines = lsline;
However, the darker line extends far beyond the last data point in that scatter plot (which is at around x=0.3):
lsline doesn't seem to have properties that allow its horizontal range to be set. Is there a workaround to set this separately for the two lines, in Matlab 2016a?
For a single data set
This is a workaround rather than a solution. lsline internally calls refline, which plots a line filling the axis as given by their current limits (xlim and ylim). So you can change those limits to the extent you want for the line, call lsline, and then restore the limits.
Example:
x = randn(1,100);
y = 2*x + randn(1,100); % random, correlated data
plot(x, y, '.') % scatter plot
xlim([-1.5 1.5]) % desired limit for line
lsline % plot line
xlim auto % restore axis limit
For several data sets
In this case you can apply the same procedure for each data set sequentially, but you need to keep only one data set visible when you call lsline; otherwise when you call it to create the second line it will also create a new version of the first (with the wrong range).
Example:
x = randn(1,100); y = 2*x + randn(1,100); % random, correlated data
h = plot(x, y, 'b.'); % scatter plot
axis([min(x) max(x) min(y) max(y)]) % desired limit for line
lsline % plot line
xlim auto % restore axis limit
hold on
x = 2*randn(1,100) - 5; y = 1.2*x + randn(1,100) + 6; % random, correlated data
plot(x, y, 'r.') % scatter plot
axis([min(x) max(x) min(y) max(y)]) % desired limit for line
set(h, 'HandleVisibility', 'off'); % hide previous plot
lsline % plot line
set(h, 'HandleVisibility', 'on'); % restore visibility
xlim auto % restore axis limit
Yet another solution: implement your own hsline. It's easy!
In MATLAB, doing a least squares fit of a straight line is trivial. Given column vectors x and y with N elements, b = [ones(N,1),x] \ y; are the parameters to the best fit line. [1,x1;1,x2]*b are the y locations of two points along the line with x-coordinates x1 and x2. Thus you can write (following Luis' example, and getting the exact same output):
N = 100;
x = randn(N,1); y = 2*x + randn(N,1); % random, correlated data
h = plot(x, y, 'b.'); % scatter plot
hold on
b = [ones(N,1),x] \ y;
x = [min(x);max(x)];
plot(x,[ones(2,1),x] * b, 'b-')
x = 2*randn(N,1) - 5; y = 1.2*x + randn(N,1) + 6; % random, correlated data
plot(x, y, 'r.') % scatter plot
b = [ones(N,1),x] \ y;
x = [min(x);max(x)];
plot(x,[ones(2,1),x] * b, 'r-')
You can get the points that define the line using
h_lines =lsline;
h_lines(ii).XData and h_lines(ii).YData will contain 2 points that define the lines for each ii=1,2 line. Use those to create en equation of a line, and plot the line in the range you want.
I am preparing a contour map where I am supposed to highlight the contour line for a specific level. For Example, my contour line values are lying between -1 and 1 and I want to highlight the line corresponding to the value 0. I tried to do this using the following procedure,
[M,c]=contourf(longitude,latitude,delta',-1:0.2:1);
s=size(c.LevelList,2);
for i=1:s
if (c.LevelList(i)==0)
c.LevelWidth=2;
end;
end;
However, it does nothing to the contour map. Can anyone please help me with the appropriate procedure?
I would suggest simply using contour on your desired levels to highlight after the initial contourf, like so:
% Input.
x = linspace(-2*pi, 2*pi, 101);
y = x + pi;
[X, Y] = meshgrid(x, y);
Z = 0.5 * (sin(X) + cos(Y));
% Levels to plot with contourf.
levelsf = -1:0.2:1;
% Levels to highlight.
levels = [0 0.3];
figure(1);
hold on;
% Contourf all levels.
contourf(X, Y, Z, levelsf);
% Highlight levels with simple contour.
contour(X, Y, Z, levels, 'r', 'LineWidth', 2);
hold off;
For highlighting levels = [0 0.3], you'll get:
I'm running a for loop which currently animates surf plots using columns 1:k (for k=1:301) of 3 different matrices (representing x, y, and z) of dimension 21 x 602. However, simultaneously I want to surf plot columns for 302:k+301, so that in essence, I get the animations of two flux tubes at the same time.
Currently, I have:
p = surf(nan(21,602), nan(21,602), nan(21,602));
for k = 1:301
% Update all of the plot objects at once
set(p, 'XData', x(:, 1:k), ...
'YData', y(:, 1:k), ...
'ZData', z(:, 1:k),'facecolor', Colour, 'edgecolor',EdgeColour,...
'facelighting','gouraud')
drawnow
end
But obviously, this is only plotting the first animation as it's currently written. How can this be adapted to also plot the other columns required (and therefore the other animation) at the same time?
Thanks
How about this:
p1 = surf([0 0 ;0 0]);
hold all
p2 = surf([0 0 ;0 0]);
for k = 1:301
% Update all of the plot objects at once
set(p1, 'XData', x(:,1:k), ...
'YData', y(:,1:k), ...
'ZData', z(:,1:k),'facecolor', Colour, 'edgecolor',EdgeColour,...
'facelighting','gouraud')
set(p2, 'XData', a(:,1:k), ...
'YData', b(:,1:k), ...
'ZData', c(:,1:k),'facecolor', Colour, 'edgecolor',EdgeColour,...
'facelighting','gouraud')
drawnow
end
hold off
x,y,z is the data for one helix, and a,b,c is the data for the other helix.
You need to create two different axes (p1 and p2) so surf wan't connect the data altogether
Hope it answers the question :)
There is example of the web that shows how to do animated plot in a single figure.
However, I want to do two subplots in a single figure, such that they will show animation in a first subplot, and then the animation ina second subplot.
Using 'figure(1)' or 'figure (2)' and 'hold on', I can do the animation plot as follows. However, How do I call the subplot to do the similiar things?
So the effect I am looking for is: 1) figure that is opened and has two subplot. 2) plot the animated curve in the 1st subplot, then plot the animated curve in the 2nd subplot. 3) I want to go back to the 1st subplot to plot more things, and also go to 2nd subplot to plot more things.
figure(1); hold on; 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
Just do the subplot's in the loop:
for k = 1:numel(x)
subplot(1,2,1)
plot(x(k),y(k),'-') %// Choose your own marker here
subplot(1,2,2)
plot(x(1:k),y(1:k))
%// MATLAB pauses for 0.001 sec before moving on to execue the next
%%// instruction and thus creating animation effect
pause(0.001);
end
% Easiest way
x = rand(1, 11); y = rand(1, 11);
z = rand(1, 11); a = rand(1, 11);
figure
for i = 1 : 10
subplot(211)
plot(x(i : i+1), y(i : i+1), '.-k');
hold on; % include this if you want to show plot history
subplot(212)
plot(z(i : i+1), a(i : i+1), '.-k');
drawnow;
pause(0.1);
end
% If you don't want to call "plot" interatively
x = rand(1, 11); y = rand(1, 11);
z = rand(1, 11); a = rand(1, 11);
figure
subplot(211)
p1 = plot(NaN, NaN, 'marker', 'o');
subplot(212)
p2 = plot(NaN, NaN, 'marker', 'd');
for i = 1 : 10
set(p1, 'xdata', x(i : i+1), 'ydata', y(i : i+1));
set(p2, 'xdata', z(i : i+1), 'ydata', a(i : i+1));
drawnow;
pause(0.1);
end
First define your plot as a construct, so p1 = plot(x,y). Then you set up your loop and in the loop your write
set(p1,'YData',y);
This will update the plot p1s YData which is y. If you want to see it in an animated form just add a pause(0.1) %seconds after the set.
I am trying to program scatterplot with specific errorbars. The only build in function i found is
errorbar()
but this only enables me to make a 2d plot with errorbars in y direction. What i am asking for is a method to plot this with errorbars in x and y direction.
At the end my goal is to make a 3D-scatter-plot with 3 errorbars.
Perfect would be if the resulting image would be a 3d-plot with 3d geometric shapes (coordinate x,y,z with expansion in the dimension proportional to the errorbars) as 'marker'.
I found this page while searching the internet: http://code.izzid.com/2007/08/19/How-to-make-a-3D-plot-with-errorbars-in-matlab.html
But unfortunately they use only one errorbar.
My data is set of 6 arrays each containing either the x,y or z coordinate or the specific standard derivation i want to show as errorbar.
The code you posted looks very easy to adapt to draw all three error bars. Try this (note that I adapted it also so that you can change the shape and colour etc of the plots as you normally would by using varargin, e.g. you can call plot3d_errorbars(...., '.r'):
function [h]=plot3d_errorbars(x, y, z, ex, ey, ez, varargin)
% create the standard 3d scatterplot
hold off;
h=plot3(x, y, z, varargin{:});
% looks better with large points
set(h, 'MarkerSize', 25);
hold on
% now draw the vertical errorbar for each point
for i=1:length(x)
xV = [x(i); x(i)];
yV = [y(i); y(i)];
zV = [z(i); z(i)];
xMin = x(i) + ex(i);
xMax = x(i) - ex(i);
yMin = y(i) + ey(i);
yMax = y(i) - ey(i);
zMin = z(i) + ez(i);
zMax = z(i) - ez(i);
xB = [xMin, xMax];
yB = [yMin, yMax];
zB = [zMin, zMax];
% draw error bars
h=plot3(xV, yV, zB, '-k');
set(h, 'LineWidth', 2);
h=plot3(xB, yV, zV, '-k');
set(h, 'LineWidth', 2);
h=plot3(xV, yB, zV, '-k');
set(h, 'LineWidth', 2);
end
Example of use:
x = [1, 2];
y = [1, 2];
z = [1, 2];
ex = [0.1, 0.1];
ey = [0.1, 0.5];
ez = [0.1, 0.3];
plot3d_errorbars(x, y, z, ex, ey, ez, 'or')