Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Incorrect polygon filling of mplot3d filled contouring #4784

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
cwebster2 opened this issue Jul 24, 2015 · 7 comments
Closed

Incorrect polygon filling of mplot3d filled contouring #4784

cwebster2 opened this issue Jul 24, 2015 · 7 comments

Comments

@cwebster2
Copy link
Contributor

I have a dataset with large gradients in a quantity I am plotting. In many cases, this results in mis-filled contours when I use many contouring levels. For example:

enter image description here

This does not occur on 2D axes, even with 2 orders of magnitude more contouring levels. I can reduce some of the fill errors by reducing the number of contouring levels or zooming in on the domain so the strong gradients aren't as relatively strong in figure space. If I don't fill the contours, e.g. calling contour rather than contourf there are no errors. This is restricted to the filling,

Here is a script that should reproduce the problem for you. Tested with matplotlib 1.4.3 and python 3.4.1.

#!/usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as p3

data=np.array([[53.9751,  51.5681,  50.7119,  51.1049,  51.5339,  51.4977,  51.2387,50.761,  50.1732,  49.8218,  49.5442,  48.936,  47.4498,  46.6484, 45.8542,  45.136,  44.5268,  44.071,  43.7665,  43.5928,  43.5269, 43.5385,  43.6053,  45.565,  47.0071,  46.8664,  47.372,  47.8324, 48.295,  48.731,  49.0522,  49.4001,  49.7111,  49.9919,  50.2527, 50.4928,  50.7135,  50.8831,  51.0806,  51.2683 ],
               [55.6671,  52.53,  50.7764,  50.5632,  51.2095,  51.5659,  51.521,  51.2143,  50.653,  50.2371,  49.989,  49.8089,  49.6058,  47.8355, 47.3124,  46.7346,  46.1616,  45.6498,  45.2462,  44.967,  44.8005, 44.7284,  44.7295,  44.7869,  46.959,  45.0194,  46.73,  48.0766, 48.9395,  49.5325,  49.8498,  50.1887,  50.4798,  50.7406,  50.9808, 51.2003,  51.4074,  51.555,  51.7429,  51.9218 ],
               [56.6513,  53.5919,  51.2774,  50.3133,  50.7705,  51.533,  51.8287, 51.7083,  51.2816,  50.7933,  50.4806,  50.2671,  50.1009,  50.0096, 49.9052,  49.4698,  47.4655,  47.0717,  46.6849,  46.3583,  46.1122, 45.952,  45.8678,  45.8485,  45.8811,  45.956,  46.0634,  47.2225, 49.4363,  50.2482,  50.527,  50.8558,  51.1358,  51.3809,  51.607, 51.8179,  52.0161,  52.1454,  52.3263,  52.497 ],
               [57.078,  54.3224,  52.0759,  50.4679,  50.4677,  51.297,  52.0284, 52.1594,  51.9395,  51.5518,  51.1419,  50.8765,  50.6686,  50.5101, 50.4078,  50.3473,  50.3592,  50.3813,  49.7504,  47.55,  47.324, 47.1365,  46.9978,  46.9119,  46.8743,  46.8811,  46.9257,  47.0013, 50.0148,  50.9106,  51.1133,  51.4282,  51.7064,  51.943,  52.1587, 52.3597,  52.4789,  52.6631,  52.8359,  52.9966 ],
               [57.3835,  54.9025,  52.8571,  50.9842,  50.5197,  51.1494,  52.0599, 52.4732,  52.4716,  52.2656,  51.9535,  51.6068,  51.3466,  51.1513, 50.9708,  50.8321,  50.7639,  50.7944,  50.8817,  49.8122,  48.2038, 48.086,  47.9704,  47.8735,  47.8035,  47.7644,  47.7574,  47.7803, 50.8194,  51.5486,  51.6645,  51.9745,  52.2349,  52.4508,  52.6481, 52.8317,  52.9412,  53.1097,  53.2699,  53.4171 ],
               [57.9157,  55.6092,  53.6306,  51.8011,  50.9372,  51.2615,  52.1406, 52.7436,  52.8528,  52.7829,  52.6322,  52.403,  52.1149,  51.866, 51.6624,  51.4773,  51.317,  51.2183,  51.2153,  51.1367,  48.5913, 48.6216,  48.6218,  48.5951,  48.5589,  48.527,  48.5081,  50.5185, 51.6998,  51.905,  52.2258,  52.4891,  52.7062,  52.8926,  53.0655, 53.2251,  53.3262,  53.4755,  53.6169,  53.7471 ],
               [58.6093,  56.432,  54.307,  52.6277,  51.584,  51.6482,  52.3762, 53.0685,  53.2545,  53.217,  53.1356,  53.0351,  52.8481,  52.6154, 52.39,  52.177,  51.9977,  51.843,  51.7172,  51.4587,  48.7481,  48.7984, 48.864,  48.9291,  48.9843,  49.0228,  50.496,  51.8667,  52.3404, 52.4759,  52.6889,  52.8851,  53.0525,  53.2072,  53.354,  53.4576, 53.5925,  53.7217,  53.8432,  53.956 ],
               [58.9719,  56.9885,  54.8768,  53.3526,  52.3025,  52.2089,  52.7762, 53.4444,  53.6768,  53.6706,  53.5692,  53.5162,  53.4373,  53.2886, 53.1113,  52.9065,  52.6988,  52.5193,  52.3544,  52.0384,  48.9624, 48.9653,  49.0005,  49.0574,  49.1258,  50.692,  51.9726,  52.4309, 52.699,  52.8194,  52.9845,  53.1336,  53.2669,  53.393,  53.5118, 53.6086,  53.7213,  53.8293,  53.9308,  54.026 ],
              [58.5754,  56.945,  55.068,  53.7798,  52.9469,  52.854,  53.3136,53.8929,  54.1205,  54.1178,  54.0128,  53.9289,  53.8906,  53.8239,53.717,  53.5724,  53.3818,  53.1892,  53.009,  49.3078,  49.2524,49.2165,  49.2032,  49.2187,  50.463,  51.9497,  52.4487,  52.7041,52.8358,  52.9776,  53.1101,  53.2293,  53.3419,  53.4487,  53.5401,53.6365,  53.7301,  53.8205,  53.9062,  53.9869 ],
              [57.623,  56.547,  55.0117,  54.0512,  53.5372,  53.5246,  53.927,54.3868,  54.5828,  54.5811,  54.4501,  54.3235,  54.2626,  54.2334,54.1802,  54.1137,  53.9897,  53.8202,  49.796,  49.6864,  49.5946,49.5216,  49.4703,  49.4432,  51.8479,  52.5574,  52.8359,  52.9722,53.0827,  53.1826,  53.2747,  53.3597,  53.4405,  53.5138,  53.5944,53.6751,  53.7536,  53.829,  53.9019,  53.9721 ],
              [56.902,  56.0005,  54.9159,  54.3352,  54.123,  54.2014,  54.5659,54.8917,  55.0307,  55.0139,  54.8838,  54.7044,  54.5863,  54.5548,54.5258,  54.4957,  54.4633,  51.4821,  50.1897,  50.0758,  49.9683,49.8704,  49.7842,  51.5064,  52.7625,  53.0724,  53.1926,  53.2682,53.3404,  53.4119,  53.4831,  53.5517,  53.6169,  53.6763,  53.7383,53.8009,  53.8644,  53.9281,  53.9905,  54.0517 ],
              [56.3455,  55.5524,  54.9336,  54.6836,  54.703,  54.8657,  55.1749,55.3844,  55.4521,  55.4019,  55.2622,  55.0281,  54.8981,  54.6591,54.7866,  54.7678,  54.7654,  54.0436,  54.2302,  52.2533,  50.3305,50.2276,  50.1268,  52.9617,  53.4395,  53.5504,  53.5481,  53.5524,53.5699,  53.6014,  53.644,  53.6931,  53.7445,  53.7996,  53.8548,53.9097,  53.9655,  54.0229,  54.0813,  54.1393 ],
              [55.7493,  55.3019,  55.1012,  55.0906,  55.234,  55.4751,  55.7134,55.8462,  55.8461,  55.7425,  55.5725,  55.3535,  55.1612,  54.958,55.0193,  54.9584,  54.9531,  54.8886,  54.8256,  54.2211,  50.6477,50.5564,  53.0546,  53.8592,  54.08,  54.0288,  53.9509,  53.8796,53.8307,  53.8073,  53.8034,  53.8142,  53.8383,  53.8725,  53.9128,53.9558,  54.0013,  54.0497,  54.103,  54.1597 ],
              [55.2575,  55.1664,  55.3165,  55.5004,  55.7345,  55.9901,  56.1852,56.2599,  56.2027,  56.0454,  55.818,  55.5754,  55.302,  55.2083,55.0224,  55.1415,  55.0656,  55.0446,  55.0263,  54.7728,  50.8924,53.4671,  54.2587,  54.5146,  54.6171,  54.519,  54.3857,  54.2497,54.1355,  54.0509,  53.9932,  53.9584,  53.941,  53.939,  53.9527,53.9798,  54.0111,  54.0465,  54.0868,  54.1339 ],
              [54.8665,  55.1533,  55.5095,  55.8512,  56.1541,  56.3995,  56.5593,56.6009,  56.5079,  56.3001,  56.0178,  55.7187,  55.448,  55.063,55.2016,  55.2116,  55.1817,  55.112,  55.1099,  55.0299,  54.3358,54.6966,  54.9199,  55.0156,  55.0728,  54.975,  54.8299,  54.6609,54.493,  54.3475,  54.2349,  54.1517,  54.0928,  54.0516,  54.0245,54.013,  54.0206,  54.0404,  54.0667,  54.0989 ],
              [54.2676,  55.1132,  55.6112,  56.09,  56.428,  56.6661,  56.8056,56.8374,  56.7339,  56.4923,  56.1474,  55.7977,  55.4805,  55.2341,54.8999,  55.2662,  55.2927,  55.185,  55.1237,  55.1268,  54.9772,55.1418,  55.2612,  55.3333,  55.379,  55.3244,  55.2153,  55.0629,54.881,  54.6926,  54.523,  54.3866,  54.2855,  54.2118,  54.1583,54.1191,  54.0935,  54.0834,  54.0885,  54.1057 ],
              [54.1771,  55.0795,  55.7075,  56.1772,  56.5183,  56.7522,  56.8898,56.9315,  56.8427,  56.6056,  56.2317,  55.8095,  55.4436,  55.183,55.0284,  54.9504,  55.2833,  55.2563,  55.1498,  55.1342,  55.1331,55.259,  55.3705,  55.4452,  55.4955,  55.5087,  55.4697,  55.3766,55.2324,  55.049,  54.8485,  54.6578,  54.4995,  54.3822,  54.3002,54.2427,  54.2022,  54.1749,  54.1598,  54.1561 ],
              [53.9112,  54.85,  55.6641,  56.0844,  56.4062,  56.6232,  56.757,56.8149,  56.7669,  56.5754,  56.2311,  55.785,  55.366,  55.0104,54.812,  54.8845,  55.1273,  55.2339,  55.1976,  55.1049,  55.0913,55.1843,  55.3048,  55.4076,  55.4709,  55.518,  55.5455,  55.5329,55.4636,  55.3349,  55.1595,  54.9529,  54.7462,  54.5681,  54.4342,54.3439,  54.2848,  54.2446,  54.2222,  54.2135 ],
              [53.9368,  54.9196,  55.4408,  55.7999,  56.0652,  56.2423,  56.348,56.4106,  56.4114,  56.3028,  56.0519,  55.6779,  55.2493,  54.8836,54.6592,  54.6347,  54.8341,  55.0606,  55.1396,  55.0967,  55.0325,55.0501,  55.1451,  55.2627,  55.3559,  55.4216,  55.4789,  55.5183,55.5245,  55.4779,  55.3701,  55.2072,  55.0029,  54.7876,  54.5915,54.4378,  54.3368,  54.2787,  54.2415,  54.2271 ],
              [53.9325,  54.6506,  55.0421,  55.2926,  55.4603,  55.5679,  55.6285,55.6792,  55.7234,  55.731,  55.639,  55.3923,  55.043,  54.6845,54.4188,  54.3242,  54.4606,  54.7449,  54.9548,  55.0171,  55.0047,54.9454,  54.9666,  55.0651,  55.1828,  55.2677,  55.3308,  55.3914,55.438,  55.4544,  55.4277,  55.3385,  55.1907,  54.9981,  54.7786,54.5691,  54.4013,  54.2898,  54.233,  54.1994 ] ])

fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
X,Y = np.meshgrid(np.arange(-30.0,-20.0,0.25), np.arange(20.0,25,0.25))
ax.contourf(X,Y,data,zdir='z',offset=0, levels=np.arange(0,75,1))
ax.set_zlim(0.0,2.0)
plt.savefig('testfig.png')
plt.close()

which produces the image:

enter image description here

In this case, reducing the contouring level will fix the mis-fill but for the plots I want to produce this isn't a feasible option.

@cwebster2
Copy link
Contributor Author

To supplement the first image I posted, here is the same data at a much lower contouring interval which still produces miss-fill.

enter image description here

@WeatherGod
Copy link
Member

This looks a lot like #186 and #178, which I had forgotten about. But I thought we fixed some of those issues in the 1.4 release...? In any case, I can reproduce the image on the master branch...

@cwebster2
Copy link
Contributor Author

Thanks. I had a feeling it was related to those issues, but wasn't sure. I'm happy to test any potential fixes. I'm trying to put together animations like this and the mis-fill is quite problematic.

@cwebster2
Copy link
Contributor Author

I've narrowed down the issue with this particular data a bit. If you do an axes3d.contour() for the 55 and 56 levels, you'll get:

contour

but if you do an axes3d.contourf() for the 55 and 56 levels you get:

