Plotting the result of a 2 parameter function in matlab (3D Graph) - matlab

Basically, I have a function f(X,Y) that would return one value for each X,Y that I give. Is there any function in matlab where I can pass the function f, the ranges for X,Y so that it plots a 3d graph showing the magnitude of f (along the z axis) for all values within the given range.
ezplot3, does this kind of, but it takes only one parameter 't'. I am very new to matlab and am trying my best to learn it fast, but I couldnt find much regarding this. Any help would be appreciated

Keep in mind, that with matlab, you're never really plotting "functions"; You're plotting arrays/vectors. So instead of trying to plot g = f(X,Y), you'll actually by plotting the vectors X, Y, and g, where X and Y are your original inputs and g is a vector containing your outputs.
I'm having a hard time visualizing what exactly you're trying to plot but basically, you can follow any standard matlab plotting example such as: http://web.cecs.pdx.edu/~gerry/MATLAB/plotting/plotting.html

It does not produce a 3D plot, but I have found the 2D scatter plot useful for this kind of task before:
scatter(x, y, 5, z)
Where z is the value of the function at the point (x, y) will produce something similar to what you want. Its perhaps not quite as pretty as a full 3D plot but can be used to good effect.
See:
http://www.mathworks.com/matlabcentral/fileexchange/35287-matlab-plot-gallery-scatter-plot-2d/content/html/Scatter_Plot_2D.html
Here is some (very ugly) code I put together to demonstrate the difference:
j=1;
y = -100:1:100;
for i = -100:1:100
y = [y -100:1:100];
count = 0;
while count < 202;
x(j) = i;
j = j+1;
count = count + 1;
end
end
z = (abs(x) + abs(y));
figure(1)
scatter(x, y, 10, z)
h=colorbar;
figure(2)
ezsurf('(abs(x) + abs(y))')

Well, this is what I was going for : http://www.mathworks.com/help/matlab/ref/ezsurf.html
if i do this
ezsurf('f(x,y)');
I get the 3d graph I wanted.
Thanks anyways!

Related

How to plot a parametric surface in Matlab

