16
16
17
17
from contextlib import ExitStack
18
18
import inspect
19
+ import itertools
19
20
import logging
20
21
from numbers import Integral
21
22
@@ -50,69 +51,41 @@ def _stale_figure_callback(self, val):
50
51
self .figure .stale = val
51
52
52
53
53
- class _AxesStack ( cbook . Stack ) :
54
+ class _AxesStack :
54
55
"""
55
- Specialization of Stack, to handle all tracking of Axes in a Figure .
56
+ Helper class to track axes in a figure .
56
57
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).
61
61
"""
62
62
63
63
def __init__ (self ):
64
- super (). __init__ ()
65
- self ._ind = 0
64
+ self . _axes = {} # Mapping of axes to "gca" order.
65
+ self ._counter = itertools . count ()
66
66
67
67
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.
75
70
76
71
def remove (self , a ):
77
72
"""Remove the axes from the stack."""
78
- super (). remove ( self ._entry_from_axes ( a ) )
73
+ self ._axes . pop ( a )
79
74
80
75
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 )
85
80
86
81
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 )
101
85
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 )
116
89
117
90
118
91
class SubplotParams :
@@ -1512,10 +1485,8 @@ def gca(self, **kwargs):
1512
1485
"new axes with default keyword arguments. To create a new "
1513
1486
"axes with non-default arguments, use plt.axes() or "
1514
1487
"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 )
1519
1490
1520
1491
def _gci (self ):
1521
1492
# Helper for `~matplotlib.pyplot.gci`. Do not use elsewhere.
@@ -1534,13 +1505,13 @@ def _gci(self):
1534
1505
Historically, the only colorable artists were images; hence the name
1535
1506
``gci`` (get current image).
1536
1507
"""
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 :
1539
1511
return None
1540
- im = self . _axstack () ._gci ()
1512
+ im = ax ._gci ()
1541
1513
if im is not None :
1542
1514
return im
1543
-
1544
1515
# If there is no image in the current Axes, search for
1545
1516
# one in a previously created Axes. Whether this makes
1546
1517
# sense is debatable, but it is the documented behavior.
@@ -2834,7 +2805,7 @@ def clf(self, keep_observers=False):
2834
2805
toolbar = self .canvas .toolbar
2835
2806
if toolbar is not None :
2836
2807
toolbar .update ()
2837
- self ._axstack . clear ()
2808
+ self ._axstack = _AxesStack ()
2838
2809
self .artists = []
2839
2810
self .lines = []
2840
2811
self .patches = []
0 commit comments