1616
1717import six
1818
19- import warnings
2019from operator import itemgetter
20+ import warnings
2121
2222import numpy as np
2323
@@ -73,6 +73,7 @@ class AxesStack(Stack):
7373
7474 """
7575 def __init__ (self ):
76+ cbook .warn_deprecated ("2.0" )
7677 Stack .__init__ (self )
7778 self ._ind = 0
7879
@@ -157,6 +158,68 @@ def __contains__(self, a):
157158 return a in self .as_list ()
158159
159160
161+ class _AxesStack (object ):
162+ """Lightweight stack that tracks Axes in a Figure.
163+ """
164+
165+ # We do not subclass the Stack class from cbook to avoid hashability
166+ # issues.
167+
168+ def __init__ (self ):
169+ self ._keys = []
170+ self ._axes = []
171+ self ._axes_ordered = []
172+
173+ def as_list (self ):
174+ """Copy of the list of axes, in the order of insertion.
175+ """
176+ return self ._axes_ordered [:]
177+
178+ def get (self , key ):
179+ """Find the axes corresponding to a key; defaults to `None`.
180+ """
181+ try :
182+ return self ._axes [self ._keys .index (key )]
183+ except ValueError :
184+ return None
185+
186+ def current_key_axes (self ):
187+ """Return the topmost key, axes pair, or `None, None` if empty.
188+ """
189+ return (self ._keys [- 1 ], self ._axes [- 1 ]) if self ._keys else (None , None )
190+
191+ def add (self , key , ax ):
192+ """Append a key, axes pair, unless the axes are already present.
193+ """
194+ # Skipping existing Axes is needed to support calling `add_axes` with
195+ # an already existing Axes.
196+ if ax in self ._axes_ordered :
197+ return
198+ self ._keys .append (key )
199+ self ._axes .append (ax )
200+ self ._axes_ordered .append (ax )
201+
202+ def bubble (self , ax ):
203+ """Move an axes and its corresponding key to the top.
204+ """
205+ idx = self ._axes .index (ax )
206+ self ._keys .append (self ._keys [idx ])
207+ self ._axes .append (self ._axes [idx ])
208+ del self ._keys [idx ], self ._axes [idx ]
209+
210+ def remove (self , ax ):
211+ """Remove an axes and its corresponding key.
212+ """
213+ del self ._keys [self ._axes .index (ax )]
214+ self ._axes .remove (ax )
215+ self ._axes_ordered .remove (ax )
216+
217+ def clear (self ):
218+ """Clear the stack.
219+ """
220+ del self ._keys [:], self ._axes [:], self ._axes_ordered [:]
221+
222+
160223class SubplotParams (object ):
161224 """
162225 A class to hold the parameters for a subplot
@@ -350,7 +413,7 @@ def __init__(self,
350413 self .subplotpars = subplotpars
351414 self .set_tight_layout (tight_layout )
352415
353- self ._axstack = AxesStack () # track all figure axes and current axes
416+ self ._axstack = _AxesStack () # track all figure axes and current axes
354417 self .clf ()
355418 self ._cachedRenderer = None
356419
@@ -398,10 +461,8 @@ def show(self, warn=True):
398461 "matplotlib is currently using a non-GUI backend, "
399462 "so cannot show the figure" )
400463
401- def _get_axes (self ):
402- return self ._axstack .as_list ()
403-
404- axes = property (fget = _get_axes , doc = "Read-only: list of axes in Figure" )
464+ axes = property (lambda self : self ._axstack .as_list (),
465+ doc = "Read-only: list of axes in Figure" )
405466
406467 def _get_dpi (self ):
407468 return self ._dpi
@@ -812,36 +873,6 @@ def delaxes(self, a):
812873 func (self )
813874 self .stale = True
814875
815- def _make_key (self , * args , ** kwargs ):
816- 'make a hashable key out of args and kwargs'
817-
818- def fixitems (items ):
819- #items may have arrays and lists in them, so convert them
820- # to tuples for the key
821- ret = []
822- for k , v in items :
823- # some objects can define __getitem__ without being
824- # iterable and in those cases the conversion to tuples
825- # will fail. So instead of using the iterable(v) function
826- # we simply try and convert to a tuple, and proceed if not.
827- try :
828- v = tuple (v )
829- except Exception :
830- pass
831- ret .append ((k , v ))
832- return tuple (ret )
833-
834- def fixlist (args ):
835- ret = []
836- for a in args :
837- if iterable (a ):
838- a = tuple (a )
839- ret .append (a )
840- return tuple (ret )
841-
842- key = fixlist (args ), fixitems (six .iteritems (kwargs ))
843- return key
844-
845876 @docstring .dedent_interpd
846877 def add_axes (self , * args , ** kwargs ):
847878 """
@@ -895,9 +926,9 @@ def add_axes(self, *args, **kwargs):
895926
896927 # shortcut the projection "key" modifications later on, if an axes
897928 # with the exact args/kwargs exists, return it immediately.
898- key = self . _make_key ( * args , ** kwargs )
929+ key = ( args , kwargs )
899930 ax = self ._axstack .get (key )
900- if ax is not None :
931+ if ax :
901932 self .sca (ax )
902933 return ax
903934
@@ -914,7 +945,7 @@ def add_axes(self, *args, **kwargs):
914945 # check that an axes of this type doesn't already exist, if it
915946 # does, set it as active and return it
916947 ax = self ._axstack .get (key )
917- if ax is not None and isinstance (ax , projection_class ):
948+ if isinstance (ax , projection_class ):
918949 self .sca (ax )
919950 return ax
920951
@@ -988,15 +1019,14 @@ def add_subplot(self, *args, **kwargs):
9881019 raise ValueError (msg )
9891020 # make a key for the subplot (which includes the axes object id
9901021 # in the hash)
991- key = self . _make_key ( * args , ** kwargs )
1022+ key = ( args , kwargs )
9921023 else :
9931024 projection_class , kwargs , key = process_projection_requirements (
9941025 self , * args , ** kwargs )
9951026
9961027 # try to find the axes with this key in the stack
9971028 ax = self ._axstack .get (key )
998-
999- if ax is not None :
1029+ if ax :
10001030 if isinstance (ax , projection_class ):
10011031 # the axes already existed, so set it as active & return
10021032 self .sca (ax )
@@ -1496,7 +1526,7 @@ def _gci(self):
14961526 do not use elsewhere.
14971527 """
14981528 # Look first for an image in the current Axes:
1499- cax = self ._axstack .current_key_axes ()[ 1 ]
1529+ ckey , cax = self ._axstack .current_key_axes ()
15001530 if cax is None :
15011531 return None
15021532 im = cax ._gci ()
0 commit comments