馃摪 Custom Issue
iplt.contourf has a longstanding workaround to improve the look of antialiased plots.
|
# Matplotlib produces visible seams between anti-aliased polygons. |
|
# But if the polygons are virtually opaque then we can cover the seams |
|
# by drawing anti-aliased lines *underneath* the polygon joins. |
|
|
|
if hasattr(result, "get_antialiased"): |
|
# Matplotlib v3.8 onwards. |
|
antialiased = any(result.get_antialiased()) |
|
# Figure out the colours and alpha level for the contour plot |
|
colors = result.get_facecolor() |
|
alpha = result.alpha or colors[0][3] |
|
# Define a zorder just *below* the polygons to ensure we minimise any boundary shift. |
|
zorder = result.zorder - 0.1 |
|
else: |
|
antialiased = result.antialiased |
|
# Figure out the alpha level for the contour plot |
|
alpha = result.alpha or result.collections[0].get_facecolor()[0][3] |
|
colors = [c[0] for c in result.tcolors] |
|
# Define a zorder just *below* the polygons to ensure we minimise any boundary shift. |
|
zorder = result.collections[0].zorder - 0.1 |
|
|
|
# If the contours are anti-aliased and mostly opaque then draw lines under |
|
# the seams. |
|
if antialiased and alpha > 0.95: |
|
levels = result.levels |
|
if result.extend == "neither": |
|
levels = levels[1:-1] |
|
colors = colors[:-1] |
|
elif result.extend == "min": |
|
levels = levels[:-1] |
|
colors = colors[:-1] |
|
elif result.extend == "max": |
|
levels = levels[1:] |
|
colors = colors[:-1] |
|
else: |
|
colors = colors[:-1] |
|
if len(levels) > 0 and np.nanmax(cube.data) > levels[0]: |
|
axes = kwargs.get("axes", None) |
|
contour( |
|
cube, |
|
levels=levels, |
|
colors=colors, |
|
antialiased=True, |
|
zorder=zorder, |
|
coords=coords, |
|
axes=axes, |
|
) |
|
# Restore the current "image" to 'result' rather than the mappable |
|
# resulting from the additional call to contour(). |
|
if axes: |
|
axes._sci(result) |
|
else: |
|
plt.sci(result) |
I believe matplotlib/matplotlib#32256 will make this workaround redundant for its stated purpose from Matplotlib v3.12 馃帀
However, the workaround also affects plots saved to pdf. Adapting the code from test_mapping.py::TestMappingSubRegion::test_simple
import cartopy.crs as ccrs
import iris
import iris.plot as iplt
import matplotlib.pyplot as plt
cube = iris.load_cube('[path-to-iris-test-data]/test_data/PP/aPProt1/rotatedMHtimecube.pp')
cube = cube[0][::10][::10]
plt.figure(layout='constrained')
plt.subplot(221)
plt.title("Default")
iplt.contourf(cube)
plt.gca().coastlines("110m")
# Second sub-plot
plt.subplot(222, projection=ccrs.Mollweide(central_longitude=120))
plt.title("Molleweide")
iplt.contourf(cube)
plt.gca().coastlines("110m")
# Third sub-plot (the projection part is redundant, but a useful
# test none-the-less)
ax = plt.subplot(223, projection=iplt.default_projection(cube))
plt.title("Native")
iplt.contour(cube)
ax.coastlines("110m")
# Fourth sub-plot
ax = plt.subplot(2, 2, 4, projection=ccrs.PlateCarree())
plt.title("PlateCarree")
iplt.contourf(cube)
ax.coastlines("110m")
plt.savefig('test.pdf')
Running with current Iris main, we get
test_workaround.pdf
If I remove the workaround from Iris I get
test_no_workaround.pdf
Note that
- Without the workaround, we do see seams between the filled contours, which may be undesirable to some users.
- With the workaround, the right-hand plots show the ends of the added line contours, which also doesn't seem desirable.
As far as I understand image processing (not much), I do not think aliasing is relevant for pdf rendering. So I do not think it would make sense to keep the current workaround triggered by the antialiased keyword just for the pdf case (and possibly other vector graphics cases that I haven't checked).
Options
- Factor out the workaround into a public function, so that pdf users who value the old behaviour can opt-in and apply it directly.
- Encourage users to pass
rasterized=True when they call contourf. Then the contours get converted to an image by the agg renderer (benefitting from matplotlib/32256) and the image is embedded into the pdf. This would mean users have to think about dpi to get a good quality. Here, I passed dpi=300 to savefig, and am using the branch from matplotlib/32256: test_no_workaround_rasterized.pdf
- Both 1 and 2 - i.e. factor out the workaround and also document the pros and cons of the two options so users can make an informed choice.
- Leave as it. I think this is the worst option because
- As stated above, having it triggered by the
antialiased keyword doesn't really make sense for pdf
- We will be calling redundant code in many cases
- Silently creating and adding an extra artist to the axes just doesn't smell good in general
- Since our image tests all save to png, they likely wouldn't show any benefit of the workaround any more. We would at least need to find a different way to cover this.
- Anything else? Presumably contourf plots made outside of Iris have either been living with the seams or using some other workaround for a long time.
馃摪 Custom Issue
iplt.contourfhas a longstanding workaround to improve the look of antialiased plots.iris/lib/iris/plot.py
Lines 1134 to 1185 in cefe4b7
I believe matplotlib/matplotlib#32256 will make this workaround redundant for its stated purpose from Matplotlib v3.12 馃帀
However, the workaround also affects plots saved to pdf. Adapting the code from test_mapping.py::TestMappingSubRegion::test_simple
Running with current Iris main, we get
test_workaround.pdf
If I remove the workaround from Iris I get
test_no_workaround.pdf
Note that
As far as I understand image processing (not much), I do not think aliasing is relevant for pdf rendering. So I do not think it would make sense to keep the current workaround triggered by the
antialiasedkeyword just for the pdf case (and possibly other vector graphics cases that I haven't checked).Options
rasterized=Truewhen they callcontourf. Then the contours get converted to an image by the agg renderer (benefitting from matplotlib/32256) and the image is embedded into the pdf. This would mean users have to think about dpi to get a good quality. Here, I passeddpi=300tosavefig, and am using the branch from matplotlib/32256: test_no_workaround_rasterized.pdfantialiasedkeyword doesn't really make sense for pdf