diff --git a/doc/api/next_api_changes/deprecations/18978-LPS.rst b/doc/api/next_api_changes/deprecations/18978-LPS.rst new file mode 100644 index 000000000000..705f672d33b5 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/18978-LPS.rst @@ -0,0 +1,5 @@ +pyplot.gca() +~~~~~~~~~~~~ + +Passing keyword arguments to ``.pyplot.gca`` will not be supported in a future +release. diff --git a/doc/api/next_api_changes/development/18978-LPS.rst b/doc/api/next_api_changes/development/18978-LPS.rst new file mode 100644 index 000000000000..cd590764492d --- /dev/null +++ b/doc/api/next_api_changes/development/18978-LPS.rst @@ -0,0 +1,8 @@ +Changes to _AxesStack, preparing for its removal +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The behavior of the internal ``.figure._AxesStack`` class has changed +significantly in the process of removing the old behavior of gca() with regard +to keyword arguments. When the deprecated behavior has been fully removed and +gca() no longer takes keyword arguments, the ``.figure._AxesStack`` class will +be removed. diff --git a/doc/users/next_whats_new/axes_kwargs_collision.rst b/doc/users/next_whats_new/axes_kwargs_collision.rst new file mode 100644 index 000000000000..f04f5e3f82b1 --- /dev/null +++ b/doc/users/next_whats_new/axes_kwargs_collision.rst @@ -0,0 +1,18 @@ +Changes to behavior of Axes creation methods (gca(), add_axes(), add_subplot()) +------------------------------------------------------------------------------- + +The behavior of the functions to create new axes (``.pyplot.subplot``, +``.figure.Figure.add_axes``, ``.figure.Figure.add_subplot``) has changed. In +the past, these functions would detect if you were attempting to create Axes +with the same keyword arguments as already-existing axes in the current figure, +and if so, they would return the existing Axes. Now, these functions will +always create new Axes. + +Correspondingly, the behavior of the functions to get the current Axes +(``.pyplot.gca``, ``.figure.Figure.gca``) has changed. In the past, these +functions accepted keyword arguments. If the keyword arguments matched an +already-existing Axes, then that Axes would be returned, otherwise new Axes +would be created with those keyword arguments. Now, an exception is raised if +there are Axes and the current Axes were not created with the same keyword +arguments. In a future release, these functions will not accept keyword +arguments at all. diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 67436b15f444..9e7ea15db0dc 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -58,7 +58,7 @@ class _AxesStack(cbook.Stack): This stack stores ``key, (ind, axes)`` pairs, where: - * **key** is a hash of the args and kwargs used in generating the Axes. + * **key** is a hash of the args used in generating the Axes. * **ind** is a serial index tracking the order in which Axes were added. AxesStack is a callable; calling it returns the current Axes. @@ -85,14 +85,6 @@ def get(self, key): item = dict(self._elements).get(key) if item is None: return None - cbook.warn_deprecated( - "2.1", - message="Adding an axes using the same arguments as a previous " - "axes currently reuses the earlier instance. In a future " - "version, a new instance will always be created and returned. " - "Meanwhile, this warning can be suppressed, and the future " - "behavior ensured, by passing a unique label to each axes " - "instance.") return item[1] def _entry_from_axes(self, e): @@ -114,18 +106,12 @@ def add(self, key, a): """ Add Axes *a*, with key *key*, to the stack, and return the stack. - If *key* is unhashable, replace it by a unique, arbitrary object. - If *a* is already on the stack, don't add it again, but return *None*. """ # All the error checking may be unnecessary; but this method # is called so seldom that the overhead is negligible. cbook._check_isinstance(Axes, a=a) - try: - hash(key) - except TypeError: - key = object() a_existing = self.get(key) if a_existing is not None: @@ -689,19 +675,12 @@ def add_axes(self, *args, **kwargs): "add_axes() got multiple values for argument 'rect'") args = (kwargs.pop('rect'), ) - # shortcut the projection "key" modifications later on, if an axes - # with the exact args/kwargs exists, return it immediately. - key = self._make_key(*args, **kwargs) - ax = self._axstack.get(key) - if ax is not None: - self.sca(ax) - return ax - if isinstance(args[0], Axes): a = args[0] if a.get_figure() is not self: raise ValueError( "The Axes must have been created in the present figure") + key = self._make_key(*args) else: rect = args[0] if not np.isfinite(rect).all(): @@ -848,7 +827,7 @@ def add_subplot(self, *args, **kwargs): "the present figure") # make a key for the subplot (which includes the axes object id # in the hash) - key = self._make_key(*args, **kwargs) + key = self._make_key(*args) else: if not args: @@ -1601,36 +1580,23 @@ def gca(self, **kwargs): %(Axes)s """ + if kwargs: + cbook.warn_deprecated( + "3.4", + message="Calling gca() with keyword arguments is deprecated. " + "gca() no longer checks whether the keyword arguments match " + "those with which the current axes were created. In a future " + "version, gca() will take no keyword arguments. The gca() " + "function should only be used to get the current axes, or if " + "no axes exist, create new axes with default keyword " + "arguments. To create a new axes with non-default arguments, " + "use plt.axes() or plt.subplot().") + ckey, cax = self._axstack.current_key_axes() # if there exists an axes on the stack see if it matches # the desired axes configuration if cax is not None: - - # if no kwargs are given just return the current axes - # this is a convenience for gca() on axes such as polar etc. - if not kwargs: - return cax - - # if the user has specified particular projection detail - # then build up a key which can represent this - else: - projection_class, _, key = \ - self._process_projection_requirements(**kwargs) - - # let the returned axes have any gridspec by removing it from - # the key - ckey = ckey[1:] - key = key[1:] - - # if the cax matches this key then return the axes, otherwise - # continue and a new axes will be created - if key == ckey and isinstance(cax, projection_class): - return cax - else: - cbook._warn_external('Requested projection is different ' - 'from current axis projection, ' - 'creating new axis with requested ' - 'projection.') + return cax # no axes found, so create one which spans the figure return self.add_subplot(1, 1, 1, **kwargs) @@ -1706,28 +1672,12 @@ def _process_projection_requirements( # Make the key without projection kwargs, this is used as a unique # lookup for axes instances - key = self._make_key(*args, **kwargs) + key = self._make_key(*args) return projection_class, kwargs, key - def _make_key(self, *args, **kwargs): - """Make a hashable key out of args and kwargs.""" - - def fixitems(items): - # items may have arrays and lists in them, so convert them - # to tuples for the key - ret = [] - for k, v in items: - # some objects can define __getitem__ without being - # iterable and in those cases the conversion to tuples - # will fail. So instead of using the np.iterable(v) function - # we simply try and convert to a tuple, and proceed if not. - try: - v = tuple(v) - except Exception: - pass - ret.append((k, v)) - return tuple(ret) + def _make_key(self, *args): + """Make a hashable key out of args.""" def fixlist(args): ret = [] @@ -1737,7 +1687,7 @@ def fixlist(args): ret.append(a) return tuple(ret) - key = fixlist(args), fixitems(kwargs.items()) + key = fixlist(args) return key def get_default_bbox_extra_artists(self): diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 7b35433bd3c2..a8a9b81a56bf 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -2410,10 +2410,13 @@ def polar(*args, **kwargs): """ # If an axis already exists, check if it has a polar projection if gcf().get_axes(): - if not isinstance(gca(), PolarAxes): + ax = gca() + if isinstance(ax, PolarAxes): + return ax + else: cbook._warn_external('Trying to create polar plot on an axis ' 'that does not have a polar projection.') - ax = gca(polar=True) + ax = axes(polar=True) ret = ax.plot(*args, **kwargs) return ret diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 49627e9ce433..8d835d705200 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -2387,28 +2387,34 @@ def _as_mpl_axes(self): # testing axes creation with plt.axes ax = plt.axes([0, 0, 1, 1], projection=prj) assert type(ax) == PolarAxes - ax_via_gca = plt.gca(projection=prj) + with pytest.warns( + MatplotlibDeprecationWarning, + match=r'Calling gca\(\) with keyword arguments is deprecated'): + ax_via_gca = plt.gca(projection=prj) assert ax_via_gca is ax plt.close() # testing axes creation with gca - ax = plt.gca(projection=prj) + with pytest.warns( + MatplotlibDeprecationWarning, + match=r'Calling gca\(\) with keyword arguments is deprecated'): + ax = plt.gca(projection=prj) assert type(ax) == mpl.axes._subplots.subplot_class_factory(PolarAxes) - ax_via_gca = plt.gca(projection=prj) + with pytest.warns( + MatplotlibDeprecationWarning, + match=r'Calling gca\(\) with keyword arguments is deprecated'): + ax_via_gca = plt.gca(projection=prj) assert ax_via_gca is ax # try getting the axes given a different polar projection - with pytest.warns(UserWarning) as rec: + with pytest.warns( + MatplotlibDeprecationWarning, + match=r'Calling gca\(\) with keyword arguments is deprecated'): ax_via_gca = plt.gca(projection=prj2) - assert len(rec) == 1 - assert 'Requested projection is different' in str(rec[0].message) - assert ax_via_gca is not ax - assert ax.get_theta_offset() == 0 - assert ax_via_gca.get_theta_offset() == np.pi # try getting the axes given an == (not is) polar projection - with pytest.warns(UserWarning): + with pytest.warns( + MatplotlibDeprecationWarning, + match=r'Calling gca\(\) with keyword arguments is deprecated'): ax_via_gca = plt.gca(projection=prj3) - assert len(rec) == 1 - assert 'Requested projection is different' in str(rec[0].message) assert ax_via_gca is ax plt.close() diff --git a/lib/matplotlib/tests/test_figure.py b/lib/matplotlib/tests/test_figure.py index c5ab3cf6d232..ee796049c6d8 100644 --- a/lib/matplotlib/tests/test_figure.py +++ b/lib/matplotlib/tests/test_figure.py @@ -8,6 +8,7 @@ import matplotlib as mpl from matplotlib import cbook, rcParams +from matplotlib.cbook import MatplotlibDeprecationWarning from matplotlib.testing.decorators import image_comparison, check_figures_equal from matplotlib.axes import Axes from matplotlib.figure import Figure @@ -154,30 +155,42 @@ def test_gca(): assert fig.add_axes() is None ax0 = fig.add_axes([0, 0, 1, 1]) - assert fig.gca(projection='rectilinear') is ax0 + with pytest.warns( + MatplotlibDeprecationWarning, + match=r'Calling gca\(\) with keyword arguments is deprecated'): + assert fig.gca(projection='rectilinear') is ax0 assert fig.gca() is ax0 ax1 = fig.add_axes(rect=[0.1, 0.1, 0.8, 0.8]) - assert fig.gca(projection='rectilinear') is ax1 + with pytest.warns( + MatplotlibDeprecationWarning, + match=r'Calling gca\(\) with keyword arguments is deprecated'): + assert fig.gca(projection='rectilinear') is ax1 assert fig.gca() is ax1 ax2 = fig.add_subplot(121, projection='polar') assert fig.gca() is ax2 - assert fig.gca(polar=True) is ax2 + with pytest.warns( + MatplotlibDeprecationWarning, + match=r'Calling gca\(\) with keyword arguments is deprecated'): + assert fig.gca(polar=True) is ax2 ax3 = fig.add_subplot(122) assert fig.gca() is ax3 # the final request for a polar axes will end up creating one # with a spec of 111. - with pytest.warns(UserWarning): - # Changing the projection will throw a warning - assert fig.gca(polar=True) is not ax3 - assert fig.gca(polar=True) is not ax2 - assert fig.gca().get_subplotspec().get_geometry() == (1, 1, 0, 0) + with pytest.warns( + MatplotlibDeprecationWarning, + match=r'Calling gca\(\) with keyword arguments is deprecated'): + # Changing the projection will raise an exception + fig.gca(polar=True) fig.sca(ax1) - assert fig.gca(projection='rectilinear') is ax1 + with pytest.warns( + MatplotlibDeprecationWarning, + match=r'Calling gca\(\) with keyword arguments is deprecated'): + assert fig.gca(projection='rectilinear') is ax1 assert fig.gca() is ax1 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