@@ -542,8 +542,8 @@ def _plot_args(self, tup, kwargs, return_kwargs=False):
542
542
class _AxesBase (martist .Artist ):
543
543
name = "rectilinear"
544
544
545
- _shared_x_axes = cbook . Grouper ()
546
- _shared_y_axes = cbook .Grouper ()
545
+ _axis_names = ( "x" , "y" ) # See _get_axis_map.
546
+ _shared_axes = { name : cbook .Grouper () for name in _axis_names }
547
547
_twinned_axes = cbook .Grouper ()
548
548
549
549
def __str__ (self ):
@@ -608,8 +608,7 @@ def __init__(self, fig, rect,
608
608
self ._aspect = 'auto'
609
609
self ._adjustable = 'box'
610
610
self ._anchor = 'C'
611
- self ._stale_viewlim_x = False
612
- self ._stale_viewlim_y = False
611
+ self ._stale_viewlims = {name : False for name in self ._axis_names }
613
612
self ._sharex = sharex
614
613
self ._sharey = sharey
615
614
self .set_label (label )
@@ -687,20 +686,21 @@ def __getstate__(self):
687
686
# that point.
688
687
state = super ().__getstate__ ()
689
688
# Prune the sharing & twinning info to only contain the current group.
690
- for grouper_name in [
691
- '_shared_x_axes' , '_shared_y_axes' , '_twinned_axes' ]:
692
- grouper = getattr ( self , grouper_name )
693
- state [grouper_name ] = (grouper .get_siblings (self )
694
- if self in grouper else None )
689
+ state [ "_shared_axes" ] = {
690
+ name : self . _shared_axes [ name ]. get_siblings ( self )
691
+ for name in self . _axis_names if self in self . _shared_axes [ name ]}
692
+ state ["_twinned_axes" ] = (self . _twinned_axes .get_siblings (self )
693
+ if self in self . _twinned_axes else None )
695
694
return state
696
695
697
696
def __setstate__ (self , state ):
698
697
# Merge the grouping info back into the global groupers.
699
- for grouper_name in [
700
- '_shared_x_axes' , '_shared_y_axes' , '_twinned_axes' ]:
701
- siblings = state .pop (grouper_name )
702
- if siblings :
703
- getattr (self , grouper_name ).join (* siblings )
698
+ shared_axes = state .pop ("_shared_axes" )
699
+ for name , shared_siblings in shared_axes .items ():
700
+ self ._shared_axes [name ].join (* shared_siblings )
701
+ twinned_siblings = state .pop ("_twinned_axes" )
702
+ if twinned_siblings :
703
+ self ._twinned_axes .join (* twinned_siblings )
704
704
self .__dict__ = state
705
705
self ._stale = True
706
706
@@ -765,16 +765,16 @@ def set_figure(self, fig):
765
765
def _unstale_viewLim (self ):
766
766
# We should arrange to store this information once per share-group
767
767
# instead of on every axis.
768
- scalex = any ( ax . _stale_viewlim_x
769
- for ax in self . _shared_x_axes . get_siblings ( self ))
770
- scaley = any ( ax . _stale_viewlim_y
771
- for ax in self ._shared_y_axes . get_siblings ( self ))
772
- if scalex or scaley :
773
- for ax in self . _shared_x_axes . get_siblings ( self ) :
774
- ax . _stale_viewlim_x = False
775
- for ax in self . _shared_y_axes . get_siblings ( self ):
776
- ax . _stale_viewlim_y = False
777
- self . autoscale_view ( scalex = scalex , scaley = scaley )
768
+ need_scale = {
769
+ name : any ( ax . _stale_viewlims [ name ]
770
+ for ax in self . _shared_axes [ name ]. get_siblings ( self ))
771
+ for name in self ._axis_names }
772
+ if any ( need_scale . values ()) :
773
+ for name in need_scale :
774
+ for ax in self . _shared_axes [ name ]. get_siblings ( self ):
775
+ ax . _stale_viewlims [ name ] = False
776
+ self . autoscale_view ( ** { f"scale { name } " : scale
777
+ for name , scale in need_scale . items ()} )
778
778
779
779
@property
780
780
def viewLim (self ):
@@ -783,13 +783,22 @@ def viewLim(self):
783
783
784
784
# API could be better, right now this is just to match the old calls to
785
785
# autoscale_view() after each plotting method.
786
- def _request_autoscale_view (self , tight = None , scalex = True , scaley = True ):
786
+ def _request_autoscale_view (self , tight = None , ** kwargs ):
787
+ # kwargs are "scalex", "scaley" (& "scalez" for 3D) and default to True
788
+ want_scale = {name : True for name in self ._axis_names }
789
+ for k , v in kwargs .items (): # Validate args before changing anything.
790
+ if k .startswith ("scale" ):
791
+ name = k [5 :]
792
+ if name in want_scale :
793
+ want_scale [name ] = v
794
+ continue
795
+ raise TypeError (
796
+ f"_request_autoscale_view() got an unexpected argument { k !r} " )
787
797
if tight is not None :
788
798
self ._tight = tight
789
- if scalex :
790
- self ._stale_viewlim_x = True # Else keep old state.
791
- if scaley :
792
- self ._stale_viewlim_y = True
799
+ for k , v in want_scale .items ():
800
+ if v :
801
+ self ._stale_viewlims [k ] = True # Else keep old state.
793
802
794
803
def _set_lim_and_transforms (self ):
795
804
"""
@@ -1143,7 +1152,7 @@ def sharex(self, other):
1143
1152
_api .check_isinstance (_AxesBase , other = other )
1144
1153
if self ._sharex is not None and other is not self ._sharex :
1145
1154
raise ValueError ("x-axis is already shared" )
1146
- self ._shared_x_axes .join (self , other )
1155
+ self ._shared_axes [ "x" ] .join (self , other )
1147
1156
self ._sharex = other
1148
1157
self .xaxis .major = other .xaxis .major # Ticker instances holding
1149
1158
self .xaxis .minor = other .xaxis .minor # locator and formatter.
@@ -1162,7 +1171,7 @@ def sharey(self, other):
1162
1171
_api .check_isinstance (_AxesBase , other = other )
1163
1172
if self ._sharey is not None and other is not self ._sharey :
1164
1173
raise ValueError ("y-axis is already shared" )
1165
- self ._shared_y_axes .join (self , other )
1174
+ self ._shared_axes [ "y" ] .join (self , other )
1166
1175
self ._sharey = other
1167
1176
self .yaxis .major = other .yaxis .major # Ticker instances holding
1168
1177
self .yaxis .minor = other .yaxis .minor # locator and formatter.
@@ -1291,8 +1300,8 @@ def cla(self):
1291
1300
self .xaxis .set_clip_path (self .patch )
1292
1301
self .yaxis .set_clip_path (self .patch )
1293
1302
1294
- self ._shared_x_axes .clean ()
1295
- self ._shared_y_axes .clean ()
1303
+ self ._shared_axes [ "x" ] .clean ()
1304
+ self ._shared_axes [ "y" ] .clean ()
1296
1305
if self ._sharex is not None :
1297
1306
self .xaxis .set_visible (xaxis_visible )
1298
1307
self .patch .set_visible (patch_visible )
@@ -1629,8 +1638,8 @@ def set_aspect(self, aspect, adjustable=None, anchor=None, share=False):
1629
1638
aspect = float (aspect ) # raise ValueError if necessary
1630
1639
1631
1640
if share :
1632
- axes = {* self ._shared_x_axes . get_siblings ( self ),
1633
- * self ._shared_y_axes .get_siblings (self )}
1641
+ axes = {sibling for name in self ._axis_names
1642
+ for sibling in self ._shared_axes [ name ] .get_siblings (self )}
1634
1643
else :
1635
1644
axes = [self ]
1636
1645
@@ -1691,8 +1700,8 @@ def set_adjustable(self, adjustable, share=False):
1691
1700
"""
1692
1701
_api .check_in_list (["box" , "datalim" ], adjustable = adjustable )
1693
1702
if share :
1694
- axs = {* self ._shared_x_axes . get_siblings ( self ),
1695
- * self ._shared_y_axes .get_siblings (self )}
1703
+ axs = {sibling for name in self ._axis_names
1704
+ for sibling in self ._shared_axes [ name ] .get_siblings (self )}
1696
1705
else :
1697
1706
axs = [self ]
1698
1707
if (adjustable == "datalim"
@@ -1812,8 +1821,8 @@ def set_anchor(self, anchor, share=False):
1812
1821
raise ValueError ('argument must be among %s' %
1813
1822
', ' .join (mtransforms .Bbox .coefs ))
1814
1823
if share :
1815
- axes = {* self ._shared_x_axes . get_siblings ( self ),
1816
- * self ._shared_y_axes .get_siblings (self )}
1824
+ axes = {sibling for name in self ._axis_names
1825
+ for sibling in self ._shared_axes [ name ] .get_siblings (self )}
1817
1826
else :
1818
1827
axes = [self ]
1819
1828
for ax in axes :
@@ -1928,8 +1937,8 @@ def apply_aspect(self, position=None):
1928
1937
xm = 0
1929
1938
ym = 0
1930
1939
1931
- shared_x = self in self ._shared_x_axes
1932
- shared_y = self in self ._shared_y_axes
1940
+ shared_x = self in self ._shared_axes [ "x" ]
1941
+ shared_y = self in self ._shared_axes [ "y" ]
1933
1942
# Not sure whether we need this check:
1934
1943
if shared_x and shared_y :
1935
1944
raise RuntimeError ("adjustable='datalim' is not allowed when both "
@@ -2839,13 +2848,13 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True):
2839
2848
if self ._xmargin and scalex and self ._autoscaleXon :
2840
2849
x_stickies = np .sort (np .concatenate ([
2841
2850
artist .sticky_edges .x
2842
- for ax in self ._shared_x_axes .get_siblings (self )
2851
+ for ax in self ._shared_axes [ "x" ] .get_siblings (self )
2843
2852
if hasattr (ax , "_children" )
2844
2853
for artist in ax .get_children ()]))
2845
2854
if self ._ymargin and scaley and self ._autoscaleYon :
2846
2855
y_stickies = np .sort (np .concatenate ([
2847
2856
artist .sticky_edges .y
2848
- for ax in self ._shared_y_axes .get_siblings (self )
2857
+ for ax in self ._shared_axes [ "y" ] .get_siblings (self )
2849
2858
if hasattr (ax , "_children" )
2850
2859
for artist in ax .get_children ()]))
2851
2860
if self .get_xscale () == 'log' :
@@ -2919,14 +2928,14 @@ def handle_single_axis(scale, autoscaleon, shared_axes, name,
2919
2928
# End of definition of internal function 'handle_single_axis'.
2920
2929
2921
2930
handle_single_axis (
2922
- scalex , self ._autoscaleXon , self ._shared_x_axes , 'x' ,
2931
+ scalex , self ._autoscaleXon , self ._shared_axes [ "x" ] , 'x' ,
2923
2932
self .xaxis , self ._xmargin , x_stickies , self .set_xbound )
2924
2933
handle_single_axis (
2925
- scaley , self ._autoscaleYon , self ._shared_y_axes , 'y' ,
2934
+ scaley , self ._autoscaleYon , self ._shared_axes [ "y" ] , 'y' ,
2926
2935
self .yaxis , self ._ymargin , y_stickies , self .set_ybound )
2927
2936
2928
2937
def _get_axis_list (self ):
2929
- return self . xaxis , self .yaxis
2938
+ return tuple ( getattr ( self , f" { name } axis" ) for name in self ._axis_names )
2930
2939
2931
2940
def _get_axis_map (self ):
2932
2941
"""
@@ -2939,12 +2948,7 @@ def _get_axis_map(self):
2939
2948
In practice, this means that the entries are typically "x" and "y", and
2940
2949
additionally "z" for 3D axes.
2941
2950
"""
2942
- d = {}
2943
- axis_list = self ._get_axis_list ()
2944
- for k , v in vars (self ).items ():
2945
- if k .endswith ("axis" ) and v in axis_list :
2946
- d [k [:- len ("axis" )]] = v
2947
- return d
2951
+ return dict (zip (self ._axis_names , self ._get_axis_list ()))
2948
2952
2949
2953
def _update_title_position (self , renderer ):
2950
2954
"""
@@ -3715,15 +3719,15 @@ def set_xlim(self, left=None, right=None, emit=True, auto=False,
3715
3719
3716
3720
self ._viewLim .intervalx = (left , right )
3717
3721
# Mark viewlims as no longer stale without triggering an autoscale.
3718
- for ax in self ._shared_x_axes .get_siblings (self ):
3719
- ax ._stale_viewlim_x = False
3722
+ for ax in self ._shared_axes [ "x" ] .get_siblings (self ):
3723
+ ax ._stale_viewlims [ "x" ] = False
3720
3724
if auto is not None :
3721
3725
self ._autoscaleXon = bool (auto )
3722
3726
3723
3727
if emit :
3724
3728
self .callbacks .process ('xlim_changed' , self )
3725
3729
# Call all of the other x-axes that are shared with this one
3726
- for other in self ._shared_x_axes .get_siblings (self ):
3730
+ for other in self ._shared_axes [ "x" ] .get_siblings (self ):
3727
3731
if other is not self :
3728
3732
other .set_xlim (self .viewLim .intervalx ,
3729
3733
emit = False , auto = auto )
@@ -4042,15 +4046,15 @@ def set_ylim(self, bottom=None, top=None, emit=True, auto=False,
4042
4046
4043
4047
self ._viewLim .intervaly = (bottom , top )
4044
4048
# Mark viewlims as no longer stale without triggering an autoscale.
4045
- for ax in self ._shared_y_axes .get_siblings (self ):
4046
- ax ._stale_viewlim_y = False
4049
+ for ax in self ._shared_axes [ "y" ] .get_siblings (self ):
4050
+ ax ._stale_viewlims [ "y" ] = False
4047
4051
if auto is not None :
4048
4052
self ._autoscaleYon = bool (auto )
4049
4053
4050
4054
if emit :
4051
4055
self .callbacks .process ('ylim_changed' , self )
4052
4056
# Call all of the other y-axes that are shared with this one
4053
- for other in self ._shared_y_axes .get_siblings (self ):
4057
+ for other in self ._shared_axes [ "y" ] .get_siblings (self ):
4054
4058
if other is not self :
4055
4059
other .set_ylim (self .viewLim .intervaly ,
4056
4060
emit = False , auto = auto )
@@ -4714,8 +4718,8 @@ def twiny(self):
4714
4718
4715
4719
def get_shared_x_axes (self ):
4716
4720
"""Return a reference to the shared axes Grouper object for x axes."""
4717
- return self ._shared_x_axes
4721
+ return self ._shared_axes [ "x" ]
4718
4722
4719
4723
def get_shared_y_axes (self ):
4720
4724
"""Return a reference to the shared axes Grouper object for y axes."""
4721
- return self ._shared_y_axes
4725
+ return self ._shared_axes [ "y" ]
0 commit comments