Skip to content

Commit f2bff29

Browse files
authored
Fix render_shapes crash when obs index name conflicts with column (#558)
1 parent 44b0720 commit f2bff29

2 files changed

Lines changed: 48 additions & 3 deletions

File tree

src/spatialdata_plot/pl/render.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,21 @@ def _render_shapes(
317317
table = None
318318
shapes = sdata_filt[element]
319319
else:
320-
element_dict, joined_table = join_spatialelement_table(
321-
sdata, spatial_element_names=element, table_name=table_name, how="inner"
322-
)
320+
# Workaround for upstream spatialdata bug (scverse/spatialdata#1099):
321+
# join_spatialelement_table calls table.obs.reset_index() which fails when
322+
# the obs index name matches an existing column (e.g. "EntityID" in Merfish data).
323+
# Temporarily drop the conflicting index name for the join, then restore it.
324+
_obs = sdata[table_name].obs
325+
_saved_index_name = _obs.index.name
326+
if _saved_index_name is not None and _saved_index_name in _obs.columns:
327+
_obs.index.name = None
328+
329+
try:
330+
element_dict, joined_table = join_spatialelement_table(
331+
sdata, spatial_element_names=element, table_name=table_name, how="inner"
332+
)
333+
finally:
334+
_obs.index.name = _saved_index_name
323335
sdata_filt[element] = shapes = element_dict[element]
324336
joined_table.uns["spatialdata_attrs"]["region"] = (
325337
joined_table.obs[joined_table.uns["spatialdata_attrs"]["region_key"]].unique().tolist()

tests/pl/test_render_shapes.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,3 +1142,36 @@ def test_datashader_alpha_not_applied_twice(sdata_blobs: SpatialData):
11421142
"on top of the alpha already in the RGBA channels — causing double transparency."
11431143
)
11441144
plt.close(fig)
1145+
1146+
1147+
def test_render_shapes_color_with_conflicting_index_name():
1148+
"""render_shapes(color=...) must not crash when obs.index.name matches an existing column.
1149+
1150+
Regression test for https://github.com/scverse/spatialdata-plot/issues/441.
1151+
In Merfish data, the table's instance_key (e.g. 'EntityID') can appear as both
1152+
the obs index name and an obs column. Upstream spatialdata's join_spatialelement_table
1153+
calls reset_index() which raises ValueError when the index name collides with a column.
1154+
"""
1155+
n = 10
1156+
rng = get_standard_RNG()
1157+
circles = [Point(i, i) for i in range(n)]
1158+
shapes_df = gpd.GeoDataFrame({"geometry": circles, "radius": np.ones(n)})
1159+
shapes_df = ShapesModel.parse(shapes_df)
1160+
1161+
obs = pd.DataFrame(
1162+
{
1163+
"region": pd.Categorical(["shapes"] * n),
1164+
"EntityID": np.arange(n),
1165+
"cell_type": pd.Categorical(rng.choice(["A", "B", "C"], n)),
1166+
}
1167+
)
1168+
table = AnnData(obs=obs)
1169+
table = TableModel.parse(table, region="shapes", region_key="region", instance_key="EntityID")
1170+
1171+
sdata = SpatialData(shapes={"shapes": shapes_df}, tables={"table": table})
1172+
1173+
# Introduce the conflicting state: index name == existing column name
1174+
sdata["table"].obs.index = pd.Index(np.arange(n), name="EntityID")
1175+
1176+
# Should not raise ValueError: cannot insert EntityID, already exists
1177+
sdata.pl.render_shapes("shapes", color="cell_type", table_name="table").pl.show()

0 commit comments

Comments
 (0)