Description
Hi!
I encountered an issue when using the render_shapes() function to visualize my Xenium data. My code works fine when selecting two values in the groups argument, but when I try to select more than two values, it raises a TypeError: unhashable type: 'Series'. Below is the detailed information and the code I am using.
Code Snippet
Here is the code that works with two values in groups:
from spatialdata import bounding_box_query
import matplotlib.pyplot as plt
import spatialdata_plot
crop0(sdata).pl.render_images("morphology_focus").pl.render_shapes(
"cell_circles",
color='celltype_v2',
groups=['Immune','Stromal'],
palette = ['#d37f28','#e4e4e4'],
).pl.show(title='Cell Type',
coordinate_systems="global",
figsize=(10, 5)
)
However, if I attempt to use more than two values in groups, I get an error. Here’s an example that fails:
crop0(sdata).pl.render_images("morphology_focus").pl.render_shapes(
"cell_circles",
color='celltype_v2',
groups=['Immune','Stromal','Endothelium'],
palette = ['#d37f28','#e4e4e4','#f4f0b1'],
).pl.show(title='Cell Type',
coordinate_systems="global",
figsize=(10, 5)
)
Error Message
When selecting more than two groups, I get the following error:
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). Got range [0.0..1.760399846212995].
INFO Using 'datashader' as plotting backend.
/home/jrchristin/miniconda3/envs/ST/lib/python3.11/site-packages/spatialdata_plot/pl/basic.py:879: UserWarning: Converting copy of 'celltype_v2' column to categorical dtype for categorical plotting. Consider converting before plotting.
_render_shapes(
/home/jrchristin/miniconda3/envs/ST/lib/python3.11/site-packages/spatialdata_plot/pl/utils.py:782: FutureWarning: The default value of 'ignore' for the `na_action` parameter in pandas.Categorical.map is deprecated and will be changed to 'None' in a future version. Please set na_action to the desired value to avoid seeing this warning
color_vector = color_source_vector.map(color_mapping)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[60], line 6
1 crop0(sdata).pl.render_images("morphology_focus").pl.render_shapes(
2 "cell_circles",
3 color='celltype_v2',
4 groups=['LumAcinar','LumDuctal','Stromal','Basal','Endothelium','Immune'],
5 palette = ['#00bfae','#bb87e0','#e4e4e4','#f33939','#f4f0b1','#d37f28'],
----> 6 ).pl.show(title='Cell Type',
7 coordinate_systems="global",
8 figsize=(10, 5)
9 )
File ~/miniconda3/envs/ST/lib/python3.11/site-packages/spatialdata_plot/pl/basic.py:879, in PlotAccessor.show(self, coordinate_systems, legend_fontsize, legend_fontweight, legend_loc, legend_fontoutline, na_in_legend, colorbar, wspace, hspace, ncols, frameon, figsize, dpi, fig, title, share_extent, pad_extent, ax, return_ax, save)
874 wanted_elements, wanted_shapes_on_this_cs, wants_shapes = _get_wanted_render_elements(
875 sdata, wanted_elements, params_copy, cs, "shapes"
876 )
878 if wanted_shapes_on_this_cs:
--> 879 _render_shapes(
880 sdata=sdata,
881 render_params=params_copy,
882 coordinate_system=cs,
883 ax=ax,
884 fig_params=fig_params,
885 scalebar_params=scalebar_params,
886 legend_params=legend_params,
887 )
889 elif cmd == "render_points" and has_points:
890 wanted_elements, wanted_points_on_this_cs, wants_points = _get_wanted_render_elements(
891 sdata, wanted_elements, params_copy, cs, "points"
892 )
File ~/miniconda3/envs/ST/lib/python3.11/site-packages/spatialdata_plot/pl/render.py:187, in _render_shapes(sdata, render_params, coordinate_system, ax, fig_params, scalebar_params, legend_params)
185 if is_point.any():
186 scale = shapes[is_point]["radius"] * render_params.scale
--> 187 sdata_filt.shapes[element].loc[is_point, "geometry"] = _geometry[is_point].buffer(scale.to_numpy())
189 # in case we are coloring by a column in table
190 if col_for_color is not None and col_for_color not in sdata_filt.shapes[element].columns:
File ~/miniconda3/envs/ST/lib/python3.11/site-packages/pandas/core/indexing.py:907, in _LocationIndexer.__setitem__(self, key, value)
905 maybe_callable = com.apply_if_callable(key, self.obj)
906 key = self._check_deprecated_callable_usage(key, maybe_callable)
--> 907 indexer = self._get_setitem_indexer(key)
908 self._has_valid_setitem_indexer(key)
910 iloc = self if self.name == "iloc" else self.obj.iloc
File ~/miniconda3/envs/ST/lib/python3.11/site-packages/pandas/core/indexing.py:780, in _LocationIndexer._get_setitem_indexer(self, key)
776 if isinstance(key, range):
777 # GH#45479 test_loc_setitem_range_key
778 key = list(key)
--> 780 return self._convert_to_indexer(key, axis=0)
File ~/miniconda3/envs/ST/lib/python3.11/site-packages/pandas/core/indexing.py:1522, in _LocIndexer._convert_to_indexer(self, key, axis)
1520 return key
1521 else:
-> 1522 return self._get_listlike_indexer(key, axis)[1]
1523 else:
1524 try:
File ~/miniconda3/envs/ST/lib/python3.11/site-packages/pandas/core/indexing.py:1558, in _LocIndexer._get_listlike_indexer(self, key, axis)
1555 ax = self.obj._get_axis(axis)
1556 axis_name = self.obj._get_axis_name(axis)
-> 1558 keyarr, indexer = ax._get_indexer_strict(key, axis_name)
1560 return keyarr, indexer
File ~/miniconda3/envs/ST/lib/python3.11/site-packages/pandas/core/indexes/base.py:6195, in Index._get_indexer_strict(self, key, axis_name)
6192 keyarr = com.asarray_tuplesafe(keyarr)
6194 if self._index_as_unique:
-> 6195 indexer = self.get_indexer_for(keyarr)
6196 keyarr = self.reindex(keyarr)[0]
6197 else:
File ~/miniconda3/envs/ST/lib/python3.11/site-packages/pandas/core/indexes/base.py:6182, in Index.get_indexer_for(self, target)
6164 """
6165 Guaranteed return of an indexer even when non-unique.
6166
(...)
6179 array([0, 2])
6180 """
6181 if self._index_as_unique:
-> 6182 return self.get_indexer(target)
6183 indexer, _ = self.get_indexer_non_unique(target)
6184 return indexer
File ~/miniconda3/envs/ST/lib/python3.11/site-packages/pandas/core/indexes/base.py:3953, in Index.get_indexer(self, target, method, limit, tolerance)
3948 target = target.astype(dtype, copy=False)
3949 return this._get_indexer(
3950 target, method=method, limit=limit, tolerance=tolerance
3951 )
-> 3953 return self._get_indexer(target, method, limit, tolerance)
File ~/miniconda3/envs/ST/lib/python3.11/site-packages/pandas/core/indexes/base.py:3980, in Index._get_indexer(self, target, method, limit, tolerance)
3977 else:
3978 tgt_values = target._get_engine_target()
-> 3980 indexer = self._engine.get_indexer(tgt_values)
3982 return ensure_platform_int(indexer)
File index.pyx:351, in pandas._libs.index.IndexEngine.get_indexer()
File pandas/_libs/hashtable_class_helper.pxi:7132, in pandas._libs.hashtable.PyObjectHashTable.lookup()
TypeError: unhashable type: 'Series'
My sdata includes:
SpatialData object, with associated Zarr store: /home/jrchristin/zejian/ST/29879_Xenium.zarr
├── Images
│ └── 'morphology_focus': DataTree[cyx] (5, 101912, 45538), (5, 50956, 22769), (5, 25478, 11384), (5, 12739, 5692), (5, 6369, 2846)
├── Labels
│ ├── 'cell_labels': DataTree[yx] (101912, 45538), (50956, 22769), (25478, 11384), (12739, 5692), (6369, 2846)
│ └── 'nucleus_labels': DataTree[yx] (101912, 45538), (50956, 22769), (25478, 11384), (12739, 5692), (6369, 2846)
├── Points
│ └── 'transcripts': DataFrame with shape: (<Delayed>, 13) (3D points)
├── Shapes
│ ├── 'cell_boundaries': GeoDataFrame shape: (698095, 1) (2D shapes)
│ ├── 'cell_circles': GeoDataFrame shape: (698095, 2) (2D shapes)
│ └── 'nucleus_boundaries': GeoDataFrame shape: (678228, 1) (2D shapes)
└── Tables
└── 'table': AnnData (698095, 477)
with coordinate systems:
▸ 'global', with elements:
morphology_focus (Images), cell_labels (Labels), nucleus_labels (Labels), transcripts (Points), cell_boundaries (Shapes), cell_circles (Shapes), nucleus_boundaries (Shapes)
Environment
Python version: 3.11
spatialdata version: '0.2.3'
spatialdata_plot version: '0.2.7.dev2+g6ffe22b'
Operating system: Ubuntu 24.04.1
Please feel free to let me know if more details are needed, or feel free to reach out for additional clarification.
Thank you!