3D scatter plot with 4D data - matlab

I need to plot a 3D figure with each data point colored with the value of a 4th variable using a colormap. Lets say I have 4 variables X,Y,Z and W where W = f(X,Y,Z). I want a 3D plot with X, Y, and Z as the three axis. The statement scatter3(X,Y,Z,'filled','b') gives me a scatter plot in 3D but I want to incorporate the value of Z in the graph by representing the points as an extra parameter (either with different areas :bigger circles for data points with high value of Z and small circles for data points with low value of Z or by plotting the data points with different colors using a colormap). However, I am a novice in MATLAB and dont really know how to proceed. Any help will be highly appreciated.
Thanks in advance!

So just use z for the size vector (4th input) as well as the color vector (5th input):
z = 10*(1:pi/50:10*pi);
y = z.*sin(z/10);
x = z.*cos(z/10);
figure(1)
scatter3(x,y,z,z,z)
view(45,10)
colorbar
The size vector needs to be greater 0, so you may need to adjust your z accordingly.

You are already nearly there... simply use
scatter3(X,Y,Z,s,W);
where s is the point size (scalar, e.g. 3) and W is a vector with your W values.
You might also want to issue an
set(gcf, 'Renderer','OpenGL');
where gcf gets your current figure you are plotting in to significantly increase responsiveness when scattering a lot of data.

Related

Scatter plot with different size for each point

I have several thousands of points to plot (about 10k) and I would like to plot them with Matlab but deciding a diferent size for each of the points (and a different color if possible). I tried to make a scatter plot for each point, but it is extremely slow compared to a single scatter call for all the points. Is there a way to plot several points in Matlab with different properties for each point, that works in a reasonable amount of time?
In case it is not possible to do it with Matlab, is there a way to do it with gnuplot?
scatter(x, y, a, c) takes arguments x and y, and then a for size, and c for colour. a can either be a single scalar, or a vector with a size for each (x,y) point. c can be an RGB triplet, or a vector, the same size as x and y. For example:
x = 1:4;
scatter(x, x, 10*x, x);
results in
So in your case, perhaps
scatter(xData, yData, [], 1:10000)
will result in your data having a different colour determined by its position in the data array.
For gnuplot it's easy, suppose you write your datafile with 3 columns, all you have to do is
plot 'data.dat' u 1:2:3:3 with circles lc palette
HERE you can find some examples (for help type help circles).
If you want just what is called variable pointsize (pointsize is not related to the real axis) you can use:
plot 'data.dat' with points ps variable pt 7
HERE you can find some examples (for help type help pointsize).
For gnuplot you can combine pointsize variable and linecolor variable or linecolor palette:
set xrange [0:10]
set samples 21
plot '+' using 1:1:(0.2*$1):1 with point pointsize variable linecolor palette pt 7 notitle

Making an accurate colorbar for a simple plot

