I have scattered data [x(:),y(:),z(:)] and I want, given a new point (x1,y1), to interpolate the surface normal at this point.
Currently I'm using "scatteredInterpolant" in matlab, and then interpolate the derivatives of the surface at the wanted point.
I would like to find a more efficient option that I can convert to mex using matlab's coder.
my current code:
F = scatteredInterpolant(X(:), Y(:), Z(:));
[Xq,Yq] = meshgrid(X(1,:),linspace(Y(1,1),Y(end,1),size(Y,1)));
Zq = F(Xq,Yq);
[ZX,ZY] = gradient(Zq);
gradX=interp2(Xq, Yq, ZX,X1, Y1);
gradY=interp2(Xq, Yq, ZY,X1, Y1);
Thanks in advance
Related
I want to plot smooth contour plot from X Y Z matrix.
sf = fit([X Y] Z, 'poly23');
plot(sf);
I have not enought smooth curve..
What I need?
You can use the functions such as griddata and csaps. Together they will lead you to the result as smooth as you wish. The first function adds additional points to your data matrix set. The second one makes the result smoother. The example of the code is below. In the example smoothing is done first in X direction and then in Y direction. Try to play around with the resolution and smoothing_parameter (the current set of these parameters should be OK though).
x = min_x:step_x:max_x;
y = min_y:step_y:max_y;
resolution = 10;
xg = min_x:(step_x/resolution):max_x;
yg = min_y:(step_y/resolution):max_y;
[X,Y] = meshgrid(x,y);
[XG,YG] = meshgrid(xg,yg);
smoothing_parameter = 0.02;
fitted = griddata(X,Y,Z,XG,YG,'cubic');
fitted_smoothed_x = csaps(xg,fitted,smoothing_parameter,xg);
fitted_smoothed_xy = csaps(yg,fitted_smoothed_x',smoothing_parameter,yg);
surf(XG,YG,fitted_smoothed_xy');
EDIT: If you want to get just a contour plot, you can do, for example, as presented below. As I don't have the real data, I will use build-in function peaks to generate some.
[X,Y,Z] = peaks(30);
figure
surfc(X,Y,Z)
view([0 90])
zlim([-10 -8])
Here you just look at your contour plot from above being below the surface.
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
In the theory of tomography imaging a sinogram is recorderded, which is series of projections at different angles of the sample. Taking FFT of this projections gives a slice in polar coordinates of the sample in the frequency space.
The command [X,Y] = pol2cart(THETA,RHO) will not do it automatically. So, how is the polar to cartesian grid interpolation implemented numerically in 2D in Matlab?
You need to do a phase transformation:
theta = 0:0.1:2*pi;
rho = linspace(0,1,numel(theta));
[x,y] = pol2cart(-theta+pi/2,rho);
figure;
subplot(1,2,1);
polar(theta,rho);
subplot(1,2,2);
plot(y,x);
axis([-1 1 -1 1]);
grid on;
The function [X,Y] = pol2cart(THETA,RHO) only performs the coordinate value conversion, i.e., X = RHO * cos(THETA) and Y = RHO * sin(THETA). However, what you need is the conversion of the data array, thus pol2cart() can do nothing to your problem.
You can refer to the function interp2(). On the other hand, since this problem is the interpolation with COMPLEX data, I am NOT sure whether interp2() could do the job directly. I also need the theory for complex interpolation.
I'm trying to create a surface plot from (x,y,z) data on an irregular grid. The datasets are located along diagonal lines of positive gradient in the (x,y) plane. The method is illustrated below
xi = linspace (min(x), max(x), 1000);
yi = linspace (min(y), max(y), 1000);
zi = linspace (min(z), max(z), 400);
[XI YI]=meshgrid(xi,yi);
F = TriScatteredInterp (x,y,z);
Vi = F(XI,YI);
surf(Xi,Yi,Vi);
shading interp;
view(2)
An example result is shown below:
The data should be smooth in the x direction (so at y=860 there should be a single, continuous blue dip). I think the problem is that the interpolation is being carried out well along each dataset but poorly between them as the spacing between the datasets is far larger than between points within a dataset.
What would be the best way to deal with this?
I am wondering if anyone knows (or is it possible?) how to generate a trend equation from a 3D surf plot from Matlab? I understand that we can create trendline for 2D plots (linear and nonlinear) and show its equation, but how about 3D plot? Can we create something like:
z = ax + by?
Regards
Kit
If you have the curve fitting toolbox you can fit 3D surfaces using cftool as described here.
Here's an example:
[X,Y] = meshgrid(1:100,1:100);
X = reshape(X,numel(X),1);
Y = reshape(Y,numel(Y),1);
Z = 3*X+4*Y;
plot3(X,Y,Z)
f = fit([X, Y], Z, 'poly11');
coeffvalues(f)