Surface plot with 3 vectors Matlab - matlab

I need to be able to do a surface plot using data from 3 vectors. I found similar information, but no method seems to work with my data. My X and Y columns are evenly spaced, but not in increasing order. I tried different methods, but none of them seem to give me what I want, which is a simple surface linking close points together. I tried the following:
[X Y]=meshgrid(x,y);
Z=griddata(x,y,z, X,Y);
surf(X,Y,Z);
This is not exactly what I want, because it creates a surface at z=0 and makes it look more like a volume plot than just a surface. It also runs very slowly on my computer (probably from creating all the gridpoints). If I could get something that doesn't require as much memory it would be ideal (my vectors have about 20k values each), but this is not a necessity.
***Edit: I also tried using the scatteredInterpolant method found here,but the function doesn't seem to be recognized by MATLAB and I get this error:
Undefined function 'scatteredInterpolant' for input arguments of type 'double'.
Also here is an image of my problem:
You can see that we can't see under the surface, there is some z=0 plane blocking it.
If you have anything for me, any help is appreciated.
Thanks in advance.
**Edit 2: I added sample vectors, they're my x,y and z values from left to right.
***Edit 3: Here's an image of the triangulation I get. As you can see some points are being ignored for some reason, which gives those long and weird looking blue triangles.
Mike

As conventional methods seem to fail, I would suggest you to do it manually.
Create a Z matrix full of NaN values. The size of the matrix should be dependant on your x and y values.
Loop over all occuring x,y, pairs and put their (average?) z value in the right position of your Z matrix.
Loop over all NaN values and interpolate their value. Perhaps using filter2.
Use surf to plot the resulting surface

If you have points which are described by vectors, and you want to plot them you could always use a Delauny triangulation. The function in matlab is called Tri=delauny(X,Y,Z). The data generated by this function can be shown with either trimesh(Tri,X,Y,Z) or trisurf(Tri,X,Y,Z). Keep in mind trisurf is only for 3D data. If you want to adjust the transparancy of plots in your graph use the alpha setting.
I hope this helps

To me it looks like you just need to sort your data before plotting.
Here is an example which I believe is similar to your case (since I could not download your data).
x = [2 1 4 3 -1 -3 -4 -2];
y = [1 2 3 4 -1 -2 -3 -4];
z = 32 - x.*x - y.*y;
[X1 Y1] = meshgrid(x,y);
Z1 = 32 - X1.*X1 -Y1.*Y1;
surf(X1,Y1,Z1)
aux = sort([x;y],2);
x = aux(1,:);
y = aux(2,:);
[X2 Y2] = meshgrid(x,y);
Z2 = 32 - X.*X - Y.*Y;
figure()
surf(X2,Y2,Z2)
The first figure results in a very problematic surface:
The second figure contains the desired surface:

Related

Limits of the Waterfall function ... or not?

I have a problem to figure out how in a waterfall figure the x axis can correspond to the x values, and not their point number. This question seems rather simple but in my particular case (due to the size of vectors) it's not easy to get the correct figure. So i really need your help ... after several hours of unsatisfied results.
Assuming that two vectors x and y of the same length are recorded at a time t. This procedure is performed k times. I finally want to plot with waterfall y versus x for the different times.
I give you a script that corresponds to the experiment where xx is just added to get here two continuous functions x and y for the different times. The result is almost perfect but I would like the x-y values on the corresponding x, y axis instead of the point number.
xx=0:0.1:8;
for t=1:2:11
x(t,:)=sin(t*xx.^2);
y(t,:)=cos(t*xx.*4);
end
waterfall(x,y)
The problem comes probably from the different size of x, y with t. Thanks in advance for your advice.
Two comments:
waterfall takes either Z or X,Y,Z as coordinates. So it takes your x matrix as Z, and the other argument is mapped to the C input, which dictates color. You can see that the plot is the same if you do waterfall(x), except with different colors.
Your x is not monotonically increasing, so if you plot x(t,:) vs y(t,:) for any t, you'll get a web-like graph, not anything nice to look at.
So I'll plot xx vs y, and I'm modifying your y a bit so it looks nicer. I hope you can take this idea and modify it to do what you need.
The code below doesn't use waterfall at all, it simply calls plot3 once for each t. It might be possible to call plot3 with your full x and y matrices, but this is just as easy.
In the plot3 call, the x-coordinates are given by xx, the y-coordinates by t (simply repeated to match the expected size), and the z-coordinates by y:
xx = 0:0.1:8;
for t = 1:2:11
y = cos(t*xx/4);
plot3(xx,repmat(t,size(xx)),y)
hold on
end
xlabel('x')
ylabel('t')
zlabel('y=cos(tx/4)')

