Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4c33d97

Browse files
authored
Merge pull request #7377 from anntzer/private-axesstack
ENH: Switch to a private, simpler AxesStack.
2 parents 2c872e3 + 0022611 commit 4c33d97

File tree

2 files changed

+67
-47
lines changed

2 files changed

+67
-47
lines changed

lib/matplotlib/figure.py

Lines changed: 66 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class AxesStack(Stack):
7272
7373
"""
7474
def __init__(self):
75+
cbook.warn_deprecated("2.1")
7576
Stack.__init__(self)
7677
self._ind = 0
7778

@@ -158,6 +159,62 @@ def __contains__(self, a):
158159
return a in self.as_list()
159160

160161

162+
class _AxesStack(object):
163+
"""Lightweight stack that tracks Axes in a Figure.
164+
"""
165+
166+
def __init__(self):
167+
# We maintain a list of (creation_index, key, axes) tuples.
168+
# We do not use an OrderedDict because 1. the keys may not be hashable
169+
# and 2. we need to directly find a pair corresponding to an axes (i.e.
170+
# we'd really need a two-way dict).
171+
self._items = []
172+
self._created = 0
173+
174+
def as_list(self):
175+
"""Copy of the list of axes, in the order of insertion.
176+
"""
177+
return [ax for _, _, ax in sorted(self._items)]
178+
179+
def get(self, key):
180+
"""Find the axes corresponding to a key; defaults to `None`.
181+
"""
182+
return next((ax for _, k, ax in self._items if k == key), None)
183+
184+
def current_key_axes(self):
185+
"""Return the topmost `(key, axes)` pair, or `(None, None)` if empty.
186+
"""
187+
_, key, ax = (self._items or [(None, None, None)])[-1]
188+
return key, ax
189+
190+
def add(self, key, ax):
191+
"""Append a `(key, axes)` pair, unless the axes are already present.
192+
"""
193+
# Skipping existing Axes is needed to support calling `add_axes` with
194+
# an already existing Axes.
195+
if not any(a == ax for _, _, a in self._items):
196+
self._items.append((self._created, key, ax))
197+
self._created += 1
198+
199+
def bubble(self, ax):
200+
"""Move an axes and its corresponding key to the top.
201+
"""
202+
idx, = (idx for idx, (_, _, a) in enumerate(self._items) if a == ax)
203+
self._items.append(self._items[idx])
204+
del self._items[idx]
205+
206+
def remove(self, ax):
207+
"""Remove an axes and its corresponding key.
208+
"""
209+
idx, = (idx for idx, (_, _, a) in enumerate(self._items) if a == ax)
210+
del self._items[idx]
211+
212+
def clear(self):
213+
"""Clear the stack.
214+
"""
215+
del self._items[:]
216+
217+
161218
class SubplotParams(object):
162219
"""
163220
A class to hold the parameters for a subplot
@@ -358,7 +415,7 @@ def __init__(self,
358415
self.subplotpars = subplotpars
359416
self.set_tight_layout(tight_layout)
360417

361-
self._axstack = AxesStack() # track all figure axes and current axes
418+
self._axstack = _AxesStack() # track all figure axes and current axes
362419
self.clf()
363420
self._cachedRenderer = None
364421

@@ -410,10 +467,8 @@ def show(self, warn=True):
410467
"matplotlib is currently using a non-GUI backend, "
411468
"so cannot show the figure")
412469

413-
def _get_axes(self):
414-
return self._axstack.as_list()
415-
416-
axes = property(fget=_get_axes, doc="Read-only: list of axes in Figure")
470+
axes = property(lambda self: self._axstack.as_list(),
471+
doc="Read-only: list of axes in Figure")
417472

418473
def _get_dpi(self):
419474
return self._dpi
@@ -835,36 +890,6 @@ def delaxes(self, a):
835890
func(self)
836891
self.stale = True
837892

838-
def _make_key(self, *args, **kwargs):
839-
'make a hashable key out of args and kwargs'
840-
841-
def fixitems(items):
842-
#items may have arrays and lists in them, so convert them
843-
# to tuples for the key
844-
ret = []
845-
for k, v in items:
846-
# some objects can define __getitem__ without being
847-
# iterable and in those cases the conversion to tuples
848-
# will fail. So instead of using the iterable(v) function
849-
# we simply try and convert to a tuple, and proceed if not.
850-
try:
851-
v = tuple(v)
852-
except Exception:
853-
pass
854-
ret.append((k, v))
855-
return tuple(ret)
856-
857-
def fixlist(args):
858-
ret = []
859-
for a in args:
860-
if iterable(a):
861-
a = tuple(a)
862-
ret.append(a)
863-
return tuple(ret)
864-
865-
key = fixlist(args), fixitems(six.iteritems(kwargs))
866-
return key
867-
868893
def add_axes(self, *args, **kwargs):
869894
"""
870895
Add an axes at position *rect* [*left*, *bottom*, *width*,
@@ -929,9 +954,9 @@ def add_axes(self, *args, **kwargs):
929954

930955
# shortcut the projection "key" modifications later on, if an axes
931956
# with the exact args/kwargs exists, return it immediately.
932-
key = self._make_key(*args, **kwargs)
957+
key = (args, kwargs)
933958
ax = self._axstack.get(key)
934-
if ax is not None:
959+
if ax:
935960
self.sca(ax)
936961
return ax
937962

@@ -951,7 +976,7 @@ def add_axes(self, *args, **kwargs):
951976
# check that an axes of this type doesn't already exist, if it
952977
# does, set it as active and return it
953978
ax = self._axstack.get(key)
954-
if ax is not None and isinstance(ax, projection_class):
979+
if isinstance(ax, projection_class):
955980
self.sca(ax)
956981
return ax
957982

@@ -1037,15 +1062,14 @@ def add_subplot(self, *args, **kwargs):
10371062
raise ValueError(msg)
10381063
# make a key for the subplot (which includes the axes object id
10391064
# in the hash)
1040-
key = self._make_key(*args, **kwargs)
1065+
key = (args, kwargs)
10411066
else:
10421067
projection_class, kwargs, key = process_projection_requirements(
10431068
self, *args, **kwargs)
10441069

10451070
# try to find the axes with this key in the stack
10461071
ax = self._axstack.get(key)
1047-
1048-
if ax is not None:
1072+
if ax:
10491073
if isinstance(ax, projection_class):
10501074
# the axes already existed, so set it as active & return
10511075
self.sca(ax)
@@ -1614,7 +1638,7 @@ def _gci(self):
16141638
do not use elsewhere.
16151639
"""
16161640
# Look first for an image in the current Axes:
1617-
cax = self._axstack.current_key_axes()[1]
1641+
ckey, cax = self._axstack.current_key_axes()
16181642
if cax is None:
16191643
return None
16201644
im = cax._gci()

lib/matplotlib/projections/__init__.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,7 @@ def process_projection_requirements(figure, *args, **kwargs):
9696
raise TypeError('projection must be a string, None or implement a '
9797
'_as_mpl_axes method. Got %r' % projection)
9898

99-
# Make the key without projection kwargs, this is used as a unique
100-
# lookup for axes instances
101-
key = figure._make_key(*args, **kwargs)
102-
103-
return projection_class, kwargs, key
99+
return projection_class, kwargs, (args, kwargs)
104100

105101

106102
def get_projection_names():

0 commit comments

Comments
 (0)