Skip to content

Commit 901a19c

Browse files
timtreisclaude
andcommitted
Fix user figure DPI being silently overridden by pl.show() (#310)
When a user created a figure with a custom DPI (e.g. plt.figure(dpi=300)) and passed its axes to .pl.show(ax=ax), the DPI was silently overwritten with the rcParams default. This happened because _prepare_params_plot() unconditionally resolved dpi=None to rcParams["figure.dpi"] and then called fig.set_dpi() on the user's figure. Now the figure's existing DPI is preserved when the user provides their own axes without an explicit dpi= argument. Explicit dpi= still overrides. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 9dc65ce commit 901a19c

2 files changed

Lines changed: 39 additions & 5 deletions

File tree

src/spatialdata_plot/pl/utils.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -244,14 +244,17 @@ def _prepare_params_plot(
244244
# handle axes and size
245245
wspace = 0.75 / rcParams["figure.figsize"][0] + 0.02 if wspace is None else wspace
246246
figsize = rcParams["figure.figsize"] if figsize is None else figsize
247-
dpi = rcParams["figure.dpi"] if dpi is None else dpi
247+
# When creating a new figure, fall back to rcParams; when the user provides
248+
# their own axes, preserve the figure's existing DPI (only override if
249+
# the user explicitly passed dpi= to show()).
250+
resolved_dpi = rcParams["figure.dpi"] if dpi is None else dpi
248251
if num_panels > 1 and ax is None:
249252
fig, grid = _panel_grid(
250253
num_panels=num_panels,
251254
hspace=hspace,
252255
wspace=wspace,
253256
ncols=ncols,
254-
dpi=dpi,
257+
dpi=resolved_dpi,
255258
figsize=figsize,
256259
)
257260
axs: None | Sequence[Axes] = [plt.subplot(grid[c]) for c in range(num_panels)]
@@ -266,14 +269,16 @@ def _prepare_params_plot(
266269
)
267270
assert ax is None or isinstance(ax, Sequence), f"Invalid type of `ax`: {type(ax)}, expected `Sequence`."
268271
axs = ax
272+
if dpi is not None:
273+
fig.set_dpi(dpi)
269274
else:
270275
axs = None
271276
if ax is None:
272-
fig, ax = plt.subplots(figsize=figsize, dpi=dpi, constrained_layout=True)
277+
fig, ax = plt.subplots(figsize=figsize, dpi=resolved_dpi, constrained_layout=True)
273278
elif isinstance(ax, Axes):
274-
# needed for rasterization if user provides Axes object
275279
fig = ax.get_figure()
276-
fig.set_dpi(dpi)
280+
if dpi is not None:
281+
fig.set_dpi(dpi)
277282

278283
# set scalebar
279284
if scalebar_dx is not None:

tests/pl/test_show.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ def test_plot_no_decorations(self, sdata_blobs: SpatialData):
4242
"""Visual test: frameon=False + title='' produces just the plot content (regression for #204)."""
4343
sdata_blobs.pl.render_images(element="blobs_image").pl.show(frameon=False, title="", colorbar=False)
4444

45+
def test_plot_user_ax_dpi_preserved(self, sdata_blobs: SpatialData):
46+
"""Visual test: rendering into a user-provided high-DPI ax produces correct layout (regression for #310)."""
47+
fig, ax = plt.subplots(dpi=200)
48+
sdata_blobs.pl.render_images(element="blobs_image").pl.show(ax=ax)
49+
4550
def test_no_plt_show_when_ax_provided(self, sdata_blobs: SpatialData):
4651
"""plt.show() must not be called when the user supplies ax= (regression for #362)."""
4752
_, ax = plt.subplots()
@@ -110,3 +115,27 @@ def test_frameon_false_multi_panel(sdata_blobs: SpatialData):
110115
for ax in axs:
111116
assert not ax.axison
112117
plt.close("all")
118+
119+
120+
def test_user_figure_dpi_preserved_when_ax_provided(sdata_blobs: SpatialData):
121+
"""User's figure DPI must not be overridden when ax is passed without explicit dpi (regression for #310)."""
122+
fig, ax = plt.subplots(dpi=300)
123+
sdata_blobs.pl.render_images(element="blobs_image").pl.show(ax=ax, show=False)
124+
assert fig.get_dpi() == 300
125+
plt.close(fig)
126+
127+
128+
def test_explicit_dpi_overrides_figure_dpi(sdata_blobs: SpatialData):
129+
"""Explicit dpi= in show() should override the figure's DPI."""
130+
fig, ax = plt.subplots(dpi=300)
131+
sdata_blobs.pl.render_images(element="blobs_image").pl.show(ax=ax, dpi=150, show=False)
132+
assert fig.get_dpi() == 150
133+
plt.close(fig)
134+
135+
136+
def test_dpi_default_used_when_no_ax(sdata_blobs: SpatialData):
137+
"""When no ax is provided and dpi is not set, rcParams default should be used."""
138+
ax = sdata_blobs.pl.render_images(element="blobs_image").pl.show(return_ax=True, show=False)
139+
fig = ax.get_figure()
140+
assert fig.get_dpi() == matplotlib.rcParams["figure.dpi"]
141+
plt.close(fig)

0 commit comments

Comments
 (0)