Plot gradient of a function which is a matrix in MATLAB - matlab

I would like to plot the gradient of the following function in MATLAB.
g(x,y) = [(x^2)-1; -y]
My code is:
x = linspace(-3,3);
y = linspace(-3,3);
[xx, yy] = meshgrid(x,y);
z = [xx.^2-1;-yy];
[dx,dy] = gradient(z,.3,.3);
contour(x,y,z)
hold on
quiver(x,y,dx,dy)
But I'm just getting this error:
The size of Y must match the size of Z or the number of rows
of Z.
I've no idea how I could make the size of both match. y is a 1x100 matrix and z a 200x100. To match them I would need y to be a 1x200 or z to be 100x100, but would I be able to plot it then?

Instead of
z = [xx.^2-1;-yy];
try each component separately:
z1 = [xx.^2-1];
z2 = [-yy];
[dx,dy] = gradient(z1,.3,.3);
contour(x,y,z1)
%etc.
Use hold on again if you really want them in the same plot.

Related

Extracting Z values after 3D plot is generated by 2D curve revolution with repmat

I am stuck with an apparently simple problem. I have to revolve of 360° a 2D curve around an axis, to obtain a 3D plot. Say, I want to do it with this sine function:
z = sin(r);
theta = 0:pi/20:2*pi;
xx = bsxfun(#times,r',cos(theta));
yy = bsxfun(#times,r',sin(theta));
zz = repmat(z',1,length(theta));
surf(xx,yy,zz)
axis equal
I now want to visualize the numerical values of the Z plane, stored in a matrix. I would normally do it this way:
ch=get(gca,'children')
X=get(ch,'Xdata')
Y=get(ch,'Ydata')
Z=get(ch,'Zdata')
If I visualize Z with
imagesc(Z)
I don't obtain the actual values of Z of the plot, but the "un-revolved" projection. I suspect that this is related to the way I generate the curve, and from the fact I don't have a function of the type
zz = f(xx,yy)
Is there any way I can obtain the grid values of xx and yy, as well as the values of zz at each gridpoint?
Thank you for your help.
Instead of bsxfun you can use meshgrid:
% The two parameters needed for the parametric equation
h = linspace(0,2) ;
th = 0:pi/20:2*pi ;
[R,T] = meshgrid(h,th) ;
% The parametric equation
% f(x) Rotation along Z
% ↓ ↓
X = sin(R) .* cos(T) ;
Y = sin(R) .* sin(T) ;
% Z = h
Z = R ;
surf(X,Y,Z,'EdgeColor',"none")
xlabel('X')
ylabel('Y')
zlabel('Z')
Which produce:
And if you want to extract the contour on the X plane (X = 0) you can use contour:
contour(Y,Z,X,[0,0])
Which produce:

How to create noise for a 2D Gaussian?

I'm trying to practice curve fitting on a 2D Gaussian, but in order to do that I need to add random noise to my predefined Gaussian. My first instinct was to cycle through two for loops and create two matrices X and Y with random numbers, but when I tried that (I don't have the code anymore) Matlab wouldn't let me plot the Gaussian because I didn't generate my X and Y values using the meshgrid function. Since I seem to need to use meshgrid, can anyone help me figure out how to generate a random meshgrid so I can add some noise to my Gaussian?
amp = 1;
x0 = 0;
y0 = 0;
sigmaX = 1;
sigmaY = 1;
%X = 1:1:100;
%Y = 1:1:100;
[X,Y] = meshgrid(-3:.1:3);
%Z = X .* exp(-X.^2 - Y.^2);
Z = amp*exp(-((X-x0).^2/(2*sigmaX^2)+(Y-y0).^2/(2*sigmaY^2)));
surf(X, Y, Z);
%Add noise now
EDIT: So I found out that rand can return a random matrix which will work with the surf function (for some reason it wasn't working for me earlier though). The result looks something like this: noisy 2D gaussian
amp = 1;
x0 = 0;
y0 = 0;
sigmaX = 1;
sigmaY = 1;
[X,Y] = meshgrid(-3:.1:3);
%Z = X .* exp(-X.^2 - Y.^2);
Z = amp*exp(-((X-x0).^2/(2*sigmaX^2)+(Y-y0).^2/(2*sigmaY^2)));
surf(X, Y, Z);
%Make some noise
[xRows, xColumns] = size(X);
[yRows, yColumns] = size(Y);
figure(2)
X = -.1 + (.1+.1)*rand(61,61);
Y = -.1 + (.1+.1)*rand(61,61);
Z = amp*exp(-((X-x0).^2/(2*sigmaX^2)+(Y-y0).^2/(2*sigmaY^2)));
surf(X, Y, Z)
But I feel like the Gaussian has largely lost it's typical bell shape and looks more like a slope field than anything. I'm going to try and refine it but I would love any input.
That's what i would do.
amp=1;
x0=0;
y0=0;
sigmaX=1;
sigmaY=1;
noiseAmp=.1;
x=[-2:.1:2];
y=[-2:.1:2];
%Create two Noise Vectors
noisez1=noiseAmp.*rand(1,length(x));
noisez2=noiseAmp.*rand(1,length(x));
% Make an meshgrid out of the two Vectors
[noiseZ1,noiseZ2]=meshgrid(noisez1,noisez2);
% Add the Meshgrids togehter
Noise=noiseZ1+noiseZ2;
[X,Y]=meshgrid(x,y);
% Add the Noise to the result of Z
Z=amp*exp(-((X-x0).^2/(2*sigmaX^2)+(Y-y0).^2/(2*sigmaY^2)))+Noise;
surf(X,Y,Z);
if you just want a 2D plot you can try this
amp=1;
noiseAmp=0.01;
x0=0;
y0=0;
sigmaX=1;
sigmaY=1;
x=[-5:.01:5];
noiseY=noiseAmp*rand(1,length(x));
y=noiseY+amp*exp(-((x-x0).^2/(2*sigmaX^2)));
plot(x,y);
where noiseAmp is the Amplitude of the noise.
But if you still want to create a 3D plot with the surf() function, you have to add a random meshgrid to the Z result.

Surf function won't graph 2D Gaussian

I'm trying to graph a simple 2D Gaussian in MATLAB using the surf function, but I'm getting an error saying that the last value in surf must be a matrix and not a vector. I don't understand how to graph the function then as every other example I've found while searching has had the third value as a vector. I feel as if I'm completely off base here with the surf function. Any ideas?
amp = 10;
x0 = 0;
y0 = 0;
sigmaX = 10
sigmaY = 10
X = 1:1:100;
Y = 1:1:100;
Z = amp*exp(-(X-x0).^2/(2*sigmaX^2)+(Y-y0).^2/(2*sigmaY^2));
disp(size(Z))
surf(X, Y, Z);
Edit
When I plot this using #Suever's answer, I get something that doesn't look like a Gaussian at all.
Here's the plot
amp = 1;
x0 = 0;
y0 = 0;
sigmaX = 1;
sigmaY = 1;
%X = 1:1:100;
%Y = 1:1:100;
[X,Y] = meshgrid(-3:.1:3);
%Z = X .* exp(-X.^2 - Y.^2);
Z = amp*exp(-(X-x0).^2/(2*sigmaX^2)+(Y-y0).^2/(2*sigmaY^2));
surf(X, Y, Z);
You have used X and Y to define a 2D domain over which you would like to compute your gaussian. If you want Z to be a function of X and Y, you need to define Z for all permutations of X and Y. If you don't provide a matrix of Z values, MATLAB has no idea how to create a surface over the X Y ranges you've provided.
You can create all permutations of X and Y using meshgrid and then compute Z over this entire domain. Then you will be able to display the result with surf.
amp = 10; x0 = 50; y0 = 50; sigmaX = 10; sigmaY = 10;
[X, Y] = meshgrid(1:100, 1:100);
% Z as you had it written (see correct version below)
Z = amp*exp(-(X-x0).^2./(2*sigmaX^2)+(Y-y0).^2./(2*sigmaY^2));
surf(X, Y, Z);
Update
Your equation for the 2D Gaussian is wrong. The - sign should be outside of the addition of the two components. The way that you had it written, you negated the X-component and then added to the Y component.
Z = amp*exp(-((X-x0).^2./(2*sigmaX^2)+(Y-y0).^2./(2*sigmaY^2)));

Extract data from ezplot in MATLAB

I am trying to extract data from an ezplot, but when I plot the extracted data, I don't get the same graph (a and b are different)...
Could anybody elaborate on what's wrong?
Here is the code:
h = #(x,y)(x-((1/0.0175)*(y/5500)*(1+(y/5500)^9)))
a = ezplot(h,[0,700,0,7000]);
t = get(a,'xdata');
M = get(a,'ydata');
theta = transpose(t)
figure
b = plot(theta,M)
ezplot produces
whilst plot produces
This is what I get by extracting from the contour, there is still a straight line 3
ezplot returns a contour object. To extract the x and y data you need to use get(a,'contourMatrix'). Then the x data will be in the first column and the y data in the second column as
t = get(a,'contourMatrix');
x = t(1, :);
y = t(2, :);
Putting this altogether for your example we get
h = #(x,y)(x-((1/0.0175)*(y/5500)*(1+(y/5500)^9)))
a = ezplot(h,[0,700,0,7000]);
t = get(a,'contourMatrix');
x = t(1, :);
y = t(2, :);
figure;
b = plot(x, y);
xlabel('x');
ylabel('y');
title('({x}-(({1}/{0.0175}) ({y}/{5500}) ({1}+({y}/{5500})^{9}))) = {0}');
The resulting ezplot is
and the same from plot
You are getting the x and y axis values in calling get(a,'xdata') and get(a,'ydata'). That is the reason you're getting the straight line.
Try this instead:
h = #(x,y)(x-((1/0.0175)*(y/5500)*(1+(y/5500)^9)));
ezplot(h,[0,700,0,7000]);
a= get(gca,'Children');
l=get(a,'Children');
t = get(l,'xdata');
M = get(l,'ydata');
theta = transpose(t);
figure
b = plot(theta,M);
Sources:
Handle Graphics: Modifying Plots
How do I extract data from MATLAB figures?

3d-plotting surface 2x^2 + 3y^2 + z^2 = 6

I was trying to plot the above surface in octave/matlab and ran into the this problem.
My code is as follows:
x = linspace(-sqrt(3),sqrt(3),1000);
y = linspace(-sqrt(2),sqrt(2),1000);
z = sqrt(6-2*x.^2-3*y.^2);
surf(x,y,z)
I got the error:
error: mesh: X, Y, Z arguments must be real.
I understand this was because some (x,y)s would result in negative 6-2*x.^2-3*y.*2, but I don't know how to tackle this because I can't trim either part of x or y. Any one can help? Thanks
It depends what you want to do with the non-real values of z.
One thing you could do is to set all these values to zero or NaN (as per #hbaderts' comment):
z = sqrt(6-2*x.^2-3*y.^2);
z( imag(z)~=0 ) = NaN;
One more thing though: your code might have a problem because z is a length-1000 vector, and you want it to be a 1000x1000 matrix. You should use meshgrid() on x and y to get two-dimensional matrices everywhere:
x = linspace(-sqrt(3),sqrt(3),1000);
y = linspace(-sqrt(2),sqrt(2),1000);
[xx,yy] = meshgrid(x,y);
z = sqrt(6-2*xx.^2-3*yy.^2);
z( imag(z)~=0 ) = NaN;
surf(xx,yy,z,'edgecolor','none')
(thanks #LuisMendo for the 'edgecolor','none' suggestion for better visualization.)
Running the above piece of code on octave gives this plot: