1616
1717from contextlib import ExitStack
1818import inspect
19+ import itertools
1920import logging
2021from numbers import Integral
2122
@@ -48,69 +49,41 @@ def _stale_figure_callback(self, val):
4849 self .figure .stale = val
4950
5051
51- class _AxesStack ( cbook . Stack ) :
52+ class _AxesStack :
5253 """
53- Specialization of Stack, to handle all tracking of Axes in a Figure .
54+ Helper class to track axes in a figure .
5455
55- This stack stores ``ind, axes`` pairs, where ``ind`` is a serial index
56- tracking the order in which axes were added.
57-
58- AxesStack is a callable; calling it returns the current axes.
56+ Axes are tracked both in the order in which they have been added
57+ (``self._axes`` insertion/iteration order) and in the separate "gca" stack
58+ (which is the index to which they map in the ``self._axes`` dict).
5959 """
6060
6161 def __init__ (self ):
62- super (). __init__ ()
63- self ._ind = 0
62+ self . _axes = {} # Mapping of axes to "gca" order.
63+ self ._counter = itertools . count ()
6464
6565 def as_list (self ):
66- """
67- Return a list of the Axes instances that have been added to the figure.
68- """
69- return [a for i , a in sorted (self ._elements )]
70-
71- def _entry_from_axes (self , e ):
72- return next (((ind , a ) for ind , a in self ._elements if a == e ), None )
66+ """List the axes that have been added to the figure."""
67+ return [* self ._axes ] # This relies on dict preserving order.
7368
7469 def remove (self , a ):
7570 """Remove the axes from the stack."""
76- super (). remove ( self ._entry_from_axes ( a ) )
71+ self ._axes . pop ( a )
7772
7873 def bubble (self , a ):
79- """
80- Move the given axes, which must already exist in the stack, to the top.
81- """
82- return super (). bubble ( self ._entry_from_axes ( a ) )
74+ """Move an axes, which must already exist in the stack, to the top."""
75+ if a not in self . _axes :
76+ raise ValueError ( "Axes has not been added yet" )
77+ self . _axes [ a ] = next ( self ._counter )
8378
8479 def add (self , a ):
85- """
86- Add Axes *a* to the stack.
87-
88- If *a* is already on the stack, don't add it again.
89- """
90- # All the error checking may be unnecessary; but this method
91- # is called so seldom that the overhead is negligible.
92- _api .check_isinstance (Axes , a = a )
93-
94- if a in self :
95- return
96-
97- self ._ind += 1
98- super ().push ((self ._ind , a ))
80+ """Add an axes to the stack, ignoring it if already present."""
81+ if a not in self ._axes :
82+ self ._axes [a ] = next (self ._counter )
9983
100- def __call__ (self ):
101- """
102- Return the active axes.
103-
104- If no axes exists on the stack, then returns None.
105- """
106- if not len (self ._elements ):
107- return None
108- else :
109- index , axes = self ._elements [self ._pos ]
110- return axes
111-
112- def __contains__ (self , a ):
113- return a in self .as_list ()
84+ def current (self ):
85+ """Return the active axes, or None if the stack is empty."""
86+ return max (self ._axes , key = self ._axes .__getitem__ , default = None )
11487
11588
11689class SubplotParams :
@@ -1503,10 +1476,8 @@ def gca(self, **kwargs):
15031476 "new axes with default keyword arguments. To create a new "
15041477 "axes with non-default arguments, use plt.axes() or "
15051478 "plt.subplot()." )
1506- if self ._axstack .empty ():
1507- return self .add_subplot (1 , 1 , 1 , ** kwargs )
1508- else :
1509- return self ._axstack ()
1479+ ax = self ._axstack .current ()
1480+ return ax if ax is not None else self .add_subplot (** kwargs )
15101481
15111482 def _gci (self ):
15121483 # Helper for `~matplotlib.pyplot.gci`. Do not use elsewhere.
@@ -1525,13 +1496,13 @@ def _gci(self):
15251496 Historically, the only colorable artists were images; hence the name
15261497 ``gci`` (get current image).
15271498 """
1528- # Look first for an image in the current Axes:
1529- if self ._axstack .empty ():
1499+ # Look first for an image in the current Axes.
1500+ ax = self ._axstack .current ()
1501+ if ax is None :
15301502 return None
1531- im = self . _axstack () ._gci ()
1503+ im = ax ._gci ()
15321504 if im is not None :
15331505 return im
1534-
15351506 # If there is no image in the current Axes, search for
15361507 # one in a previously created Axes. Whether this makes
15371508 # sense is debatable, but it is the documented behavior.
@@ -2759,7 +2730,7 @@ def clf(self, keep_observers=False):
27592730 toolbar = getattr (self .canvas , 'toolbar' , None )
27602731 if toolbar is not None :
27612732 toolbar .update ()
2762- self ._axstack . clear ()
2733+ self ._axstack = _AxesStack ()
27632734 self .artists = []
27642735 self .lines = []
27652736 self .patches = []
0 commit comments