replicate matlab interp3 in python, interpolate to unevenly spaced matrix - matlab

I need to replicate a specific case of MATLAB's interp3 functioning that I cannot replicate using scipy.
I have the first 3D space defined as x, y, z (meshgrids or vectors), and values p. I need to interpolate those values in a new 3D space defined as x_new, y, z. For context x, x_new, y, and z are 4999x84x83 matrices.
The problem is that x_new changes in all its directions, so it cannot be considered a regular meshgrid or a vector.
The line I need to replicate is the following:
fn = interp3(y, x, z, p, y, x_new, z, 'linear');
In Python I tried to implement it using scipy as:
points = (x,y,z)
values = p
xi = (x_new,y,z)
fn = scipy.interpolate.interpn(points, values, xi, method='linear', bounds_error=True, fill_value=nan)
Or using griddata as:
fn = scipy.interpolate.griddata((x,y,z), p, (x_new,y,z), method='linear', fill_value=0, rescale=False)
But both methods give rise to errors due to the non-even spacing of the x_new matrix.
Is there a method to replicate the interp3 function in Python? I can give you access to data if you want to try this problem first-hand.

thanks to Ander comment now it works just like Matlab. Like this:
points = np.c_[(np.ravel(x_new), np.ravel(y), np.ravel(z))]
X, Y, Z = np.shape(p)
x_vect=x[:,0]
y_vect=y[:,0]
z_vect=z[:,0]
Vi = interpn((x_vect,y_vect,z_vect), p, points,bounds_error=False,fill_value=0, method='nearest')
Vi = np.reshape(Vi, (X, Y, Z))

Related

How to plot function of 3 variables with Octave?

I am new to Octave (and matlab for that matter). I have a function that looks like this
I would like to plot g(x,0.5,5) say.
Here it is what I tried in Octave
I defined an anonymous function
f=#(n,x,t) 1./n.*log(n.*pi.*t).*sin(n.*pi.*x);
then another anonymous function
g=#(m,x,t)x.^2+sum(f([1:m],x,t));
Finally defined
x=-1:0.1:1;
plot(x,g(5,x,0.5))
but I get an error. Is this the right way of plotting this function? I must be doing a simple beginner error?
When you call f(n,x,t), you are passing a 1-by-5 vector for n and a 1-by-21 vector for x. These have different numbers of elements, and therefore can't be multiplied element-by-element. However, you can rewrite f to accommodate vectors for each and perform the sum from g by using matrix multiplication:
f = #(n, x, t) (1./n.*log(n.*pi.*t))*sin(pi.*n(:)*x);
g = #(m, x, t) x.^2 + f(1:m, x, t);
And now your plot will work:
x = -1:0.1:1;
plot(x, g(5, x, 0.5));

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.

Why changes the orientation of the 3D image when using isosurface vs plot3 and ind2sub?

I have a indexed 3D image A, that I can visualize with isosurface.
If I create another version of the same image using ind2sub, when I plot it with plot3, one of the axes is flipped.
Here is an example:
isosurface(A)
[x, y, z] = ind2sub(size(A),find(A==1));
plot3(x, y, z,'b.');
And here and example image:
Is this a normal behavior or am I missing anything in the process?
If I go back in the process I reach the same point:
Y = zeros(size(A));
Y(sub2ind(size(A), x, y, z))=1;
Obviously, isequal(A,Y) gives 1.
Because ind2sub returns rows then columns as the first two outputs, not x,y.
[y, x, z] = ind2sub(size(A),find(A==1));

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

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!

Create 2D grid from vector data in Matlab

I am trying to create a 2-D grid from a vector.
So, for example I have:
x = 1:1:10;
z = 2:2:20;
Now, I want to create a grid which has x on both side of the grid cell and z as grid cell value.
I tried doing it as :
[X,Y] = meshgrid(x, x);
newZ = griddata(x, x ,z, X, Y);
But this gives me error:
The underlying triangulation is empty - the points may be
collinear.
Need help solving this.
In a high level, griddata() takes a 2d surface with variable z-value at each point as the first part of the input, and the query points as the second part of the input. To be more specific, when we look into the definition of the function:
vq = griddata(x,y,v,xq,yq)
x and y specifies the range of x and y values, v is like z-value in a plane, and xq and yq together are query points. Here, v (in your case, z) is expected to be a 2d matrix, to be more specific, the size of v is [length(x), length(y)], whereas in your case, you put z as a vector. Matlab generates the warning since the size doesn't match.
For your reference: http://www.mathworks.com/help/matlab/ref/griddata.html?refresh=true