Matlab Surface Plot of Z^2 = Z type equation - matlab

i'm currently trying to plot this function:
Z^2 = (X.^2+Y.^2+2*w.*Z.*Y.*a)./(1-w^2*a^2)
Geogebra gives a lightcone https://en.wikipedia.org/wiki/Light_cone but crushes if i change the parameters a bit. I tried then matlab:
[X,Y] = meshgrid(-10:.5:10);
a=2;
w=1;
Z = (X.^2+Y.^2+2*w.*sqrt(abs(Z)).*Y.*a)./(1-w^2*a^2);
surf(X,Y,Z)
zlim([-5,5])
And it has too few points. I wish i could add some changing meshgrid, like (-5:.1:5), but it gives:
Arrays have incompatible sizes for this operation.
Probably due to sqrt(abs(Z)) in the equation. I don't know how to fix it.
Thanks

It's easier to directly generate the cone data with command cylinder
t = 0:pi/10:2*pi;
r =linspace(2,0,numel(t))
[X,Y,Z] = cylinder(r);
figure
hs1=surf(X,Y,Z)
Note that I have added the handle hs1 which is output of surf.
This way you can change any property of the generated cone surface explained in detail here :
https://uk.mathworks.com/help/matlab/ref/matlab.graphics.chart.primitive.surface-properties.html

Related

Plot a surface in MATLAB

I want to plot a surface in MATLAB using surf. I have this equation: x = y^2 +4z^2.
What I am doing is the following:
[x,y] = meshgrid(-4:.1:4, -4:.1:4);
z = sqrt((x - y.^2)./4); % Basically I'm just clearing for z
surf(x,y,z)
But with this I am getting the error: Error using surf X,Y,Z and C cannot be complex. I know there is a complex number because of the values that x and y have, plus the square root. Is there another way to plot a surface in MATLAB? because I really don't know what to do, and my skills are very basics.
Why do you feel that you need to grid x and y, and not use the form of the original equation itself?
This seems to work perfectly fine
[y,z] = meshgrid(-4:.1:4, -4:.1:4);
x = y.^2 + 4*z.^2;
surf(x,y,z)
to produce

How to plot my differential equation with quiver?

I want to solve my differential equation and plot velocity vectors but I am having some trouble with that. I tried this:
syms y(x);
ode = (1+exp(x))*y*diff(y,x)-2*exp(x) == 0;
ySol = dsolve(ode)
[X,Y] = meshgrid(-2:.2:2);
Z = 2*exp(X)/((1+exp(X)).*Y);
[DX,DY] = gradient(Z,.2,.2);
figure
contour(X,Y,Z)
hold on
quiver(X,Y,DX,DY)
hold off
and I get this error:
Warning: Matrix is singular to working precision.
Warning: Contour not rendered for non-finite ZData
It is probably something simple that I do not see but I am just starting using Matlab and I cold not find a right way to do my task. Please help me...
EDIT
As bconrad suggested, I changed my Z function like this:
Z = 2*exp(X)/((1+exp(X)).*Y);
and the previous errors are fixed. However, my prime goal, to plot velocity vectors is not accomplished yet because I get a graph like this:
Don’t have the ability to check at the moment, but I reckon you want an element by element division in that line. You’re missing a dot on the division, try
Z = 2*exp(X)./((1+exp(X)).*Y);
I took a closer look once at my station. The zero-division mentioned by Pablo forces inf's in Z, so quiver get's confused when scaling the vectors (understandably) and just doesn't show them. Try this (with the ode part removed):
[X,Y] = meshgrid(-2 : .2 : 2);
Z = 2 * exp(X) ./ ((1 + exp(X)) .* Y);
Z(isinf(Z)) = nan; % To avoid 0-division problems
[DX, DY] = gradient(Z, .2, .2);
figure
contour(X, Y, Z, 30, 'k')
hold on
quiver(X, Y, DX, DY, 6)
hold off
I've done 3 things here:
Added the line Z(isinf(Z)) = nan; forcing infinite values to be essentially ignored by quiver
Added the arguments 30, 'k' to the contour function to show 30 lines, and make them black (a bit more visible)
Added the argument 6 to the quiver function. This overrides the automatic length-scaling of the vectors.
You'll want to play with the arguments in the contour and quiver functions to make your figure appear as you'd like.
PS: There is a handy arrow function on the file exchange that I find gives better control when creating vector field plots. See https://www.mathworks.com/matlabcentral/fileexchange/278-arrow - the ratings do it justice.

