Contour plot: distorted contours and blank spaces in plots.

57 vues (au cours des 30 derniers jours)
Srh Fwl
Srh Fwl le 30 Mar 2023
I would be grateful if someone would please help me understand how to use "contour."
The plot below shows what I have so far. It's based on an example I found in the Matlab documentation. There are three problems:
  1. The contours should be quite smooth but are distorted/wavy at the bottom of the plot (i..e, at around 1000 on the y axis). Changing the grid resolution doesn't have any effect.
  2. It's fine to have blank space at the bottom of the plot because I have other data to plot from approximately 0 to 30 on the x axis and 0 to 500 on the y axis. However, I want the contours to extend smoothly throughout the entire domain (to 30 on the x axis and 3000 on the y axis) above 500 on the y axis.
  3. This plot uses "contourf." I want to use "contour" (i.e., only have contour lines and not filled areas) but when I use "contour," the plot is blank!
My data points are not evenly spaced, so I have tried to interpolate over a grid by using "meshgrid" but there must be something I don't understand. In an answer to another question here, I saw that "NaN" data can lead to blank spaces in contour plots, so I got rid of all NaNs. However, i still have blank spaces. Also, I do have data at "3000" (y axis).
Here is my code and my data below that.
[XI, YI] = meshgrid(0:0.01:30, 0:10:3000);
ZI_nG = griddata(Data.A, Data.B, Data.C, XI, YI);
[c,h] = contourf(XI, YI, ZI, 'EdgeColor', 'none', 'LineWidth',1.5)
xlim([0 30])
ylim([0 3000])
Here are the data. I import them from an external file as table "Data." Column 2 is Data.Y, column 1 is Data.X, and column 3 is what I want to contour.
573 0.3 31
773 0.3 17
773 0.5 18
823 0.5 16
973 0.5 11
973 0.7 13
800 1 20
800 3 31
800 4.5 38
800 6 44
800 8 53
800 11 61
1000 1 14
1000 3 21
1000 4.5 25
1000 6 30
1000 8 36
1000 11 51
1000 16 62
1000 20 71
1000 25 74
1500 0.5 4
1500 1 6
1500 4.5 14
1500 6 19
1500 8 25
1500 16 46
2000 1 4
2000 4.5 10
2000 6 14
2000 8 21
2000 11 29
2000 16 37
2000 20 39
2000 25 42
2000 30 44
2273 1 3
2273 3 6
2273 4.5 8
2273 6 13
2273 8 20
2273 10 24
2273 20 36
2273 30 40
3000 1 2
3000 4.5 10
3000 6 15
  1 commentaire
Bjorn Gustavsson
Bjorn Gustavsson le 30 Mar 2023
If you want to extrapolate you should not look past scatteredInterpolant - which is the newer tool to re-interpolating scattered data - with extrapolation capabilities. One point to still remember is that the normalization of the coordinate-points (centering and dividing by the standard deviation of the coordinates) is often very helpful in removing the narrow triangles - If I recall right one version of these triangulation-based tools used to have a "normalize"-option that used to do this - this you can still do, but it requires you to remember that you've done it...

Connectez-vous pour commenter.

Réponses (2)

Bjorn Gustavsson
Bjorn Gustavsson le 30 Mar 2023
The reason you get these jagged contour-lines is that the triangulation-based interpolation you use is based on a Delaunay-triangulation of your data-points. With such difference in scales on the x-and y-axes that will produce very narrow triangles, which is mathematically correct, but typically not what we anticipate - based off of human "white-balancing" of the data-points we select we make an almost instinctive/automatic re-scaling of the triangulation coordinates that we expect. You can circumvent that problem by manually centre-and-std-rescale the coordinates:
tri = delaunay(data(:,1),data(:,2));
dt = delaunayTriangulation(data(:,1:2));
subplot(2,2,1)
triplot(dt)
subplot(2,2,3)
scatter(data(:,1),data(:,2),73,data(:,3),'filled')
hold on
[C,h] = tricontour(tri,data(:,1),data(:,2),data(:,3),[10:10:70]);
subplot(2,2,2)
dt2 = delaunayTriangulation([(data(:,1)-mean(data(:,1)))/std(data(:,1)),(data(:,2)-mean(data(:,2)))/std(data(:,2))]);
tri2 = delaunay((data(:,1)-mean(data(:,1)))/std(data(:,1)),(data(:,2)-mean(data(:,2)))/std(data(:,2)));
triplot(dt2)
subplot(2,2,4)
scatter(data(:,1),data(:,2),73,data(:,3),'filled')
hold on
[C,h] = tricontour(tri2,data(:,1),data(:,2),data(:,3),[10:10:70]);
In the left column I've shown the default triangulation and the corresponding contour-plot, while in the right column I explicitly rescale the coordinates to the triangulation. Note the very many narrow triangles in the "problem-area" in the upper left panel and the much "nicer" triangles in the upper right. The contour-plots looks correspondingly nicer in the lower right panel.
Contour-plots made with the tricontour-function from the file exchange.
HTH
  3 commentaires
Bjorn Gustavsson
Bjorn Gustavsson le 30 Mar 2023
Ah, you had something like a 50-50 at chosing the tricontour I used, and this time we had bad luck - I should've given you the link to the version I use: contour-plot-for-scattered-data (by Duane Hanselman), hopefully that solves this issue.
Srh Fwl
Srh Fwl le 30 Mar 2023
@Bjorn Gustavsson, thank you; it did. Now I will work on understanding your answer. Thank you!

