Contour plot: distorted contours and blank spaces in plots.
35 views (last 30 days)
Show older comments
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:
- 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.
- 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.
- 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 Comment
Bjorn Gustavsson
on 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...
Answers (2)
Bjorn Gustavsson
on 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 Comments
Bjorn Gustavsson
on 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.
Cris LaPierre
on 30 Mar 2023
Edited: Cris LaPierre
on 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.
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 Comments
Cris LaPierre
on 30 Mar 2023
Edited: Cris LaPierre
on 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])
See Also
Categories
Find more on Contour Plots in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!