16
16
17
17
import six
18
18
19
- import warnings
20
19
from operator import itemgetter
20
+ import warnings
21
21
22
22
import numpy as np
23
23
@@ -73,6 +73,7 @@ class AxesStack(Stack):
73
73
74
74
"""
75
75
def __init__ (self ):
76
+ cbook .warn_deprecated ("2.0" )
76
77
Stack .__init__ (self )
77
78
self ._ind = 0
78
79
@@ -157,6 +158,59 @@ def __contains__(self, a):
157
158
return a in self .as_list ()
158
159
159
160
161
+ class _AxesStack (object ):
162
+ """Lightweight stack that tracks Axes in a Figure.
163
+ """
164
+
165
+ def __init__ (self ):
166
+ # We maintain a list of (creation_index, key, axes) tuples.
167
+ self ._items = []
168
+ self ._created = 0
169
+
170
+ def as_list (self ):
171
+ """Copy of the list of axes, in the order of insertion.
172
+ """
173
+ return [ax for _ , _ , ax in sorted (self ._items )]
174
+
175
+ def get (self , key ):
176
+ """Find the axes corresponding to a key; defaults to `None`.
177
+ """
178
+ return next ((ax for _ , k , ax in self ._items if k == key ), None )
179
+
180
+ def current_key_axes (self ):
181
+ """Return the topmost key, axes pair, or `None, None` if empty.
182
+ """
183
+ _ , key , ax = (self ._items or [(None , None , None )])[- 1 ]
184
+ return key , ax
185
+
186
+ def add (self , key , ax ):
187
+ """Append a key, axes pair, unless the axes are already present.
188
+ """
189
+ # Skipping existing Axes is needed to support calling `add_axes` with
190
+ # an already existing Axes.
191
+ if not any (a == ax for _ , _ , a in self ._items ):
192
+ self ._items .append ((self ._created , key , ax ))
193
+ self ._created += 1
194
+
195
+ def bubble (self , ax ):
196
+ """Move an axes and its corresponding key to the top.
197
+ """
198
+ idx , = (idx for idx , (_ , _ , a ) in enumerate (self ._items ) if a == ax )
199
+ self ._items .append (self ._items [idx ])
200
+ del self ._items [idx ]
201
+
202
+ def remove (self , ax ):
203
+ """Remove an axes and its corresponding key.
204
+ """
205
+ idx , = (idx for idx , (_ , _ , a ) in enumerate (self ._items ) if a == ax )
206
+ del self ._items [idx ]
207
+
208
+ def clear (self ):
209
+ """Clear the stack.
210
+ """
211
+ del self ._items [:]
212
+
213
+
160
214
class SubplotParams (object ):
161
215
"""
162
216
A class to hold the parameters for a subplot
@@ -350,7 +404,7 @@ def __init__(self,
350
404
self .subplotpars = subplotpars
351
405
self .set_tight_layout (tight_layout )
352
406
353
- self ._axstack = AxesStack () # track all figure axes and current axes
407
+ self ._axstack = _AxesStack () # track all figure axes and current axes
354
408
self .clf ()
355
409
self ._cachedRenderer = None
356
410
@@ -398,10 +452,8 @@ def show(self, warn=True):
398
452
"matplotlib is currently using a non-GUI backend, "
399
453
"so cannot show the figure" )
400
454
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" )
455
+ axes = property (lambda self : self ._axstack .as_list (),
456
+ doc = "Read-only: list of axes in Figure" )
405
457
406
458
def _get_dpi (self ):
407
459
return self ._dpi
@@ -812,36 +864,6 @@ def delaxes(self, a):
812
864
func (self )
813
865
self .stale = True
814
866
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
867
@docstring .dedent_interpd
846
868
def add_axes (self , * args , ** kwargs ):
847
869
"""
@@ -895,9 +917,9 @@ def add_axes(self, *args, **kwargs):
895
917
896
918
# shortcut the projection "key" modifications later on, if an axes
897
919
# with the exact args/kwargs exists, return it immediately.
898
- key = self . _make_key ( * args , ** kwargs )
920
+ key = ( args , kwargs )
899
921
ax = self ._axstack .get (key )
900
- if ax is not None :
922
+ if ax :
901
923
self .sca (ax )
902
924
return ax
903
925
@@ -914,7 +936,7 @@ def add_axes(self, *args, **kwargs):
914
936
# check that an axes of this type doesn't already exist, if it
915
937
# does, set it as active and return it
916
938
ax = self ._axstack .get (key )
917
- if ax is not None and isinstance (ax , projection_class ):
939
+ if isinstance (ax , projection_class ):
918
940
self .sca (ax )
919
941
return ax
920
942
@@ -988,15 +1010,14 @@ def add_subplot(self, *args, **kwargs):
988
1010
raise ValueError (msg )
989
1011
# make a key for the subplot (which includes the axes object id
990
1012
# in the hash)
991
- key = self . _make_key ( * args , ** kwargs )
1013
+ key = ( args , kwargs )
992
1014
else :
993
1015
projection_class , kwargs , key = process_projection_requirements (
994
1016
self , * args , ** kwargs )
995
1017
996
1018
# try to find the axes with this key in the stack
997
1019
ax = self ._axstack .get (key )
998
-
999
- if ax is not None :
1020
+ if ax :
1000
1021
if isinstance (ax , projection_class ):
1001
1022
# the axes already existed, so set it as active & return
1002
1023
self .sca (ax )
@@ -1496,7 +1517,7 @@ def _gci(self):
1496
1517
do not use elsewhere.
1497
1518
"""
1498
1519
# Look first for an image in the current Axes:
1499
- cax = self ._axstack .current_key_axes ()[ 1 ]
1520
+ ckey , cax = self ._axstack .current_key_axes ()
1500
1521
if cax is None :
1501
1522
return None
1502
1523
im = cax ._gci ()
0 commit comments