2727
2828from legend import Legend
2929from 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
3232from matplotlib .blocking_input import BlockingMouseInput , BlockingKeyMouseInput
3333
3434import matplotlib .cbook as cbook
4141
4242class AxesStack (Stack ):
4343 """
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+
4956 """
5057 def __init__ (self ):
5158 Stack .__init__ (self )
@@ -74,9 +81,14 @@ def _entry_from_axes(self, e):
7481 return (k , (ind , e ))
7582
7683 def remove (self , a ):
84+ """Remove the axes from the stack."""
7785 Stack .remove (self , self ._entry_from_axes (a ))
7886
7987 def bubble (self , a ):
88+ """
89+ Move the given axes, which must already exist in the
90+ stack, to the top.
91+ """
8092 return Stack .bubble (self , self ._entry_from_axes (a ))
8193
8294 def add (self , key , a ):
@@ -107,11 +119,21 @@ def add(self, key, a):
107119 self ._ind += 1
108120 return Stack .push (self , (key , (self ._ind , a )))
109121
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+ """
111129 if not len (self ._elements ):
112- return self ._default
130+ return self ._default , self . _default
113131 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 ]
115137
116138 def __contains__ (self , a ):
117139 return a in self .as_list ()
@@ -692,6 +714,8 @@ def add_axes(self, *args, **kwargs):
692714 """
693715 if not len (args ): return
694716
717+ # shortcut the projection "key" modifications later on, if an axes
718+ # with the exact args/kwargs exists, return it immediately.
695719 key = self ._make_key (* args , ** kwargs )
696720 ax = self ._axstack .get (key )
697721 if ax is not None :
@@ -703,17 +727,18 @@ def add_axes(self, *args, **kwargs):
703727 assert (a .get_figure () is self )
704728 else :
705729 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 )
717742
718743 self ._axstack .add (key , a )
719744 self .sca (a )
@@ -725,10 +750,18 @@ def add_subplot(self, *args, **kwargs):
725750 Add a subplot. Examples::
726751
727752 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)
732765
733766 *kwargs* are legal :class:`~matplotlib.axes.Axes` kwargs plus
734767 *projection*, which chooses a projection type for the axes.
@@ -755,39 +788,32 @@ def add_subplot(self, *args, **kwargs):
755788 args = tuple ([int (c ) for c in str (args [0 ])])
756789
757790 if isinstance (args [0 ], SubplotBase ):
791+
758792 a = args [0 ]
759793 assert (a .get_figure () is self )
760- key = self ._make_key (* args , ** kwargs )
794+ key = self ._make_key (* args [ 1 :] , ** kwargs )
761795 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
777800 ax = self ._axstack .get (key )
801+
778802 if ax is not None :
779803 if isinstance (ax , projection_class ):
804+ # the axes already existed, so set it as active & return
780805 self .sca (ax )
781806 return ax
782807 else :
783- self ._axstack .remove (ax )
784808 # Undocumented convenience behavior:
785809 # subplot(111); subplot(111, projection='polar')
786810 # will replace the first with the second.
787811 # Without this, add_subplot would be simpler and
788812 # more similar to add_axes.
813+ self ._axstack .remove (ax )
789814
790815 a = subplot_class_factory (projection_class )(self , * args , ** kwargs )
816+
791817 self ._axstack .add (key , a )
792818 self .sca (a )
793819 return a
@@ -1046,24 +1072,40 @@ def gca(self, **kwargs):
10461072 """
10471073 Return the current axes, creating one if necessary
10481074
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:
10501078 %(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+
10511085 """
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+
10671109 return self .add_subplot (111 , ** kwargs )
10681110
10691111 def sca (self , a ):
@@ -1094,7 +1136,7 @@ def savefig(self, *args, **kwargs):
10941136
10951137 savefig(fname, dpi=None, facecolor='w', edgecolor='w',
10961138 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)
10981140
10991141 Save the current figure.
11001142
0 commit comments