Retrieving data on coordinates which or not on the data grid through interpolation - matlab

I'm using Matlab to read a large (NetCDF) data set with information about a magnetic field. The data set is a three-dimensional array of 318x562x554 and I can retrieve have three one-dimensional array (318x1, 562x1 and 554x1) with each axis values of the coordinates. I would like to know the magnetic field values on points that do not fit on the data set grid. These points are in this case trajectory coordinates of a spacecraft placed in a two-dimensional array (3xn,n depends on how many coordinates you have).
x = ncread(file,'X_axis');
y = ncread(file,'Y_axis');
z = ncread(file,'Z_axis');
Bx = ncread(file,'Bx');
[x2,y2,z2] = meshgrid(y,x,z);
length = numel(interval_ET_5000);
Bx_intp = zeros(1,length);
for i = 1:length
[xi,yi,zi] = meshgrid(position_MEX_Mars_5000(1,i),...
position_MEX_Mars_5000(2,i),...
position_MEX_Mars_5000(3,i));
F = interp3(x2,y2,z2,Bx,xi,yi,zi);
Bx_intp(i) = F;
end
I have tried many things that didn't even work. This 'works' but not correct because the values in Bx_intp are way to high. Also because of the doing coordinates one at the time in a for loop makes it very slow, a normal run is about 3500 coordinates.
So basicly what I am looking for is a reverse scatteredInterpolant. This function accepts random data points and you interpolate the values on a meshgrid. But now I have a regular grid and I want interpolation on random points.

Thanks for the tip Ashish Uthama! I got it working with the code below. For other people with the same problem. You need ndgrid instead of meshgrid for griddedInterpolant and the coordinates need to be monotonic increasing.
x = ncread(file,'X_axis');
y = ncread(file,'Y_axis');
z = ncread(file,'Z_axis');
Bx = ncread(file,'Bx');
[x2,y2,z2] = ndgrid(x,y,z);
F = griddedInterpolant(x2,y2,z2,Bx,'linear','none');
Bx_intp = F(position_MEX_Mars_5000(1,i),...
position_MEX_Mars_5000(2,i),...
position_MEX_Mars_5000(3,i));

Related

In Matlab, how to programmatically add datatip to trisurf objects with known vertices index?

Trisurf(f,x,y,z) function can draw a patch object. How can I add datatip to this object at the known vertices index with code?
I tried to use the following codes in 2017b
cursorMode = datacursormode(gcf);
hdtip = cursorMode.createDatatip(h_surf); %h_surf is the handle of trisurf
hdtip.Cursor.Position=pos; %this commond seems cannot find the exact vertex and depends on the view angle, where pos is the vertex coordinates.
hdtip.Cursor.DataIndex=idx; %try to use this command to assign the vertex index, but not successful.DataIndex seems not the vertex index.
Accordint to #Woffie's suggestions, I tuned a little bit to reproduce the error with different view angle in 2017b and 2019b.
First to enable view([180,0]); line. Run the code to get the correct result. And then without closing the figure,comment this line, only remain view([0,0]); to get the wrong result. But if add Close all to the front of the script, should get the correct result each time. (But still don't know the reason, whether it's a bug or not and how to avoid it smartly.)
It might be good to note, in 2D plots, this usually is not a problem since one doesn't usually change the view.
ngrid=1000;%actualy doesnot matter.
x=linspace(-3,3,ngrid+1);
y=linspace(-3,3,ngrid+1);
[x,y] = meshgrid(x,y);
tri = delaunay(x,y);
z = peaks(x,y);
x=(x+3)/6;y=(y+3)/6;
h_surf = trisurf(tri,x,y,z,'EdgeAlpha',0.1);
x0=0.25;y0=0.44;%the above normlization are not necessary but easier to setup the query node.
z0=z(round(y0*ngrid)+1,round(x0*ngrid)+1);
pos=[x0,y0,z0];
view([0,0]);
view([180,0]); %toggle between these two view angles to see the difference.
cursorMode = datacursormode(gcf);
hdtip = cursorMode.createDatatip(h_surf);
hdtip.Cursor.Position = pos;
hdtip.Cursor.Position
BTW, I also figured out how to use hdtip.Cursor.DataIndex=idx. Basically, DataIndex here is the linear index for h_surf.XData(or YData or ZData), while the XData, YData, ZData are mxn matrice as the node/vertex coordinates of all faces in h_surf, where m is the number of nodes in each face and n is the number of the faces. So it will be straightforward to convert to node index into DataIndex.
I'll use the trisurf example from the docs to create a mesh:
[x,y] = meshgrid(1:15,1:15);
tri = delaunay(x,y);
z = peaks(15);
h_surf = trisurf(tri,x,y,z);
Now the tri matrix contains the indices within x, y, and z for each vertex in the mesh. We can choose a vertex index idx, and the corresponding value from each of the x/y/z arrays to use as the .Position property of your data cursor. Contrary to your comment, the Position property does not depend on the view angle, it is the position relative to the axes (and therefore your data).
So
idx = 123; % intex within triangulation "tri"
xcurs = x(tri(idx)); % = 5 in this example
ycurs = y(tri(idx)); % = 6 in this example
zcurs = z(tri(idx)); % = 0.65233 in this example
cursorMode = datacursormode(gcf);
hdtip = cursorMode.createDatatip(h_surf);
hdtip.Cursor.Position = [xcurs,ycurs,zcurs];
You could determine idx however you want, then use a common idx to extract the aligned x, y, and z coordinates.
Two different views to show the data tip stays in place:
This example was run using MATLAB R2017b.