I am trying to make a simple plot (for this example doing a plot of y=x^2 will suffice) where I want to set the colors of the points based on their magnitude given some colormap.
Following along my simple example say I had:
x = 1:10;
y = x.^2;
Use gscatter(x,y,jet(10)); legend hide; colorbar which produces a plot with the points colored but the colorbar does not agree with the colored values. (Can't post picture as this is my first post). Using a caxis([1,100]) command gives the right range but the colors are still off.
So I have two questions:
(1) How can I fix the colors to fit to a colorbar given a range? In my real data, I am looking at values that range from -50 to 50 in some instances and have many more data points.
(2) I want to create a different plot with the same points (but on different axes) and I want the colors of each point on this new plot to have the same colors as their counterparts in the previous plot. How can I, programmatically, extract the color from each point so I can plot it on two different sets of axes?
I would just move the points into a matrix and do an imagesc() command but they aren't spaced as integers or equally so simple scaling wouldn't work either.
Thanks for any help!
Regarding you first question, you need to interpolate the y values into a linear index to the colormap. Something like:
x = 1:10;
y = x.^4;
csize = 128;
cmap = jet(csize);
ind = interp1(linspace(min(y),max(y),csize),1:csize,y,'nearest');
scatter(x,y,14,cmap(ind,:),'filled')
colorbar
caxis([min(y) max(y)])
Using interp1 in this case is an overkill; you could calculate it directly. However, I think in this way it is clearer.
I think it also answers your 2nd question, since you have the index of the color of each data point, so you can use it again in the same way.

Matlab - Multiple 2D plots along a 3rd dimension

I'm trying to plot many 2D plots (x,y).
But...
each 2D plot is for a constant z.
So really my data is (x,y,z) but not z(x,y), which I believe are the requirements for using the "surf" command.
Could anyone help with this?
Example,
x = velocity
y = drag
I have multiple runs of y(x) for a constant temperature, z.
I just want to plot each (x,y) along a 3rd axis, temperature z.
Ideally I'd also want some sort of contour between the (x,y) plots so I can show the peaks/troughs etc.
Any help would be great.
If the runs are not independent (there is some trend over multiple runs) then it may make sense to use surf. You then need to construct your data such you have an X,Y, and Z - in this case I'd suggest you use the drag measurements as your Z (height).
Assuming that you have all the drag/velocity data in drag and velocity which are both of size [data points x number of runs]:
% construct matrix of run numbers
runs = repmat(1:numruns, [1, datapoints]);
runs = reshape(runs, datapoints, numruns);
% plot and label
surf(runs,velocity,drag);
xlabel('runs')
ylabel('velocity')
zlabel('drag')

How to set an arbitrary direction on a contour plot to perform operation in Matlab

I am looking for help for my particular problem.
I have a contour plot created from XYZ data. This plot contains 2 broad peaks with one more intense than the other.
When the most intense peak is aligned with the Y axis, I can perform a fitting of every YZ curve at each X values. I usually do a gaussian fit to plot the peak center on the same graph.
In some cases I need to perform the same fitting but no along the Y axis direction (in this case I just plot YZ scan at every different X values) but along another arbitrary direction.
For the moment the only way I found is the following:
-plot the contour plot and find for the position of the most intense peak
-if the position is not aligned with the Y axis, then rotate all the datas and plot again the contour
-perform the YZ gaussian fit for every X value
- Rotate the resulting XY position to go back to the original plot
-plot the XY position as a line on the original contour plot
this is quite long and requires a lot of memory. i would like ot know if there is a more elegant/faster way.
Thanks for your help
David
I take it you want to extract data from the (x,y,z) data along some arbitrary line in order to make a fit. A contour plot will show only part of the data, the full z(x,y) data can be shown with imagesc etc. Say you want the data along line defined by two points (x1,y1) -> (x2,y2). According to the eq of the line, the line y=a*x+b the slope a is (y2-y1)/(x2-x1) and b=y1-a*x1. For example, I'll select (x,y) coordinates in the following contour:
Create data and end points:
m=peaks(100);
x1=11 ; x2=97;
y1=66; y2=40;
Thus the line parameters are:
a=(y2-y1)/(x2-x1);
b=y1-a*x1;
and the line is:
x=x1:x2;
y=round(a*x+b);
select the proper (x,y) elements using linear indexing:
ind=sub2ind(size(m),y,x)
plot:
subplot(2,1,1)
contour(m,10); hold on
line([x1 x2],[y1 y2],'Color',[1 0 0]);
subplot(2,1,2)
plot(m(ind))
You can now use vec=m(ind) to fit your function.

Matlab 3d plot of indexed data

I am trying to plot a 3d view of a very large CT dataset. My data is in a 3d matrix of 2000x2000x1000 dimension. The object is surrounded by air, which is set to NaN in my matrix.
I would like to be able to see the greyscale value of the surface of the object (no isosurface) but I cannot quite work out how to do that in Matlab. Can anyone help me please?
Given that I a dealing with a huge matrix and I am only interested in the surface of the object, does anyone know a good trick how to reduce the size of my dataset?
The function surf(X,Y,Z) allows you to plot 3d data, where (X,Y) gives the coordinates in the x-y-plane while Z gives the z-coordinate and the surface color.
By default the function does not plot anything for the NaN entries, so you should be good to go with the surf function.
To set the surf-function to use a grayscale plotting use:
surf(matrix3d);
colormap(gray);
This plots the matrix in a surface plot and sets the colormap to grayscale.
In addition, as I understand your data, you might be able to eliminate entire plane-segments in your matrix. If for instance the plane A(1,1:2000,1:1000) is NaN in all entries you could eliminate all those entries (thus the entire Y,Z-plane in entry X=1). This will however require some heavy for loops, which might be over the top. This depends on how many data matrices you have compared to how many different plot you want for each matrix.
I will try to give you some ideas. I assume lack of a direct 3D "surface detector".
Since you have a 3D matrix where XY-planes are CT scan slices and each slice is an image, I would try to find edges of each slice say with edge. This would require some preprocessing like first thresholding each slice image. Then I can either use scatter3 to display the edge data as a 3D point cloud or delaunay3 to display the edge data as a surface.
I hope this will help you achieve what you are asking for.
I managed to get it working:
function [X,Y,Z,C] = extract_surface(file_name,slice_number,voxel_size)
LT = imread(file_name);%..READ THE 2D MAP
BW = im2bw(LT,1);%..THRESHOLD TO BINARY
B = bwboundaries(BW,8,'noholes');%..FIND THE OUTLINE OF THE IMAGE
X = B{1}(:,1);%..EXTRACT X AND Y COORDINATES
Y = B{1}(:,2);
indices = sub2ind(size(LT),X,Y);%..FIND THE CORRESPONDING LINEAR INDICES
C = LT(indices);%..NOW READ THE VALUES AT THE OUTLINE POSITION
Z = ones(size(X))*slice_number;
I can then plot this with
figure
scatter3(X,Y,Z,2,C)
Now the only thing I could improve is to have all these points in the scatter plot connected with a surface. #upperBound you suggested delaunay3 for this purpose - I cannot quite figure out how to do this. Do you have a tip?