Report
When using sq.pl.spatial_scatter() with a custom spatial_key, I noticed inconsistent behavior in how background images are validated and loaded.
My AnnData contains two coordinate systems:
adata.obsm["spatial"]
adata.obsm["spatial_trans"]
I want to use spatial_trans for plotting:
sq.pl.spatial_scatter(
adata,
spatial_key="spatial_trans",
img="hires",
img_res_key="hires",
...
)
The issue appears to be in src/squidpy/pl/_spatial_utils.py, around lines 166–173:
image_mapping = Key.uns.library_mapping(adata, spatial_key, Key.uns.image_key, library_id)
if img_res_key is None:
img_res_key = _get_unique_map(image_mapping)[0]
elif img_res_key not in _get_unique_map(image_mapping):
raise KeyError(
f"Image key: `{img_res_key}` does not exist. Available image keys: `{image_mapping.values()}`"
)
img = [adata.uns[Key.uns.spatial][i][Key.uns.image_key][img_res_key] for i in library_id]
Here, the image validation around line 166 uses:
adata.uns[spatial_key][library_id]["images"]
while the actual image loading around line 173 uses:
adata.uns["spatial"][library_id]["images"]
This leads to inconsistent behavior whenever spatial_key != "spatial":
- If images are stored under
adata.uns["spatial_trans"], validation succeeds, but image loading fails because the image is actually loaded from adata.uns["spatial"].
- If images are stored under
adata.uns["spatial"], image loading would be correct, but validation fails first because library_mapping() checks adata.uns["spatial_trans"].
For example, with images stored under adata.uns["spatial"], I get:
KeyError: "`images` not found in `adata.uns['spatial_trans']['library_id'])`
with following `library_id`: ['sham', 'MCAO_1d', 'MCAO_3d', 'MCAO_14d']."
I think either line 166 or line 173 should be changed so that image validation and image loading use the same location.
If the intended structure is that images are always stored under:
adata.uns["spatial"][library_id]["images"]
and spatial_key only specifies the coordinate system in adata.obsm, then line 166 could be changed from:
image_mapping = Key.uns.library_mapping(
adata, spatial_key, Key.uns.image_key, library_id
)
to:
image_mapping = Key.uns.library_mapping(
adata, Key.uns.spatial, Key.uns.image_key, library_id
)
Alternatively, if spatial_key is intended to specify both the coordinate system and the corresponding entry in adata.uns, then line 173 should probably use spatial_key instead of Key.uns.spatial.
Either way, making these two lookups consistent should resolve the issue when using custom spatial coordinate keys.
I'd be happy to submit a PR to fix this once the intended behavior of spatial_key is confirmed.
Versions
| Package | Version |
| -------- | --------- |
| tifffile | 2026.5.15 |
| scanpy | 1.12.1 |
| squidpy | 1.8.1 |
| anndata | 0.12.16 |
| numpy | 2.4.6 |
| Dependency | Version |
| ------------------------ | ---------------------- |
| stack_data | 0.6.3 |
| debugpy | 1.8.16 |
| matplotlib-scalebar | 0.9.0 |
| spatialdata | 0.7.3 |
| zstandard | 0.25.0 |
| MarkupSafe | 3.0.3 |
| natsort | 8.4.0 |
| llvmlite | 0.47.0 |
| comm | 0.2.3 |
| lz4 | 4.4.5 |
| parso | 0.8.7 |
| rich | 15.0.0 |
| shapely | 2.1.2 |
| lazy-loader | 0.5 |
| more-itertools | 11.1.0 |
| Pygments | 2.20.0 |
| fast-array-utils | 1.4.1 |
| cloudpickle | 3.1.2 |
| numcodecs | 0.16.5 |
| setuptools | 82.0.1 |
| tqdm | 4.67.3 |
| cytoolz | 1.1.0 |
| google-crc32c | 1.8.0 |
| python-dateutil | 2.9.0.post0 |
| imagecodecs | 2025.11.11 |
| xarray-dataclass | 3.0.0 |
| jupyter_core | 5.9.1 |
| legacy-api-wrap | 1.5 |
| packaging | 26.2 |
| matplotlib | 3.10.9 |
| pyproj | 3.7.2 |
| zarr | 3.2.1 |
| sparse | 0.18.0 |
| tornado | 6.5.5 |
| validators | 0.35.0 |
| numba | 0.65.1 |
| h5py | 3.16.0 |
| platformdirs | 4.9.6 |
| pathlib_abc | 0.5.2 |
| fsspec | 2026.4.0 |
| pillow | 12.2.0 |
| xxhash | 3.7.0 |
| seaborn | 0.13.2 |
| threadpoolctl | 3.6.0 |
| dask | 2026.1.1 |
| scipy | 1.17.1 |
| donfig | 0.8.1.post1 |
| wcwidth | 0.2.14 |
| dask-image | 2025.11.0 |
| xarray | 2026.4.0 |
| pandas | 2.3.3 |
| pooch | 1.9.0 (v1.9.0) |
| PyYAML | 6.0.3 |
| traitlets | 5.15.0 |
| scikit-learn | 1.8.0 |
| pyarrow | 24.0.0 |
| ipykernel | 7.2.0 |
| annsel | 0.1.2 |
| spatial_image | 1.2.3 |
| pyzmq | 27.1.0 |
| networkx | 3.6.1 |
| multiscale_spatial_image | 2.0.3 |
| six | 1.17.0 |
| pyparsing | 3.3.2 |
| decorator | 5.2.1 |
| narwhals | 2.21.2 |
| session-info2 | 0.4.1 |
| msgpack | 1.1.2 |
| certifi | 2026.6.17 (2026.06.17) |
| geopandas | 1.1.3 |
| Jinja2 | 3.1.6 |
| charset-normalizer | 3.4.7 |
| pure_eval | 0.2.3 |
| toolz | 1.1.0 |
| cycler | 0.12.1 |
| psutil | 7.2.2 |
| scverse-misc | 0.0.7 |
| jupyter_client | 8.8.0 |
| universal_pathlib | 0.3.10 |
| scikit-image | 0.26.0 |
| ome-zarr | 0.15.0 |
| pytz | 2026.2 |
| typing_extensions | 4.15.0 |
| tblib | 3.2.2 |
| executing | 2.2.1 |
| ipywidgets | 8.1.7 |
| ImageIO | 2.37.3 |
| kiwisolver | 1.5.0 |
| joblib | 1.5.3 |
| prompt_toolkit | 3.0.52 |
| docrep | 0.3.2 |
| statsmodels | 0.14.6 |
| jedi | 0.20.0 |
| asttokens | 3.0.1 |
| patsy | 1.0.2 |
| ipython | 9.11.0 |
| Component | Info |
| --------- | ------------------------------------------------------------------------------ |
| Python | 3.12.12 | packaged by conda-forge | (main, Oct 13 2025, 14:34:15) [GCC 14.3.0] |
| OS | Linux-6.8.0-137-generic-x86_64-with-glibc2.39 |
| Updated | 2026-08-19 09:19 |
Report
When using
sq.pl.spatial_scatter()with a customspatial_key, I noticed inconsistent behavior in how background images are validated and loaded.My
AnnDatacontains two coordinate systems:I want to use
spatial_transfor plotting:The issue appears to be in
src/squidpy/pl/_spatial_utils.py, around lines 166–173:Here, the image validation around line 166 uses:
while the actual image loading around line 173 uses:
This leads to inconsistent behavior whenever
spatial_key != "spatial":adata.uns["spatial_trans"], validation succeeds, but image loading fails because the image is actually loaded fromadata.uns["spatial"].adata.uns["spatial"], image loading would be correct, but validation fails first becauselibrary_mapping()checksadata.uns["spatial_trans"].For example, with images stored under
adata.uns["spatial"], I get:I think either line 166 or line 173 should be changed so that image validation and image loading use the same location.
If the intended structure is that images are always stored under:
and
spatial_keyonly specifies the coordinate system inadata.obsm, then line 166 could be changed from:to:
Alternatively, if
spatial_keyis intended to specify both the coordinate system and the corresponding entry inadata.uns, then line 173 should probably usespatial_keyinstead ofKey.uns.spatial.Either way, making these two lookups consistent should resolve the issue when using custom spatial coordinate keys.
I'd be happy to submit a PR to fix this once the intended behavior of spatial_key is confirmed.
Versions