diff --git a/doc/api/next_api_changes/removals/19033-AL.rst b/doc/api/next_api_changes/removals/19033-AL.rst new file mode 100644 index 000000000000..258950c1b86a --- /dev/null +++ b/doc/api/next_api_changes/removals/19033-AL.rst @@ -0,0 +1,6 @@ +The private ``matplotlib.axes._subplots._subplot_classes`` dict has been removed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Support for passing ``None`` to ``subplot_class_factory`` has been removed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Explicitly pass in the base `~matplotlib.axes.Axes` class instead. diff --git a/doc/missing-references.json b/doc/missing-references.json index 5a5d6237a549..6cc524e98b59 100644 --- a/doc/missing-references.json +++ b/doc/missing-references.json @@ -20,7 +20,6 @@ "doc/users/prev_whats_new/whats_new_3.1.0.rst:335" ], "cbar_axes": [ - "lib/mpl_toolkits/axes_grid1/axes_grid.py:docstring of mpl_toolkits.axes_grid1.axes_grid.ImageGrid.__init__:45", "lib/mpl_toolkits/axes_grid1/axes_grid.py:docstring of mpl_toolkits.axes_grid1.axes_grid.ImageGrid:45", "lib/mpl_toolkits/axisartist/axes_grid.py:docstring of mpl_toolkits.axisartist.axes_grid.ImageGrid:45" ], @@ -79,39 +78,35 @@ ], "matplotlib.axes.Axes.lines": [ "doc/tutorials/intermediate/artists.rst:100", - "doc/tutorials/intermediate/artists.rst:440" + "doc/tutorials/intermediate/artists.rst:442" ], "matplotlib.axes.Axes.patch": [ "doc/api/prev_api_changes/api_changes_0.98.x.rst:89", - "doc/tutorials/intermediate/artists.rst:186", - "doc/tutorials/intermediate/artists.rst:424" + "doc/tutorials/intermediate/artists.rst:187", + "doc/tutorials/intermediate/artists.rst:426" ], "matplotlib.axes.Axes.patches": [ - "doc/tutorials/intermediate/artists.rst:463" + "doc/tutorials/intermediate/artists.rst:465" ], "matplotlib.axes.Axes.transAxes": [ - "lib/mpl_toolkits/axes_grid1/anchored_artists.py:docstring of mpl_toolkits.axes_grid1.anchored_artists.AnchoredDirectionArrows.__init__:8", "lib/mpl_toolkits/axes_grid1/anchored_artists.py:docstring of mpl_toolkits.axes_grid1.anchored_artists.AnchoredDirectionArrows:8" ], "matplotlib.axes.Axes.transData": [ - "lib/mpl_toolkits/axes_grid1/anchored_artists.py:docstring of mpl_toolkits.axes_grid1.anchored_artists.AnchoredAuxTransformBox.__init__:11", "lib/mpl_toolkits/axes_grid1/anchored_artists.py:docstring of mpl_toolkits.axes_grid1.anchored_artists.AnchoredAuxTransformBox:11", - "lib/mpl_toolkits/axes_grid1/anchored_artists.py:docstring of mpl_toolkits.axes_grid1.anchored_artists.AnchoredEllipse.__init__:8", "lib/mpl_toolkits/axes_grid1/anchored_artists.py:docstring of mpl_toolkits.axes_grid1.anchored_artists.AnchoredEllipse:8", - "lib/mpl_toolkits/axes_grid1/anchored_artists.py:docstring of mpl_toolkits.axes_grid1.anchored_artists.AnchoredSizeBar.__init__:8", "lib/mpl_toolkits/axes_grid1/anchored_artists.py:docstring of mpl_toolkits.axes_grid1.anchored_artists.AnchoredSizeBar:8" ], "matplotlib.axes.Axes.viewLim": [ "doc/api/prev_api_changes/api_changes_0.99.x.rst:23" ], "matplotlib.axes.Axes.xaxis": [ - "doc/tutorials/intermediate/artists.rst:608" + "doc/tutorials/intermediate/artists.rst:610" ], "matplotlib.axes.Axes.yaxis": [ - "doc/tutorials/intermediate/artists.rst:608" + "doc/tutorials/intermediate/artists.rst:610" ], "matplotlib.axis.Axis.label": [ - "doc/tutorials/intermediate/artists.rst:655" + "doc/tutorials/intermediate/artists.rst:657" ], "matplotlib.cm.ScalarMappable.callbacksSM": [ "doc/api/prev_api_changes/api_changes_0.98.0.rst:10" @@ -124,11 +119,11 @@ ], "matplotlib.figure.Figure.patch": [ "doc/api/prev_api_changes/api_changes_0.98.x.rst:89", - "doc/tutorials/intermediate/artists.rst:186", - "doc/tutorials/intermediate/artists.rst:319" + "doc/tutorials/intermediate/artists.rst:187", + "doc/tutorials/intermediate/artists.rst:320" ], "matplotlib.figure.Figure.transFigure": [ - "doc/tutorials/intermediate/artists.rst:368" + "doc/tutorials/intermediate/artists.rst:369" ], "max": [ "lib/matplotlib/transforms.py:docstring of matplotlib.transforms.Bbox.p1:4" @@ -256,15 +251,6 @@ "doc/tutorials/intermediate/artists.rst:44", "doc/tutorials/intermediate/artists.rst:67" ], - "matplotlib.axes._axes.Axes": [ - "doc/api/artist_api.rst:189", - "doc/api/axes_api.rst:609", - "lib/matplotlib/projections/geo.py:docstring of matplotlib.projections.geo.GeoAxes:1", - "lib/matplotlib/projections/polar.py:docstring of matplotlib.projections.polar.PolarAxes:1", - "lib/mpl_toolkits/axes_grid1/mpl_axes.py:docstring of mpl_toolkits.axes_grid1.mpl_axes.Axes:1", - "lib/mpl_toolkits/axisartist/axislines.py:docstring of mpl_toolkits.axisartist.axislines.Axes:1", - "lib/mpl_toolkits/mplot3d/axes3d.py:docstring of mpl_toolkits.mplot3d.axes3d.Axes3D:1" - ], "matplotlib.axes._base._AxesBase": [ "doc/api/artist_api.rst:189", "doc/api/axes_api.rst:609", @@ -428,16 +414,6 @@ "lib/matplotlib/transforms.py:docstring of matplotlib.transforms.BlendedAffine2D:1", "lib/matplotlib/transforms.py:docstring of matplotlib.transforms.BlendedGenericTransform:1" ], - "matplotlib.tri.trifinder.TriFinder": [ - "lib/matplotlib/tri/trifinder.py:docstring of matplotlib.tri.trifinder.TrapezoidMapTriFinder:1" - ], - "matplotlib.tri.triinterpolate.TriInterpolator": [ - "lib/matplotlib/tri/triinterpolate.py:docstring of matplotlib.tri.triinterpolate.CubicTriInterpolator:1", - "lib/matplotlib/tri/triinterpolate.py:docstring of matplotlib.tri.triinterpolate.LinearTriInterpolator:1" - ], - "matplotlib.tri.trirefine.TriRefiner": [ - "lib/matplotlib/tri/trirefine.py:docstring of matplotlib.tri.trirefine.UniformTriRefiner:1" - ], "matplotlib.widgets._SelectorWidget": [ "lib/matplotlib/widgets.py:docstring of matplotlib.widgets.LassoSelector:1", "lib/matplotlib/widgets.py:docstring of matplotlib.widgets.PolygonSelector:1", @@ -485,7 +461,7 @@ "lib/mpl_toolkits/axisartist/axislines.py:docstring of mpl_toolkits.axisartist.axislines.AxisArtistHelper.Fixed:1", "lib/mpl_toolkits/axisartist/axislines.py:docstring of mpl_toolkits.axisartist.axislines.AxisArtistHelper.Floating:1" ], - "mpl_toolkits.axisartist.floating_axes.Floating AxesHostAxes": [ + "mpl_toolkits.axisartist.floating_axes.FloatingAxesHostAxes": [ ":1", "doc/api/_as_gen/mpl_toolkits.axisartist.floating_axes.rst:31::1" ], @@ -498,11 +474,11 @@ }, "py:data": { "matplotlib.axes.Axes.transAxes": [ - "lib/matplotlib/axes/_axes.py:docstring of matplotlib.axes._axes.Axes.legend:219", - "lib/matplotlib/figure.py:docstring of matplotlib.figure.FigureBase.legend:220", - "lib/matplotlib/legend.py:docstring of matplotlib.legend.Legend:179", - "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.figlegend:220", - "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.legend:219" + "lib/matplotlib/axes/_axes.py:docstring of matplotlib.axes._axes.Axes.legend:222", + "lib/matplotlib/figure.py:docstring of matplotlib.figure.FigureBase.legend:223", + "lib/matplotlib/legend.py:docstring of matplotlib.legend.Legend:182", + "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.figlegend:223", + "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.legend:222" ] }, "py:func": { @@ -541,7 +517,6 @@ ], "_iter_collection": [ "lib/matplotlib/backend_bases.py:docstring of matplotlib.backend_bases.RendererBase.draw_path_collection:12", - "lib/matplotlib/backends/backend_agg.py:docstring of matplotlib.backends.backend_agg.RendererAgg.draw_path_collection:12", "lib/matplotlib/backends/backend_pdf.py:docstring of matplotlib.backends.backend_pdf.RendererPdf.draw_path_collection:12", "lib/matplotlib/backends/backend_ps.py:docstring of matplotlib.backends.backend_ps.RendererPS.draw_path_collection:12", "lib/matplotlib/backends/backend_svg.py:docstring of matplotlib.backends.backend_svg.RendererSVG.draw_path_collection:12", @@ -549,7 +524,6 @@ ], "_iter_collection_raw_paths": [ "lib/matplotlib/backend_bases.py:docstring of matplotlib.backend_bases.RendererBase.draw_path_collection:12", - "lib/matplotlib/backends/backend_agg.py:docstring of matplotlib.backends.backend_agg.RendererAgg.draw_path_collection:12", "lib/matplotlib/backends/backend_pdf.py:docstring of matplotlib.backends.backend_pdf.RendererPdf.draw_path_collection:12", "lib/matplotlib/backends/backend_ps.py:docstring of matplotlib.backends.backend_ps.RendererPS.draw_path_collection:12", "lib/matplotlib/backends/backend_svg.py:docstring of matplotlib.backends.backend_svg.RendererSVG.draw_path_collection:12", @@ -574,24 +548,22 @@ "lib/matplotlib/transforms.py:docstring of matplotlib.transforms.Affine2DBase:13" ], "matplotlib.collections._CollectionWithSizes.set_sizes": [ - "lib/matplotlib/axes/_axes.py:docstring of matplotlib.axes._axes.Axes.barbs:172", - "lib/matplotlib/axes/_axes.py:docstring of matplotlib.axes._axes.Axes.broken_barh:82", - "lib/matplotlib/axes/_axes.py:docstring of matplotlib.axes._axes.Axes.fill_between:112", - "lib/matplotlib/axes/_axes.py:docstring of matplotlib.axes._axes.Axes.fill_betweenx:112", - "lib/matplotlib/axes/_axes.py:docstring of matplotlib.axes._axes.Axes.hexbin:168", - "lib/matplotlib/axes/_axes.py:docstring of matplotlib.axes._axes.Axes.pcolor:165", - "lib/matplotlib/axes/_axes.py:docstring of matplotlib.axes._axes.Axes.quiver:202", - "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.barbs:172", - "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.broken_barh:82", - "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.fill_between:112", - "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.fill_betweenx:112", - "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.hexbin:168", - "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.pcolor:165", - "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.quiver:202", - "lib/matplotlib/quiver.py:docstring of matplotlib.quiver.Barbs.__init__:176", - "lib/matplotlib/quiver.py:docstring of matplotlib.quiver.Barbs:206", - "lib/matplotlib/quiver.py:docstring of matplotlib.quiver.Quiver.__init__:206", - "lib/matplotlib/quiver.py:docstring of matplotlib.quiver.Quiver:239" + "lib/matplotlib/axes/_axes.py:docstring of matplotlib.axes._axes.Axes.barbs:171", + "lib/matplotlib/axes/_axes.py:docstring of matplotlib.axes._axes.Axes.broken_barh:81", + "lib/matplotlib/axes/_axes.py:docstring of matplotlib.axes._axes.Axes.fill_between:111", + "lib/matplotlib/axes/_axes.py:docstring of matplotlib.axes._axes.Axes.fill_betweenx:111", + "lib/matplotlib/axes/_axes.py:docstring of matplotlib.axes._axes.Axes.hexbin:167", + "lib/matplotlib/axes/_axes.py:docstring of matplotlib.axes._axes.Axes.pcolor:164", + "lib/matplotlib/axes/_axes.py:docstring of matplotlib.axes._axes.Axes.quiver:201", + "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.barbs:171", + "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.broken_barh:81", + "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.fill_between:111", + "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.fill_betweenx:111", + "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.hexbin:167", + "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.pcolor:164", + "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.quiver:201", + "lib/matplotlib/quiver.py:docstring of matplotlib.quiver.Barbs:205", + "lib/matplotlib/quiver.py:docstring of matplotlib.quiver.Quiver:238" ], "matplotlib.dates.DateFormatter.__call__": [ "doc/users/prev_whats_new/whats_new_1.5.rst:497" @@ -727,7 +699,6 @@ "doc/users/event_handling.rst:179" ], "Size.from_any": [ - "lib/mpl_toolkits/axes_grid1/axes_grid.py:docstring of mpl_toolkits.axes_grid1.axes_grid.ImageGrid.__init__:57", "lib/mpl_toolkits/axes_grid1/axes_grid.py:docstring of mpl_toolkits.axes_grid1.axes_grid.ImageGrid:57", "lib/mpl_toolkits/axisartist/axes_grid.py:docstring of mpl_toolkits.axisartist.axes_grid.ImageGrid:57" ], diff --git a/lib/matplotlib/axes/_subplots.py b/lib/matplotlib/axes/_subplots.py index 5e8d3822fa53..beefc077f703 100644 --- a/lib/matplotlib/axes/_subplots.py +++ b/lib/matplotlib/axes/_subplots.py @@ -1,6 +1,4 @@ -import functools - -from matplotlib import _api +from matplotlib import _api, cbook from matplotlib.axes._axes import Axes from matplotlib.gridspec import GridSpec, SubplotSpec @@ -36,15 +34,6 @@ def __init__(self, fig, *args, **kwargs): # This will also update the axes position. self.set_subplotspec(SubplotSpec._from_subplot_args(fig, args)) - def __reduce__(self): - # get the first axes class which does not inherit from a subplotbase - axes_class = next( - c for c in type(self).__mro__ - if issubclass(c, Axes) and not issubclass(c, SubplotBase)) - return (_picklable_subplot_class_constructor, - (axes_class,), - self.__getstate__()) - @_api.deprecated( "3.4", alternative="get_subplotspec", addendum="(get_subplotspec returns a SubplotSpec instance.)") @@ -169,53 +158,6 @@ def _make_twin_axes(self, *args, **kwargs): return twin -# this here to support cartopy which was using a private part of the -# API to register their Axes subclasses. - -# In 3.1 this should be changed to a dict subclass that warns on use -# In 3.3 to a dict subclass that raises a useful exception on use -# In 3.4 should be removed - -# The slow timeline is to give cartopy enough time to get several -# release out before we break them. -_subplot_classes = {} - - -@functools.lru_cache(None) -def subplot_class_factory(axes_class=None): - """ - Make a new class that inherits from `.SubplotBase` and the - given axes_class (which is assumed to be a subclass of `.axes.Axes`). - This is perhaps a little bit roundabout to make a new class on - the fly like this, but it means that a new Subplot class does - not have to be created for every type of Axes. - """ - if axes_class is None: - _api.warn_deprecated( - "3.3", message="Support for passing None to subplot_class_factory " - "is deprecated since %(since)s; explicitly pass the default Axes " - "class instead. This will become an error %(removal)s.") - axes_class = Axes - try: - # Avoid creating two different instances of GeoAxesSubplot... - # Only a temporary backcompat fix. This should be removed in - # 3.4 - return next(cls for cls in SubplotBase.__subclasses__() - if cls.__bases__ == (SubplotBase, axes_class)) - except StopIteration: - return type("%sSubplot" % axes_class.__name__, - (SubplotBase, axes_class), - {'_axes_class': axes_class}) - - +subplot_class_factory = cbook._make_class_factory( + SubplotBase, "{}Subplot", "_axes_class") Subplot = subplot_class_factory(Axes) # Provided for backward compatibility. - - -def _picklable_subplot_class_constructor(axes_class): - """ - Stub factory that returns an empty instance of the appropriate subplot - class when called with an axes class. This is purely to allow pickling of - Axes and Subplots. - """ - subplot_class = subplot_class_factory(axes_class) - return subplot_class.__new__(subplot_class) diff --git a/lib/matplotlib/cbook/__init__.py b/lib/matplotlib/cbook/__init__.py index d334d48eafb2..4f080f8e6fe1 100644 --- a/lib/matplotlib/cbook/__init__.py +++ b/lib/matplotlib/cbook/__init__.py @@ -2188,3 +2188,53 @@ def _unikey_or_keysym_to_mplkey(unikey, keysym): "next": "pagedown", # Used by tk. }.get(key, key) return key + + +@functools.lru_cache(None) +def _make_class_factory(mixin_class, fmt, attr_name=None): + """ + Return a function that creates picklable classes inheriting from a mixin. + + After :: + + factory = _make_class_factory(FooMixin, fmt, attr_name) + FooAxes = factory(Axes) + + ``Foo`` is a class that inherits from ``FooMixin`` and ``Axes`` and **is + picklable** (picklability is what differentiates this from a plain call to + `type`). Its ``__name__`` is set to ``fmt.format(Axes.__name__)`` and the + base class is stored in the ``attr_name`` attribute, if not None. + + Moreover, the return value of ``factory`` is memoized: calls with the same + ``Axes`` class always return the same subclass. + """ + + @functools.lru_cache(None) + def class_factory(axes_class): + # The parameter is named "axes_class" for backcompat but is really just + # a base class; no axes semantics are used. + base_class = axes_class + + class subcls(mixin_class, base_class): + # Better approximation than __module__ = "matplotlib.cbook". + __module__ = mixin_class.__module__ + + def __reduce__(self): + return (_picklable_class_constructor, + (mixin_class, fmt, attr_name, base_class), + self.__getstate__()) + + subcls.__name__ = subcls.__qualname__ = fmt.format(base_class.__name__) + if attr_name is not None: + setattr(subcls, attr_name, base_class) + return subcls + + class_factory.__module__ = mixin_class.__module__ + return class_factory + + +def _picklable_class_constructor(mixin_class, fmt, attr_name, base_class): + """Internal helper for _make_class_factory.""" + factory = _make_class_factory(mixin_class, fmt, attr_name) + cls = factory(base_class) + return cls.__new__(cls) diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 3736888fdde5..184e513d5a69 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -6340,21 +6340,6 @@ def test_spines_properbbox_after_zoom(): np.testing.assert_allclose(bb.get_points(), bb2.get_points(), rtol=1e-6) -def test_cartopy_backcompat(): - - class Dummy(matplotlib.axes.Axes): - ... - - class DummySubplot(matplotlib.axes.SubplotBase, Dummy): - _axes_class = Dummy - - matplotlib.axes._subplots._subplot_classes[Dummy] = DummySubplot - - FactoryDummySubplot = matplotlib.axes.subplot_class_factory(Dummy) - - assert DummySubplot is FactoryDummySubplot - - def test_gettightbbox_ignore_nan(): fig, ax = plt.subplots() remove_ticks_and_titles(fig) diff --git a/lib/matplotlib/tests/test_pickle.py b/lib/matplotlib/tests/test_pickle.py index 5c169cb23303..c8b9260bc291 100644 --- a/lib/matplotlib/tests/test_pickle.py +++ b/lib/matplotlib/tests/test_pickle.py @@ -10,6 +10,7 @@ import matplotlib.pyplot as plt import matplotlib.transforms as mtransforms import matplotlib.figure as mfigure +from mpl_toolkits.axes_grid1 import parasite_axes def test_simple(): @@ -212,3 +213,8 @@ def test_unpickle_canvas(): out.seek(0) fig2 = pickle.load(out) assert fig2.canvas is not None + + +def test_mpl_toolkits(): + ax = parasite_axes.host_axes([0, 0, 1, 1]) + assert type(pickle.loads(pickle.dumps(ax))) == parasite_axes.HostAxes diff --git a/lib/mpl_toolkits/axes_grid1/parasite_axes.py b/lib/mpl_toolkits/axes_grid1/parasite_axes.py index 7aba5d9efa19..a140be9ef260 100644 --- a/lib/mpl_toolkits/axes_grid1/parasite_axes.py +++ b/lib/mpl_toolkits/axes_grid1/parasite_axes.py @@ -1,6 +1,6 @@ import functools -from matplotlib import _api +from matplotlib import _api, cbook import matplotlib.artist as martist import matplotlib.image as mimage import matplotlib.transforms as mtransforms @@ -95,12 +95,8 @@ def apply_aspect(self, position=None): # end of aux_transform support -@functools.lru_cache(None) -def parasite_axes_class_factory(axes_class): - return type("%sParasite" % axes_class.__name__, - (ParasiteAxesBase, axes_class), {}) - - +parasite_axes_class_factory = cbook._make_class_factory( + ParasiteAxesBase, "{}Parasite") ParasiteAxes = parasite_axes_class_factory(Axes) @@ -277,7 +273,7 @@ def _add_twin_axes(self, axes_class, **kwargs): *kwargs* are forwarded to the parasite axes constructor. """ if axes_class is None: - axes_class = self._get_base_axes() + axes_class = self._base_axes_class ax = parasite_axes_class_factory(axes_class)(self, **kwargs) self.parasites.append(ax) ax._remove_method = self._remove_any_twin @@ -304,11 +300,10 @@ def get_tightbbox(self, renderer, call_axes_locator=True, return Bbox.union([b for b in bbs if b.width != 0 or b.height != 0]) -@functools.lru_cache(None) -def host_axes_class_factory(axes_class): - return type("%sHostAxes" % axes_class.__name__, - (HostAxesBase, axes_class), - {'_get_base_axes': lambda self: axes_class}) +host_axes_class_factory = cbook._make_class_factory( + HostAxesBase, "{}HostAxes", "_base_axes_class") +HostAxes = host_axes_class_factory(Axes) +SubplotHost = subplot_class_factory(HostAxes) def host_subplot_class_factory(axes_class): @@ -317,10 +312,6 @@ def host_subplot_class_factory(axes_class): return subplot_host_class -HostAxes = host_axes_class_factory(Axes) -SubplotHost = subplot_class_factory(HostAxes) - - def host_axes(*args, axes_class=Axes, figure=None, **kwargs): """ Create axes that can act as a hosts to parasitic axes. diff --git a/lib/mpl_toolkits/axisartist/floating_axes.py b/lib/mpl_toolkits/axisartist/floating_axes.py index 32fdedad0d27..ac146729b8d0 100644 --- a/lib/mpl_toolkits/axisartist/floating_axes.py +++ b/lib/mpl_toolkits/axisartist/floating_axes.py @@ -5,10 +5,9 @@ # TODO : # see if tick_iterator method can be simplified by reusing the parent method. -import functools - import numpy as np +from matplotlib import cbook import matplotlib.patches as mpatches from matplotlib.path import Path import matplotlib.axes as maxes @@ -351,12 +350,8 @@ def adjust_axes_lim(self): self.set_ylim(ymin-dy, ymax+dy) -@functools.lru_cache(None) -def floatingaxes_class_factory(axes_class): - return type("Floating %s" % axes_class.__name__, - (FloatingAxesBase, axes_class), {}) - - +floatingaxes_class_factory = cbook._make_class_factory( + FloatingAxesBase, "Floating{}") FloatingAxes = floatingaxes_class_factory( host_axes_class_factory(axislines.Axes)) FloatingSubplot = maxes.subplot_class_factory(FloatingAxes) 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