Contour plot ignores a set of data points
Afficher commentaires plus anciens
Hello,
I'm constructing a contour plot using location (longitude and latitude) and respective depth data. However, the output contour plot seems to ignore (or interpolate in a way that is not intended) a set of data points. This makes the result undesirable. Is there any thing that I can do to fix this?
Following is the piece of code that I use to plot the contour plot.
% reading the bathy data
data = xlsread('datafile.xlsx');
lon = data(:,1); % Longitude
lat = data(:,2); % Latitude
alt = data(:,3); % Altitude
[xq,yq] = meshgrid(min(lon):.001:max(lon), min(lat):.001:max(lat));
[x,y,z] = griddata(lon,lat,alt,xq,yq, 'cubic');
contourf(x,y,z);
I have attached the figues for reference.
- Data_Points.png (Locations of the data points)
- Overlay.png (Result contour plot is overlaid on Google Earth)
- Overlay2.png (Result contourf plot)
12 commentaires
Subhadeep Koley
le 28 Mai 2020
Jake
le 28 Mai 2020
John D'Errico
le 28 Mai 2020
Modifié(e) : John D'Errico
le 28 Mai 2020
This is just some random conjecture on my part, but it seems from the pictures you post as if you may not want the contours to cross over irregularly shaped land regions that intrude into the water. As one might expect, such a boundary will be highly complex and irregular, certainly not convex in any respect. And all you seem to have is the point set, which indicates only information sampled where there is water.
If I am correct, then it is not that the contour plot ignores the points provided, but that the contour plot has no hint that the points exist. You are not contouring data in fact. The contour plot is applied to the result of a griddata operation ON your data. contourf sees only what griddata produces.
The problem of course is then you used meshgrid to populate the region with a grid, then interpolated using griddata. The real problem is then griddata, which has no clue that a void between two points is not valid to interpolate across, whereas another void is perfectly valid to cross. Note that EVERY pair of points has a void between them. Points are just points after all, scattered data. If some of the data is slightly more scattered, what is the griddata algoithm to know?
As such, I think (think - but this is only my perhaps weak conjecture) is you are asking for a way to force the contours to live ONLY inside a polygonal region describing the shoreline. Griddata has no such concept of course, and that makes what you tried to do fail.
If so, it is theoretically possible to solve such a problem. The scheme I would follow would have me triangulate the polygonal shoreline region, then using the data which lives only inside that polygonal region, use that data to infer a surface on that triangulation. Once you now have z(x,y) over a triangulated region, you can interpolate to produce contours that live only within the shoreline polygon. At least that would be my algorithmic approach. However, I'd not be amazed if perhaps the mapping toolbox already has some existing capability to solve this problem too.
At the very least, one simpler option might be to use what griddata produces, then force the grid points outside the polygonal region of interest to take on NaN values. inpolygon or polyshapes can offer the necessary tests. This will give you a slightly coarse approximation to the shoreline, and the contours will not cross through a region of NaNs.
Jake
le 28 Mai 2020
John D'Errico
le 28 Mai 2020
Oh geez. I had to stick my neck out. I had to stick my nose into this. ;-) Well, first, I would not even consider suggesting a re-creation of the wheel. Does the mapping toolbox have such capability, or something that would be sufficient? If so, then you never want to do work twice. And I lack the mapping TB, so I have no clue in this respect.
So hoping to avoid some effort here, does the mapping TB have what you can use?
Jake
le 28 Mai 2020
Bjorn Gustavsson
le 28 Mai 2020
The easiest way (if there is no mapping-toolbox methods that allow you to define a perimeter on the tri-scatter-interpolation), would be for you to determine the points that lie along the perimeter of your data-set. Then you can "simply" use the coordinates of those points to determine which points are inside and outside the boundary using inpolygon as John suggested. The inpolygon call migh be a bit time-consuming, but for any set of coordinates from meshgrid you only need to do this once. Then you get away from the spurious contours by setting everything outside to nan.
John D'Errico
le 28 Mai 2020
Modifié(e) : John D'Errico
le 28 Mai 2020
A very simple example of what I described is shown here:
px = [0, 1, .5, .49, 0];
py = [0, 0, sqrt(3), sqrt(3)-.5, 0];
ps = polyshape(px,py);
[x,y] = meshgrid(linspace(0,1,100),linspace(0,1.8,200));
z = x.^2 + y.^2;
inp = ps.isinterior(x(:),y(:));
z(~inp) = NaN;
H = contourf(x,y,z);
hold on
HB = plot(ps);
HB.FaceColor = 'none';

The edges are coarsely stairstepped, since I used only a fairly coarse mesh. Also note that the result lives ENTIRELY inside the polygonal region. So the steps intrude into the polyshape, because contourf will not contour any part of the grid that even touches a NaN. A finer mesh would reduce the stairstepping artifacts.
I defined z there using a simple computation, but nothing would have prevented me from using a tool like griddata or scatteredInterpolant if I had real data.
Is this a bit of a hack? Well, sadly, yes. That is because griddata still is using data from acrsss a hole to infer the shape of that surface in some region. I just deleted what griddata did in those regions, so contourf did not see the stuff I wanted hidden. The point is, griddata is still doing what is technically a bad thing, because it does not understand what you want. And that MAY introduce artifacts into the result. (Carefully consider this issue, as it may easily produce non-obvious artifacts. I can give an example of where this would be a problem.)
However, if you can live with this simplistic solution, then it may be a good choice for you.
Jake
le 28 Mai 2020
Jake
le 28 Mai 2020
Bjorn Gustavsson
le 28 Mai 2020
James, you might get away with generating a perimeter manually selecting points along a perimeter. Once you've plotted your points like in the Data_Points.PNG image you can manually select points along a perimeter (with the accuracy of your chosing) using ginput. If that becomes too tedious you might find this file-exchange contribution useful: snake-algorithm, some of the alpha-shape contributions, or active contour contributions.
Jake
le 28 Mai 2020
Réponse acceptée
Plus de réponses (0)
Catégories
En savoir plus sur Lighting, Transparency, and Shading dans Centre d'aide et File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!