Draw 3D model of more than one curve in matlab with vectors

I'm doing a project that involves making a 3D model of the cornea in matlab. I have 6 plot3 in the same graph to draw one cornea
but now i want a surface plot.
Don't mind the curve orientation.
Note that all the plot3 have x, y and z that are vectors
Thanks in advance
If I were you I would use the Surf command doku surf. It is used to display [x,y,z] data. Since you have not have as many touples of data (just 6) you will have to interpolate all the other values. Therefore I would use the scattered interpolant function doku scattered interpolant.
!!!!!!!!!!!!!!Take care all this is pseudocode!!!!!!!!!!!!!!!!
F = scatteredInterpolant(x_existing,y_existing,z_existing);
generates a scattered interpolant object. You do already feed your already existing data in there. Afterwards you generate the points at which you want to interpolate:
%generates samples from -4 t0 4 in 0.05 steps
[x_sample,y_sample] = meshgrid(-4:0.05:4,-4:0.05:4);
Now you calculate the fitted z values using the scattered interpolant obj
z_interpolated=F(x_sample,y_sample) %interpolates
surf(x_sample,y_sample,z_interpolated) %plots with surf between -4 and 4
!!!!!!!!!!!!!!!From here working code!!!!!!!!!!!!!!!!!!!!!
%serialiasation of data (special for this usecase)
x_data=[h0(30:632,6);(a30(28:408,3))+0.527;(a60(276:632,3));(a90(26:575,3))+3.417;(a120(188:586,3))-0.6625;(a150(16:380,3))+1.173];
y_data=[(h0(30:632,5));((a30(28:408,2))-0.9128);(a60(276:632,2));(a90(26:575,2));(a120(188:586,2))-0.3825;((a150(16:380,2))+2.032)];
z_data=[yA0;yA30+0.162;yA60;yA90+0.837;yA120+0.135;yA150+0.135];
% cleaning the data of nan values
x_data=x_data(~isnan(z_data));
y_data=y_data(~isnan(z_data));
z_data=z_data(~isnan(z_data));%random for the looks
%interpolating
F=scatteredInterpolant(x_data,y_data,z_data);
%read yourself what this does
F.Method = 'natural';
F.ExtrapolationMethod = 'none';
%choosing sample points
[x_sample,y_sample] = meshgrid(-6:0.05:6,-6:0.05:6);
%interpolation
z_interpolated=F(x_sample,y_sample);
%plot
surf(x_sample,y_sample,z_interpolated)
I hope I was able to help you. If you try it and it works it would be very nice of you to post the working code here so that in the future here stands a working solution.

3-D Plotting with MATLAB for Galton's Skewness and Moor's Kurtosis

