@@ -462,6 +462,13 @@ def __init__(self, fig, rect,
462
462
to share the x-axis with
463
463
*sharey* an class:`~matplotlib.axes.Axes` instance
464
464
to share the y-axis with
465
+ *share_tickers* [ *True* | *False* ] whether the major and
466
+ minor `Formatter` and `Locator` instances
467
+ are always shared (if `True`) or can be set
468
+ independently (if `False`) between this set
469
+ of axes and `sharex` and `sharey`. This
470
+ argument has no meaning if neither `sharex`
471
+ nor `sharey` are set. Defaults to `True`.
465
472
*title* the title string
466
473
*visible* [ *True* | *False* ] whether the axes is
467
474
visible
@@ -476,6 +483,14 @@ def __init__(self, fig, rect,
476
483
*yticklabels* sequence of strings
477
484
*yticks* sequence of floats
478
485
================ =========================================
486
+
487
+ .. warning::
488
+
489
+ Setting `share_tickers` to `False` and changing the
490
+ `Locator`s of a shared axis may not play with autoscaling.
491
+ Autoscaling may need to access the `Locator` object of the
492
+ base axis. Normally, with `share_tickers=True`, the axes
493
+ are guaranteed to share a `Locator` instance.
479
494
""" % {'scale' : ' | ' .join (
480
495
[repr (x ) for x in mscale .get_scale_names ()])}
481
496
martist .Artist .__init__ (self )
@@ -493,6 +508,10 @@ def __init__(self, fig, rect,
493
508
self .set_anchor ('C' )
494
509
self ._sharex = sharex
495
510
self ._sharey = sharey
511
+ # share_tickers is only used as a modifier for sharex/y. It
512
+ # should not remain in kwargs by the time kwargs updates the
513
+ # instance dictionary.
514
+ self ._share_tickers = kwargs .pop ('share_tickers' , True )
496
515
if sharex is not None :
497
516
self ._shared_x_axes .join (self , sharex )
498
517
if sharex ._adjustable == 'box' :
@@ -968,50 +987,52 @@ def cla(self):
968
987
self .callbacks = cbook .CallbackRegistry ()
969
988
970
989
if self ._sharex is not None :
971
- # major and minor are class instances with
972
- # locator and formatter attributes
973
- self .xaxis .major = self ._sharex .xaxis .major
974
- self .xaxis .minor = self ._sharex .xaxis .minor
990
+ # The tickers need to exist but can be empty until after the
991
+ # call to Axis._set_scale since they will be overwritten
992
+ # anyway
993
+ self .xaxis .major = maxis .Ticker ()
994
+ self .xaxis .minor = maxis .Ticker ()
995
+
996
+ # Copy the axis limits
975
997
x0 , x1 = self ._sharex .get_xlim ()
976
998
self .set_xlim (x0 , x1 , emit = False , auto = None )
977
999
978
- # Save the current formatter/locator so we don't lose it
979
- majf = self ._sharex .xaxis .get_major_formatter ()
980
- minf = self ._sharex .xaxis .get_minor_formatter ()
981
- majl = self ._sharex .xaxis .get_major_locator ()
982
- minl = self ._sharex .xaxis .get_minor_locator ()
983
-
984
1000
# This overwrites the current formatter/locator
985
1001
self .xaxis ._set_scale (self ._sharex .xaxis .get_scale ())
986
1002
987
- # Reset the formatter/locator
988
- self .xaxis .set_major_formatter (majf )
989
- self .xaxis .set_minor_formatter (minf )
990
- self .xaxis .set_major_locator (majl )
991
- self .xaxis .set_minor_locator (minl )
1003
+ # Reset the formatter/locator. Axis handle gets marked as
1004
+ # stale in previous line, no need to repeat.
1005
+ if self ._share_tickers :
1006
+ self .xaxis .major = self ._sharex .xaxis .major
1007
+ self .xaxis .minor = self ._sharex .xaxis .minor
1008
+ else :
1009
+ self .xaxis .major .update_from (self ._sharex .xaxis .major )
1010
+ self .xaxis .minor .update_from (self ._sharex .xaxis .minor )
992
1011
else :
993
1012
self .xaxis ._set_scale ('linear' )
994
1013
995
1014
if self ._sharey is not None :
996
- self .yaxis .major = self ._sharey .yaxis .major
997
- self .yaxis .minor = self ._sharey .yaxis .minor
1015
+ # The tickers need to exist but can be empty until after the
1016
+ # call to Axis._set_scale since they will be overwritten
1017
+ # anyway
1018
+ self .yaxis .major = maxis .Ticker ()
1019
+ self .yaxis .minor = maxis .Ticker ()
1020
+
1021
+ # Copy the axis limits
998
1022
y0 , y1 = self ._sharey .get_ylim ()
999
1023
self .set_ylim (y0 , y1 , emit = False , auto = None )
1000
1024
1001
- # Save the current formatter/locator so we don't lose it
1002
- majf = self ._sharey .yaxis .get_major_formatter ()
1003
- minf = self ._sharey .yaxis .get_minor_formatter ()
1004
- majl = self ._sharey .yaxis .get_major_locator ()
1005
- minl = self ._sharey .yaxis .get_minor_locator ()
1006
-
1007
1025
# This overwrites the current formatter/locator
1008
1026
self .yaxis ._set_scale (self ._sharey .yaxis .get_scale ())
1009
1027
1010
- # Reset the formatter/locator
1011
- self .yaxis .set_major_formatter (majf )
1012
- self .yaxis .set_minor_formatter (minf )
1013
- self .yaxis .set_major_locator (majl )
1014
- self .yaxis .set_minor_locator (minl )
1028
+ # Reset the formatter/locator. Axis handle gets marked as
1029
+ # stale in previous line, no need to repeat.
1030
+ if self ._share_tickers :
1031
+ self .yaxis .major = self ._sharey .yaxis .major
1032
+ self .yaxis .minor = self ._sharey .yaxis .minor
1033
+ else :
1034
+ self .yaxis .major .update_from (self ._sharey .yaxis .major )
1035
+ self .yaxis .minor .update_from (self ._sharey .yaxis .minor )
1015
1036
else :
1016
1037
self .yaxis ._set_scale ('linear' )
1017
1038
@@ -3898,15 +3919,29 @@ def _make_twin_axes(self, *kl, **kwargs):
3898
3919
ax2 = self .figure .add_axes (self .get_position (True ), * kl , ** kwargs )
3899
3920
return ax2
3900
3921
3901
- def twinx (self ):
3922
+ def twinx (self , share_tickers = True ):
3902
3923
"""
3903
- Create a twin Axes sharing the xaxis
3924
+ Create a twin Axes sharing the xaxis.
3904
3925
3905
- Create a new Axes instance with an invisible x-axis and an independent
3906
- y-axis positioned opposite to the original one (i.e. at right). The
3907
- x-axis autoscale setting will be inherited from the original Axes.
3908
- To ensure that the tick marks of both y-axes align, see
3909
- `~matplotlib.ticker.LinearLocator`
3926
+ Create a new Axes instance with an invisible x-axis and an
3927
+ independent y-axis positioned opposite to the original one (i.e.
3928
+ at right). The x-axis autoscale setting will be inherited from
3929
+ the original Axes. To ensure that the tick marks of both y-axes
3930
+ align, see :class:`matplotlib.ticker.LinearLocator`.
3931
+
3932
+ `share_tickers` determines if the shared axis will always have
3933
+ the same major and minor `Formatter` and `Locator` objects as
3934
+ this one. This is usually desirable since the axes overlap.
3935
+ However, if one of the axes is shifted so that they are both
3936
+ visible, it may be useful to set this parameter to ``False``.
3937
+
3938
+ .. warning::
3939
+
3940
+ Setting `share_tickers` to `False` and modifying the
3941
+ `Locator` of either axis may cause problems with
3942
+ autoscaling. Autoscaling may require access to the
3943
+ `Locator`, so the behavior will be undefined if the base and
3944
+ twinned axis do not share a `Locator` instance.
3910
3945
3911
3946
Returns
3912
3947
-------
@@ -3918,7 +3953,7 @@ def twinx(self):
3918
3953
For those who are 'picking' artists while using twinx, pick
3919
3954
events are only called for the artists in the top-most axes.
3920
3955
"""
3921
- ax2 = self ._make_twin_axes (sharex = self )
3956
+ ax2 = self ._make_twin_axes (sharex = self , share_tickers = share_tickers )
3922
3957
ax2 .yaxis .tick_right ()
3923
3958
ax2 .yaxis .set_label_position ('right' )
3924
3959
ax2 .yaxis .set_offset_position ('right' )
@@ -3928,15 +3963,29 @@ def twinx(self):
3928
3963
ax2 .patch .set_visible (False )
3929
3964
return ax2
3930
3965
3931
- def twiny (self ):
3966
+ def twiny (self , share_tickers = True ):
3932
3967
"""
3933
- Create a twin Axes sharing the yaxis
3968
+ Create a twin Axes sharing the yaxis.
3969
+
3970
+ Create a new Axes instance with an invisible y-axis and an
3971
+ independent x-axis positioned opposite to the original one (i.e.
3972
+ at top). The y-axis autoscale setting will be inherited from the
3973
+ original Axes. To ensure that the tick marks of both x-axes
3974
+ align, see :class:`matplotlib.ticker.LinearLocator`
3975
+
3976
+ `share_tickers` determines if the shared axis will always have
3977
+ the same major and minor `Formatter` and `Locator` objects as
3978
+ this one. This is usually desirable since the axes overlap.
3979
+ However, if one of the axes is shifted so that they are both
3980
+ visible, it may be useful to set this parameter to ``False``.
3981
+
3982
+ .. warning::
3934
3983
3935
- Create a new Axes instance with an invisible y-axis and an independent
3936
- x-axis positioned opposite to the original one (i.e. at top). The
3937
- y-axis autoscale setting will be inherited from the original Axes.
3938
- To ensure that the tick marks of both x-axes align, see
3939
- `~matplotlib.ticker.LinearLocator`
3984
+ Setting `share_tickers` to `False` and modifying the
3985
+ `Locator` of either axis may cause problems with
3986
+ autoscaling. Autoscaling may require access to the
3987
+ `Locator`, so the behavior will be undefined if the base and
3988
+ twinned axis do not share a `Locator` instance.
3940
3989
3941
3990
Returns
3942
3991
-------
@@ -3948,7 +3997,7 @@ def twiny(self):
3948
3997
For those who are 'picking' artists while using twiny, pick
3949
3998
events are only called for the artists in the top-most axes.
3950
3999
"""
3951
- ax2 = self ._make_twin_axes (sharey = self )
4000
+ ax2 = self ._make_twin_axes (sharey = self , share_tickers = share_tickers )
3952
4001
ax2 .xaxis .tick_top ()
3953
4002
ax2 .xaxis .set_label_position ('top' )
3954
4003
ax2 .set_autoscaley_on (self .get_autoscaley_on ())
0 commit comments