Skip to content

Plotting UMAP converts cell_id to category --> hinders plotting with spatialdata.plot #3960

@KarolineHoller

Description

@KarolineHoller

Please make sure these conditions are met

  • I have checked that this issue has not already been reported.
  • I have confirmed this bug exists on the latest version of scanpy.
  • (optional) I have confirmed this bug exists on the main branch of scanpy.

What happened?

Hi,
I'm using sc.pl.umap to plot a UMAP embedding in a SpatialData object sdata.tables. In this case, I'm using the anndata object cell_segmentations.

sc.pl.umap(sdata.tables["cell_segmentations"], color = "n_genes")
shows a notification: "...storing 'cell_id' as categorial"

Plotting the segmented cells on an HE image withspatialdata_plot throws an Error:

TypeError: Only int, np.int16, np.int32, np.int64, uint equivalents or string allowed as dtype for instance_key column in obs. Dtype found to be category

Same occurs with location_id for binned sdata.tables.

Minimal code sample

import scanpy as sc
import spatialdata as sd
import spatialdata_plot

sc.pl.umap(sdata.tables["cell_segmentations"], color = "n_genes")   
sdata.pl.render_images("H914Apex2_hires_image").pl.render_shapes(elements = "H914Apex2_cell_segmentations",
                                                                        color='n_genes',
                                                                         ).pl.show("H914Apex2", figsize = (8,4))

Error output

sdata = sd.SpatialData(
    145         images=self._sdata.images if images is None else images,
    146         labels=self._sdata.labels if labels is None else labels,
    147         points=self._sdata.points if points is None else points,
    148         shapes=self._sdata.shapes if shapes is None else shapes,
    149         tables=self._sdata.tables if tables is None else tables,
    150     )
    151     sdata.plotting_tree = self._sdata.plotting_tree if hasattr(self._sdata, "plotting_tree") else OrderedDict()
    153     return sdata

File /wuppertal/gpfjz/miniforge3/envs/spatialdata_2601/lib/python3.12/site-packages/spatialdata/_core/spatialdata.py:178, in SpatialData.__init__(self, images, labels, points, shapes, tables, attrs)
    176         for k, v in tables.items():
    177             with collect_error(location=("tables", k)):
--> 178                 self.validate_table_in_spatialdata(v)
    179                 self.tables[k] = v
    181 self._query = QueryManager(self)

File /wuppertal/gpfjz/miniforge3/envs/spatialdata_2601/lib/python3.12/site-packages/spatialdata/_core/spatialdata.py:203, in SpatialData.validate_table_in_spatialdata(self, table)
    183 def validate_table_in_spatialdata(self, table: AnnData) -> None:
    184     """
    185     Validate the presence of the annotation target of a SpatialData table in the SpatialData object.
    186 
   (...)    201         The dtypes of the instance key column in the table and the annotation target do not match.
    202     """
--> 203     TableModel().validate(table)
    204     if TableModel.ATTRS_KEY in table.uns:
    205         region, _, instance_key = get_table_keys(table)

File /wuppertal/gpfjz/miniforge3/envs/spatialdata_2601/lib/python3.12/site-packages/spatialdata/models/models.py:1096, in TableModel.validate(self, data)
   1093     if data.obs[instance_key].isnull().values.any():
   1094         raise ValueError("`table.obs[instance_key]` must not contain null values, but it does.")
-> 1096 self._validate_table_annotation_metadata(data)
   1098 return data

File /wuppertal/gpfjz/miniforge3/envs/spatialdata_2601/lib/python3.12/site-packages/spatialdata/models/models.py:1044, in TableModel._validate_table_annotation_metadata(self, data)
   1033 if (dtype := data.obs[attr[self.INSTANCE_KEY]].dtype) not in [
   1034     int,
   1035     np.int16,
   (...)   1041     "O",
   1042 ] or (dtype == "O" and (val_dtype := type(data.obs[attr[self.INSTANCE_KEY]].iloc[0])) is not str):
   1043     dtype = dtype if dtype != "O" else val_dtype
-> 1044     raise TypeError(
   1045         f"Only int, np.int16, np.int32, np.int64, uint equivalents or string allowed as dtype for "
   1046         f"instance_key column in obs. Dtype found to be {dtype}"
   1047     )
   1048 expected_regions = attr[self.REGION_KEY] if isinstance(attr[self.REGION_KEY], list) else [attr[self.REGION_KEY]]
   1049 found_regions = data.obs[attr[self.REGION_KEY_KEY]].unique().tolist()

TypeError: Only int, np.int16, np.int32, np.int64, uint equivalents or string allowed as dtype for instance_key column in obs. Dtype found to be category

Versions

Details
| Package          | Version |
| ---------------- | ------- |
| anndata          | 0.12.0  |
| spatialdata      | 0.6.1   |
| scanpy           | 1.12    |
| spatialdata-plot | 0.2.13  |
| celltypist       | 1.7.1   |

