Plotting two dependent function with respect to each other - matlab

I am writing a small code in Matlab to achieve following:
X, Y, and Z are all vectors and correspond to different physical quantities.
x1 and x2 are two different vectors made from allowed values which X can have.
Now I have Y as function of x1
Y=f(x1)
and Z as function of x2
Z=g(x2)
I do not know the functions 'f' and 'g' explicitly but I have a table which gives me Y and Z corresponding to x1 and x2 respectively.
So I can plot Y=f(x1) and Z = g(x2) in MATLAB using plotyy function using a common x-scale but 2 different y axis.
I want to plot Y as function of Z. What will be the most efficient way to do this? I guess I might need to use interpolation somewhere in this.
Thanks in advance !

As mentioned by #mikkola, interpolation would be the way to go. You could interpolate Y onto the domain of Z, Z onto the domain of Y, or Y and Z onto a completely different domain. Do be careful though, as you want to make sure you interpolate, not extrapolate. The default for interp1 is linear interpolation, but you can get it to implement other types of interpolation by passing in an optional parameter.
The following is an example with two different domains x1 and x2, corresponding to functions Y=sin(x) and Z=cos(x). These are interpolated onto a different domain x3 so that Y and Z can be plotted against each other, yielding a circle as we would expect.
% Two different domains
x1 = 0:0.02:2*pi;
x2 = 0:0.03:2*pi;
% Yielding two different functions
Y = sin(x1);
Z = cos(x2);
% Interpolate them both onto a common domain (x3)
x3 = 0:0.01:2*pi;
Yi = interp1(x1,Y,x3);
Zi = interp1(x2,Z,x3);
% Plot - circle, as expected
figure;
plot(Yi,Zi)

Related

How can i plot an ellipse and parabola together in Matlab?

I need to plot a parabola and ellipse. However the ellipse is giving me trouble. Can anyone help? The equations are: y = -5*x^2 + 2 and (x^2/16) + (y^2/2) = 4
I've tried this code but obviously I feel like like it isn't right.
x = linspace(-5, 5);
y1 = (x.^2/16) + (y.^2/2) - 1;
y2 = -5*x.^2 +2;
figure(1)
plot(x, y1)
hold on
plot(x, y2)
hold off
Firstly, you did not define a range variable x. Secondly, the ellipse won't pass the vertical line test and can't be plotted like a regular function f(x). Thirdly, your equation y1 = (x.^2/16) + (y.^2/2) - 1; is non-sensical because you have y on each side.
You could correct your method by defining a range variable x1 and x2 that each have appropriate ranges for the functions your plotting. What I mean by this is that you probably don't want the same range for each function, because the ellipse is undefined over most of the range that the parabola is defined. To plot the ellipse using f(x) you could observe that there are + and - values that are identical, using this fact you could plot your ellipse by two functions one to represent the top half and one to represent the bottom half, each of these would pass the vertical line test.
OR
You could utilize ezplot and have a nice time with it because it makes your life easier. Here is a solution.
ezplot('x^2/16+y^2/2-4'); axis equal; hold on
ezplot('-5*x^2+2-y')
There are multiple ways to plot an ellipse, e.g. you could also use a parametric representation of the equation.
In your approach though, when plotting functions using plot(x,y) command, you need to express your dependent variable (y) through independent variable (x). You defined the range for x, which is what you substitute into your equations in order to find y's. While for the parabola, the dependency of y from x is obvious, you forgot to derive such a relationship for the ellipse. In this case it will be +-sqrt((1 - x^2/16)*2). So in your approach, you'll have to take into account both negative and positive y's for the same value of x. Also there's discrepancy in your written equation for the ellipse (=4) and the one in Matlab code (=1).
x = linspace(-5, 5);
y1 = sqrt((1 - x.^2/16)*2);
y2 = -5*x.^2 +2;
figure(1)
plot(x, real(y1), 'r', x, -real(y1), 'r')
hold on
plot(x, y2)
hold off
Since the ellipse has real y's not on the whole x domain, if you want to plot only real parts, specify real(y1) or abs(y1) (even though Matlab does it for you, too). You can also dismiss complex numbers for certain x when computing y1, but you'll need a for-loop for that.
In order to make things simpler, you can check the function fimplicit, ezplot is not recommended according to Matlab's documentation. Or if you want to plot the ellipse in a parametric way, fplot will work, too.
Another (more classic) approach for parametric plotting is given here already, then you don't need any other functions than what you already use. I think it is the simplest and most elegant way to plot an ellipse.
You will not be able to generate points for the ellipse using a function f(x) from a Cartesian linspace range. Instead, you can still use linspace but for the angle in a polar notation, from 0 to 2*pi. You should also be able to easily adjust radius and offset on both axis on the cos and sin expressions.
x = linspace(-5, 5);
y2 = -5*x.^2 +2;
figure(1)
clf;
plot(x, y2)
hold on
a = linspace(0,2*pi);
x2 = 4*cos(a);
y2 = sqrt(2)*sin(a);
plot(x2, y2)
xlim([-5,5]);
ylim([-5,5]);
hold off

