I have two variables x and y. I decide to plot the square root of their difference using contour as follows:
x=0:0.1:100;
y=0:0.1:100;
G=sqrt(x-y);
test2 = G;
test2(~(G<0)) = nan;
[C,h]=contourf(x,y,G,'ShowText','off');
set(gca,'FontSize',20)
However I get this error : Error using contourf (line 69)
Z must be size 2x2 or greater.
If that is resolved, I want to reach my goal and plot the actual function which relies on x, y and G itself as follows:
Function = 2 sqrt(x) / G * acoth((sqrt(x) + y/2 )/G )
I give an example
x=0:0.1:100;
y=0:0.1:100;
[X, Y]=meshgrid(x,y);
G=sqrt(X-Y);
test2 = G;
test2(~(G<0)) = nan;
[C,h]=contourf(X,Y,abs(G),'ShowText','off');
set(gca,'FontSize',20)
Input for contour should be 2D array, but your arrays are 1D.
Here, G is complex number. When you plot G, you should plot absolute G.
The result will be like below.
Regarding your function,
H=((2*sqrt(X))./G).*acoth((sqrt(X) + Y/2 )./G );
Related
I have two grid coordinates matrices, X and Y, created by calling [X, Y] = meshgrid(x, y), so their elements represent coordinates. How can I plot a surface on the xy-plane, using heights from matrix V, only for coordinates that satisfy a specific equation? For example, my plot extends up to radius a, but I dont want to plot any data to the set of points that satisfy the equation sqrt(x^2 + (y-c)^2) < b, where b, c (a>b) are given constants and x=X(i,j), y=Y(i,j). Is there an easy way to do this, other than creating the two grid coordinates matrices (up to radius a) and then manually removing elements from X, Y, V, using nested for loops? I have not found any way to limit the plotting area I am interested in by changing x, y.
Using Logical Indexing
Just in case you're still looking for any implementation details. Referencing the comment by #Ander Biguri. I have to add that it might be easier to use mesh parameters X and Y directly in the logical indexing. Here is a little playground script that might help future readers. Below Region_Array is a logical array that specifies where the condition in this case sqrt(X.^2 + (Y-c).^2) < b is true. When true Region_Array is indexed with the value "1" and elsewhere with "0". I've split this into two steps just in case the complementary region is quickly wanted. The images/plots below show the resulting surf() and masks/regions. MATLAB has some thorough documentation and examples overviewing logical indexing: Find Array Elements That Meet a Condition
Trivial Surface Plot:
Masks/Regions Not to be Plotted:
Playground Script:
%Random test axes%
x = linspace(0,100,50);
y = linspace(0,100,50);
[X,Y] = meshgrid(x,y);
%Trivial plot of ones%
V = ones(length(x),length(y));
%Constant parameters%
b = 20;
c = 10;
%Eliminating within the curved region%
figure(1)
Region_Array = sqrt(X.^2 + (Y-c).^2) < b;
V(Region_Array) = NaN;
subplot(1,2,1); surf(X,Y,V);
axis([0 100 0 100]);
title("Eliminating Within the Curved Region");
%Eliminating outside the curved region%
V = ones(length(x),length(y));
V(~Region_Array) = NaN;
subplot(1,2,2); surf(X,Y,V);
axis([0 100 0 100]);
title("Eliminating Outside the Curved Region");
figure(2)
subplot(1,2,1); imshow(~Region_Array,'InitialMagnification',200);
title("Region Array Mask/Map (Inside)")
subplot(1,2,2); imshow(Region_Array,'InitialMagnification',200);
title("Region Array Mask/Map (Outside)")
Ran using MATLAB R2019b
I want to plot a two-dimensional function of the polar coordinates r and theta in three-dimensional cartesian coordinates. I have that (sorry about bad maths formatting, LaTeX not compatible, it seems)
f(r,theta) = r/2 * (cos(theta - pi/4) + sqrt(1 + 1/2 * cos(2*theta)))
Converting r and theta to cartesian coordinates
x = r * cos(theta), y = r * sin(theta)
Further, the domain is -1<r<1 and 0<theta<2 * pi, which I define by
r = -1:2/50:1;
and
theta = 0:2*pi/50:2*pi;
giving me two vectors of the same dimensions.
I can define the x and y values used for plotting as row vectors by
x = r. * cos(theta);
and
y = r. * sin(theta);
So now I need to define the z values, which will depend on the values of x and y. I thought I should make a 101x101 where each matrix element contains a data point of the final surface. But how should I do this? I thought about using a double for loop:
for i=1:numel(r)
for j=1:numel(theta)
z(i,j) = r(i)/2 .* cos(theta(j) - pi/4) + r(i).*sqrt(1 + 1/2 * cos(2.*theta(j)));
end
end
Then simply surf(z)
While this definitely gives me a surface, it gives me the incorrect surface! I don't know what is happening here. The incorrect surface is given in Figure 1, while the correct one is given in Figure 2. Can anyone help me out? For reference, the correct surface was plotted with GeoGebra, using
A = Function[<expression 1>, <Expresison 2>, <Expression 3>, <var 1>, <start>, <stop>, <var 2>, <start>, <stop>]
Figure 1. Incorrect surface.
Figure 2. Correct surface.
As others have said, you can use meshgrid to make this work.
Here's your example using gridded r and theta and an anonymous function to replace the double loop:
r = -1:2/50:1;
theta = 0:2*pi/50:2*pi;
% define anonymous function f(r,theta)
f = #(r,theta) r/2 .* (cos(theta - pi/4) + sqrt(1 + 1/2 .* cos(2.*theta)));
% generate grids for r and theta
[r, theta] = meshgrid(r,theta);
% calculate z from gridded r and theta
z = f(r,theta);
% convert r,theta to x,y and plot with surf
x = r.*cos(theta);
y = r.*sin(theta);
surf(x,y,z);
You need to use meshgrid to get matrix coordinates if you want to use surf. Taking your x and y (lower case), call
[X,Y] = meshgrid(x,y);
Then X and Y (upper case) will have the same values as you gave it, but laid out in the two-dimensional array as expected by surf. Loop over the indices here and compute your Z, which should have all(size(Z) == size(X)).
https://www.mathworks.com/help/matlab/ref/meshgrid.html
I need to plot level surfaces of a 3 variable function. The variables are in a column vector X = [x, y, z]^t. The function is f(X) = X^t * A * X. Where ^t means transpose and A is a 3x3 constant matrix. I know for a fact that A is symmetric and therefore diagonalizable, i.e. A = V * D * V^t. Just in case it turns out to be useful.
I intend to use isosurface to get the points of the function where it equals a certain level and then use patch to plot.
However I can't figure out how to compute the value of the function for every point in the grid. Ideally I'd like to do
x = linspace(-1, 1,10); y=x; z = x;
[XX,YY,ZZ]=meshgrid(x,y,z);
f = [XX YY ZZ]'*A*[XX YY ZZ];
level = 1;
s = isosurface(XX,YY,ZZ,f,level);
patch(s, 'EdgeColor','none','FaceColor','blue');
but this won't work obviously because of the sizes of XX and A. What I've done so far is do the math myself to obtain the function as a polynomial of XX, YY and ZZ but it's incredibly ugly and not practical.
Anybody knows how to do this? Thanks!
If I understand correctly, this does that you want. In the following explanation I will use 10x10x10 points as given in your example (although the code works for any number of points). Also, I define a random 3x3 matrix A.
Once XX, YY and ZZ have been generated as 10x10x10 arrays (step 1), the key is to build a 1000x3 matrix in which the first column is x coordinate, the second is y and the third is z. This is variable XYZ in the code below (step 2).
Since XYZ is a matrix, not a vector, the function f can't be computed using matrix multiplication. But it can be obtained efficiently with bsxfun. First compute an intermediate 1000x3x3 variable (XYZ2) with all 3x3 products of coordinates for each of the 1000 points (step 3). Then reshape it into a 1000x9 matrix and multiply by the 9x1 vector obtained from linearizing A (step 4).
The f thus obtained has size 1000x1. You need to reshape it into a 10x10x10 array to match XX, YY and ZZ (step 5). Then you can use isosurface as per your code (step 6).
A = rand(3);
x = linspace(-1, 1,10); y = x; z = x;
[XX,YY,ZZ] = meshgrid(x,y,z); %// step 1
XYZ = [XX(:) YY(:) ZZ(:)]; %// step 2
XYZ2 = bsxfun(#times, XYZ, permute(XYZ, [1 3 2])); %// step 3
f = reshape(XYZ2,[],numel(A))*A(:); %// step 4
f = reshape(f, size(XX)); %// step 5
level = 1;
s = isosurface(XX,YY,ZZ,f,level);
patch(s, 'EdgeColor','none','FaceColor','blue'); %// step 6
I suspect that you could explicitly define your function as
ffun = #(x,y,z) [x y z]*A*[x; y; z];
then use arrayfun to apply this function to each element of your coordinate vectors:
f = arrayfun(ffun,XX,YY,ZZ);
This will return f(i)=ffun(XX(i),YY(i),ZZ(i)) for each i in 1:numel(XX), which I think is what you are after. The output f will have the same shape as your input arrays, which seems perfectly fine to use with isosurface later.
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:
I am trying to plot the following equation in MATLAB:
ratio = sqrt(1+1/(kr)^2)
With k and r on the x and y axes, and ratio on the z axis. I used meshgrid to create a matrix with values for x and y varying from 1 to 10:
[x,y] = meshgrid([1:1:10],[1:1:10]);
The problem now is to create values for z. I've tried to just type the whole equation in, but that gives this result:
>> Z = sqrt(1+1/(x .* y)^2)???
Error using ==> mldivide
Matrix dimensions must agree.
So what I did is go to through the whole process manually, which produces the right graph in the end:
z = z^2;
z = 1 ./ z;
z = 1 + z;
z = sqrt(z);
mesh(x,y,z)
Is there a more elegant way to do this? Or a way to type in the equation and let MATLAB handle the rest?
Try this:
Z = sqrt(1+1./(x .* y).^2);
surf(Z);
The problem that you had is related to using / instead of ./ and ^2 instead of .^2