I know there are many plotting documents for Matlab online and I am pretty sure that it has been asked many times. I aplogize in advance for any inconvenience.
I am dealing with a new distribution and I need to draw 3D plot for different values of parameters (I can do it with Excel or any other programs, however, since my other graphs is drawn with MATLAB, and I need to put this 3D in Matlab, too, to publish it as an article). I calculated the result using MATLAB loops, however, plotting gives me the hardest time. I had no other choice but to ask for your assistance. I have these equations for different alphas and betas with a constant sigma and calculate Galton's Skewness and Moor's Kurtosis given with the last two equations.
median=sqrt(2*(sigma^2)*beta*gammaincinv(0.5,alpha));
q1=sqrt(2*(sigma^2)*beta*gammaincinv((6/8),alpha));
q3=sqrt(2*(sigma^2)*beta*gammaincinv((2/8),alpha));
q4=sqrt(2*(sigma^2)*beta*gammaincinv((7/8),alpha));
q5=sqrt(2*(sigma^2)*beta*gammaincinv((5/8),alpha));
q6=sqrt(2*(sigma^2)*beta*gammaincinv((3/8),alpha));
q7=sqrt(2*(sigma^2)*beta*gammaincinv((1/8),alpha));
galtonskewness=(q1-2*median+q3)/(q1-q3);
moorskurtosis=(q4-q5+q6-q7)/(q1-q3);
Let's assume that,
sigma=1
beta=[0.1 0.2 0.5 1 2 5];
alpha=[0.1 0.2 0.5 1 2 5];
I have used mesh(X,Y,Z) for the same range of alphas and betas with the same increment but I take the error "these values cannot be complex". I just want to draw something like the one below.
It must be something easy that I am missing out, but I do not understand where the mistake is. I appreciate any help. Thank you!
I ran the above code for a 2D mesh of points for alpha and beta between 0.1 and 5 for both dimensions and I got results for both.
I suspect it's due to your alpha and beta declaration. You are only providing a few points, and if you try to use mesh, it won't get good results. Therefore, define a meshgrid of points for both alpha and beta, then vectorize your MATLAB code to produce the kurotsis and skewness curves. Only under certain situations should you use for loops. In general, you should avoid using them whenever possible.
How meshgrid works is that given a range of X and Y values, it will produce two (or three if you want 3D co-ordinates) arrays where each location in each array gives you the spatial co-ordinate at that particular location. Therefore, if we did something like:
[X,Y] = meshgrid(1:3, 1:3);
This is what we get:
X =
1 2 3
1 2 3
1 2 3
Y =
1 1 1
2 2 2
3 3 3
Notice that in a 2D grid, for the top-left corner, (x,y) = (1,1), and so for the corresponding location in X, we get 1 and Y we get 1. If you do the same logic for any other position in the 2D grid, you simply look at the X and Y values in each array and it will tell you what the component is for each dimension.
As such, instead of looping through all possible points in your grid, generate them all using meshgrid, then vectorize the computation by calculating your values all at once rather than individually. Once you do this, you have the right structure to be able to put this into mesh.
Therefore, try doing this instead:
%// Define meshgrid of points
[alpha,beta] = meshgrid(0.1:0.1:5, 0.1:0.1:5);
%// From your code
sigma = 1;
%// Calculate quantities - Notice that this is all vectorized
med=sqrt(2*(sigma^2)*beta.*gammaincinv(0.5,alpha));
q1=sqrt(2*(sigma^2)*beta.*gammaincinv((6/8),alpha));
q3=sqrt(2*(sigma^2)*beta.*gammaincinv((2/8),alpha));
q4=sqrt(2*(sigma^2)*beta.*gammaincinv((7/8),alpha));
q5=sqrt(2*(sigma^2)*beta.*gammaincinv((5/8),alpha));
q6=sqrt(2*(sigma^2)*beta.*gammaincinv((3/8),alpha));
q7=sqrt(2*(sigma^2)*beta.*gammaincinv((1/8),alpha));
galtonskewness=(q1-2*med+q3)./(q1-q3);
moorskurtosis=(q4-q5+q6-q7)./(q1-q3);
%// Show our meshes
figure;
mesh(alpha, beta, galtonskewness);
figure;
mesh(alpha, beta, moorskurtosis);
Also take note that I renamed your median variable to med. MATLAB has a function called median and so you don't want to unintentionally shadow over this function with a variable of the same name.
This is what I get:
Take note that I'm not getting the plots that you have placed in your post. It may be because I'm choosing the wrong variables to define the mesh, or perhaps your equations may be incorrect. Double check what you know in theory to what you have here in code and try again.
This should hopefully give you enough to start with though!

How to create 3D joint density plot MATLAB?