contourf

You can see similar results if you narrow the two contours to be 55.0 and 55.2.

I'm going to be taking a look at the contourset returned by contourf and trying to pinpoint where it is going wrong. I'm assuming the return from Axes.contourf() is proper (since 2d plots are fine) and the issue is either in the transform to 3d or in the projection for drawing.

@cwebster2
Copy link
Contributor Author

Some more investigation! Using the same test data above and plotting except that levels=[55.0,55.2] in the contourf call. All of these are running against the master branch as of around 18Z 25 July 2015.

This produces this miss-filled contour

image

The dumped contents of self._vec in Poly3DCollection::do_3d_projection (art3d.py:564) contain this data:

image

This represented 2 distinct polygons with the larger one containing two holes. After the 3d projection (art3d.py:576), the txs,tys and tzs have two elements each and render to these shapes:

image
image

In the second image you can see the lines that are causing the mis-fill. I'm still not familiar enough with the code to know how paths are determined to be lines or moves and the nuances of rendering but I'm continuing to dig and posting these updates in case anyone else can shed some light.

@ianthomas23
Copy link
Member

@cwebster2: if you want some light shed, this is a well-known problem that has been hanging around since 2010. I wrote the following in PR #1928:

The root cause of issue #178 is that a 2D PolyCollection has both 2D vertices and 2D codes. The codes are used so that single arrays of vertices and codes can be used for multiple polygons, such as when a contour needs to render a hole polygon inside another polygon. Up until now, Poly3DCollection has had no understanding of these codes and so has rendered all the vertices as though they were a single polygon, causing incorrect rendering.