Connectez-vous pour commenter.


Cris LaPierre
Cris LaPierre le 30 Mar 2023
Modifié(e) : Cris LaPierre le 30 Mar 2023
griddata does not extrapolate your data. Everything outside the known data is set to NaN, which appears white in your contour plot.
scatteredInterpolant and griddedInterpolant will extrapolate, but the results did not look to me like they were meaningful.
I think overlaying the raw data on your contourf plot can be helpful in seeing what is happening.
A = [573 773 773 800 800 800 800 800 800 823 973 973 1000 1000 1000 1000 1000 1000 1000 1000 1000 1500 1500 1500 1500 1500 1500 2000 2000 2000 2000 2000 2000 2000 2000 2000 2273 2273 2273 2273 2273 2273 2273 2273 3000 3000 3000]';
B = [0.3 0.3 0.5 1 3 4.5 6 8 11 0.5 0.5 0.7 1 3 4.5 6 8 11 16 20 25 0.5 1 4.5 6 8 16 1 4.5 6 8 11 16 20 25 30 1 3 4.5 6 8 10 20 30 1 4.5 6]';
C = [31 17 18 20 31 38 44 53 61 16 11 13 14 21 25 30 36 51 62 71 74 4 6 14 19 25 46 4 10 14 21 29 37 39 42 44 3 6 8 13 20 24 36 40 2 10 15]';
Data = table(A,B,C);
[XI, YI] = meshgrid(0:0.01:30, 0:10:3000);
ZI_nG = griddata(Data.B, Data.A, Data.C, XI, YI);
[c,h] = contourf(XI, YI, ZI_nG, 'EdgeColor', 'none', 'LineWidth',1.5);
xlim([0 30])
ylim([0 3000])
% Overlay raw data
hold on
scatter(Data.B,Data.A,[],Data.C,'filled',"MarkerFaceColor","flat","MarkerEdgeColor","k")
hold off
There appears to be an anomally in your data that is causing the jump you see at 1000. Here is a 3D view of a mesh plot of your data looking at the y axis.
You could try specifying a different method for griddata, but I don't think those results are better
figure
ZI_nat = griddata(Data.B, Data.A, Data.C, XI, YI,'natural');
contourf(XI, YI, ZI_nat, 'EdgeColor', 'none', 'LineWidth',1.5);
xlim([0 30])
ylim([0 3000])
% Overlay raw data
hold on
scatter(Data.B,Data.A,[],Data.C,'filled',"MarkerFaceColor","flat","MarkerEdgeColor","k")
hold off
As I see it, the 'jump' represents your actual data and, if you don't want it, you should look into filtering or smoothing your data. As for the 'blank spaces', what should they be? One approach could be to replace all the NaNs with some value using fillmissing.
figure
ZI = fillmissing(ZI_nG,'constant',0);
contourf(XI, YI, ZI, 'EdgeColor', 'none', 'LineWidth',1.5);
xlim([0 30])
ylim([0 3000])
  2 commentaires
Srh Fwl
Srh Fwl le 30 Mar 2023
@Cris LaPierre, thank you very much for taking time to do this. I actually like your second-last plot! I think it's the one you're referring to where you don't think that specifying a different method for griddata is any better. I'd like to end up with contour lines just like that, minus the fill colours and "noise" (the little horizontal blips).
The situation is that I have just a few data points and want to make a best guess at contouring the entire space above 500 on the y axis based on them. Thanks for your help. I'll try to reproduce your second-last plot.
Cris LaPierre
Cris LaPierre le 30 Mar 2023
Modifié(e) : Cris LaPierre le 30 Mar 2023
Reproducing should be easy, as I've given you the code. The main difference is specifying a gridding method
ZI_nat = griddata(Data.B, Data.A, Data.C, XI, YI,'natural');
If you don't want a filled contour, then use contour instead.
A = [573 773 773 800 800 800 800 800 800 823 973 973 1000 1000 1000 1000 1000 1000 1000 1000 1000 1500 1500 1500 1500 1500 1500 2000 2000 2000 2000 2000 2000 2000 2000 2000 2273 2273 2273 2273 2273 2273 2273 2273 3000 3000 3000]';
B = [0.3 0.3 0.5 1 3 4.5 6 8 11 0.5 0.5 0.7 1 3 4.5 6 8 11 16 20 25 0.5 1 4.5 6 8 16 1 4.5 6 8 11 16 20 25 30 1 3 4.5 6 8 10 20 30 1 4.5 6]';
C = [31 17 18 20 31 38 44 53 61 16 11 13 14 21 25 30 36 51 62 71 74 4 6 14 19 25 46 4 10 14 21 29 37 39 42 44 3 6 8 13 20 24 36 40 2 10 15]';
Data = table(A,B,C);
[XI, YI] = meshgrid(0:0.01:30, 0:10:3000);
ZI_nat = griddata(Data.B, Data.A, Data.C, XI, YI,'natural');
contour(XI, YI, ZI_nat, 'LineWidth',1.5);
xlim([0 30])
ylim([0 3000])

Connectez-vous pour commenter.

Catégories

En savoir plus sur Contour Plots dans Help Center et File Exchange

Produits


Version

R2021a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by