I 'm having a problem with creating a joint density function from data. What I have is queue sizes from a stock as two vectors saved as:
X = [askQueueSize bidQueueSize];
I then use the hist3-function to create a 3D histogram. This is what I get:
http://dl.dropbox.com/u/709705/hist-plot.png
What I want is to have the Z-axis normalized so that it goes from [0 1].
How do I do that? Or do someone have a great joint density matlab function on stock?
This is similar (How to draw probability density function in MatLab?) but in 2D.
What I want is 3D with x:ask queue, y:bid queue, z:probability.
Would greatly appreciate if someone could help me with this, because I've hit a wall over here.
I couldn't see a simple way of doing this. You can get the histogram counts back from hist3 using
[N C] = hist3(X);
and the idea would be to normalise them with:
N = N / sum(N(:));
but I can't find a nice way to plot them back to a histogram afterwards (You can use bar3(N), but I think the axes labels will need to be set manually).
The solution I ended up with involves modifying the code of hist3. If you have access to this (edit hist3) then this may work for you, but I'm not really sure what the legal situation is (you need a licence for the statistics toolbox, if you copy hist3 and modify it yourself, this is probably not legal).
Anyway, I found the place where the data is being prepared for a surf plot. There are 3 matrices corresponding to x, y, and z. Just before the contents of the z matrix were calculated (line 256), I inserted:
n = n / sum(n(:));
which normalises the count matrix.
Finally once the histogram is plotted, you can set the axis limits with:
xlim([0, 1]);
if necessary.
With help from a guy at mathworks forum, this is the great solution I ended up with:
(data_x and data_y are values, which you want to calculate at hist3)
x = min_x:step:max_x; % axis x, which you want to see
y = min_y:step:max_y; % axis y, which you want to see
[X,Y] = meshgrid(x,y); *%important for "surf" - makes defined grid*
pdf = hist3([data_x , data_y],{x y}); %standard hist3 (calculated for yours axis)
pdf_normalize = (pdf'./length(data_x)); %normalization means devide it by length of
%data_x (or data_y)
figure()
surf(X,Y,pdf_normalize) % plot distribution
This gave me the joint density plot in 3D. Which can be checked by calculating the integral over the surface with:
integralOverDensityPlot = sum(trapz(pdf_normalize));
When the variable step goes to zero the variable integralOverDensityPlot goes to 1.0
Hope this help someone!
There is a fast way how to do this with hist3 function:
[bins centers] = hist3(X); % X should be matrix with two columns
c_1 = centers{1};
c_2 = centers{2};
pdf = bins / (sum(sum(bins))*(c_1(2)-c_1(1)) * (c_2(2)-c_2(1)));
If you "integrate" this you will get 1.
sum(sum(pdf * (c_1(2)-c_1(1)) * (c_2(2)-c_2(1))))

Connecting final and initial point in simple x-y plot (Plotting closed curve/polygon)

Say, for example, I had ...
x = [1 1 2 2];
y = [1 2 2 1];
plot(x, y, 'b-');
I will get a plot with lines connecting the points (1,1), (1,2), and (2,2). Is there any way to connect the final point with the first, thus completing the square on the plot?
I'm also pulling in lines of text with points, so simply adding another point 1,1 is not an option.
impoly can be useful, however, it creates a modifiable curve which is slower than plot.
You can write a simple function for that:
function plotc(x,y,varargin)
x = [x(:) ; x(1)];
y = [y(:) ; y(1)];
plot(x,y,varargin{:})
end
By the way, the (:) colon operator is used as defensive programming means. In this way, x and y can be either row or column vectors.
The varargin allows using additional parameters, like:
plotc(x,y,'Color','r');
plotc(x,y,'Parent',a,'LineWidth',2);
Unless your final and last points are the same then plot won't know that you want a closed curve. So either add an additional point to your list to plot or try using, for example, rectangle.
Do you have the Image Processing Toolbox? If yes,
impoly(hparent, position, 'Closed')
might be of use to you.
http://www.mathworks.de/help/toolbox/images/ref/impoly.html