Skip to content

Commit c3f978e

Browse files
timtreisclaude
andcommitted
Reject tuple norms with clear error, standardize na_is_transparent guards
- Reject tuple/sequence norms in _type_check_params with a clear TypeError pointing users to use a list instead - Extract na_is_transparent local in all three groups-filtering guards (shapes, points, labels) for consistent style - Add test_norm_tuple_raises Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent fe75761 commit c3f978e

File tree

3 files changed

+15
-7
lines changed

3 files changed

+15
-7
lines changed

src/spatialdata_plot/pl/render.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,8 @@ def _render_shapes(
275275
# When groups are specified, filter out non-matching elements by default.
276276
# Only show non-matching elements if the user explicitly sets na_color.
277277
_na = render_params.cmap_params.na_color
278-
if groups is not None and values_are_categorical and (_na.default_color_set or _na.get_alpha_as_float() == 0.0):
278+
na_is_transparent = _na.default_color_set or _na.get_alpha_as_float() == 0.0
279+
if groups is not None and values_are_categorical and na_is_transparent:
279280
keep, color_source_vector, color_vector = _filter_groups_transparent_na(
280281
groups, color_source_vector, color_vector
281282
)
@@ -1522,12 +1523,8 @@ def _render_labels(
15221523
# When groups are specified, zero out non-matching label IDs so they render as background.
15231524
# Only show non-matching labels if the user explicitly sets na_color.
15241525
_na = render_params.cmap_params.na_color
1525-
if (
1526-
groups is not None
1527-
and categorical
1528-
and color_source_vector is not None
1529-
and (_na.default_color_set or _na.get_alpha_as_float() == 0.0)
1530-
):
1526+
na_is_transparent = _na.default_color_set or _na.get_alpha_as_float() == 0.0
1527+
if groups is not None and categorical and color_source_vector is not None and na_is_transparent:
15311528
keep_vec = color_source_vector.isin(groups)
15321529
matching_ids = instance_id[keep_vec]
15331530
keep_mask = np.isin(label.values, matching_ids)

src/spatialdata_plot/pl/utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2394,6 +2394,8 @@ def _type_check_params(param_dict: dict[str, Any], element_type: str) -> dict[st
23942394

23952395
norm = param_dict.get("norm")
23962396
if norm is not None:
2397+
if element_type == "images" and isinstance(norm, Sequence) and not isinstance(norm, list):
2398+
raise TypeError("'norm' must be a list of Normalize objects, not a tuple or other sequence.")
23972399
if element_type == "images" and isinstance(norm, list):
23982400
if len(norm) == 0:
23992401
raise ValueError("'norm' list must not be empty.")

tests/pl/test_render_images.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,15 @@ def test_norm_list_empty_raises(self, sdata_blobs: SpatialData):
191191
norm=[],
192192
).pl.show()
193193

194+
def test_norm_tuple_raises(self, sdata_blobs: SpatialData):
195+
"""Tuple of norms is rejected — only list is accepted."""
196+
with pytest.raises(TypeError, match="not a tuple"):
197+
sdata_blobs.pl.render_images(
198+
element="blobs_image",
199+
channel=[0, 1, 2],
200+
norm=(Normalize(), Normalize(), Normalize()),
201+
).pl.show()
202+
194203
def test_plot_correctly_normalizes_multichannel_images(self, sdata_raccoon: SpatialData):
195204
sdata_raccoon["raccoon_int16"] = Image2DModel.parse(
196205
sdata_raccoon["raccoon"].data.astype(np.uint16) * 257, # 255 * 257 = 65535,

0 commit comments

Comments
 (0)