That PR contains a (poor quality) candidate fix that needs reworking by someone who knows something about the mplot3d codebase and cares about fixing such problems. No such person has come forward in the last couple of years.

@cwebster2
Copy link
Contributor Author

@ianthomas23 perfect! I think I skimmed across that earlier but forgot about it as a dove into the code. Thanks for pointing it out. I have a local branch that is probably 90% of your code but slightly reorganized. Once I regenerate my plots and make sure nothing blows up I'll see if I can clean it up any better and submit a PR. You saved a ton of time for me, thank you very much! (and this has been a longstanding problem with my 3d plots that I had chalked up to me doing something wrong before I looked more into it)

cwebster2 added a commit to cwebster2/matplotlib that referenced this issue Jul 25, 2015
Fixes matplotlib#4784 by adding path code information to the Poly3DCollection.
This adds two new methods, path_to_3d_segment_with_codes and
paths_to_3d_segments_with_codes which are meant to replace the
versions without "_with_codes".  A method was added to PolyCollection
to allow Poly3DCollection to set vertices with path codes.

This code was adapted from a PR by @ianthomas23.
cwebster2 added a commit to cwebster2/matplotlib that referenced this issue Jul 26, 2015
Fixes matplotlib#4784 by adding path code information to the Poly3DCollection.
This adds two new methods, path_to_3d_segment_with_codes and
paths_to_3d_segments_with_codes which are meant to replace the
versions without "_with_codes".  A method was added to PolyCollection
to allow Poly3DCollection to set vertices with path codes.

This code was adapted from a PR by @ianthomas23.
cwebster2 added a commit to cwebster2/matplotlib that referenced this issue Jul 27, 2015
Fixes matplotlib#4784 by adding path code information to the Poly3DCollection.
This adds two new methods, path_to_3d_segment_with_codes and
paths_to_3d_segments_with_codes which are meant to replace the
versions without "_with_codes".  A method was added to PolyCollection
to allow Poly3DCollection to set vertices with path codes.

This code was adapted from a PR by @ianthomas23.
cwebster2 added a commit to cwebster2/matplotlib that referenced this issue Jul 27, 2015
Fixes matplotlib#4784 by adding path code information to the Poly3DCollection.
This adds two new methods, path_to_3d_segment_with_codes and
paths_to_3d_segments_with_codes which are meant to replace the
versions without "_with_codes".  A method was added to PolyCollection
to allow Poly3DCollection to set vertices with path codes.

Add image test for a case that causes improper polygon rendering
without this fix.

This code was adapted from a PR by @ianthomas23.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants