`spatial_scatter` uses inconsistent `spatial_key` for image validation and loading
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 598
- Forks
- 121
- Avg merge
- 3d 11h
- Merged PRs (30d)
- 3
Description
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 fromadata.uns["spatial"]. - If images are stored under
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:
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 |
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/squidpy/pl/_spatial_utils.py around lines 166–173 and trace how Key.uns.library_mapping validates images versus how the image list is loaded. Confirm the intended relationship between spatial_key and adata.uns storage, then make both lookups consistent and verify that spatial_scatter works with a custom spatial_key and background image.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- data-visualization
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100