@@ -769,7 +769,7 @@ def __init__(self, *args, **kwargs):
769769 self ._inset_zoom = False
770770 self ._inset_zoom_artists = None
771771 self ._panel_hidden = False # True when "filled" with cbar/legend
772- self ._panel_align = set () # store align values for "filled" cbar/legend
772+ self ._panel_align = {} # store ' align' and 'length' for "filled" cbar/legend
773773 self ._panel_parent = None
774774 self ._panel_share = False
775775 self ._panel_sharex_group = False
@@ -852,17 +852,37 @@ def _add_guide_frame(
852852 self .add_artist (patch )
853853 return patch
854854
855- def _add_guide_panel (self , loc = 'fill' , align = 'center' , ** kwargs ):
855+ def _add_guide_panel (self , loc = 'fill' , align = 'center' , length = 0 , ** kwargs ):
856856 """
857857 Add a panel to be filled by an "outer" colorbar or legend.
858858 """
859+ # Helper function: Return bounds inferred from given align setting.
860+ def _align_bbox (align , length ):
861+ if align in ('left' , 'bottom' ):
862+ bounds = [[0 , 0 ], [length , 0 ]]
863+ elif align in ('top' , 'right' ):
864+ bounds = [[1 - length , 0 ], [1 , 0 ]]
865+ else :
866+ bounds = [[0.5 * (1 - length ), 0 ], [0.5 * (1 + length ), 0 ]]
867+ return mtransforms .Bbox (bounds )
868+ # NOTE: For colorbars we include 'length' when determining whether to allocate
869+ # new panel but for legend just test whether that 'align' position was filled.
859870 # WARNING: Hide content but 1) do not use ax.set_visible(False) so that
860871 # tight layout will include legend and colorbar and 2) do not use
861872 # ax.clear() so that top panel title and a-b-c label can remain.
862- if loc in ('left' , 'right' , 'top' , 'bottom' ):
863- ax = self .panel_axes (loc , filled = True , ** kwargs )
864- elif loc == 'fill' :
873+ if loc == 'fill' :
865874 ax = self
875+ elif loc in ('left' , 'right' , 'top' , 'bottom' ):
876+ ax = None
877+ bbox = _align_bbox (align , length )
878+ for pax in self ._panel_dict [loc ]:
879+ if not pax ._panel_hidden or align in pax ._panel_align :
880+ continue
881+ if not any (bbox .overlaps (_align_bbox (a , l )) for a , l in pax ._panel_align .items ()): # noqa: E501
882+ ax = pax
883+ break
884+ if ax is None :
885+ ax = self .panel_axes (loc , filled = True , ** kwargs )
866886 else :
867887 raise ValueError (f'Invalid filled panel location { loc !r} .' )
868888 for s in ax .spines .values ():
@@ -871,7 +891,7 @@ def _add_guide_panel(self, loc='fill', align='center', **kwargs):
871891 ax .yaxis .set_visible (False )
872892 ax .patch .set_facecolor ('none' )
873893 ax ._panel_hidden = True
874- ax ._panel_align . add ( align )
894+ ax ._panel_align [ align ] = length
875895 return ax
876896
877897 def _add_inset_axes (
@@ -919,6 +939,7 @@ def _add_inset_axes(
919939 def _add_colorbar (
920940 self , mappable , values = None , * ,
921941 loc = None , space = None , pad = None , align = None ,
942+ width = None , length = None , shrink = None ,
922943 label = None , title = None , reverse = False ,
923944 rotation = None , grid = None , edges = None , drawedges = None ,
924945 extend = None , extendsize = None , extendfrac = None ,
@@ -940,6 +961,7 @@ def _add_colorbar(
940961 # and implement inset colorbars the same as inset legends.
941962 grid = _not_none (grid = grid , edges = edges , drawedges = drawedges , default = rc ['colorbar.grid' ]) # noqa: E501
942963 align = _translate_loc (align , 'panel' , default = 'center' , c = 'center' , center = 'center' ) # noqa: E501
964+ length = _not_none (length = length , shrink = shrink )
943965 label = _not_none (title = title , label = label )
944966 labelloc = _not_none (labelloc = labelloc , labellocation = labellocation )
945967 locator = _not_none (ticks = ticks , locator = locator )
@@ -989,16 +1011,16 @@ def _add_colorbar(
9891011 # Generate and prepare the colorbar axes
9901012 # NOTE: The inset axes function needs 'label' to know how to pad the box
9911013 # TODO: Use seperate keywords for frame properties vs. colorbar edge properties?
992- width = kwargs .pop ('width' , None )
9931014 if loc in ('fill' , 'left' , 'right' , 'top' , 'bottom' ):
994- kwargs ['align' ] = align
1015+ length = _not_none (length , rc ['colorbar.length' ])
1016+ kwargs .update ({'align' : align , 'length' : length })
9951017 extendsize = _not_none (extendsize , rc ['colorbar.extend' ])
996- ax = self ._add_guide_panel (loc , width = width , space = space , pad = pad )
1018+ ax = self ._add_guide_panel (loc , align , length = length , width = width , space = space , pad = pad ) # noqa: E501
9971019 cax , kwargs = ax ._parse_colorbar_filled (** kwargs )
9981020 else :
999- kwargs [ 'label' ] = label # for frame calculations
1021+ kwargs . update ({ 'label' : label , 'length' : length , 'width' : width })
10001022 extendsize = _not_none (extendsize , rc ['colorbar.insetextend' ])
1001- cax , kwargs = self ._parse_colorbar_inset (loc = loc , pad = pad , width = width , ** kwargs ) # noqa: E501
1023+ cax , kwargs = self ._parse_colorbar_inset (loc = loc , pad = pad , ** kwargs ) # noqa: E501
10021024
10031025 # Parse the colorbar mappable
10041026 # NOTE: Account for special case where auto colorbar is generated from 1D
@@ -1160,7 +1182,7 @@ def _add_legend(
11601182
11611183 # Generate and prepare the legend axes
11621184 if loc in ('fill' , 'left' , 'right' , 'top' , 'bottom' ):
1163- lax = self ._add_guide_panel (loc , width = width , space = space , pad = pad )
1185+ lax = self ._add_guide_panel (loc , align , width = width , space = space , pad = pad )
11641186 kwargs .setdefault ('borderaxespad' , 0 )
11651187 if not frameon :
11661188 kwargs .setdefault ('borderpad' , 0 )
@@ -1837,8 +1859,8 @@ def _parse_colorbar_arg(
18371859 return mappable , locator , formatter , kwargs
18381860
18391861 def _parse_colorbar_filled (
1840- self , length = None , shrink = None , align = None ,
1841- tickloc = None , ticklocation = None , orientation = None , ** kwargs
1862+ self , length = None , align = None , tickloc = None , ticklocation = None ,
1863+ orientation = None , ** kwargs
18421864 ):
18431865 """
18441866 Return the axes and adjusted keyword args for a panel-filling colorbar.
@@ -1847,7 +1869,7 @@ def _parse_colorbar_filled(
18471869 side = self ._panel_side
18481870 side = _not_none (side , 'left' if orientation == 'vertical' else 'bottom' )
18491871 align = _not_none (align , 'center' )
1850- length = _not_none (length = length , shrink = shrink , default = rc ['colorbar.length' ])
1872+ length = _not_none (length = length , default = rc ['colorbar.length' ])
18511873 ticklocation = _not_none (tickloc = tickloc , ticklocation = ticklocation )
18521874
18531875 # Calculate inset bounds for the colorbar
0 commit comments