Draw a line with non-Cartesian coordinates in MATLAB

MATLAB's surf command allows you to pass it optional X and Y data that specify non-cartesian x-y components. (they essentially change the basis vectors). I desire to pass similar arguments to a function that will draw a line.
How do I plot a line using a non-cartesian coordinate system?
My apologies if my terminology is a little off. This still might technically be a cartesian space but it wouldn't be square in the sense that one unit in the x-direction is orthogonal to one unit in the y-direction. If you can correct my terminology, I would really appreciate it!
EDIT:
Below better demonstrates what I mean:
The commands:
datA=1:10;
datB=1:10;
X=cosd(8*datA)'*datB;
Y=datA'*log10(datB*3);
Z=ones(size(datA'))*cosd(datB);
XX=X./(1+Z);
YY=Y./(1+Z);
surf(XX,YY,eye(10)); view([0 0 1])
produces the following graph:
Here, the X and Y dimensions are not orthogonal nor equi-spaced. One unit in x could correspond to 5 cm in the x direction but the next one unit in x could correspond to 2 cm in the x direction + 1 cm in the y direction. I desire to replicate this functionality but drawing a line instead of a surf For instance, I'm looking for a function where:
straightLine=[(1:10)' (1:10)'];
my_line(XX,YY,straightLine(:,1),straightLine(:,2))
would produce a line that traced the red squares on the surf graph.
I'm still not certain of what your input data are about, and what you want to plot. However, from how you want to plot it, I can help.
When you call
surf(XX,YY,eye(10)); view([0 0 1]);
and want to get only the "red parts", i.e. the maxima of the function, you are essentially selecting a subset of the XX, YY matrices using the diagonal matrix as indicator. So you could select those points manually, and use plot to plot them as a line:
Xplot = diag(XX);
Yplot = diag(YY);
plot(Xplot,Yplot,'r.-');
The call to diag(XX) will take the diagonal elements of the matrix XX, which is exactly where you'll get the red patches when you use surf with the z data according to eye().
Result:
Also, if you're just trying to do what your example states, then there's no need to use matrices just to take out the diagonal eventually. Here's the same result, using elementwise operations on your input vectors:
datA = 1:10;
datB = 1:10;
X2 = cosd(8*datA).*datB;
Y2 = datA.*log10(datB*3);
Z2 = cosd(datB);
XX2 = X2./(1+Z2);
YY2 = Y2./(1+Z2);
plot(Xplot,Yplot,'rs-',XX2,YY2,'bo--','linewidth',2,'markersize',10);
legend('original','vector')
Result:
Matlab has many built-in function to assist you.
In 2D the easiest way to do this is polar that allows you to make a graph using theta and rho vectors:
theta = linspace(0,2*pi,100);
r = sin(2*theta);
figure(1)
polar(theta, r), grid on
So, you would get this.
There also is pol2cart function that would convert your data into x and y format:
[x,y] = pol2cart(theta,r);
figure(2)
plot(x, y), grid on
This would look slightly different
Then, if we extend this to 3D, you are only left with plot3. So, If you have data like:
theta = linspace(0,10*pi,500);
r = ones(size(theta));
z = linspace(-10,10,500);
you need to use pol2cart with 3 arguments to produce this:
[x,y,z] = pol2cart(theta,r,z);
figure(3)
plot3(x,y,z),grid on
Finally, if you have spherical data, you have sph2cart:
theta = linspace(0,2*pi,100);
phi = linspace(-pi/2,pi/2,100);
rho = sin(2*theta - phi);
[x,y,z] = sph2cart(theta, phi, rho);
figure(4)
plot3(x,y,z),grid on
view([-150 70])
That would look this way

I need help graphing a spherical equation in Cartesian coordinates in MATLAB

I know about the function sph2cart, but I feel like I must be using it wrong. In a Calculus textbook, I saw that this following spherical equation:
ρ = 1 + 1/5*sin(6θ)*sin(5Φ)
produces something that looks like this:
I wanted to reproduce this in a Matlab graph, so I wrote the following code
[q,t] = meshgrid(linspace(0,pi,100),linspace(0,2*pi,100));
rho = 1+1/5*sin(6*t)*sin(5*q);
[x,y,z] = sph2cart(t,q,rho);
surf(x,y,z)
axis square, axis equal
And I got the following graph:
Why is this happening? Why am I not getting the bumpy sphere my calc textbook shows?
There are two problems:
You need .* rather than * between your sin(6*t) and sin(5*q) since you want per element multiplication not matrix multiplication.
You want q to run from 0-PI and t to run from 0-2PI
This code produces the result you're looking for.
[q,t] = meshgrid(linspace(0,2*pi,100),linspace(0,pi,100));
rho = 1+(1/5*sin(6*t).*sin(5*q));
[x,y,z] = sph2cart(t,q,rho);
surf(x,y,z)
axis square, axis equal

How to plot a 3-column matrix as a color map in MATLAB?

I have a matrix containing the temperature value for a set of GPS coordinates. So my matrix looks like this :
Longitude Latitude Value
--------- -------- -----
12.345678 23.456789 25
12.345679 23.456790 26
%should be :
% x y z
etc.
I want to convert this matrix into a human-viewable plot like a color plot (2D or 3D), how can I do this?
3D can be something like this :
or just the 2-D version of this (looking from top z-axis).
What Have I Tried
I know MATLAB has surf and mesh functions but I cannot figure out how to use them.
If I call
surf(matrix(:,1) , matrix(:,2) , matrix(:,3));
I get the error :
Error using surf (line 75)
Z must be a matrix, not a scalar or vector
Thanks in advance for any help !
P.S : It would also be great if there is a function that "fills" the gaps by interpolation (smoothing, whatever :) ). Since I have discrete data, it would be more beautiful to represent it as a continous function.
P.S 2 : I also want to use plot_google_map in the z=0 plane.
A surprisingly hard-to-find answer. But I'm lucky that somebody else has asked almost the same question here.
I'm posting the answer that worked for me :
x = matrix(:,1);
y = matrix(:,2);
z = matrix(:,3);
xi=linspace(min(x),max(x),30)
yi=linspace(min(y),max(y),30)
[XI YI]=meshgrid(xi,yi);
ZI = griddata(x,y,z,XI,YI);
contourf(XI,YI,ZI)
which prints a nice color map.
One option that avoids unnecessarily gridding your data would be to compute the Delaunay triangulation of the scattered data points and then using a command like trisurf to plot the data. Here's an example:
N=50;
x = 2*pi*rand(N,1);
y = 2*pi*rand(N,1);
z = sin(x).*sin(y);
matrix = [x y z];
tri = delaunay(matrix(:,1),matrix(:,2));
trisurf(tri,matrix(:,1),matrix(:,2),matrix(:,3))
shading interp
Suppose your matrix is nx3. Then you can create the grid as follows:
xMin=min(myMat(:,1));
xMax=max(myMat(:,1));
yMin=min(myMat(:,2));
yMax=max(myMat(:,2));
step_x=0.5; %depends on your data
[xGrid,yGrid]=meshgrid(xMin:step_x:xMax,yMin:step_y:yMax);
Now, put your data in the third column to the appropriate indices, in the new matrix say, valMat.
You can use surf now as follows:
surf(xGrid,yGrid,valMat);
If you want interpolation, you can convolve a Gaussian kernel (maybe 3x3) with valMat.