27
27
28
28
from legend import Legend
29
29
from transforms import Affine2D , Bbox , BboxTransformTo , TransformedBbox
30
- from projections import projection_factory , get_projection_names , \
31
- get_projection_class
30
+ from projections import get_projection_names , get_projection_class , \
31
+ process_projection_requirements
32
32
from matplotlib .blocking_input import BlockingMouseInput , BlockingKeyMouseInput
33
33
34
34
import matplotlib .cbook as cbook
41
41
42
42
class AxesStack (Stack ):
43
43
"""
44
- Specialization of the Stack to handle all
45
- tracking of Axes in a Figure. This requires storing
46
- key, (ind, axes) pairs. The key is based on the args and kwargs
47
- used in generating the Axes. ind is a serial number for tracking
48
- the order in which axes were added.
44
+ Specialization of the Stack to handle all tracking of Axes in a Figure.
45
+ This stack stores ``key, (ind, axes)`` pairs, where:
46
+
47
+ * **key** should be a hash of the args and kwargs
48
+ used in generating the Axes.
49
+ * **ind** is a serial number for tracking the order
50
+ in which axes were added.
51
+
52
+ The AxesStack is a callable, where ``ax_stack()`` returns
53
+ the current axes. Alternatively the :meth:`current_key_axes` will
54
+ return the current key and associated axes.
55
+
49
56
"""
50
57
def __init__ (self ):
51
58
Stack .__init__ (self )
@@ -74,9 +81,14 @@ def _entry_from_axes(self, e):
74
81
return (k , (ind , e ))
75
82
76
83
def remove (self , a ):
84
+ """Remove the axes from the stack."""
77
85
Stack .remove (self , self ._entry_from_axes (a ))
78
86
79
87
def bubble (self , a ):
88
+ """
89
+ Move the given axes, which must already exist in the
90
+ stack, to the top.
91
+ """
80
92
return Stack .bubble (self , self ._entry_from_axes (a ))
81
93
82
94
def add (self , key , a ):
@@ -107,11 +119,21 @@ def add(self, key, a):
107
119
self ._ind += 1
108
120
return Stack .push (self , (key , (self ._ind , a )))
109
121
110
- def __call__ (self ):
122
+ def current_key_axes (self ):
123
+ """
124
+ Return a tuple of ``(key, axes)`` for the active axes.
125
+
126
+ If no axes exists on the stack, then returns ``(None, None)``.
127
+
128
+ """
111
129
if not len (self ._elements ):
112
- return self ._default
130
+ return self ._default , self . _default
113
131
else :
114
- return self ._elements [self ._pos ][1 ][1 ]
132
+ key , (index , axes ) = self ._elements [self ._pos ]
133
+ return key , axes
134
+
135
+ def __call__ (self ):
136
+ return self .current_key_axes ()[1 ]
115
137
116
138
def __contains__ (self , a ):
117
139
return a in self .as_list ()
@@ -692,6 +714,8 @@ def add_axes(self, *args, **kwargs):
692
714
"""
693
715
if not len (args ): return
694
716
717
+ # shortcut the projection "key" modifications later on, if an axes
718
+ # with the exact args/kwargs exists, return it immediately.
695
719
key = self ._make_key (* args , ** kwargs )
696
720
ax = self ._axstack .get (key )
697
721
if ax is not None :
@@ -703,17 +727,18 @@ def add_axes(self, *args, **kwargs):
703
727
assert (a .get_figure () is self )
704
728
else :
705
729
rect = args [0 ]
706
- ispolar = kwargs .pop ('polar' , False )
707
- projection = kwargs .pop ('projection' , None )
708
- if ispolar :
709
- if projection is not None and projection != 'polar' :
710
- raise ValueError (
711
- "polar=True, yet projection='%s'. " +
712
- "Only one of these arguments should be supplied." %
713
- projection )
714
- projection = 'polar'
715
-
716
- a = projection_factory (projection , self , rect , ** kwargs )
730
+ projection_class , kwargs , key = \
731
+ process_projection_requirements (self , * args , ** kwargs )
732
+
733
+ # check that an axes of this type doesn't already exist, if it
734
+ # does, set it as active and return it
735
+ ax = self ._axstack .get (key )
736
+ if ax is not None and isinstance (ax , projection_class ):
737
+ self .sca (ax )
738
+ return ax
739
+
740
+ # create the new axes using the axes class given
741
+ a = projection_class (self , rect , ** kwargs )
717
742
718
743
self ._axstack .add (key , a )
719
744
self .sca (a )
@@ -725,10 +750,18 @@ def add_subplot(self, *args, **kwargs):
725
750
Add a subplot. Examples::
726
751
727
752
fig.add_subplot(111)
728
- fig.add_subplot(1,1,1) # equivalent but more general
729
- fig.add_subplot(212, axisbg='r') # add subplot with red background
730
- fig.add_subplot(111, polar=True) # add a polar subplot
731
- fig.add_subplot(sub) # add Subplot instance sub
753
+
754
+ # equivalent but more general
755
+ fig.add_subplot(1,1,1)
756
+
757
+ # add subplot with red background
758
+ fig.add_subplot(212, axisbg='r')
759
+
760
+ # add a polar subplot
761
+ fig.add_subplot(111, projection='polar')
762
+
763
+ # add Subplot instance sub
764
+ fig.add_subplot(sub)
732
765
733
766
*kwargs* are legal :class:`~matplotlib.axes.Axes` kwargs plus
734
767
*projection*, which chooses a projection type for the axes.
@@ -755,39 +788,32 @@ def add_subplot(self, *args, **kwargs):
755
788
args = tuple ([int (c ) for c in str (args [0 ])])
756
789
757
790
if isinstance (args [0 ], SubplotBase ):
791
+
758
792
a = args [0 ]
759
793
assert (a .get_figure () is self )
760
- key = self ._make_key (* args , ** kwargs )
794
+ key = self ._make_key (* args [ 1 :] , ** kwargs )
761
795
else :
762
- kwargs = kwargs .copy ()
763
- ispolar = kwargs .pop ('polar' , False )
764
- projection = kwargs .pop ('projection' , None )
765
- if ispolar :
766
- if projection is not None and projection != 'polar' :
767
- raise ValueError (
768
- "polar=True, yet projection='%s'. " +
769
- "Only one of these arguments should be supplied." %
770
- projection )
771
- projection = 'polar'
772
-
773
- projection_class = get_projection_class (projection )
774
-
775
- # Remake the key without projection kwargs:
776
- key = self ._make_key (* args , ** kwargs )
796
+ projection_class , kwargs , key = \
797
+ process_projection_requirements (self , * args , ** kwargs )
798
+
799
+ # try to find the axes with this key in the stack
777
800
ax = self ._axstack .get (key )
801
+
778
802
if ax is not None :
779
803
if isinstance (ax , projection_class ):
804
+ # the axes already existed, so set it as active & return
780
805
self .sca (ax )
781
806
return ax
782
807
else :
783
- self ._axstack .remove (ax )
784
808
# Undocumented convenience behavior:
785
809
# subplot(111); subplot(111, projection='polar')
786
810
# will replace the first with the second.
787
811
# Without this, add_subplot would be simpler and
788
812
# more similar to add_axes.
813
+ self ._axstack .remove (ax )
789
814
790
815
a = subplot_class_factory (projection_class )(self , * args , ** kwargs )
816
+
791
817
self ._axstack .add (key , a )
792
818
self .sca (a )
793
819
return a
@@ -1046,24 +1072,40 @@ def gca(self, **kwargs):
1046
1072
"""
1047
1073
Return the current axes, creating one if necessary
1048
1074
1049
- The following kwargs are supported
1075
+ The following kwargs are supported for ensuring the returned axes
1076
+ adheres to the given projection etc., and for axes creation if
1077
+ the active axes does not exist:
1050
1078
%(Axes)s
1079
+
1080
+ .. note::
1081
+ When specifying kwargs to ``gca`` to find the pre-created active
1082
+ axes, they should be equivalent in every way to the kwargs which
1083
+ were used in its creation.
1084
+
1051
1085
"""
1052
- ax = self ._axstack ()
1053
- if ax is not None :
1054
- ispolar = kwargs .get ('polar' , False )
1055
- projection = kwargs .get ('projection' , None )
1056
- if ispolar :
1057
- if projection is not None and projection != 'polar' :
1058
- raise ValueError (
1059
- "polar=True, yet projection='%s'. " +
1060
- "Only one of these arguments should be supplied." %
1061
- projection )
1062
- projection = 'polar'
1063
-
1064
- projection_class = get_projection_class (projection )
1065
- if isinstance (ax , projection_class ):
1066
- return ax
1086
+ ckey , cax = self ._axstack .current_key_axes ()
1087
+ # if there exists an axes on the stack see if it maches
1088
+ # the desired axes configuration
1089
+ if cax is not None :
1090
+
1091
+ # if no kwargs are given just return the current axes
1092
+ # this is a convenience for gca() on axes such as polar etc.
1093
+ if not kwargs :
1094
+ return cax
1095
+
1096
+ # if the user has specified particular projection detail
1097
+ # then build up a key which can represent this
1098
+ else :
1099
+ # we don't want to modify the original kwargs
1100
+ # so take a copy so that we can do what we like to it
1101
+ kwargs_copy = kwargs .copy ()
1102
+ projection_class , _ , key = \
1103
+ process_projection_requirements (self , ** kwargs_copy )
1104
+ # if the cax matches this key then return the axes, otherwise
1105
+ # continue and a new axes will be created
1106
+ if key == ckey and isinstance (cax , projection_class ):
1107
+ return cax
1108
+
1067
1109
return self .add_subplot (111 , ** kwargs )
1068
1110
1069
1111
def sca (self , a ):
@@ -1094,7 +1136,7 @@ def savefig(self, *args, **kwargs):
1094
1136
1095
1137
savefig(fname, dpi=None, facecolor='w', edgecolor='w',
1096
1138
orientation='portrait', papertype=None, format=None,
1097
- transparent=False, bbox_inches=None, pad_inches=0.1):
1139
+ transparent=False, bbox_inches=None, pad_inches=0.1)
1098
1140
1099
1141
Save the current figure.
1100
1142
0 commit comments