@@ -72,7 +72,6 @@ class AxesStack(Stack):
72
72
73
73
"""
74
74
def __init__ (self ):
75
- cbook .warn_deprecated ("2.1" )
76
75
Stack .__init__ (self )
77
76
self ._ind = 0
78
77
@@ -92,6 +91,13 @@ def get(self, key):
92
91
item = dict (self ._elements ).get (key )
93
92
if item is None :
94
93
return None
94
+ cbook .warn_deprecated (
95
+ "2.1" ,
96
+ "Adding an axes using the same arguments as a previous axes "
97
+ "currently reuses the earlier instance. In a future version, "
98
+ "a new instance will always be created and returned. Meanwhile, "
99
+ "this warning can be suppressed, and the future behavior ensured, "
100
+ "by passing a unique label to each axes instance." )
95
101
return item [1 ]
96
102
97
103
def _entry_from_axes (self , e ):
@@ -159,62 +165,6 @@ def __contains__(self, a):
159
165
return a in self .as_list ()
160
166
161
167
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
-
218
168
class SubplotParams (object ):
219
169
"""
220
170
A class to hold the parameters for a subplot
@@ -415,7 +365,7 @@ def __init__(self,
415
365
self .subplotpars = subplotpars
416
366
self .set_tight_layout (tight_layout )
417
367
418
- self ._axstack = _AxesStack () # track all figure axes and current axes
368
+ self ._axstack = AxesStack () # track all figure axes and current axes
419
369
self .clf ()
420
370
self ._cachedRenderer = None
421
371
@@ -467,8 +417,10 @@ def show(self, warn=True):
467
417
"matplotlib is currently using a non-GUI backend, "
468
418
"so cannot show the figure" )
469
419
470
- axes = property (lambda self : self ._axstack .as_list (),
471
- doc = "Read-only: list of axes in Figure" )
420
+ def _get_axes (self ):
421
+ return self ._axstack .as_list ()
422
+
423
+ axes = property (fget = _get_axes , doc = "Read-only: list of axes in Figure" )
472
424
473
425
def _get_dpi (self ):
474
426
return self ._dpi
@@ -890,6 +842,36 @@ def delaxes(self, a):
890
842
func (self )
891
843
self .stale = True
892
844
845
+ def _make_key (self , * args , ** kwargs ):
846
+ 'make a hashable key out of args and kwargs'
847
+
848
+ def fixitems (items ):
849
+ #items may have arrays and lists in them, so convert them
850
+ # to tuples for the key
851
+ ret = []
852
+ for k , v in items :
853
+ # some objects can define __getitem__ without being
854
+ # iterable and in those cases the conversion to tuples
855
+ # will fail. So instead of using the iterable(v) function
856
+ # we simply try and convert to a tuple, and proceed if not.
857
+ try :
858
+ v = tuple (v )
859
+ except Exception :
860
+ pass
861
+ ret .append ((k , v ))
862
+ return tuple (ret )
863
+
864
+ def fixlist (args ):
865
+ ret = []
866
+ for a in args :
867
+ if iterable (a ):
868
+ a = tuple (a )
869
+ ret .append (a )
870
+ return tuple (ret )
871
+
872
+ key = fixlist (args ), fixitems (six .iteritems (kwargs ))
873
+ return key
874
+
893
875
def add_axes (self , * args , ** kwargs ):
894
876
"""
895
877
Add an axes at position *rect* [*left*, *bottom*, *width*,
@@ -926,14 +908,14 @@ def add_axes(self, *args, **kwargs):
926
908
fig.add_axes(rect, projection='polar')
927
909
fig.add_axes(ax)
928
910
929
- If the figure already has an axes with the same parameters,
930
- then it will simply make that axes current and return it. If
931
- you do not want this behavior, e.g., you want to force the
932
- creation of a new Axes , you must use a unique set of args and
933
- kwargs. The axes :attr:`~matplotlib.axes.Axes.label`
934
- attribute has been exposed for this purpose. e.g., if you want
935
- two axes that are otherwise identical to be added to the
936
- figure, make sure you give them unique labels::
911
+ If the figure already has an axes with the same parameters, then it
912
+ will simply make that axes current and return it. This behavior
913
+ has been deprecated as of Matplotlib 2.1. Meanwhile, if you do
914
+ not want this behavior (i.e. , you want to force the creation of a
915
+ new Axes), you must use a unique set of args and kwargs. The axes
916
+ :attr:`~matplotlib.axes.Axes.label` attribute has been exposed for this
917
+ purpose: if you want two axes that are otherwise identical to be added
918
+ to the figure, make sure you give them unique labels::
937
919
938
920
fig.add_axes(rect, label='axes1')
939
921
fig.add_axes(rect, label='axes2')
@@ -954,9 +936,9 @@ def add_axes(self, *args, **kwargs):
954
936
955
937
# shortcut the projection "key" modifications later on, if an axes
956
938
# with the exact args/kwargs exists, return it immediately.
957
- key = ( args , kwargs )
939
+ key = self . _make_key ( * args , ** kwargs )
958
940
ax = self ._axstack .get (key )
959
- if ax :
941
+ if ax is not None :
960
942
self .sca (ax )
961
943
return ax
962
944
@@ -976,7 +958,7 @@ def add_axes(self, *args, **kwargs):
976
958
# check that an axes of this type doesn't already exist, if it
977
959
# does, set it as active and return it
978
960
ax = self ._axstack .get (key )
979
- if isinstance (ax , projection_class ):
961
+ if ax is not None and isinstance (ax , projection_class ):
980
962
self .sca (ax )
981
963
return ax
982
964
@@ -1021,14 +1003,14 @@ def add_subplot(self, *args, **kwargs):
1021
1003
-----
1022
1004
If the figure already has a subplot with key (*args*,
1023
1005
*kwargs*) then it will simply make that subplot current and
1024
- return it.
1006
+ return it. This behavior is deprecated.
1025
1007
1026
1008
Examples
1027
1009
--------
1028
1010
fig.add_subplot(111)
1029
1011
1030
1012
# equivalent but more general
1031
- fig.add_subplot(1,1, 1)
1013
+ fig.add_subplot(1, 1, 1)
1032
1014
1033
1015
# add subplot with red background
1034
1016
fig.add_subplot(212, facecolor='r')
@@ -1047,29 +1029,29 @@ def add_subplot(self, *args, **kwargs):
1047
1029
return
1048
1030
1049
1031
if len (args ) == 1 and isinstance (args [0 ], int ):
1050
- args = tuple ([int (c ) for c in str (args [0 ])])
1051
- if len (args ) != 3 :
1052
- raise ValueError ("Integer subplot specification must " +
1053
- "be a three digit number. " +
1054
- "Not {n:d}" .format (n = len (args )))
1032
+ if not 100 <= args [0 ] <= 999 :
1033
+ raise ValueError ("Integer subplot specification must be a "
1034
+ "three-digit number, not {}" .format (args [0 ]))
1035
+ args = tuple (map (int , str (args [0 ])))
1055
1036
1056
1037
if isinstance (args [0 ], SubplotBase ):
1057
1038
1058
1039
a = args [0 ]
1059
1040
if a .get_figure () is not self :
1060
- msg = ("The Subplot must have been created in the present"
1061
- " figure" )
1041
+ msg = ("The Subplot must have been created in the present "
1042
+ "figure" )
1062
1043
raise ValueError (msg )
1063
1044
# make a key for the subplot (which includes the axes object id
1064
1045
# in the hash)
1065
- key = ( args , kwargs )
1046
+ key = self . _make_key ( * args , ** kwargs )
1066
1047
else :
1067
1048
projection_class , kwargs , key = process_projection_requirements (
1068
1049
self , * args , ** kwargs )
1069
1050
1070
1051
# try to find the axes with this key in the stack
1071
1052
ax = self ._axstack .get (key )
1072
- if ax :
1053
+
1054
+ if ax is not None :
1073
1055
if isinstance (ax , projection_class ):
1074
1056
# the axes already existed, so set it as active & return
1075
1057
self .sca (ax )
@@ -1638,7 +1620,7 @@ def _gci(self):
1638
1620
do not use elsewhere.
1639
1621
"""
1640
1622
# Look first for an image in the current Axes:
1641
- ckey , cax = self ._axstack .current_key_axes ()
1623
+ cax = self ._axstack .current_key_axes ()[ 1 ]
1642
1624
if cax is None :
1643
1625
return None
1644
1626
im = cax ._gci ()
0 commit comments