Skip to content

Commit b05fb5b

Browse files
committed
feat(show): validate title count up front
Builds on the per-panel title fix (#695): before the panel loop, validate that `title`, when a list, has length 1 or exactly num_panels. This: - surfaces the error before any drawing (not mid-render), - rejects an over-long title list (previously silently truncated), and - makes the per-panel IndexError dead code, so the try/except is removed. The error is now a ValueError (the right type for an invalid argument) raised once up front, instead of an IndexError raised per panel mid-render. No test pinned the old exception type. Adds non-visual regression tests for single- and multi-panel title-count validation. Pre-existing mypy error in utils.py (_resolve_measure_table returning Any) is unrelated and unchanged here; it is fixed separately in #714.
1 parent 6557e30 commit b05fb5b

2 files changed

Lines changed: 31 additions & 4 deletions

File tree

‎src/spatialdata_plot/pl/basic.py‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,6 +1519,14 @@ def show(
15191519
panels = [(cs, None) for cs in coordinate_systems]
15201520
num_panels = len(panels)
15211521

1522+
# Titles are panel-level: require one title (broadcast to all panels) or exactly one
1523+
# per panel. Validating up front surfaces the error before any drawing, and also rejects
1524+
# an over-long list (previously silently truncated).
1525+
if title is not None and len(title) not in (1, num_panels):
1526+
raise ValueError(
1527+
f"The number of titles ({len(title)}) must be 1 or match the number of panels ({num_panels})."
1528+
)
1529+
15221530
if ax is not None:
15231531
n_ax = 1 if isinstance(ax, Axes) else len(ax)
15241532
if num_panels != n_ax:
@@ -1801,10 +1809,8 @@ def _draw_colorbar(
18011809
elif len(title) == 1:
18021810
t = title[0]
18031811
else:
1804-
try:
1805-
t = title[i]
1806-
except IndexError as e:
1807-
raise IndexError("The number of titles must match the number of panels.") from e
1812+
# len(title) == num_panels is guaranteed by the up-front check above.
1813+
t = title[i]
18081814
ax.set_title(t)
18091815
ax.set_aspect("equal")
18101816
if fig_params.frameon is False:

‎tests/pl/test_show.py‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,27 @@ def test_fig_parameter_default_no_warning(sdata_blobs: SpatialData):
136136
plt.close("all")
137137

138138

139+
def test_title_count_validated_up_front_single_panel(sdata_blobs: SpatialData):
140+
"""A multi-title list on a single panel is rejected before drawing (regression for #695)."""
141+
with pytest.raises(ValueError, match="number of titles"):
142+
sdata_blobs.pl.render_images(element="blobs_image").pl.show(title=["a", "b"], show=False)
143+
plt.close("all")
144+
145+
146+
def test_title_count_multi_panel(sdata_blobs: SpatialData):
147+
"""For N panels a title list must be length 1 (broadcast) or N; over-long lists raise (regression for #695)."""
148+
set_transformation(sdata_blobs["blobs_image"], Identity(), "second_cs")
149+
base = sdata_blobs.pl.render_images(element="blobs_image")
150+
# too many titles (3 for 2 panels) now raises instead of silently dropping the surplus
151+
with pytest.raises(ValueError, match="number of titles"):
152+
base.pl.show(title=["a", "b", "c"], show=False)
153+
plt.close("all")
154+
# exactly one title per panel is accepted and applied
155+
axs = base.pl.show(title=["left", "right"], return_ax=True, show=False)
156+
assert sorted(a.get_title() for a in axs) == ["left", "right"]
157+
plt.close("all")
158+
159+
139160
def test_fig_parameter_warns_with_ax_list(sdata_blobs: SpatialData):
140161
"""Passing fig= alongside a list of axes should also emit the deprecation (regression for #625)."""
141162
set_transformation(sdata_blobs["blobs_image"], Identity(), "second_cs")

0 commit comments

Comments
 (0)