| Dependency               | Version               |
| ------------------------ | --------------------- |
| ome-zarr                 | 0.12.2                |
| cytoolz                  | 1.1.0                 |
| zarr                     | 3.1.5                 |
| charset-normalizer       | 3.4.4                 |
| matplotlib-inline        | 0.2.1                 |
| setuptools               | 80.10.2               |
| jaraco.text              | 4.0.0                 |
| pathlib_abc              | 0.5.2                 |
| tqdm                     | 4.67.1                |
| lz4                      | 4.4.5                 |
| tblib                    | 3.2.2                 |
| cycler                   | 0.12.1                |
| babel                    | 2.17.0                |
| traitlets                | 5.14.3                |
| scipy                    | 1.17.0                |
| matplotlib-scalebar      | 0.9.0                 |
| idna                     | 3.11                  |
| google-crc32c            | 1.8.0                 |
| xarray-schema            | 0.0.3                 |
| jaraco.context           | 6.1.0                 |
| debugpy                  | 1.8.19                |
| pure_eval                | 0.2.3                 |
| toolz                    | 1.1.0                 |
| pyct                     | 0.6.0                 |
| llvmlite                 | 0.46.0                |
| requests                 | 2.32.5                |
| kiwisolver               | 1.4.9                 |
| multiscale_spatial_image | 2.0.3                 |
| colorama                 | 0.4.6                 |
| multipledispatch         | 0.6.0                 |
| donfig                   | 0.8.1.post1           |
| legacy-api-wrap          | 1.5                   |
| pillow                   | 12.1.0                |
| Pint                     | 0.25.2                |
| scikit-learn             | 1.8.0                 |
| attrs                    | 25.4.0                |
| asttokens                | 3.0.1                 |
| comm                     | 0.2.3                 |
| xarray-dataclass         | 3.0.0                 |
| numcodecs                | 0.16.5                |
| parso                    | 0.8.5                 |
| geopandas                | 1.1.2                 |
| pandas                   | 3.0.0                 |
| flexcache                | 0.3                   |
| xarray-spatial           | 0.5.2                 |
| torch                    | 2.7.1                 |
| PySocks                  | 1.7.1                 |
| platformdirs             | 4.5.1                 |
| typing_extensions        | 4.15.0                |
| dask-image               | 2025.11.0             |
| ipython                  | 9.9.0                 |
| python-dateutil          | 2.9.0.post0           |
| msgpack                  | 1.1.2                 |
| decorator                | 5.2.1                 |
| MarkupSafe               | 3.0.3                 |
| session-info2            | 0.3                   |
| networkx                 | 3.6.1                 |
| PyYAML                   | 6.0.3                 |
| jupyter_core             | 5.9.1                 |
| defusedxml               | 0.7.1                 |
| pyproj                   | 3.7.2                 |
| executing                | 2.2.1                 |
| rich                     | 14.3.1                |
| packaging                | 26.0                  |
| urllib3                  | 2.6.3                 |
| scikit-image             | 0.26.0                |
| spatial_image            | 1.2.3                 |
| h5py                     | 3.15.1                |
| fast-array-utils         | 1.3.1                 |
| tornado                  | 6.5.4                 |
| shapely                  | 2.1.2                 |
| natsort                  | 8.4.0                 |
| dask                     | 2024.11.2             |
| prompt_toolkit           | 3.0.52                |
| wcwidth                  | 0.5.0                 |
| jedi                     | 0.19.2                |
| numba                    | 0.63.1                |
| stack_data               | 0.6.3                 |
| Pygments                 | 2.19.2                |
| pytz                     | 2025.2                |
| six                      | 1.17.0                |
| backports.zstd           | 1.3.0                 |
| xarray                   | 2026.1.0              |
| datashader               | 0.18.2                |
| pyparsing                | 3.3.2                 |
| threadpoolctl            | 3.6.0                 |
| Jinja2                   | 3.1.6                 |
| ipykernel                | 7.1.0                 |
| universal_pathlib        | 0.3.8                 |
| lazy_loader              | 0.4                   |
| cloudpickle              | 3.1.2                 |
| flexparser               | 0.4                   |
| psutil                   | 7.2.2                 |
| pyarrow                  | 23.0.0                |
| jaraco.functools         | 4.4.0                 |
| numpy                    | 2.3.5                 |
| Brotli                   | 1.2.0                 |
| certifi                  | 2026.1.4 (2026.01.04) |
| matplotlib               | 3.10.8                |
| backports.tarfile        | 1.2.0                 |
| jupyter_client           | 8.8.0                 |
| pyzmq                    | 27.1.0                |
| more-itertools           | 10.8.0                |
| joblib                   | 1.5.3                 |
| fsspec                   | 2026.1.0              |

| Component | Info                                                                           |
| --------- | ------------------------------------------------------------------------------ |
| Python    | 3.12.12 | packaged by conda-forge | (main, Jan 26 2026, 23:51:32) [GCC 14.3.0] |
| OS        | Linux-5.15.0-1093-nvidia-x86_64-with-glibc2.35                                 |                                              
| Updated   | 2026-01-29 10:50   

Metadata

Metadata

Assignees

No one assigned

    Labels

    Triage 🩺This issue needs to be triaged by a maintainer

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions