Skip to content

Cartopy axes_grid_basic example broken by Matplotlib 3.6 #24053

@dopplershift

Description

@dopplershift

Cartopy's axes_grid_basic was broken by Matplotlib 3.6. The relevant call is:

    axgr = AxesGrid(fig, 111, axes_class=axes_class,
                    nrows_ncols=(3, 2),
                    axes_pad=0.6,
                    cbar_location='right',
                    cbar_mode='single',
                    cbar_pad=0.2,
                    cbar_size='3%',
                    label_mode='')  # note the empty label_mode

In #23550, we began explicitly checking for the documented values of label_mode, ('All', 'L', '1'), which this runs afoul of. It appears the previous code let '' (or any option not handled) essentially work as a noop for set_label_mode().

Based on the output when the example worked, '1' would be fine behavior-wise, but that currently produces in this example:

/Users/rmay/repos/cartopy/examples/miscellanea/axes_grid_basic.py:48: MatplotlibDeprecationWarning: The resize_event function was deprecated in Matplotlib 3.6 and will be removed two minor releases later. Use callbacks.process('resize_event', ResizeEvent(...)) instead.
  fig = plt.figure()
Traceback (most recent call last):
  File "/Users/rmay/repos/cartopy/examples/miscellanea/axes_grid_basic.py", line 78, in <module>
    main()
  File "/Users/rmay/repos/cartopy/examples/miscellanea/axes_grid_basic.py", line 49, in main
    axgr = AxesGrid(fig, 111,
  File "/Users/rmay/miniconda3/envs/py310/lib/python3.10/site-packages/mpl_toolkits/axes_grid1/axes_grid.py", line 391, in __init__
    super().__init__(
  File "/Users/rmay/miniconda3/envs/py310/lib/python3.10/site-packages/mpl_toolkits/axes_grid1/axes_grid.py", line 174, in __init__
    self.set_label_mode(label_mode)
  File "/Users/rmay/miniconda3/envs/py310/lib/python3.10/site-packages/mpl_toolkits/axes_grid1/axes_grid.py", line 295, in set_label_mode
    _tick_only(ax, bottom_on=True, left_on=True)
  File "/Users/rmay/miniconda3/envs/py310/lib/python3.10/site-packages/mpl_toolkits/axes_grid1/axes_grid.py", line 16, in _tick_only
    ax.axis["bottom"].toggle(ticklabels=bottom_off, label=bottom_off)
TypeError: 'method' object is not subscriptable

This is because, while AxesGrid supposedly supports arbitrary classes by passing axes_class, there's a huge caveat: the default is mpl_toolkits.axes_grid1.mpl_axes.Axes (TERRIBLY CONFUSING NAME--it's imported as just Axes in axis_grid.py). This is a custom subclass that adds:

    @property
    def axis(self):
        return self._axislines

    def clear(self):
        # docstring inherited
        super().clear()
        # Init axis artists.
        self._axislines = self.AxisDict(self)
        self._axislines.update(
            bottom=SimpleAxisArtist(self.xaxis, 1, self.spines["bottom"]),
            top=SimpleAxisArtist(self.xaxis, 2, self.spines["top"]),
            left=SimpleAxisArtist(self.yaxis, 1, self.spines["left"]),
            right=SimpleAxisArtist(self.yaxis, 2, self.spines["right"]))

Options I can think of:

  1. Restore a noop option for set_label_mode
  2. Fix AxesGrid to work more generally with axes_class--monkey-patch/subclass to add the necessary modifications
  3. Document that axes_class needs to have certain behavior
  4. Fix AxesGrid to not rely on a property that OVERRIDES matplotlib.axes.Axes.axis with a different type that also manually dispatches to the unbound axis() method 😱
    class AxisDict(dict):
        def __init__(self, axes):
            self.axes = axes
            super().__init__()

        def __getitem__(self, k):
            if isinstance(k, tuple):
                r = SimpleChainedObjects(
                    # super() within a list comprehension needs explicit args.
                    [super(Axes.AxisDict, self).__getitem__(k1) for k1 in k])
                return r
            elif isinstance(k, slice):
                if k.start is None and k.stop is None and k.step is None:
                    return SimpleChainedObjects(list(self.values()))
                else:
                    raise ValueError("Unsupported slice")
            else:
                return dict.__getitem__(self, k)

        def __call__(self, *v, **kwargs):
            return maxes.Axes.axis(self.axes, *v, **kwargs)

Anyone have any opinions?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      pFad - Phonifier reborn

      Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

      Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


      Alternative Proxies:

      Alternative Proxy

      pFad Proxy

      pFad v3 Proxy

      pFad v4 Proxy