3D Oceanic Temperature Interpolations in MATLAB

I am running autonomous underwater vehicle missions which give me lat, long, depth, and temperature data that I am trying to create 3D interpolations with. I am able to create the 3D model of the environment but I am trying to have the color fill be the interpolated temperature at each associated position.
The image below is the 3d depth chart I get that I want to have the fill color be the temperatures at those locations:
I have tried using colormap where surf(X, Y, Z, C) and C is the temperature data but that does not work.
This is what I have for code where VPSA is my data set and X = longitude, y = latitude, Z = depth, and C = temperature
%Making Variables:
X = VPSA {:,1};
Y = VPSA {:,2};
Z = VPSA {:,3};
C = VPSA {:,4};
%Three axis plot
%Plotting Variable with coordinates
xi = linspace(min(X),max(X),1000);
yi = linspace(min(Y),max(Y),1000);
[Xi,Yi] = meshgrid(xi,yi);
Zi = griddata(X,Y,Z, Xi,Yi);
mesh (Xi,Yi,-Zi)
xlabel('Latitude')
ylabel('Longitude')
zlabel('Depth')
UPDATE: I added the following lines of code
Ci = griddata(X,Y,C,Xi,Yi);
mesh(Xi,Yi,-Zi,Ci)
to get the following figure, but it is so hard to tell what is going on, I wonder if there is a way to smooth the interpolation out into a box so it isn't as jagged.
Thank you!!
I am assuming that the original X,Y,Z,C data points are matched, and you can use the command mesh(X,Y,Z,C) to get a usable plot. Now you are looking to do the same, but with an interpolated dataset.
In this case, you only need to give the mesh command a the color data C.
C also needs to be interpolated, so maybe something like:
Ci = griddata(X,Y,C,Xi,Yi); % Interpolate C the same way you did for Z
mesh(Xi,Yi,-Zi,Ci)
Edit: Apologies for the previous incorrect answer.
It's hard to know exactly what you mean by "does not work" or what the nature of your temperature matrix C is, but the specification for C is as follows:
same size as Z (more specifically, each element in Z corresponds to each element of C in the same position)
each element in C is an integer, corresponding to a position in the current colormap. (which means if you update your colormap, your surface plot will update accordingly)
The integers can be inspected / changed after plotting, via the cdata property of your surface plot.
You may have to change whether your plot treats your colormap as scaled or direct (i.e. the cdatamapping). Have a look at your object's properties to find out.

Derivative on scatter data in Matlab

I have some data collected from a GPS network. My data consist of two arrays of the station coords (lat, long) and another two arrays populated with the vertical and the horizontal velocity of each station.
My script for interpolating is:
clear all; clc; format compact
load('lat_long_Ve_Vn.mat');
x = 34.5:0.1:42;
y = 19:0.1:28.5;
[Xq,Yq] = meshgrid(x,y);
Ve_i = griddata(lat,long,Ve,Xq,Yq);
Vn_i = griddata(lat,long,Vn,Xq,Yq);
I get the interpolated data for each node on my grid with two vectors, Ve_i and Ve_n
I want to calculate the following derivatives but I have no idea on how to do it.
I should mention that Vx is my Ve_i and Vy is my Vn_i, and I don't have a mathematical formula so I can calculate the derivatives with MuPAD. Any idea on how to do it?
If you use Gradient:
[Vxx Vxy] = gradient(Vx);
[Vyx Vyy] = gradient(Vy);

Finding the belonging value of given point on a grid of 3D histogram?

