From 30ee515dc684cd131a86086a00a3d21c5eeb7217 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sat, 3 Mar 2018 01:42:55 -0800 Subject: [PATCH] Work towards removing reuse-of-axes-on-collision. Currently, Matplotlib reuses axes when add_axes() is called a second time with the same arguments. This behavior is deprecated since 2.1. However we forgot to deprecate the same behavior in gca(), so we can't remove that behavior yet. Also cleanup docstrings of Stack class. Also, process_projection_requirements cannot modify the outer kwargs (because `**kwargs` is always a copy), so remove the incorrect note regarding the need for copies. --- lib/matplotlib/cbook/__init__.py | 45 ++++++++++++++------------ lib/matplotlib/figure.py | 14 +++++--- lib/matplotlib/projections/__init__.py | 10 ++---- 3 files changed, 37 insertions(+), 32 deletions(-) diff --git a/lib/matplotlib/cbook/__init__.py b/lib/matplotlib/cbook/__init__.py index d4d6ce6b2bc4..1e43f4b6f3e2 100644 --- a/lib/matplotlib/cbook/__init__.py +++ b/lib/matplotlib/cbook/__init__.py @@ -1168,9 +1168,9 @@ def __setitem__(self, k, v): class Stack(object): """ - Implement a stack where elements can be pushed on and you can move - back and forth. But no pop. Should mimic home / back / forward - in a browser + Stack of elements with a movable cursor. + + Mimics home/back/forward in a web browser. """ def __init__(self, default=None): @@ -1178,62 +1178,65 @@ def __init__(self, default=None): self._default = default def __call__(self): - """return the current element, or None""" + """Return the current element, or None.""" if not len(self._elements): return self._default else: return self._elements[self._pos] def __len__(self): - return self._elements.__len__() + return len(self._elements) def __getitem__(self, ind): - return self._elements.__getitem__(ind) + return self._elements[ind] def forward(self): - """move the position forward and return the current element""" - n = len(self._elements) - if self._pos < n - 1: - self._pos += 1 + """Move the position forward and return the current element.""" + self._pos = min(self._pos + 1, len(self._elements) - 1) return self() def back(self): - """move the position back and return the current element""" + """Move the position back and return the current element.""" if self._pos > 0: self._pos -= 1 return self() def push(self, o): """ - push object onto stack at current position - all elements - occurring later than the current position are discarded + Push *o* to the stack at current position. Discard all later elements. + + *o* is returned. """ - self._elements = self._elements[:self._pos + 1] - self._elements.append(o) + self._elements = self._elements[:self._pos + 1] + [o] self._pos = len(self._elements) - 1 return self() def home(self): - """push the first element onto the top of the stack""" + """ + Push the first element onto the top of the stack. + + The first element is returned. + """ if not len(self._elements): return self.push(self._elements[0]) return self() def empty(self): + """Return whether the stack is empty.""" return len(self._elements) == 0 def clear(self): - """empty the stack""" + """Empty the stack.""" self._pos = -1 self._elements = [] def bubble(self, o): """ - raise *o* to the top of the stack and return *o*. *o* must be - in the stack - """ + Raise *o* to the top of the stack. *o* must be present in the stack. + *o* is returned. + """ if o not in self._elements: raise ValueError('Unknown element o') old = self._elements[:] @@ -1249,7 +1252,7 @@ def bubble(self, o): return o def remove(self, o): - 'remove element *o* from the stack' + """Remove *o* from the stack.""" if o not in self._elements: raise ValueError('Unknown element o') old = self._elements[:] diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 7d72a291d949..e8ad7f56bd0f 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -1792,11 +1792,8 @@ def gca(self, **kwargs): # if the user has specified particular projection detail # then build up a key which can represent this else: - # we don't want to modify the original kwargs - # so take a copy so that we can do what we like to it - kwargs_copy = kwargs.copy() projection_class, _, key = process_projection_requirements( - self, **kwargs_copy) + self, **kwargs) # let the returned axes have any gridspec by removing it from # the key @@ -1806,6 +1803,15 @@ def gca(self, **kwargs): # 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): + cbook.warn_deprecated( + "3.0", + "Calling `gca()` 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 cax else: warnings.warn('Requested projection is different from ' diff --git a/lib/matplotlib/projections/__init__.py b/lib/matplotlib/projections/__init__.py index 1e423420b0b6..9e01b4bb4295 100644 --- a/lib/matplotlib/projections/__init__.py +++ b/lib/matplotlib/projections/__init__.py @@ -67,15 +67,11 @@ def get_projection_class(projection=None): def process_projection_requirements(figure, *args, **kwargs): """ - Handle the args/kwargs to for add_axes/add_subplot/gca, - returning:: + Handle the args/kwargs to add_axes/add_subplot/gca, returning:: (axes_proj_class, proj_class_kwargs, proj_stack_key) - Which can be used for new axes initialization/identification. - - .. note:: **kwargs** is modified in place. - + which can be used for new axes initialization/identification. """ ispolar = kwargs.pop('polar', False) projection = kwargs.pop('projection', None) @@ -94,7 +90,7 @@ def process_projection_requirements(figure, *args, **kwargs): kwargs.update(**extra_kwargs) else: raise TypeError('projection must be a string, None or implement a ' - '_as_mpl_axes method. Got %r' % projection) + '_as_mpl_axes method. Got %r' % projection) # Make the key without projection kwargs, this is used as a unique # lookup for axes instances