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
@@ -48,69 +49,41 @@ def _stale_figure_callback(self, val):
48
49
self .figure .stale = val
49
50
50
51
51
- class _AxesStack ( cbook . Stack ) :
52
+ class _AxesStack :
52
53
"""
53
- Specialization of Stack, to handle all tracking of Axes in a Figure .
54
+ Helper class to track axes in a figure .
54
55
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).
59
59
"""
60
60
61
61
def __init__ (self ):
62
- super (). __init__ ()
63
- self ._ind = 0
62
+ self . _axes = {} # Mapping of axes to "gca" order.
63
+ self ._counter = itertools . count ()
64
64
65
65
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.
73
68
74
69
def remove (self , a ):
75
70
"""Remove the axes from the stack."""
76
- super (). remove ( self ._entry_from_axes ( a ) )
71
+ self ._axes . pop ( a )
77
72
78
73
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 )
83
78
84
79
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 )
99
83
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 )
114
87
115
88
116
89
class SubplotParams :
@@ -1503,10 +1476,8 @@ def gca(self, **kwargs):
1503
1476
"new axes with default keyword arguments. To create a new "
1504
1477
"axes with non-default arguments, use plt.axes() or "
1505
1478
"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 )
1510
1481
1511
1482
def _gci (self ):
1512
1483
# Helper for `~matplotlib.pyplot.gci`. Do not use elsewhere.
@@ -1525,13 +1496,13 @@ def _gci(self):
1525
1496
Historically, the only colorable artists were images; hence the name
1526
1497
``gci`` (get current image).
1527
1498
"""
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 :
1530
1502
return None
1531
- im = self . _axstack () ._gci ()
1503
+ im = ax ._gci ()
1532
1504
if im is not None :
1533
1505
return im
1534
-
1535
1506
# If there is no image in the current Axes, search for
1536
1507
# one in a previously created Axes. Whether this makes
1537
1508
# sense is debatable, but it is the documented behavior.
@@ -2759,7 +2730,7 @@ def clf(self, keep_observers=False):
2759
2730
toolbar = getattr (self .canvas , 'toolbar' , None )
2760
2731
if toolbar is not None :
2761
2732
toolbar .update ()
2762
- self ._axstack . clear ()
2733
+ self ._axstack = _AxesStack ()
2763
2734
self .artists = []
2764
2735
self .lines = []
2765
2736
self .patches = []
0 commit comments