Skip to content

Commit adeb876

Browse files
committed
Accept both 'location' and 'loc' in legend_params
matplotlib.legend.Legend natively uses 'loc' while Figure.colorbar and matplotlib_scalebar both use 'location', which would force users to remember a different key name for legend_params than for colorbar_params and scalebar_params. We accept both spellings so the three escape-hatch dicts read consistently; 'location' is documented as canonical and wins when both are passed. Inline comments at the merge site and the validation whitelist explain the matplotlib quirk so future maintainers don't 'simplify' the alias away.
1 parent 3edc721 commit adeb876

3 files changed

Lines changed: 32 additions & 7 deletions

File tree

src/spatialdata_plot/pl/basic.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -968,10 +968,11 @@ def show(
968968
See the matplotlib-scalebar documentation for the full list of options.
969969
legend_params : dict[str, Any] | None
970970
Bundled legend options. Mirrors ``colorbar_params`` / ``scalebar_params``. Accepted keys:
971-
``loc``, ``fontsize``, ``fontweight``, ``fontoutline``, ``na_in_legend`` — all forwarded
972-
to the corresponding flat ``legend_*`` mechanics. When a key is set both as a flat
973-
kwarg (e.g. ``legend_fontsize=12``) and inside this dict, the dict value wins. Unknown
974-
keys raise ``ValueError`` to surface typos early.
971+
``location`` (canonical, alias ``loc`` accepted to match
972+
:class:`matplotlib.legend.Legend`), ``fontsize``, ``fontweight``, ``fontoutline``,
973+
``na_in_legend``. When a key is set both as a flat kwarg (e.g. ``legend_fontsize=12``)
974+
and inside this dict, the dict value wins. Unknown keys raise ``ValueError`` to surface
975+
typos early.
975976
976977
Returns
977978
-------
@@ -1141,10 +1142,14 @@ def show(
11411142
)
11421143
# Merge dict-form legend_params over the flat legend_* kwargs (dict wins). Unknown keys
11431144
# have already been rejected by _validate_show_parameters; treat the dict as authoritative.
1145+
# Note: matplotlib.legend.Legend uses `loc`, while Figure.colorbar and matplotlib_scalebar
1146+
# use `location`. We accept both spellings so legend_params reads consistently with
1147+
# colorbar_params / scalebar_params; `location` is the canonical name and wins if both are
1148+
# passed.
11441149
if legend_params:
11451150
legend_fontsize = legend_params.get("fontsize", legend_fontsize)
11461151
legend_fontweight = legend_params.get("fontweight", legend_fontweight)
1147-
legend_loc = legend_params.get("loc", legend_loc)
1152+
legend_loc = legend_params.get("location", legend_params.get("loc", legend_loc))
11481153
legend_fontoutline = legend_params.get("fontoutline", legend_fontoutline)
11491154
na_in_legend = legend_params.get("na_in_legend", na_in_legend)
11501155

src/spatialdata_plot/pl/utils.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2277,7 +2277,10 @@ def _validate_show_parameters(
22772277
if legend_params is not None:
22782278
if not isinstance(legend_params, dict):
22792279
raise TypeError("Parameter 'legend_params' must be a dictionary or None.")
2280-
allowed_legend_keys = {"loc", "fontsize", "fontweight", "fontoutline", "na_in_legend"}
2280+
# `location` is the canonical name (matches colorbar_params / scalebar_params); `loc` is
2281+
# accepted as an alias because that is what matplotlib.legend.Legend natively uses, so
2282+
# copy-paste from matplotlib examples keeps working.
2283+
allowed_legend_keys = {"loc", "location", "fontsize", "fontweight", "fontoutline", "na_in_legend"}
22812284
unknown = set(legend_params) - allowed_legend_keys
22822285
if unknown:
22832286
raise ValueError(

tests/pl/test_show.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,11 +316,28 @@ def test_legend_params_default_none_is_noop(sdata_blobs: SpatialData):
316316
({"legend_params": []}, TypeError),
317317
({"legend_params": "loc=upper right"}, TypeError),
318318
({"legend_params": {"loc": "upper right", "frameon": True}}, ValueError),
319-
({"legend_params": {"location": "upper right"}}, ValueError), # matplotlib uses "loc", not "location"
319+
({"legend_params": {"locaton": "upper right"}}, ValueError), # typo of "location"
320320
],
321321
)
322322
def test_legend_params_validation_rejects_bad_inputs(sdata_blobs: SpatialData, kwargs, exc):
323323
"""_validate_show_parameters surfaces actionable errors for bad legend_params inputs."""
324324
with pytest.raises(exc):
325325
sdata_blobs.pl.render_shapes(element="blobs_circles").pl.show(show=False, **kwargs)
326326
plt.close("all")
327+
328+
329+
def test_legend_params_location_alias_for_loc(sdata_blobs: SpatialData):
330+
"""legend_params accepts both 'location' (canonical) and 'loc' (matplotlib-native alias)."""
331+
# Both spellings reach LegendParams.legend_loc; verify by confirming neither raises and the
332+
# canonical 'location' takes precedence when both are passed (the alias resolution is a small
333+
# consequence of mirroring colorbar_params / scalebar_params naming).
334+
sdata_blobs.pl.render_shapes(element="blobs_circles").pl.show(
335+
legend_params={"loc": "upper right"}, return_ax=True, show=False
336+
)
337+
sdata_blobs.pl.render_shapes(element="blobs_circles").pl.show(
338+
legend_params={"location": "upper right"}, return_ax=True, show=False
339+
)
340+
sdata_blobs.pl.render_shapes(element="blobs_circles").pl.show(
341+
legend_params={"loc": "upper left", "location": "lower right"}, return_ax=True, show=False
342+
)
343+
plt.close("all")

0 commit comments

Comments
 (0)