@@ -137,7 +137,8 @@ def do_constrained_layout(fig, h_pad, w_pad,
137137 layoutgrids [fig ].update_variables ()
138138 if check_no_collapsed_axes (layoutgrids , fig ):
139139 reposition_axes (layoutgrids , fig , renderer , h_pad = h_pad ,
140- w_pad = w_pad , hspace = hspace , wspace = wspace )
140+ w_pad = w_pad , hspace = hspace , wspace = wspace ,
141+ compress = True )
141142 else :
142143 _api .warn_external (warn_collapsed )
143144
@@ -651,7 +652,7 @@ def get_pos_and_bbox(ax, renderer):
651652
652653
653654def reposition_axes (layoutgrids , fig , renderer , * ,
654- w_pad = 0 , h_pad = 0 , hspace = 0 , wspace = 0 ):
655+ w_pad = 0 , h_pad = 0 , hspace = 0 , wspace = 0 , compress = False ):
655656 """
656657 Reposition all the Axes based on the new inner bounding box.
657658 """
@@ -662,7 +663,7 @@ def reposition_axes(layoutgrids, fig, renderer, *,
662663 bbox = bbox .transformed (trans_fig_to_subfig ))
663664 reposition_axes (layoutgrids , sfig , renderer ,
664665 w_pad = w_pad , h_pad = h_pad ,
665- wspace = wspace , hspace = hspace )
666+ wspace = wspace , hspace = hspace , compress = compress )
666667
667668 for ax in fig ._localaxes :
668669 if ax .get_subplotspec () is None or not ax .get_in_layout ():
@@ -689,10 +690,10 @@ def reposition_axes(layoutgrids, fig, renderer, *,
689690 for nn , cbax in enumerate (ax ._colorbars [::- 1 ]):
690691 if ax == cbax ._colorbar_info ['parents' ][0 ]:
691692 reposition_colorbar (layoutgrids , cbax , renderer ,
692- offset = offset )
693+ offset = offset , compress = compress )
693694
694695
695- def reposition_colorbar (layoutgrids , cbax , renderer , * , offset = None ):
696+ def reposition_colorbar (layoutgrids , cbax , renderer , * , offset = None , compress = False ):
696697 """
697698 Place the colorbar in its new place.
698699
@@ -706,6 +707,8 @@ def reposition_colorbar(layoutgrids, cbax, renderer, *, offset=None):
706707 offset : array-like
707708 Offset the colorbar needs to be pushed to in order to
708709 account for multiple colorbars.
710+ compress : bool
711+ Whether we're in compressed layout mode.
709712 """
710713
711714 parents = cbax ._colorbar_info ['parents' ]
@@ -724,6 +727,31 @@ def reposition_colorbar(layoutgrids, cbax, renderer, *, offset=None):
724727 aspect = cbax ._colorbar_info ['aspect' ]
725728 shrink = cbax ._colorbar_info ['shrink' ]
726729
730+ # For colorbars with a single parent in compressed layout,
731+ # use the actual visual size of the parent axis after apply_aspect()
732+ # has been called. This ensures colorbars align with their parent axes.
733+ # This fix is specific to single-parent colorbars where alignment is critical.
734+ if compress and len (parents ) == 1 :
735+ from matplotlib .transforms import Bbox
736+ # Get the actual parent position after apply_aspect()
737+ parent_ax = parents [0 ]
738+ actual_pos = parent_ax .get_position (original = False )
739+ # Transform to figure coordinates
740+ actual_pos_fig = actual_pos .transformed (fig .transSubfigure - fig .transFigure )
741+
742+ if location in ('left' , 'right' ):
743+ # For vertical colorbars, use the actual parent bbox height
744+ # for colorbar sizing
745+ # Keep the pb x-coordinates but use actual y-coordinates
746+ pb = Bbox .from_extents (pb .x0 , actual_pos_fig .y0 ,
747+ pb .x1 , actual_pos_fig .y1 )
748+ elif location in ('top' , 'bottom' ):
749+ # For horizontal colorbars, use the actual parent bbox width
750+ # for colorbar sizing
751+ # Keep the pb y-coordinates but use actual x-coordinates
752+ pb = Bbox .from_extents (actual_pos_fig .x0 , pb .y0 ,
753+ actual_pos_fig .x1 , pb .y1 )
754+
727755 cbpos , cbbbox = get_pos_and_bbox (cbax , renderer )
728756
729757 # Colorbar gets put at extreme edge of outer bbox of the subplotspec
0 commit comments