Skip to content

Commit 11e4d2e

Browse files
committed
Merge remote-tracking branch 'origin/main' into refactor/issue-696-split-utils
# Conflicts: # src/spatialdata_plot/pl/render.py
2 parents e0238c3 + 7a1b3a3 commit 11e4d2e

4 files changed

Lines changed: 195 additions & 166 deletions

File tree

src/spatialdata_plot/pl/_datashader.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,90 @@ def _ds_shade_categorical(
337337
return _apply_user_alpha(shaded, alpha)
338338

339339

340+
def _shade_datashader_aggregate(
341+
cvs: ds.Canvas,
342+
frame: Any,
343+
*,
344+
col_for_color: str | None,
345+
color_vector: Any,
346+
color_by_categorical: bool,
347+
norm: Normalize | None,
348+
cmap: Any,
349+
na_color: Color,
350+
alpha: float,
351+
ds_reduction: _DsReduction | None,
352+
default_reduction: _DsReduction,
353+
kind: Literal["shapes", "points"],
354+
spread_px: int | None = None,
355+
shade_how: str = "linear",
356+
density: bool = False,
357+
uniform_alpha: bool = False,
358+
strip_alpha_hex: bool = False,
359+
) -> tuple[Any, Any | None, tuple[Any, Any] | None, Any]:
360+
"""Aggregate ``frame`` over ``cvs`` and shade it; the core shared by shapes and points.
361+
362+
Runs the steps every datashader caller repeats: ``_ds_aggregate`` -> ``_apply_ds_norm`` ->
363+
transparent-NA guard -> ``_build_color_key`` -> categorical/continuous shade dispatch. Returns
364+
``(shaded, nan_shaded, reduction_bounds, color_vector)``; ``color_vector`` is returned because the
365+
points path strips hex alpha off it and the caller's legend must match. Callers keep their
366+
element-specific prep (geometry transform / point parse), outline rendering, ``_render_ds_image``
367+
and ``_build_ds_colorbar``.
368+
"""
369+
agg, reduction_bounds, nan_agg = _ds_aggregate(
370+
cvs, frame, col_for_color, color_by_categorical, ds_reduction, default_reduction, kind
371+
)
372+
agg, color_span = _apply_ds_norm(agg, norm)
373+
na_color_hex = _hex_no_alpha(na_color.get_hex())
374+
if na_color.is_fully_transparent():
375+
nan_agg = None
376+
color_key = _build_color_key(frame, col_for_color, color_by_categorical, color_vector, na_color_hex)
377+
378+
if (
379+
strip_alpha_hex
380+
and color_vector is not None
381+
and len(color_vector) > 0
382+
and isinstance(color_vector[0], str)
383+
and color_vector[0].startswith("#")
384+
):
385+
# color_vector usually holds only a few distinct hex strings (one per category), so strip
386+
# alpha on the unique values and map back rather than parsing once per point.
387+
unique_hex, inverse = np.unique(color_vector, return_inverse=True)
388+
color_vector = np.asarray([_hex_no_alpha(c) for c in unique_hex])[inverse]
389+
390+
# density without a color column collapses to a sequential count gradient; everything else with no
391+
# explicit continuous value (categorical or no color) goes through the categorical shader.
392+
plain_density = density and col_for_color is None
393+
nan_shaded = None
394+
if not plain_density and (color_by_categorical or col_for_color is None):
395+
shaded = _ds_shade_categorical(
396+
agg,
397+
color_key,
398+
color_vector,
399+
alpha,
400+
spread_px=spread_px,
401+
how=shade_how,
402+
density=density,
403+
uniform_alpha=uniform_alpha,
404+
)
405+
else:
406+
shaded, nan_shaded, reduction_bounds = _ds_shade_continuous(
407+
agg,
408+
color_span,
409+
norm,
410+
cmap,
411+
alpha,
412+
reduction_bounds,
413+
nan_agg,
414+
na_color_hex,
415+
spread_px=spread_px,
416+
ds_reduction=ds_reduction,
417+
how=shade_how,
418+
uniform_alpha=uniform_alpha,
419+
)
420+
421+
return shaded, nan_shaded, reduction_bounds, color_vector
422+
423+
340424
# ---------------------------------------------------------------------------
341425
# Image rendering
342426
# ---------------------------------------------------------------------------

src/spatialdata_plot/pl/basic.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1677,7 +1677,10 @@ def _resolve_coordinate_systems(
16771677
if cs not in sdata.coordinate_systems:
16781678
raise ValueError(f"Unknown coordinate system '{cs}', valid choices are: {sdata.coordinate_systems}")
16791679

1680-
elements_to_be_rendered = _get_elements_to_be_rendered(render_cmds, cs_index, cs)
1680+
# Union elements across all coordinate systems, not just the last one validated above.
1681+
elements_to_be_rendered = list(
1682+
dict.fromkeys(e for cs in coordinate_systems for e in _get_elements_to_be_rendered(render_cmds, cs_index, cs))
1683+
)
16811684

16821685
# filter out cs without relevant elements
16831686
cmds = [cmd for cmd, _ in render_cmds]

0 commit comments

Comments
 (0)