scverse / scverse/spatialdata-plot

Additive RGB color blending for render_shapes / render_labels (and render_points)

Open
#677 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
86
Forks
21
Avg merge
14h 50m
Merged PRs (30d)
3

Description

Motivation

Spun out from #321 (the thread there mixes two unrelated asks — this issue is the second one, originally raised by @brainfo).

`render_images` already supports multi-channel additive compositing: you pass several channels with per-channel colormaps and they blend into a single RGB image, mirroring napari / ImageJ / FIJI for fluorescence microscopy. The same idiom is useful for sequencing-based spatial data, where a user wants to visualize co-expression of 2–3 genes per cell/spot/region on a single axis — red for gene A, green for gene B, blue for gene C, additively blended so co-expressing cells appear yellow/cyan/white.

Today this requires manual post-processing (the user in #321 mentions doing it in Illustrator).

Proposed API

Mirror the existing `render_images` multi-channel convention by letting `color` accept a list of obs/var columns on `render_shapes`, `render_labels`, and `render_points`:

```python
sdata.pl.render_shapes(
color=["Sox2", "Pax6", "Tbr2"],
palette=["red", "green", "blue"], # one color per channel
channels_as_legend=True,
).pl.show()

sdata.pl.render_labels(
color=["Sox2", "Pax6"],
palette=["red", "green"],
).pl.show()

sdata.pl.render_points(
color=["Sox2", "Pax6"],
).pl.show()
```

Output: a single axis (no multi-panel grid). Each shape / label / point gets one composited color derived from its per-column values blended via per-channel colormaps, identical in spirit to the additive multi-channel path already in `render_images`.

Why this is feasible

  • The additive-blending machinery already exists in `pl/render.py` for the multi-channel image path (see `render_images` branches 2A/2B/2C). The same per-channel cmap + sum + clip logic applies.
  • Single-axis output sidesteps the hierarchy-of-axes complexity that made multi-panel `color=[...]` (the other ask from #321) undesirable.
  • `channels_as_legend` already exists for `render_images`; can extend.

Scope

  • In scope: 2–3-column color lists on `render_shapes`, `render_labels`, `render_points`. Per-channel `cmap` or `palette`. Additive blend on a single axis.
  • Out of scope (defer or decline):
    • Multi-panel grids (`sc.pl.umap`-style) — already declined in #321.
    • Arbitrary blend modes beyond additive — start with the existing `render_images` semantics.
    • PCA-based or learned color reductions for >3 channels.

Edge cases to design for

  • Length mismatch between `color` list and `palette` list.
  • Mixing categorical and continuous columns in the same `color` list (probably reject with a clear error).
  • NaN handling per column (skip vs zero vs error — likely error, matching the recent `render_images` NaN rejection).
  • Per-column `norm` / `vmin` / `vmax` — accept a list, parallel to the per-channel `norm` already supported on `render_images`.
  • `groups` semantics when `color` is a list — likely ignored with a warning.

Relation to #321

#321 conflates two asks under "plotting multiple genes":

  1. Multi-panel grid for several genes — declined; possibly hosted in a future Squidpy 2.0 wrapper.
  2. Single-axis additive blend for co-expression visualization — this issue.

The documentation sub-tasks in #321 (`save`, `ncols` on `pl.show()`) are already resolved.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in pl/render.py by reading the existing render_images multi-channel branches 2A/2B/2C, then trace render_shapes, render_labels, and render_points. Done means supporting 2–3 continuous columns as per-channel colors on one axis with additive blending, while defining the listed palette-length, mixed-type, NaN, normalization, and groups behaviors.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
data-visualization
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.