@@ -612,21 +612,28 @@ class _AxesBase(martist.Artist):
612612
613613 def __str__ (self ):
614614 return "{0}({1[0]:g},{1[1]:g};{1[2]:g}x{1[3]:g})" .format (
615- type (self ).__name__ , self ._position .bounds )
616-
617- def __init__ (self , fig ,
618- * args ,
619- facecolor = None , # defaults to rc axes.facecolor
620- frameon = True ,
621- sharex = None , # use Axes instance's xaxis info
622- sharey = None , # use Axes instance's yaxis info
623- label = '' ,
624- xscale = None ,
625- yscale = None ,
626- box_aspect = None ,
627- forward_navigation_events = "auto" ,
628- ** kwargs
629- ):
615+ type (self ).__name__ , self ._position .bounds
616+ )
617+
618+ def set_zorder (self , level ):
619+ super ().set_zorder (level )
620+ self ._update_twinned_axes_patch_visibility ()
621+
622+ def __init__ (
623+ self ,
624+ fig ,
625+ * args ,
626+ facecolor = None , # defaults to rc axes.facecolor
627+ frameon = True ,
628+ sharex = None , # use Axes instance's xaxis info
629+ sharey = None , # use Axes instance's yaxis info
630+ label = "" ,
631+ xscale = None ,
632+ yscale = None ,
633+ box_aspect = None ,
634+ forward_navigation_events = "auto" ,
635+ ** kwargs ,
636+ ):
630637 """
631638 Build an Axes in a figure.
632639
@@ -3316,6 +3323,7 @@ def set_frame_on(self, b):
33163323 b : bool
33173324 """
33183325 self ._frameon = b
3326+ self ._update_twinned_axes_patch_visibility ()
33193327 self .stale = True
33203328
33213329 def get_axisbelow (self ):
@@ -4680,12 +4688,36 @@ def get_tightbbox(self, renderer=None, *, call_axes_locator=True,
46804688 bbox = a .get_tightbbox (renderer )
46814689 if bbox is not None and bbox ._is_finite ():
46824690 bb .append (bbox )
4683- return mtransforms .Bbox .union (
4684- [b for b in bb if b .width != 0 or b .height != 0 ])
4691+ return mtransforms .Bbox .union ([b for b in bb if b .width != 0 or b .height != 0 ])
46854692
4686- def _make_twin_axes (self , * args , ** kwargs ):
4693+ def _update_twinned_axes_patch_visibility (self ):
4694+ """
4695+ Update patch visibility for a group of twinned Axes.
4696+
4697+ Only the bottom-most Axes in the group (lowest zorder, breaking ties by
4698+ creation/insertion order) has a visible background patch.
4699+ """
4700+ if self not in self ._twinned_axes :
4701+ return
4702+ twinned = list (self ._twinned_axes .get_siblings (self ))
4703+ if not twinned :
4704+ return
4705+ fig = self .get_figure (root = False )
4706+ fig_axes = fig .axes if fig is not None else []
4707+ insertion_order = {ax : idx for idx , ax in enumerate (fig_axes )}
4708+
4709+ twinned .sort (
4710+ key = lambda ax : (ax .get_zorder (), insertion_order .get (ax , len (fig_axes )))
4711+ )
4712+ bottom = twinned [0 ]
4713+ for ax in twinned :
4714+ patch = getattr (ax , "patch" , None )
4715+ if patch is not None :
4716+ patch .set_visible ((ax is bottom ) and ax .get_frame_on ())
4717+
4718+ def _make_twin_axes (self , * args , delta_zorder = 0.0 , ** kwargs ):
46874719 """Make a twinx Axes of self. This is used for twinx and twiny."""
4688- if ' sharex' in kwargs and ' sharey' in kwargs :
4720+ if " sharex" in kwargs and " sharey" in kwargs :
46894721 # The following line is added in v2.2 to avoid breaking Seaborn,
46904722 # which currently uses this internal API.
46914723 if kwargs ["sharex" ] is not self and kwargs ["sharey" ] is not self :
@@ -4695,17 +4727,20 @@ def _make_twin_axes(self, *args, **kwargs):
46954727 twin = self .get_figure (root = False ).add_subplot (ss , * args , ** kwargs )
46964728 else :
46974729 twin = self .get_figure (root = False ).add_axes (
4698- self .get_position (True ), * args , ** kwargs ,
4699- axes_locator = _TransformedBoundsLocator (
4700- [0 , 0 , 1 , 1 ], self .transAxes ))
4701- self .set_adjustable ('datalim' )
4702- twin .set_adjustable ('datalim' )
4703- twin .set_zorder (self .zorder )
4730+ self .get_position (True ),
4731+ * args ,
4732+ ** kwargs ,
4733+ axes_locator = _TransformedBoundsLocator ([0 , 0 , 1 , 1 ], self .transAxes ),
4734+ )
4735+ self .set_adjustable ("datalim" )
4736+ twin .set_adjustable ("datalim" )
4737+ twin .set_zorder (self .get_zorder () + delta_zorder )
47044738
47054739 self ._twinned_axes .join (self , twin )
4740+ self ._update_twinned_axes_patch_visibility ()
47064741 return twin
47074742
4708- def twinx (self , axes_class = None , ** kwargs ):
4743+ def twinx (self , axes_class = None , * , delta_zorder = 0.0 , * *kwargs ):
47094744 """
47104745 Create a twin Axes sharing the xaxis.
47114746
@@ -4726,6 +4761,12 @@ def twinx(self, axes_class=None, **kwargs):
47264761
47274762 .. versionadded:: 3.11
47284763
4764+ delta_zorder : float, default: 0
4765+ A zorder offset for the twin Axes, relative to the original Axes.
4766+ The twin's zorder is set to ``self.get_zorder() + delta_zorder``.
4767+ By default (*delta_zorder* is 0), the twin has the same zorder as
4768+ the original Axes.
4769+
47294770 kwargs : dict
47304771 The keyword arguments passed to `.Figure.add_subplot` or `.Figure.add_axes`.
47314772
@@ -4743,18 +4784,17 @@ def twinx(self, axes_class=None, **kwargs):
47434784 """
47444785 if axes_class :
47454786 kwargs ["axes_class" ] = axes_class
4746- ax2 = self ._make_twin_axes (sharex = self , ** kwargs )
4787+ ax2 = self ._make_twin_axes (sharex = self , delta_zorder = delta_zorder , ** kwargs )
47474788 ax2 .yaxis .tick_right ()
4748- ax2 .yaxis .set_label_position (' right' )
4749- ax2 .yaxis .set_offset_position (' right' )
4789+ ax2 .yaxis .set_label_position (" right" )
4790+ ax2 .yaxis .set_offset_position (" right" )
47504791 ax2 .set_autoscalex_on (self .get_autoscalex_on ())
47514792 self .yaxis .tick_left ()
47524793 ax2 .xaxis .set_visible (False )
4753- ax2 .patch .set_visible (False )
47544794 ax2 .xaxis .units = self .xaxis .units
47554795 return ax2
47564796
4757- def twiny (self , axes_class = None , ** kwargs ):
4797+ def twiny (self , axes_class = None , * , delta_zorder = 0.0 , * *kwargs ):
47584798 """
47594799 Create a twin Axes sharing the yaxis.
47604800
@@ -4775,6 +4815,12 @@ def twiny(self, axes_class=None, **kwargs):
47754815
47764816 .. versionadded:: 3.11
47774817
4818+ delta_zorder : float, default: 0
4819+ A zorder offset for the twin Axes, relative to the original Axes.
4820+ The twin's zorder is set to ``self.get_zorder() + delta_zorder``.
4821+ By default (*delta_zorder* is 0), the twin has the same zorder as
4822+ the original Axes.
4823+
47784824 kwargs : dict
47794825 The keyword arguments passed to `.Figure.add_subplot` or `.Figure.add_axes`.
47804826
@@ -4792,13 +4838,12 @@ def twiny(self, axes_class=None, **kwargs):
47924838 """
47934839 if axes_class :
47944840 kwargs ["axes_class" ] = axes_class
4795- ax2 = self ._make_twin_axes (sharey = self , ** kwargs )
4841+ ax2 = self ._make_twin_axes (sharey = self , delta_zorder = delta_zorder , ** kwargs )
47964842 ax2 .xaxis .tick_top ()
4797- ax2 .xaxis .set_label_position (' top' )
4843+ ax2 .xaxis .set_label_position (" top" )
47984844 ax2 .set_autoscaley_on (self .get_autoscaley_on ())
47994845 self .xaxis .tick_bottom ()
48004846 ax2 .yaxis .set_visible (False )
4801- ax2 .patch .set_visible (False )
48024847 ax2 .yaxis .units = self .yaxis .units
48034848 return ax2
48044849
0 commit comments