@@ -163,6 +163,7 @@ def add(
163163 # NOTE: The inset axes function needs 'label' to know how to pad the box
164164 # TODO: Use seperate keywords for frame properties vs. colorbar edge properties?
165165 frame = _not_none (frame = frame , frameon = frameon )
166+ bbox_to_anchor = kwargs .pop ("bbox_to_anchor" , None )
166167 inset_side = loc in ("left" , "right" , "top" , "bottom" ) and getattr (
167168 ax , "_inset_parent" , None
168169 )
@@ -197,7 +198,14 @@ def add(
197198 ** kwargs ,
198199 )
199200 else :
200- kwargs .update ({"label" : label , "length" : length , "width" : width })
201+ kwargs .update (
202+ {
203+ "bbox_to_anchor" : bbox_to_anchor ,
204+ "label" : label ,
205+ "length" : length ,
206+ "width" : width ,
207+ }
208+ )
201209 extendsize = _not_none (extendsize , rc ["colorbar.insetextend" ])
202210 cax , kwargs = ax ._parse_colorbar_inset (
203211 loc = loc ,
@@ -366,9 +374,7 @@ def add(
366374 cax ._inset_colorbar_obj = obj
367375 cax ._inset_colorbar_labelloc = labelloc
368376 cax ._inset_colorbar_ticklen = ticklen
369- has_frame = getattr (cax , "_inset_colorbar_frame" , None ) is not None
370- if has_frame :
371- _register_inset_colorbar_reflow (ax .figure )
377+ _register_inset_colorbar_reflow (ax .figure )
372378 kw_outline = {"edgecolor" : color , "linewidth" : linewidth }
373379 if obj .outline is not None :
374380 obj .outline .update (kw_outline )
@@ -806,6 +812,52 @@ def _solve_inset_colorbar_bounds(
806812 return list (layout ["inset" ]), list (layout ["frame" ])
807813
808814
815+ def _anchor_inset_colorbar_bounds (
816+ bounds_inset : list [float ],
817+ bounds_frame : list [float ],
818+ loc : str ,
819+ bbox_to_anchor ,
820+ ) -> Tuple [list [float ], list [float ]]:
821+ """Align an inset colorbar footprint to a legend-style anchor box."""
822+ if bbox_to_anchor is None :
823+ return bounds_inset , bounds_frame
824+ if isinstance (bbox_to_anchor , mtransforms .BboxBase ):
825+ bbox = bbox_to_anchor
826+ else :
827+ try :
828+ values = tuple (bbox_to_anchor )
829+ except TypeError as exc :
830+ raise ValueError (
831+ "bbox_to_anchor must be a 2- or 4-tuple, or a matplotlib Bbox."
832+ ) from exc
833+ if len (values ) == 2 :
834+ bbox = mtransforms .Bbox .from_bounds (* values , 0 , 0 )
835+ elif len (values ) == 4 :
836+ bbox = mtransforms .Bbox .from_bounds (* values )
837+ else :
838+ raise ValueError (
839+ "bbox_to_anchor must be a 2- or 4-tuple, or a matplotlib Bbox."
840+ )
841+
842+ x , y , width , height = bounds_frame
843+ if loc == "upper left" :
844+ source , target = (x , y + height ), (bbox .x0 , bbox .y1 )
845+ elif loc == "lower left" :
846+ source , target = (x , y ), (bbox .x0 , bbox .y0 )
847+ elif loc == "lower right" :
848+ source , target = (x + width , y ), (bbox .x1 , bbox .y0 )
849+ else : # ``best`` resolves to upper right in the inset layout.
850+ source , target = (x + width , y + height ), (bbox .x1 , bbox .y1 )
851+ dx , dy = target [0 ] - source [0 ], target [1 ] - source [1 ]
852+ inset = list (bounds_inset )
853+ frame = list (bounds_frame )
854+ inset [0 ] += dx
855+ inset [1 ] += dy
856+ frame [0 ] += dx
857+ frame [1 ] += dy
858+ return inset , frame
859+
860+
809861def _legacy_inset_colorbar_bounds (
810862 * ,
811863 axes : maxes .Axes ,
@@ -1089,9 +1141,15 @@ def _reflow_inset_colorbar_frame(
10891141 bounds = solver .solve ()
10901142 except Exception :
10911143 return
1144+ bounds_inset , bounds_frame = _anchor_inset_colorbar_bounds (
1145+ list (bounds ["inset" ]),
1146+ list (bounds ["frame" ]),
1147+ loc ,
1148+ layout .get ("bbox_to_anchor" ),
1149+ )
10921150 _apply_inset_colorbar_layout (
10931151 cax ,
1094- bounds_inset = list ( bounds [ "inset" ]) ,
1095- bounds_frame = list ( bounds [ "frame" ]) ,
1152+ bounds_inset = bounds_inset ,
1153+ bounds_frame = bounds_frame ,
10961154 frame = frame ,
10971155 )
0 commit comments