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,62 @@ 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
+ # We do not use an OrderedDict because 1. the keys may not be hashable
168
+ # and 2. we need to directly find a pair corresponding to an axes (i.e.
169
+ # we'd really need a two-way dict).
170
+ self ._items = []
171
+ self ._created = 0
172
+
173
+ def as_list (self ):
174
+ """Copy of the list of axes, in the order of insertion.
175
+ """
176
+ return [ax for _ , _ , ax in sorted (self ._items )]
177
+
178
+ def get (self , key ):
179
+ """Find the axes corresponding to a key; defaults to `None`.
180
+ """
181
+ return next ((ax for _ , k , ax in self ._items if k == key ), None )
182
+
183
+ def current_key_axes (self ):
184
+ """Return the topmost `(key, axes)` pair, or `(None, None)` if empty.
185
+ """
186
+ _ , key , ax = (self ._items or [(None , None , None )])[- 1 ]
187
+ return key , ax
188
+
189
+ def add (self , key , ax ):
190
+ """Append a `(key, axes)` pair, unless the axes are already present.
191
+ """
192
+ # Skipping existing Axes is needed to support calling `add_axes` with
193
+ # an already existing Axes.
194
+ if not any (a == ax for _ , _ , a in self ._items ):
195
+ self ._items .append ((self ._created , key , ax ))
196
+ self ._created += 1
197
+
198
+ def bubble (self , ax ):
199
+ """Move an axes and its corresponding key to the top.
200
+ """
201
+ idx , = (idx for idx , (_ , _ , a ) in enumerate (self ._items ) if a == ax )
202
+ self ._items .append (self ._items [idx ])
203
+ del self ._items [idx ]
204
+
205
+ def remove (self , ax ):
206
+ """Remove an axes and its corresponding key.
207
+ """
208
+ idx , = (idx for idx , (_ , _ , a ) in enumerate (self ._items ) if a == ax )
209
+ del self ._items [idx ]
210
+
211
+ def clear (self ):
212
+ """Clear the stack.
213
+ """
214
+ del self ._items [:]
215
+
216
+
160
217
class SubplotParams (object ):
161
218
"""
162
219
A class to hold the parameters for a subplot
@@ -350,7 +407,7 @@ def __init__(self,
350
407
self .subplotpars = subplotpars
351
408
self .set_tight_layout (tight_layout )
352
409
353
- self ._axstack = AxesStack () # track all figure axes and current axes
410
+ self ._axstack = _AxesStack () # track all figure axes and current axes
354
411
self .clf ()
355
412
self ._cachedRenderer = None
356
413
@@ -398,10 +455,8 @@ def show(self, warn=True):
398
455
"matplotlib is currently using a non-GUI backend, "
399
456
"so cannot show the figure" )
400
457
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" )
458
+ axes = property (lambda self : self ._axstack .as_list (),
459
+ doc = "Read-only: list of axes in Figure" )
405
460
406
461
def _get_dpi (self ):
407
462
return self ._dpi
@@ -812,36 +867,6 @@ def delaxes(self, a):
812
867
func (self )
813
868
self .stale = True
814
869
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
870
@docstring .dedent_interpd
846
871
def add_axes (self , * args , ** kwargs ):
847
872
"""
@@ -895,9 +920,9 @@ def add_axes(self, *args, **kwargs):
895
920
896
921
# shortcut the projection "key" modifications later on, if an axes
897
922
# with the exact args/kwargs exists, return it immediately.
898
- key = self . _make_key ( * args , ** kwargs )
923
+ key = ( args , kwargs )
899
924
ax = self ._axstack .get (key )
900
- if ax is not None :
925
+ if ax :
901
926
self .sca (ax )
902
927
return ax
903
928
@@ -914,7 +939,7 @@ def add_axes(self, *args, **kwargs):
914
939
# check that an axes of this type doesn't already exist, if it
915
940
# does, set it as active and return it
916
941
ax = self ._axstack .get (key )
917
- if ax is not None and isinstance (ax , projection_class ):
942
+ if isinstance (ax , projection_class ):
918
943
self .sca (ax )
919
944
return ax
920
945
@@ -988,15 +1013,14 @@ def add_subplot(self, *args, **kwargs):
988
1013
raise ValueError (msg )
989
1014
# make a key for the subplot (which includes the axes object id
990
1015
# in the hash)
991
- key = self . _make_key ( * args , ** kwargs )
1016
+ key = ( args , kwargs )
992
1017
else :
993
1018
projection_class , kwargs , key = process_projection_requirements (
994
1019
self , * args , ** kwargs )
995
1020
996
1021
# try to find the axes with this key in the stack
997
1022
ax = self ._axstack .get (key )
998
-
999
- if ax is not None :
1023
+ if ax :
1000
1024
if isinstance (ax , projection_class ):
1001
1025
# the axes already existed, so set it as active & return
1002
1026
self .sca (ax )
@@ -1496,7 +1520,7 @@ def _gci(self):
1496
1520
do not use elsewhere.
1497
1521
"""
1498
1522
# Look first for an image in the current Axes:
1499
- cax = self ._axstack .current_key_axes ()[ 1 ]
1523
+ ckey , cax = self ._axstack .current_key_axes ()
1500
1524
if cax is None :
1501
1525
return None
1502
1526
im = cax ._gci ()
0 commit comments