Skip to content

Commit 2718a9d

Browse files
committed
added issue fix
1 parent 2d17933 commit 2718a9d

File tree

3 files changed

+64
-52
lines changed

3 files changed

+64
-52
lines changed

src/spatialdata_plot/pl/basic.py

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import contextlib
44
import sys
5-
import warnings
65
from collections import OrderedDict
76
from copy import deepcopy
87
from pathlib import Path
@@ -771,7 +770,7 @@ def show(
771770
legend_loc: str | None = "right margin",
772771
legend_fontoutline: int | None = None,
773772
na_in_legend: bool = True,
774-
colorbar: bool | None = None,
773+
colorbar: bool = True,
775774
colorbar_params: dict[str, object] | None = None,
776775
wspace: float | None = None,
777776
hspace: float = 0.25,
@@ -811,8 +810,7 @@ def show(
811810
return_ax :
812811
Whether to return the axes object created. False by default.
813812
colorbar :
814-
DEPRECATED: use per-layer ``colorbar``/``colorbar_params`` instead. If provided, it will be honored
815-
but will emit a DeprecationWarning.
813+
Global switch to enable/disable all colorbars. Per-layer settings are ignored when this is False.
816814
colorbar_params :
817815
Global overrides passed to colorbars for all axes. Accepts the same keys as per-layer ``colorbar_params``
818816
(e.g., ``loc``, ``width``, ``pad``, ``label``).
@@ -943,16 +941,7 @@ def show(
943941
ncols=ncols,
944942
frameon=frameon,
945943
)
946-
# colorbar is deprecated: warn when explicitly provided
947-
legend_colorbar = True if colorbar is None else colorbar
948-
if colorbar is not None:
949-
warnings.warn(
950-
"Parameter 'colorbar' in `.show()` is deprecated. "
951-
"Please control colorbars via the per-layer `colorbar` and `colorbar_params` arguments.",
952-
DeprecationWarning,
953-
stacklevel=2,
954-
)
955-
944+
legend_colorbar = colorbar
956945
legend_params = LegendParams(
957946
legend_fontsize=legend_fontsize,
958947
legend_fontweight=legend_fontweight,
@@ -1200,22 +1189,15 @@ def _get_axes_exterior_offsets(ax: Axes) -> dict[str, float]:
12001189
"top": base_offsets["top"],
12011190
"bottom": base_offsets["bottom"],
12021191
}
1203-
# keep only unique bars per (location, label, layout+kwargs). Last request wins.
1204-
unique_specs_map: dict[tuple[Any, ...], ColorbarSpec] = {}
1192+
# keep only one bar per unique mappable on an axes; allow multiple bars even with identical params.
1193+
unique_specs: list[ColorbarSpec] = []
1194+
seen_mappables: set[int] = set()
12051195
for spec in axis_colorbar_requests:
1206-
layer_layout, layer_kwargs, layer_label_override = _split_colorbar_params(spec.params)
1207-
global_layout, global_kwargs, global_label_override = _split_colorbar_params(colorbar_params)
1208-
layout = {**{"location": "right"}, **layer_layout, **global_layout}
1209-
kwargs_key = tuple(sorted({**layer_kwargs, **global_kwargs}.items()))
1210-
label_key = global_label_override or layer_label_override or spec.label
1211-
key = (
1212-
layout.get("location", "right"),
1213-
label_key,
1214-
tuple(sorted(layout.items())),
1215-
kwargs_key,
1216-
)
1217-
unique_specs_map[key] = spec
1218-
unique_specs = list(unique_specs_map.values())
1196+
mappable_id = id(spec.mappable)
1197+
if mappable_id in seen_mappables:
1198+
continue
1199+
seen_mappables.add(mappable_id)
1200+
unique_specs.append(spec)
12191201

12201202
for spec in unique_specs:
12211203
_draw_colorbar(spec, location_offsets)

src/spatialdata_plot/pl/utils.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1985,7 +1985,7 @@ def _validate_show_parameters(
19851985
legend_loc: str | None,
19861986
legend_fontoutline: int | None,
19871987
na_in_legend: bool,
1988-
colorbar: bool | None,
1988+
colorbar: bool,
19891989
colorbar_params: dict[str, object] | None,
19901990
wspace: float | None,
19911991
hspace: float,
@@ -2044,8 +2044,8 @@ def _validate_show_parameters(
20442044
if not isinstance(na_in_legend, bool):
20452045
raise TypeError("Parameter 'na_in_legend' must be a boolean.")
20462046

2047-
if colorbar is not None and not isinstance(colorbar, bool):
2048-
raise TypeError("Parameter 'colorbar' must be a boolean or None.")
2047+
if not isinstance(colorbar, bool):
2048+
raise TypeError("Parameter 'colorbar' must be a boolean.")
20492049

20502050
if colorbar_params is not None and not isinstance(colorbar_params, dict):
20512051
raise TypeError("Parameter 'colorbar_params' must be a dictionary or None.")

tests/pl/test_colorbar.py

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import matplotlib
2+
import numpy as np
23
import scanpy as sc
34
from spatialdata import SpatialData
5+
from spatialdata.models import Image2DModel, Labels2DModel
46

57
import spatialdata_plot # noqa: F401
68
from tests.conftest import DPI, PlotTester, PlotTesterMeta
@@ -19,54 +21,82 @@
1921

2022

2123
class TestColorbarControls(PlotTester, metaclass=PlotTesterMeta):
24+
def _make_multi_image_single_channel_sdata(self) -> SpatialData:
25+
img1 = Image2DModel.parse(np.linspace(0, 1, 2500, dtype=float).reshape(1, 50, 50), dims=("c", "y", "x"))
26+
img2 = Image2DModel.parse(np.linspace(2, 0, 2500, dtype=float).reshape(1, 50, 50), dims=("c", "y", "x"))
27+
labels = Labels2DModel.parse(np.arange(2500, dtype=int).reshape(50, 50), dims=("y", "x"))
28+
return SpatialData(images={"img1": img1, "img2": img2}, labels={"lab": labels})
29+
2230
def test_plot_image_auto_colorbar_for_single_channel(self, sdata_blobs: SpatialData):
23-
sdata_blobs.pl.render_images(element="img").pl.show()
31+
sdata_blobs.pl.render_images("blobs_image", element="img").pl.show()
2432

2533
def test_plot_colorbar_img_default_location(self, sdata_blobs: SpatialData):
26-
(sdata_blobs.pl.render_images(channel=0, cmap="Reds").pl.show())
34+
(sdata_blobs.pl.render_images("blobs_image", channel=0, cmap="Reds").pl.show())
2735

2836
def test_plot_colorbar_img_bottom(self, sdata_blobs: SpatialData):
29-
(sdata_blobs.pl.render_images(channel=0, cmap="Reds", colorbar_params={"loc": "bottom"}).pl.show())
37+
(
38+
sdata_blobs.pl.render_images(
39+
"blobs_image", channel=0, cmap="Reds", colorbar_params={"loc": "bottom"}
40+
).pl.show()
41+
)
3042

3143
def test_plot_colorbar_img_left(self, sdata_blobs: SpatialData):
32-
(sdata_blobs.pl.render_images(channel=0, cmap="Reds", colorbar_params={"loc": "left"}).pl.show())
44+
(sdata_blobs.pl.render_images("blobs_image", channel=0, cmap="Reds", colorbar_params={"loc": "left"}).pl.show())
3345

3446
def test_plot_colorbar_img_top(self, sdata_blobs: SpatialData):
35-
(sdata_blobs.pl.render_images(channel=0, cmap="Reds", colorbar_params={"loc": "top"}).pl.show())
47+
(sdata_blobs.pl.render_images("blobs_image", channel=0, cmap="Reds", colorbar_params={"loc": "top"}).pl.show())
3648

3749
def test_plot_colorbar_can_adjust_width(self, sdata_blobs: SpatialData):
38-
(sdata_blobs.pl.render_images(channel=0, cmap="Reds", colorbar_params={"width": 0.4}).pl.show())
50+
(sdata_blobs.pl.render_images("blobs_image", channel=0, cmap="Reds", colorbar_params={"width": 0.4}).pl.show())
3951

4052
def test_plot_colorbar_can_adjust_title(self, sdata_blobs: SpatialData):
41-
(sdata_blobs.pl.render_images(channel=0, cmap="Reds", colorbar_params={"label": "Intensity"}).pl.show())
53+
(
54+
sdata_blobs.pl.render_images(
55+
"blobs_image", channel=0, cmap="Reds", colorbar_params={"label": "Intensity"}
56+
).pl.show()
57+
)
4258

4359
def test_plot_colorbar_can_adjust_pad(self, sdata_blobs: SpatialData):
44-
(sdata_blobs.pl.render_images(channel=0, cmap="Reds", colorbar_params={"pad": 0.4}).pl.show())
60+
(sdata_blobs.pl.render_images("blobs_image", channel=0, cmap="Reds", colorbar_params={"pad": 0.4}).pl.show())
4561

4662
def test_plot_colorbar_can_have_colorbars_on_different_sides(self, sdata_blobs: SpatialData):
4763
(
48-
sdata_blobs.pl.render_images(channel=0, cmap="Reds", colorbar_params={"loc": "top"})
49-
.pl.render_labels(element="blobs_labels", color="instance_id", colorbar_params={"loc": "bottom"})
64+
sdata_blobs.pl.render_images("blobs_image", channel=0, cmap="Reds", colorbar_params={"loc": "top"})
65+
.pl.render_labels("blobs_labels", color="instance_id", colorbar_params={"loc": "bottom"})
5066
.pl.show()
5167
)
5268

5369
def test_plot_colorbar_can_have_two_colorbars_on_same_side(self, sdata_blobs: SpatialData):
5470
(
55-
sdata_blobs.pl.render_images(channel=0, cmap="Reds")
56-
.pl.render_labels(element="blobs_labels", color="instance_id")
71+
sdata_blobs.pl.render_images("blobs_image", channel=0, cmap="Reds")
72+
.pl.render_labels("blobs_labels", color="instance_id")
5773
.pl.show()
5874
)
5975

6076
def test_plot_colorbar_can_have_colorbars_on_all_sides(self, sdata_blobs: SpatialData):
6177
# primarily shows that spacing is correct between colorbars and plot elements
78+
shared_params = {
79+
"element": "blobs_image",
80+
"channel": 0,
81+
"cmap": "Reds",
82+
}
6283
(
63-
sdata_blobs.pl.render_images(channel=0, cmap="Reds", colorbar_params={"loc": "top", "label": "top_1"})
64-
.pl.render_images(channel=0, cmap="Reds", colorbar_params={"loc": "right", "label": "right_1"})
65-
.pl.render_images(channel=0, cmap="Reds", colorbar_params={"loc": "left", "label": "left_1"})
66-
.pl.render_images(channel=0, cmap="Reds", colorbar_params={"loc": "bottom", "label": "bottom_1"})
67-
.pl.render_images(channel=0, cmap="Reds", colorbar_params={"loc": "top", "label": "top_2"})
68-
.pl.render_images(channel=0, cmap="Reds", colorbar_params={"loc": "right", "label": "right_2"})
69-
.pl.render_images(channel=0, cmap="Reds", colorbar_params={"loc": "left", "label": "left_2"})
70-
.pl.render_images(channel=0, cmap="Reds", colorbar_params={"loc": "bottom", "label": "bottom_2"})
84+
sdata_blobs.pl.render_images(**shared_params, colorbar_params={"loc": "top", "label": "top_1"})
85+
.pl.render_images(**shared_params, colorbar_params={"loc": "right", "label": "right_1"})
86+
.pl.render_images(**shared_params, colorbar_params={"loc": "left", "label": "left_1"})
87+
.pl.render_images(**shared_params, colorbar_params={"loc": "bottom", "label": "bottom_1"})
88+
.pl.render_images(**shared_params, colorbar_params={"loc": "top", "label": "top_2"})
89+
.pl.render_images(**shared_params, colorbar_params={"loc": "right", "label": "right_2"})
90+
.pl.render_images(**shared_params, colorbar_params={"loc": "left", "label": "left_2"})
91+
.pl.render_images(**shared_params, colorbar_params={"loc": "bottom", "label": "bottom_2"})
7192
.pl.show()
7293
)
94+
95+
def test_plot_multiple_images_in_one_cs_result_in_multiple_colorbars(self):
96+
sdata = self._make_multi_image_single_channel_sdata()
97+
sdata.pl.render_images(channel=0, cmap="Reds").pl.show()
98+
99+
def test_plot_can_globally_turn_off_colorbars(self):
100+
# adresses https://github.com/scverse/spatialdata-plot/issues/431
101+
sdata = self._make_multi_image_single_channel_sdata()
102+
sdata.pl.render_images(channel=0, cmap="Reds").pl.show(colorbar=False)

0 commit comments

Comments
 (0)