Skip to content

Commit 193086f

Browse files
committed
Fix datashader outline column-attach using positional assignment (#681)
`transformed_element.assign(col=series)` aligns by index. When the post-inner-join element carries a non-contiguous index (e.g. [0, 2, 5, ...]) but the outline source vector is built with a default RangeIndex(0..n-1), rows whose indices don't intersect get NaN. Those NaNs are then lifted to the `ds_nan` sentinel by `_inject_ds_nan_sentinel`, and one polygon ends up rendered as `na_color` instead of its real category — visible as a gray outline among otherwise correctly-colored polygons on the Linux CI runners. The matplotlib path is unaffected because it goes through `_color_vector_to_rgba`, which operates positionally. Fix: assign positionally via `df[col] = pd.Categorical(...)` (which uses position-based assignment for ExtensionArray-typed RHS), on an explicit copy so the caller's dataframe is not mutated.
1 parent 947b8f8 commit 193086f

1 file changed

Lines changed: 13 additions & 7 deletions

File tree

src/spatialdata_plot/pl/_datashader.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -433,15 +433,21 @@ def _render_ds_outline_by_column(
433433
color_by_categorical = outline_color_source_vector is not None
434434
na_color_hex = _hex_no_alpha(cmap_params.na_color.get_hex())
435435

436-
# Attach the outline vector under a private column name so a fill column with
437-
# the same key never gets overwritten. Use .assign() to avoid mutating the
438-
# caller's dataframe.
436+
# Attach the outline vector under a private column name so a fill column with the
437+
# same key never gets overwritten. Assign positionally (via a Series indexed to the
438+
# element) — `.assign(col=series)` aligns by index, which silently inserts NaN when
439+
# the element's index is non-contiguous (e.g. after an inner-join). The NaNs would
440+
# then be lifted to the `ds_nan` sentinel and one polygon's outline would render as
441+
# `na_color` instead of its real category.
442+
transformed_element = transformed_element.copy()
439443
if color_by_categorical:
440-
cat_series = pd.Categorical(outline_color_source_vector)
441-
attach_value: Any = _inject_ds_nan_sentinel(pd.Series(cat_series))
444+
cat = pd.Categorical(outline_color_source_vector)
445+
attach_cat = _inject_ds_nan_sentinel(pd.Series(cat))
446+
transformed_element[_OUTLINE_INTERNAL_COL] = pd.Categorical(
447+
attach_cat.to_numpy(), categories=attach_cat.cat.categories
448+
)
442449
else:
443-
attach_value = np.asarray(outline_color_vector)
444-
transformed_element = transformed_element.assign(**{_OUTLINE_INTERNAL_COL: attach_value})
450+
transformed_element[_OUTLINE_INTERNAL_COL] = np.asarray(outline_color_vector)
445451

446452
if color_by_categorical:
447453
agg_outline = cvs.line(

0 commit comments

Comments
 (0)