I use 2D dataset like below,
37.0235000000000 18.4548000000000
28.4454000000000 15.7814000000000
34.6958000000000 20.9239000000000
26.0374000000000 17.1070000000000
27.1619000000000 17.6757000000000
28.4101000000000 15.9183000000000
33.7340000000000 17.1615000000000
34.7948000000000 18.2695000000000
34.5622000000000 19.3793000000000
36.2884000000000 18.4551000000000
26.1695000000000 16.8195000000000
26.2090000000000 14.2081000000000
26.0264000000000 21.8923000000000
35.8194000000000 18.4811000000000
to create a 3D histogram.
How can I find the histogram value of a point on a grid? For example, if [34.7948000000000 18.2695000000000] point is given, I would like to find the corresponding value of a histogram for a given point on the grid.
I used this code
point = feat_vec(i,:); // take the point given by the data set
X = centers{1}(1,:); // take center of the bins at one dimension
Y = centers{2}(1,:); // take center of the bins at other dim.
distanceX = abs(X-point(1)); // find distance to all bin centers at one dimension
distanceY = abs(Y-point(2)); // find distance to center points of other dimension
[~,indexX] = min(distanceX); // find the index of minimum distant center point
[~,indexY] = min(distanceY); // find the index of minimum distant center point for other dimension
You could use interp2 to accomplish that!
If X (1-D Vector, length N) and Y (1-D vector, length M) determine discrete coordinate on the axes where your histogram has defined values Z (matrix, size M x N). Getting value for one particular point with coordinates (XI, YI) could be done with:
% generate grid
[XM, YM] = meshgrid(X, Y);
% interpolate desired value
ZI = interp2(XM, YM, Z, XI, YI, 'spline')
In general, this kind of problem is interpolation problem. If you would want to get values for multiple points, you would have to generate grid for them in similar fashion done in code above. You could also use another interpolating method, for example linear (refer to linked documentation!)
I think you mean this:
[N,C] = hist3(X,...) returns the positions of the bin centers in a
1-by-2 cell array of numeric vectors, and does not plot the histogram.
That being said, if you have a 2D point x=[x1, x2], you are only to look up the closest points in C, and take the corresponding value in N.
In Matlab code:
[N, C] = hist3(data); % with your data format...
[~,indX] = min(abs(C{1}-x(1)));
[~,indY] = min(abs(C{2}-x(2)));
result = N(indX,indY);
done. (You can make it into your own function say result = hist_val(data, x).)
EDIT:
I just saw, that my answer in essence is just a more detailed version of #Erogol's answer.

How to use TriScatteredInterp in MatLab?

I am having a problem with TriScatteredInterp in MatLab.
I am using a set of coordinate points with the corresponding temperature at that location. They are all in degrees in the form (long, lat, temp). I want to make an interpolant on these points so I can find out the values at other points and build a grid.
This is what I have done so far:
long = data(:,1)
lat = data(:,2)
values = data(:,3)
lat = lat.*(pi/180)
long = long.*(pi/180)
X = cos(lat).*cos(long)
Y = cos(lat).*sin(long)
Z = sin(lat)
F = TriScatteredInterp(X,Y,Z,values)
[long1 lat1] = meshgrid(-pi:pi/360:pi, -pi/2:pi/360:pi/2);
X1 = cos(lat1).*cos(long1)
Y1 = cos(lat1).*sin(long1)
Z1 = sin(lat1);
F.Method = 'natural'
InterpVals = F(X1,Y1,Z1);
mesh(long1, lat1, InterpVals)
As you can see for every (long, lat) point, I have computed the corresponding point on the sphere and have used the 3d version of TriScatteredInterp.
The problem is that the interpolation only works for the 'nearest' method, as for the linear or natural is producing just NaN's. As I have read this happens when the points that I want to interpolate are outside of the convex hull of the triangulation, but as the points needed are exactly on the sphere, and the input points are covering the entire range (Long : -180 to 180, Lat : -90 to 90), I just don't see how all the points could be outside the convex hull. Any help will be appreciated , ty.
You should interpolate values on the bi-dimensional original data (long, lat), not on the tri-dimensional one (X, Y, Z).
Note that I included some dummy data generator, for the readers that do not have access to your data()!
n = 100;
long = rand(n,1)*720-360;
lat = rand(n,1)*180-90;
values = rand(n,1)*30-5;
lat = lat.*(pi/180);
long = long.*(pi/180);
F = TriScatteredInterp(long,lat,values);
[long1 lat1] = meshgrid(-pi:pi/36:pi, -pi/2:pi/24:pi/2);
InterpVals = F(long1,lat1);
X1 = cos(lat1).*cos(long1);
Y1 = cos(lat1).*sin(long1);
Z1 = sin(lat1);
mesh(X1,Y1,Z1,InterpVals); %note here the meshing on the regular grid (X1,Y1,Z1)
There is still an issue on the edges of the map, as the interpolator doesn't know that the data "wraps" around. The content of InterpVals on those edges will be.. NaN!
Edit: suggestions for the wrapping:
1) rewrite TriScatteredInterp so that it uses modulos;
2) mirror the data around the "edges" of the map, interpolate, then crop it back to original size;
3) check out the Matlab Mapping Toolbox, which analyze and visualize geographic information.