@@ -614,6 +614,10 @@ def __str__(self):
614614 return "{0}({1[0]:g},{1[1]:g};{1[2]:g}x{1[3]:g})" .format (
615615 type (self ).__name__ , self ._position .bounds )
616616
617+ def set_zorder (self , level ):
618+ super ().set_zorder (level )
619+ self ._update_twinned_axes_patch_visibility ()
620+
617621 def __init__ (self , fig ,
618622 * args ,
619623 facecolor = None , # defaults to rc axes.facecolor
@@ -3324,6 +3328,7 @@ def set_frame_on(self, b):
33243328 b : bool
33253329 """
33263330 self ._frameon = b
3331+ self ._update_twinned_axes_patch_visibility ()
33273332 self .stale = True
33283333
33293334 def get_axisbelow (self ):
@@ -4705,7 +4710,32 @@ def get_tightbbox(self, renderer=None, *, call_axes_locator=True,
47054710 return mtransforms .Bbox .union (
47064711 [b for b in bb if b .width != 0 or b .height != 0 ])
47074712
4708- def _make_twin_axes (self , * args , ** kwargs ):
4713+ def _update_twinned_axes_patch_visibility (self ):
4714+ """
4715+ Update patch visibility for a group of twinned Axes.
4716+
4717+ Only the bottom-most Axes in the group (lowest zorder, breaking ties by
4718+ creation/insertion order) has a visible background patch.
4719+ """
4720+ if self not in self ._twinned_axes :
4721+ return
4722+ twinned = list (self ._twinned_axes .get_siblings (self ))
4723+ if not twinned :
4724+ return
4725+ fig = self .get_figure (root = False )
4726+ fig_axes = fig .axes if fig is not None else []
4727+ insertion_order = {ax : idx for idx , ax in enumerate (fig_axes )}
4728+
4729+ twinned .sort (
4730+ key = lambda ax : (ax .get_zorder (), insertion_order .get (ax , len (fig_axes )))
4731+ )
4732+ bottom = twinned [0 ]
4733+ for ax in twinned :
4734+ patch = getattr (ax , "patch" , None )
4735+ if patch is not None :
4736+ patch .set_visible ((ax is bottom ) and ax .get_frame_on ())
4737+
4738+ def _make_twin_axes (self , * args , delta_zorder = 0.0 , ** kwargs ):
47094739 """Make a twinx Axes of self. This is used for twinx and twiny."""
47104740 if 'sharex' in kwargs and 'sharey' in kwargs :
47114741 # The following line is added in v2.2 to avoid breaking Seaborn,
@@ -4722,12 +4752,13 @@ def _make_twin_axes(self, *args, **kwargs):
47224752 [0 , 0 , 1 , 1 ], self .transAxes ))
47234753 self .set_adjustable ('datalim' )
47244754 twin .set_adjustable ('datalim' )
4725- twin .set_zorder (self .zorder )
4755+ twin .set_zorder (self .get_zorder () + delta_zorder )
47264756
47274757 self ._twinned_axes .join (self , twin )
4758+ self ._update_twinned_axes_patch_visibility ()
47284759 return twin
47294760
4730- def twinx (self , axes_class = None , ** kwargs ):
4761+ def twinx (self , axes_class = None , * , delta_zorder = 0.0 , * *kwargs ):
47314762 """
47324763 Create a twin Axes sharing the xaxis.
47334764
@@ -4748,6 +4779,12 @@ def twinx(self, axes_class=None, **kwargs):
47484779
47494780 .. versionadded:: 3.11
47504781
4782+ delta_zorder : float, default: 0
4783+ A zorder offset for the twin Axes, relative to the original Axes.
4784+ The twin's zorder is set to ``self.get_zorder() + delta_zorder``.
4785+ By default (*delta_zorder* is 0), the twin has the same zorder as
4786+ the original Axes.
4787+
47514788 kwargs : dict
47524789 The keyword arguments passed to `.Figure.add_subplot` or `.Figure.add_axes`.
47534790
@@ -4765,18 +4802,17 @@ def twinx(self, axes_class=None, **kwargs):
47654802 """
47664803 if axes_class :
47674804 kwargs ["axes_class" ] = axes_class
4768- ax2 = self ._make_twin_axes (sharex = self , ** kwargs )
4805+ ax2 = self ._make_twin_axes (sharex = self , delta_zorder = delta_zorder , ** kwargs )
47694806 ax2 .yaxis .tick_right ()
47704807 ax2 .yaxis .set_label_position ('right' )
47714808 ax2 .yaxis .set_offset_position ('right' )
47724809 ax2 .set_autoscalex_on (self .get_autoscalex_on ())
47734810 self .yaxis .tick_left ()
47744811 ax2 .xaxis .set_visible (False )
4775- ax2 .patch .set_visible (False )
47764812 ax2 .xaxis .units = self .xaxis .units
47774813 return ax2
47784814
4779- def twiny (self , axes_class = None , ** kwargs ):
4815+ def twiny (self , axes_class = None , * , delta_zorder = 0.0 , * *kwargs ):
47804816 """
47814817 Create a twin Axes sharing the yaxis.
47824818
@@ -4797,6 +4833,12 @@ def twiny(self, axes_class=None, **kwargs):
47974833
47984834 .. versionadded:: 3.11
47994835
4836+ delta_zorder : float, default: 0
4837+ A zorder offset for the twin Axes, relative to the original Axes.
4838+ The twin's zorder is set to ``self.get_zorder() + delta_zorder``.
4839+ By default (*delta_zorder* is 0), the twin has the same zorder as
4840+ the original Axes.
4841+
48004842 kwargs : dict
48014843 The keyword arguments passed to `.Figure.add_subplot` or `.Figure.add_axes`.
48024844
@@ -4814,13 +4856,12 @@ def twiny(self, axes_class=None, **kwargs):
48144856 """
48154857 if axes_class :
48164858 kwargs ["axes_class" ] = axes_class
4817- ax2 = self ._make_twin_axes (sharey = self , ** kwargs )
4859+ ax2 = self ._make_twin_axes (sharey = self , delta_zorder = delta_zorder , ** kwargs )
48184860 ax2 .xaxis .tick_top ()
48194861 ax2 .xaxis .set_label_position ('top' )
48204862 ax2 .set_autoscaley_on (self .get_autoscaley_on ())
48214863 self .xaxis .tick_bottom ()
48224864 ax2 .yaxis .set_visible (False )
4823- ax2 .patch .set_visible (False )
48244865 ax2 .yaxis .units = self .yaxis .units
48254866 return ax2
48264867
0 commit comments