Skip to content

render_points(color="z") silently drops the column and crashes with misleading error #615

@timtreis

Description

@timtreis

render_points(color="z") silently drops the column and crashes with misleading error

Description

When a points element has a data column named "z" and the user passes color="z", _reparse_points re-registers the element via PointsModel.parse(..., coordinates={"x": "x", "y": "y"}). This silently strips "z" because spatialdata treats it as a reserved spatial coordinate name. The color column vanishes before the color vector is computed, producing KeyError: "Unable to locate color key 'z' for element 'p'." — even though the column is plainly visible in the original element's .columns. The error message gives no indication that an internal re-registration step dropped the column.

Environment

spatialdata-plot: 0.3.4.dev (main, 5cfedc7)
spatialdata: 0.5.0
Python: 3.13

Minimal Reproducible Example

import matplotlib; matplotlib.use("Agg")
import matplotlib.pyplot as plt
import pandas as pd
import dask; dask.config.set({"dataframe.query-planning": False})
import spatialdata as sd
from spatialdata.models import PointsModel
import spatialdata_plot

# Points with a data column named "z" (not a 3-D spatial z — just a data column)
pts = PointsModel.parse(
    pd.DataFrame({"x": [1., 2., 3.], "y": [1., 2., 3.], "z": [0.1, 0.5, 0.9]}),
    coordinates={"x": "x", "y": "y"},
)
print("Column 'z' exists:", "z" in pts.columns)  # True

sdata = sd.SpatialData(points={"p": pts})
fig, ax = plt.subplots()
sdata.pl.render_points("p", color="z").pl.show(ax=ax)
# KeyError: "Unable to locate color key 'z' for element 'p'."

Expected vs. Actual

Expected: Renders points colored by the "z" data column. Or, if this cannot be supported, raises a clear and actionable error:

"Column 'z' was dropped during internal re-registration because it conflicts with the reserved spatial coordinate name 'z'. Rename the column before plotting."

Actual: KeyError: "Unable to locate color key 'z' for element 'p'. Please ensure the key exists in a table annotating this element." — misleading because "z" is visible in pts.columns.

Fix Sketch

In _reparse_points (render.py:~808), after PointsModel.parse, compare the original DataFrame's columns to the result. If any columns are missing, emit a clear warning naming the dropped columns and the reason (reserved coordinate name conflict).

A more robust fix: before calling PointsModel.parse, detect columns whose names conflict with reserved spatial coordinate names ("x", "y", "z") and temporarily rename them (e.g., "z""__z_data__"), then rename back after parsing. Alternatively, skip _reparse_points entirely when no spatial filtering has actually occurred, which avoids the re-registration side effect altogether.

Labels: bug, points, priority: medium


Triage tier: Tier 2

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions