1616from dask .dataframe import DataFrame as DaskDataFrame
1717from geopandas import GeoDataFrame
1818from matplotlib .axes import Axes
19+ from matplotlib .backend_bases import RendererBase
1920from matplotlib .colors import Colormap , Normalize
2021from matplotlib .figure import Figure
22+ from mpl_toolkits .axes_grid1 import make_axes_locatable
23+ from mpl_toolkits .axes_grid1 .axes_divider import AxesDivider
2124from spatialdata import get_extent
2225from spatialdata ._utils import _deprecation_alias
2326from xarray import DataArray , DataTree
@@ -953,7 +956,12 @@ def show(
953956 colorbar = legend_colorbar ,
954957 )
955958
956- def _draw_colorbar (spec : ColorbarSpec ) -> None :
959+ def _draw_colorbar (
960+ spec : ColorbarSpec ,
961+ divider : AxesDivider ,
962+ renderer : RendererBase ,
963+ location_offsets : dict [str , float ],
964+ ) -> None :
957965 base_layout = {
958966 "location" : CBAR_DEFAULT_LOCATION ,
959967 "fraction" : CBAR_DEFAULT_FRACTION ,
@@ -965,23 +973,20 @@ def _draw_colorbar(spec: ColorbarSpec) -> None:
965973 cbar_kwargs = {** layer_kwargs , ** global_kwargs }
966974
967975 location = cast (str , layout .get ("location" , base_layout ["location" ]))
968- allowed_locations = {"left" , "right" , "top" , "bottom" }
969- if location not in allowed_locations :
976+ if location not in {"left" , "right" , "top" , "bottom" }:
970977 location = CBAR_DEFAULT_LOCATION
971978 default_orientation = "vertical" if location in {"right" , "left" } else "horizontal"
972979 cbar_kwargs .setdefault ("orientation" , default_orientation )
973980
974981 fraction = float (cast (float | int , layout .get ("fraction" , base_layout ["fraction" ])))
975982 pad = float (cast (float | int , layout .get ("pad" , base_layout ["pad" ])))
976983
977- cb = fig_params .fig .colorbar (
978- spec .mappable ,
979- ax = spec .ax ,
980- location = location ,
981- fraction = fraction ,
982- pad = pad ,
983- ** cbar_kwargs ,
984- )
984+ total_pad = location_offsets .get (location , 0.0 ) + pad
985+ size_spec = f"{ max (fraction , 0 ) * 100 :.3f} %"
986+ pad_spec = f"{ max (total_pad , 0 ) * 100 :.3f} %"
987+ cax = divider .append_axes (location , size = size_spec , pad = pad_spec )
988+
989+ cb = fig_params .fig .colorbar (spec .mappable , cax = cax , ** cbar_kwargs )
985990 if location == "left" :
986991 cb .ax .yaxis .set_ticks_position ("left" )
987992 cb .ax .yaxis .set_label_position ("left" )
@@ -1005,6 +1010,20 @@ def _draw_colorbar(spec: ColorbarSpec) -> None:
10051010 if spec .alpha is not None :
10061011 with contextlib .suppress (Exception ):
10071012 cb .solids .set_alpha (spec .alpha )
1013+ bbox_axes = cb .ax .get_tightbbox (renderer ).transformed (spec .ax .transAxes .inverted ())
1014+ span = float (bbox_axes .width if location in {"left" , "right" } else bbox_axes .height )
1015+ location_offsets [location ] = total_pad + span
1016+
1017+ def _get_axes_exterior_offsets (ax : Axes , renderer : RendererBase ) -> dict [str , float ]:
1018+ axes_bbox = ax .get_window_extent (renderer )
1019+ tight_bbox = ax .get_tightbbox (renderer )
1020+ width = axes_bbox .width if axes_bbox .width != 0 else 1.0
1021+ height = axes_bbox .height if axes_bbox .height != 0 else 1.0
1022+ left = max (0.0 , (axes_bbox .x0 - tight_bbox .x0 ) / width )
1023+ right = max (0.0 , (tight_bbox .x1 - axes_bbox .x1 ) / width )
1024+ bottom = max (0.0 , (axes_bbox .y0 - tight_bbox .y0 ) / height )
1025+ top = max (0.0 , (tight_bbox .y1 - axes_bbox .y1 ) / height )
1026+ return {"left" : left , "right" : right , "top" : top , "bottom" : bottom }
10081027
10091028 cs_contents = _get_cs_contents (sdata )
10101029
@@ -1164,8 +1183,11 @@ def _draw_colorbar(spec: ColorbarSpec) -> None:
11641183 seen_mappables .add (mappable_id )
11651184 unique_specs .append (spec )
11661185
1186+ renderer = fig_params .fig .canvas .get_renderer ()
1187+ divider = make_axes_locatable (ax )
1188+ location_offsets = _get_axes_exterior_offsets (ax , renderer )
11671189 for spec in unique_specs :
1168- _draw_colorbar (spec )
1190+ _draw_colorbar (spec , divider , renderer , location_offsets )
11691191
11701192 if fig_params .fig is not None and save is not None :
11711193 save_fig (fig_params .fig , path = save )
0 commit comments