16
16
17
17
import six
18
18
19
- import warnings
20
19
from operator import itemgetter
20
+ import warnings
21
+ from weakref import WeakKeyDictionary
21
22
22
23
import numpy as np
23
24
@@ -73,6 +74,7 @@ class AxesStack(Stack):
73
74
74
75
"""
75
76
def __init__ (self ):
77
+ cbook .warn_deprecated ("2.0" )
76
78
Stack .__init__ (self )
77
79
self ._ind = 0
78
80
@@ -157,6 +159,63 @@ def __contains__(self, a):
157
159
return a in self .as_list ()
158
160
159
161
162
+ class _AxesStack (object ):
163
+ """Lightweight stack that tracks Axes in a Figure.
164
+ """
165
+
166
+ # We do not subclass the Stack class from cbook to avoid hashability
167
+ # issues.
168
+
169
+ def __init__ (self ):
170
+ self ._keys = []
171
+ self ._axes = []
172
+ self ._axes_order = WeakKeyDictionary ()
173
+ self ._index = - 1
174
+
175
+ axes = property (
176
+ lambda self : sorted (self ._axes , key = self ._axes_order .__getitem__ ),
177
+ doc = "Copy of the list of axes, in the order of insertion." )
178
+
179
+ def get (self , key ):
180
+ """Find the axes corresponding to a key; defaults to `None`.
181
+ """
182
+ try :
183
+ return self ._axes [self ._keys .index (key )]
184
+ except ValueError :
185
+ return None
186
+
187
+ def current_key_axes (self ):
188
+ """Return the topmost key, axes pair, or `None, None` if empty.
189
+ """
190
+ return (self ._keys [- 1 ], self ._axes [- 1 ]) if self ._keys else (None , None )
191
+
192
+ def add (self , key , ax ):
193
+ """Append a key, axes pair.
194
+ """
195
+ self ._keys .append (key )
196
+ self ._axes .append (ax )
197
+ self ._axes_order [ax ] = self ._index = self ._index + 1
198
+
199
+ def bubble (self , ax ):
200
+ """Move an axes and its corresponding key to the top.
201
+ """
202
+ idx = self ._axes .index (ax )
203
+ self ._keys .append (self ._keys [idx ])
204
+ self ._axes .append (self ._axes [idx ])
205
+ del self ._keys [idx ], self ._axes [idx ]
206
+
207
+ def remove (self , ax ):
208
+ """Remove an axes and its corresponding key.
209
+ """
210
+ idx = self ._axes .index (ax )
211
+ del self ._keys [idx ], self ._axes [idx ]
212
+
213
+ def clear (self ):
214
+ """Clear the stack.
215
+ """
216
+ del self ._keys [:], self ._axes [:] # Py2 doesn't have list.clear.
217
+
218
+
160
219
class SubplotParams (object ):
161
220
"""
162
221
A class to hold the parameters for a subplot
@@ -350,7 +409,7 @@ def __init__(self,
350
409
self .subplotpars = subplotpars
351
410
self .set_tight_layout (tight_layout )
352
411
353
- self ._axstack = AxesStack () # track all figure axes and current axes
412
+ self ._axstack = _AxesStack () # track all figure axes and current axes
354
413
self .clf ()
355
414
self ._cachedRenderer = None
356
415
@@ -399,7 +458,7 @@ def show(self, warn=True):
399
458
"so cannot show the figure" )
400
459
401
460
def _get_axes (self ):
402
- return self ._axstack .as_list ()
461
+ return self ._axstack .axes
403
462
404
463
axes = property (fget = _get_axes , doc = "Read-only: list of axes in Figure" )
405
464
@@ -812,36 +871,6 @@ def delaxes(self, a):
812
871
func (self )
813
872
self .stale = True
814
873
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
-
845
874
@docstring .dedent_interpd
846
875
def add_axes (self , * args , ** kwargs ):
847
876
"""
@@ -895,9 +924,9 @@ def add_axes(self, *args, **kwargs):
895
924
896
925
# shortcut the projection "key" modifications later on, if an axes
897
926
# with the exact args/kwargs exists, return it immediately.
898
- key = self . _make_key ( * args , ** kwargs )
927
+ key = ( args , kwargs )
899
928
ax = self ._axstack .get (key )
900
- if ax is not None :
929
+ if ax :
901
930
self .sca (ax )
902
931
return ax
903
932
@@ -914,7 +943,7 @@ def add_axes(self, *args, **kwargs):
914
943
# check that an axes of this type doesn't already exist, if it
915
944
# does, set it as active and return it
916
945
ax = self ._axstack .get (key )
917
- if ax is not None and isinstance (ax , projection_class ):
946
+ if isinstance (ax , projection_class ):
918
947
self .sca (ax )
919
948
return ax
920
949
@@ -988,15 +1017,14 @@ def add_subplot(self, *args, **kwargs):
988
1017
raise ValueError (msg )
989
1018
# make a key for the subplot (which includes the axes object id
990
1019
# in the hash)
991
- key = self . _make_key ( * args , ** kwargs )
1020
+ key = ( args , kwargs )
992
1021
else :
993
1022
projection_class , kwargs , key = process_projection_requirements (
994
1023
self , * args , ** kwargs )
995
1024
996
1025
# try to find the axes with this key in the stack
997
1026
ax = self ._axstack .get (key )
998
-
999
- if ax is not None :
1027
+ if ax :
1000
1028
if isinstance (ax , projection_class ):
1001
1029
# the axes already existed, so set it as active & return
1002
1030
self .sca (ax )
@@ -1496,7 +1524,7 @@ def _gci(self):
1496
1524
do not use elsewhere.
1497
1525
"""
1498
1526
# Look first for an image in the current Axes:
1499
- cax = self ._axstack .current_key_axes ()[ 1 ]
1527
+ ckey , cax = self ._axstack .current_key_axes ()
1500
1528
if cax is None :
1501
1529
return None
1502
1530
im = cax ._gci ()
0 commit comments