Skip to content

Commit 03a3c1c

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 03a3c1c

2 files changed

Lines changed: 29 additions & 6 deletions

File tree

‎src/spatialdata_plot/pl/basic.py‎

Lines changed: 11 additions & 6 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:
@@ -1794,17 +1802,14 @@ def _draw_colorbar(
17941802
colorbar_requests=axis_colorbar_requests,
17951803
)
17961804

1797-
# Title/aspect/frameon are panel-level: set once per panel, after the
1798-
# per-command loop above (not once per render command).
1805+
# Title/aspect/frameon are panel-level: set once per panel.
17991806
if title is None:
18001807
t = panel_key if panel_key is not None else cs
18011808
elif len(title) == 1:
18021809
t = title[0]
18031810
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
1811+
# len(title) == num_panels is guaranteed by the up-front check above.
1812+
t = title[i]
18081813
ax.set_title(t)
18091814
ax.set_aspect("equal")
18101815
if fig_params.frameon is False:

‎tests/pl/test_show.py‎

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

138138

139+
def test_title_count_validation(sdata_blobs: SpatialData):
140+
"""title must be length 1 or one-per-panel; mismatches raise up front (regression for #695)."""
141+
base = sdata_blobs.pl.render_images(element="blobs_image")
142+
with pytest.raises(ValueError, match="number of titles"): # single panel, too many
143+
base.pl.show(title=["a", "b"], show=False)
144+
plt.close("all")
145+
146+
set_transformation(sdata_blobs["blobs_image"], Identity(), "second_cs")
147+
base2 = sdata_blobs.pl.render_images(element="blobs_image")
148+
with pytest.raises(ValueError, match="number of titles"): # 2 panels, too many (was silently truncated)
149+
base2.pl.show(title=["a", "b", "c"], show=False)
150+
plt.close("all")
151+
152+
axs = base2.pl.show(title=["left", "right"], return_ax=True, show=False) # one per panel -> applied
153+
assert sorted(a.get_title() for a in axs) == ["left", "right"]
154+
plt.close("all")
155+
156+
139157
def test_fig_parameter_warns_with_ax_list(sdata_blobs: SpatialData):
140158
"""Passing fig= alongside a list of axes should also emit the deprecation (regression for #625)."""
141159
set_transformation(sdata_blobs["blobs_image"], Identity(), "second_cs")

0 commit comments

Comments
 (0)