Contours not displaying properly with matplotlib 3.8

In an environment running an up-to-date Holoviz set of packages:

geoviews = 1.10.1
holoviews = 1.17.1
bokeh = 3.2.2
panel = 1.2.3

I’ve discovered that both line and filled contours do not properly display if Matplotlib 3.8.0 is installed. Things work properly with MPL 3.7.3.

Here is a fully-reproducible code block:

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import geoviews as gv
from geoviews import opts

gv.extension('bokeh')

Z = xr.open_dataset('http://thredds.atmos.albany.edu:8080/thredds/dodsC/atm533/2012103000_z500_era5.nc').z

gds= gv.Dataset(Z.isel(time=0), kdims=['longitude','latitude'], vdims=['z'])
contour = gv.project(gds.to(gv.LineContours, ['longitude', 'latitude'],crs=ccrs.PlateCarree()))
(gv.tile_sources.OSM * contour).opts(
    opts.LineContours(tools=['hover'], frame_width=700, frame_height=400,show_legend=True, line_width=3))

For Matplotlib <3.8, here is the (correct and expected) result:

For Matplotlib 3.8.0, here is the result:

This misbehavior occurs in a variety of relevant recent package versions (e.g. cartopy, jupyterlab 3 and 4).

1 Like

Thanks for reporting this; would you mind opening an issue on GitHub? I was able to reproduce by upgrading to matplotlib==3.8.0.

Here’s the barebones:

import geoviews as gv
import xarray as xr

gv.extension("bokeh")

Z = xr.open_dataset(
    "http://thredds.atmos.albany.edu:8080/thredds/dodsC/atm533/2012103000_z500_era5.nc"
).z

gv.LineContours(Z.isel(time=0), kdims=["longitude", "latitude"], vdims=["z"])

Yeah I know! I kept trying different Holoviz-related package versions and after seeing no differences, I started casting a wider net and was surprised that it was Matplotlib, since I wasn’t even using its backend! I will open up an issue shortly, thanks!

I suppose it’s a HoloViews issue actually: holoviews.operation.element — HoloViews v1.17.1


    def _process(self, element, key=None):
        try:
            from matplotlib.contour import QuadContourSet
            from matplotlib.axes import Axes
            from matplotlib.figure import Figure
            from matplotlib.dates import num2date, date2num
        except ImportError:
            raise ImportError("contours operation requires matplotlib.")
        extent = element.range(0) + element.range(1)[::-1]

Or perhaps a matplotlib issue since we’re just using QuadContourSet?

Or because of this:
https://matplotlib.org/stable/api/prev_api_changes/api_changes_3.8.0.html#contourset-is-now-a-single-collection

And we need to loop differently:

Prior to this release, ContourSet (the object returned by contour) was a custom object holding multiple Collections (and not an Artist) -- one collection per level, each connected component of that level's contour being an entry in the corresponding collection.

ContourSet is now instead a plain Collection (and thus an Artist). The collection contains a single path per contour level; this path may be non-continuous in case there are multiple connected components.
1 Like