I have a parametric B-Spline surface, S
S=[x(:);y(:);z(:)];
Right now, I am plotting the surface by just plotting each column of S as a single point:
plot3(S(1,:),S(2,:),S(3,:),'.')
The result is this:
Unfortunately, by plotting individual points, we lose the sense of depth and curvy-ness when we look at this picture.
Any ideas on how to implement SURF or MESH command for a parametric surface? These functions seem to require a matrix representing a meshgrid which I dont think I can use since the X x Y domain of S is not a quadrilateral. However, I like the lighting and color interpolation that can be conveniently included when using these functions, as this would fix the visualization problem shown in figure above.
I am open to any other suggestions as well.
Thanks.
Without seeing your equations it's hard to offer an exact solution, but you can accomplish this by using fsurf (ezsurf if you have an older version of MATLAB).
There are specific sections regarding plotting parametric surfaces using ezsurf and fsurf
syms s t
r = 2 + sin(7*s + 5*t);
x = r*cos(s)*sin(t);
y = r*sin(s)*sin(t);
z = r*cos(t);
fsurf(x, y, z, [0 2*pi 0 pi]) % or ezsurf(x, y, z, [0 2*pi 0 pi])
If you want to have a piece-wise function, you can either write a custom function
function result = xval(s)
if s < 0.5
result = 1 - 2*s;
else
result = 2 * x - 1;
end
end
And pass a function handle to fsurf
fsurf(#xval, ...)
Or you can define x to be piece-wise using a little bit of manipulation of the function
x = (-1)^(s > 0.5) * (1 - 2*s)

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

How do I plot relations in matlab?

I want to plot relations like y^2=x^2(x+3) in MATLAB without using ezplot or doing algebra to find each branch of the function.
Does anyone know how I can do this? I usually create a linspace and then create a function over the linspace. For example
x=linspace(-pi,pi,1001);
f=sin(x);
plot(x,f)
Can I do something similar for the relation I have provided?
What you could do is use solve and allow MATLAB's symbolic solver to symbolically solve for an expression of y in terms of x. Once you do this, you can use subs to substitute values of x into the expression found from solve and plot all of these together. Bear in mind that you will need to cast the result of subs with double because you want the numerical result of the substitution. Not doing this will still leave the answer in MATLAB's symbolic format, and it is incompatible for use when you want to plot the final points on your graph.
Also, what you'll need to do is that given equations like what you have posted above, you may have to loop over each solution, substitute your values of x into each, then add them to the plot.
Something like the following. Here, you also have control over the domain as you have desired:
syms x y;
eqn = solve('y^2 == x^2*(x+3)', 'y'); %// Solve for y, as an expression of x
xval = linspace(-1, 1, 1000);
%// Spawn a blank figure and remember stuff as we throw it in
figure;
hold on;
%// For as many solutions as we have...
for idx = 1 : numel(eqn)
%// Substitute our values of x into each solution
yval = double(subs(eqn(idx), xval));
%// Plot the points
plot(xval, yval);
end
%// Add a grid
grid;
Take special care of how I used solve. I specified y because I want to solve for y, which will give me an expression in terms of x. x is our independent variable, and so this is important. I then specify a grid of x points from -1 to 1 - exactly 1000 points actually. I spawn a blank figure, then for as many solutions to the equation that we have, we determine the output y values for each solution we have given the x values that I made earlier. I then plot these on a graph of these points. Note that I used hold on to add more points with each invocation to plot. If I didn't do this, the figure would refresh itself and only remember the most recent call to plot. You want to put all of the points on here generated from all of the solution. For some neatness, I threw a grid in.
This is what I get:
Ok I was about to write my answer and I just saw that #rayryeng proposed a similar idea (Good job Ray!) but here it goes. The idea is also to use solve to get an expression for y, then convert the symbolic function to an anonymous function and then plot it. The code is general for any number of solutions you get from solve:
clear
clc
close all
syms x y
FunXY = y^2 == x^2*(x+3);
%//Use solve to solve for y.
Y = solve(FunXY,y);
%// Create anonymous functions, stored in a cell array.
NumSol = numel(Y); %// Number of solutions.
G = cell(1,NumSol);
for k = 1:NumSol
G{k} = matlabFunction(Y(k))
end
%// Plot the functions...
figure
hold on
for PlotCounter = 1:NumSol
fplot(G{PlotCounter},[-pi,pi])
end
hold off
The result is the following:
n = 1000;
[x y] = meshgrid(linspace(-3,3,n),linspace(-3,3,n));
z = nan(n,n);
z = (y .^ 2 <= x .^2 .* (x + 3) + .1);
z = z & (y .^ 2 >= x .^2 .* (x + 3) - .1);
contour(x,y,z)
It's probably not what you want, but I it's pretty cool!

Extract cross sections from a plot of multiple spheres in Matlab

I know the locations of spheres (center and radius) in a box. I want to extract cross sections. I am able to plot the spheres placed in a cube using the following Matlab code:
[X,Y,Z] = sphere;
for SpNum = 1:NumSpheres
surf( X*Radius(SpNum)+Center(SpNum,1), Y*Radius(SpNum)+Center(SpNum,2), Z*Radius(SpNum)+Center(SpNum,3), ...
'FaceColor','r' );
%shading interp;
hold on;
end
axis tight; daspect([1 1 1]);
In the above code, each sphere could have different radius and they do not overlap (so the centers are also different).
The above code does not however generate cross sections. I want to extract cross sections similar to what we get from say X-ray CT data: a series of images in the Z-direction. I think 'interp2/interp3' and 'slice' functions are the relevant functions, but I am not sure how to use them to generate the cross sections. I would appreciate if anyone could give pointers or provide some sample code for my problem?
-- Thanks in advance.
Update:
I tried using meshgrid to generate the grid points followed by the function F(X,Y,Z) as follows:
[X,Y,Z] = meshgrid(1:100,1:100,1:100);
F = zeros(size(X),'uint8');
for SpNum = 1:NumSpheres
F( sqrt((X - Center(SpNum,1)).^2 + (Y - Center(SpNum,2)).^2 + (Z - Center(SpNum,3)).^2) <= Radius(SpNum) ) = 1;
end
surf(F);
followed by:
z = 1;
I = interp3(X, Y, Z, X*Radius(SpNum)+Center(SpNum,1), Y*Radius(SpNum)+Center(SpNum,2), Z*Radius(SpNum)+Center(SpNum,3), z, 'spline');
figure, imshow(I);
I know that interp3 is the function to use since it interpolates the values of the function F(X,Y,Z) which represent the spheres at different location within a bounded box (say 1:100, 1:100, 1:100). The interpolated values at particular 'z' (= 1, 2, 3... 100) should give me 100 cross sections (in the form of 2-D images).
The flaw is in the function F itself, since 'surf' throws an error saying that F should be an array - "CData must be an M-by-N matrix or M-by-N-by-3 array".
Can anyone please help.
I finally figured it. For the benefit of others, here is the code.
% A 3-D matrix 'F' which has its value at particular coordinate set to 255 if it belongs to any one of the spheres and 0 otherwise.
[X,Y,Z] = meshgrid(1:100,1:100,1:100);
F = zeros(size(X));
for SpNum = 1:NumSpheres
F( sqrt((X - Center(SpNum,1)).^2 + (Y - Center(SpNum,2)).^2 + (Z - Center(SpNum,3)).^2) <= Radius(SpNum) ) = 255;
end
% Extract cross sections from F using interp3 function along the z-axis.
I = zeros(size(X));
for z = 1:100
I(:,:,z) = interp3(X, Y, Z, F, 1:100, (1:100)', z, 'spline');
end
implay(I,4);
You could test and visualize the output by setting Center (a 3-D vector) and Radius of each sphere (some arbitrary NumSpheres) to some random values. The above code will display a window with cross-sections.
Previously, I was trying to use 'surf' to render the spheres which is not right. To render, you have to use the first code snippet. Another mistake I made was using a row vector for the 6th argument instead of column vector.
Hope this helps.
--
Cheers,
Ram.

How to integrate over a discrete 2D surface in MATLAB?

I have a function z = f(x, y), where z is the value at point (x, y). How may I integrate z over the x-y plane in MATLAB?
By function above, I actually mean I have something similar to a hash table. That is, given a (x, y) pair, I can look up the table to find the corresponding z value.
The problem would be rather simple, if the points were uniformly distributed over x-y plane, in which case I can simply sum up all the z values, multiply it with the bottom area, and finally divide it by the number of points I have. However, the distribution is not uniform as shown below. So I am actually asking for the computation method that minimises the error.
The currently accepted answer will only work for gridded data. If your data is scattered you can use the following approach instead:
scatteredInterpolant + integral2:
f = scatteredInterpolant(x(:), y(:), z(:), 'linear');
int = integral2(#(x,y) f(x,y), xmin, xmax, ymin, ymax);
This defines the linear interpolant f of the data z(i) = f(x(i),y(i)) and uses it as an argument to integral2. Note that ymin and ymax, instead of doubles, can be function handles depending on x. So usually you will be integrating rectangles, but this could be used for integration regions a bit more complicated.
If your integration area is rather complicated or has holes, you should consider triangulating your data.
DIY using triangulation:
Let's say your integration area is given by the triangulation trep, which for example could be obtained by trep = delaunayTriangulation(x(:), y(:)). If you have your values z corresponding to z(i) = f(trep.Points(i,1), trep.Points(i,2)), you can use the following integration routine. It computes the exact integral of the linear interpolant. This is done by evaluating the areas of all the triangles and then using these areas as weights for the midpoint(mean)-value on each triangle.
function int = integrateTriangulation(trep, z)
P = trep.Points; T = trep.ConnectivityList;
d21 = P(T(:,2),:)-P(T(:,1),:);
d31 = P(T(:,3),:)-P(T(:,1),:);
areas = abs(1/2*(d21(:,1).*d31(:,2)-d21(:,2).*d31(:,1)));
int = areas'*mean(z(T),2);
If you have a discrete dataset for which you have all the x and y values over which z is defined, then just obtain the Zdata matrix corresponding to those (x,y) pairs. Save this matrix, and then you can make it a continuous function using interp2:
function z_interp = fun(x,y)
z_interp = interp2(Xdata,Ydata,Zdata,x,y);
end
Then you can use integral2 to find the integral:
q = integral2(#fun,xmin,xmax,ymin,ymax)
where #fun is your function handle that takes in two inputs.
I had to integrate a biavariate normal distribution recently in MatLab. The idea is very simple. Matlab defines a surface through a meshgrid, so from x, y you need to do this:
x = -10:0.05:10;
y = x;
[X,Y] = meshgrid(x',y');
...for example. Then, let's call FX the function that defines the value at each point of the surface. To calculate the integral you just need to do this:
surfint = zeros(length(X),1);
for a = 1:length(X)
surfint(a,1) = trapz(x,FX(:,a));
end
trapz(x, surfint)
For me, this is the simplest way.