Defining surfaces not just in terms of z

I have three different surfaces and I want to display all of them in one figure.
The problem is, that I have one surface defined in terms of z (means that I got x and y values and a grid which specifies the z-values for each combination) and two other ones which are defined in terms of x. This means that there exist various z-values for one x,y-pair.
My idea was:
figure
surf(x,y,zgrid)
hold on
surf(x,ygrid,z)
surf(x,ygrid2,z)
hold off
I hoped MATLAB would manage it by itself but it doesn't.
Do you have any ideas how to get the wanted results? I want to display all of them in one plot to show the cross-sections.
Here is an image of how it should more or less look like:
If there is a more beautiful method to display this, please let me know.
You didn't specify what exactly was going wrong, but I'll hazard an educated guess that you got an error like the following when you tried to plot your second surface:
Error using surf (line 82)
Z must be a matrix, not a scalar or vector.
I'm guessing your x, y, and z variables are vectors, instead of matrices. The surf function allows for the X and Y inputs to be vectors, which it then expands into matrices using meshgrid. It doesn't do this for the Z input, though.
It's best practice, in my opinion, to just use matrices for all your inputs anyway. Here's an example where I do this (using meshgrid) to plot three surfaces of a cube:
% Top surface (in z plane):
[x, y] = meshgrid(1:10, 1:10);
surf(x, y, 10.*ones(10), 'FaceColor', 'r');
hold on;
% Front surface (in y plane):
[x, z] = meshgrid(1:10, 1:10);
surf(x, ones(10), z, 'FaceColor', 'b');
% Side surface (in x plane):
[y, z] = meshgrid(1:10, 1:10);
surf(ones(10), y, z, 'FaceColor', 'g');
axis equal
And here's the plot:

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 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.

How to plot a specific function in matlab

I have this function:
and I want plot it, I think the result is a periodic function...
I tried this but got only one point :(
x1=-50:0.1:50;
x2=-50:0.1:50;
plot(cos(sqrt(power(x1,2)+power(x2,2)))/(power(x1,2)+power(x2,2)));
where is my problem and what is the correct way?
appreciate any help.
You need to plot it as a 3-D surface. For example, use surf:
[X1, X2] = meshgrid(-5:0.25:5, -5:0.25:5);
F = cos(sqrt(X1 .^ 2 + X2 .^ 2)) ./ (X1 .^ 2 + X2 .^ 2 + 1);
surf(X1, X2, F)
Note two things:
You forgot the "+1" in the denominator.
I've reduced the range of x1 and x2 coordinates, for better visualization.
If the black edges look annoying and seem to clutter the plot, you can remove the edge lines by disabling the EdgeColor property (as user Shai pointed out):
surf(X1, X2, F, 'EdgeColor', 'None')
The final result should look something like this:
That's a 3d plot, since there are two inputs x1 and x2. So you've got to use plot3 (or surf as #EitanT points out, or any 3d plotting function).
You're now only plotting the pairs (-50;-50), (-49.9;-49.9),...,(50;50), because you start from two vectors, you probably want to cover all the combinations. Therefore, use meshgrid (for higher dimensions, there is also ndgrid):
x1=-50:0.1:50;
x2=-50:0.1:50;
[X1, X2] = meshgrid(x1,x2);
You now use matrix operations, read through this link and you'll see that you need elementwise operations: a.*b instead of a*b, etc. power(a,b) is already the element-wise operation (the same as a.^b), matrix equivalent is mpower(a,b) or a^b.
f = cos(sqrt(power(X1,2)+power(X2,2)))./(power(X1,2)+power(X2,2)+1);
plot3(X1,X2,f);