1616
1717from contextlib import ExitStack
1818import inspect
19+ import itertools
1920import logging
2021from numbers import Integral
2122
@@ -50,69 +51,41 @@ def _stale_figure_callback(self, val):
5051 self .figure .stale = val
5152
5253
53- class _AxesStack ( cbook . Stack ) :
54+ class _AxesStack :
5455 """
55- Specialization of Stack, to handle all tracking of Axes in a Figure .
56+ Helper class to track axes in a figure .
5657
57- This stack stores ``ind, axes`` pairs, where ``ind`` is a serial index
58- tracking the order in which axes were added.
59-
60- AxesStack is a callable; calling it returns the current axes.
58+ Axes are tracked both in the order in which they have been added
59+ (``self._axes`` insertion/iteration order) and in the separate "gca" stack
60+ (which is the index to which they map in the ``self._axes`` dict).
6161 """
6262
6363 def __init__ (self ):
64- super (). __init__ ()
65- self ._ind = 0
64+ self . _axes = {} # Mapping of axes to "gca" order.
65+ self ._counter = itertools . count ()
6666
6767 def as_list (self ):
68- """
69- Return a list of the Axes instances that have been added to the figure.
70- """
71- return [a for i , a in sorted (self ._elements )]
72-
73- def _entry_from_axes (self , e ):
74- return next (((ind , a ) for ind , a in self ._elements if a == e ), None )
68+ """List the axes that have been added to the figure."""
69+ return [* self ._axes ] # This relies on dict preserving order.
7570
7671 def remove (self , a ):
7772 """Remove the axes from the stack."""
78- super (). remove ( self ._entry_from_axes ( a ) )
73+ self ._axes . pop ( a )
7974
8075 def bubble (self , a ):
81- """
82- Move the given axes, which must already exist in the stack, to the top.
83- """
84- return super (). bubble ( self ._entry_from_axes ( a ) )
76+ """Move an axes, which must already exist in the stack, to the top."""
77+ if a not in self . _axes :
78+ raise ValueError ( "Axes has not been added yet" )
79+ self . _axes [ a ] = next ( self ._counter )
8580
8681 def add (self , a ):
87- """
88- Add Axes *a* to the stack.
89-
90- If *a* is already on the stack, don't add it again.
91- """
92- # All the error checking may be unnecessary; but this method
93- # is called so seldom that the overhead is negligible.
94- _api .check_isinstance (Axes , a = a )
95-
96- if a in self :
97- return
98-
99- self ._ind += 1
100- super ().push ((self ._ind , a ))
82+ """Add an axes to the stack, ignoring it if already present."""
83+ if a not in self ._axes :
84+ self ._axes [a ] = next (self ._counter )
10185
102- def __call__ (self ):
103- """
104- Return the active axes.
105-
106- If no axes exists on the stack, then returns None.
107- """
108- if not len (self ._elements ):
109- return None
110- else :
111- index , axes = self ._elements [self ._pos ]
112- return axes
113-
114- def __contains__ (self , a ):
115- return a in self .as_list ()
86+ def current (self ):
87+ """Return the active axes, or None if the stack is empty."""
88+ return max (self ._axes , key = self ._axes .__getitem__ , default = None )
11689
11790
11891class SubplotParams :
@@ -1512,10 +1485,8 @@ def gca(self, **kwargs):
15121485 "new axes with default keyword arguments. To create a new "
15131486 "axes with non-default arguments, use plt.axes() or "
15141487 "plt.subplot()." )
1515- if self ._axstack .empty ():
1516- return self .add_subplot (1 , 1 , 1 , ** kwargs )
1517- else :
1518- return self ._axstack ()
1488+ ax = self ._axstack .current ()
1489+ return ax if ax is not None else self .add_subplot (** kwargs )
15191490
15201491 def _gci (self ):
15211492 # Helper for `~matplotlib.pyplot.gci`. Do not use elsewhere.
@@ -1534,13 +1505,13 @@ def _gci(self):
15341505 Historically, the only colorable artists were images; hence the name
15351506 ``gci`` (get current image).
15361507 """
1537- # Look first for an image in the current Axes:
1538- if self ._axstack .empty ():
1508+ # Look first for an image in the current Axes.
1509+ ax = self ._axstack .current ()
1510+ if ax is None :
15391511 return None
1540- im = self . _axstack () ._gci ()
1512+ im = ax ._gci ()
15411513 if im is not None :
15421514 return im
1543-
15441515 # If there is no image in the current Axes, search for
15451516 # one in a previously created Axes. Whether this makes
15461517 # sense is debatable, but it is the documented behavior.
@@ -2834,7 +2805,7 @@ def clf(self, keep_observers=False):
28342805 toolbar = self .canvas .toolbar
28352806 if toolbar is not None :
28362807 toolbar .update ()
2837- self ._axstack . clear ()
2808+ self ._axstack = _AxesStack ()
28382809 self .artists = []
28392810 self .lines = []
28402811 self .patches = []
0 commit comments