Skip to content

perf(render_images): stream multi-channel composite (avoid O(n_channels) RGBA cube)#736

Merged
timtreis merged 2 commits into
mainfrom
perf/issue-734-image-composite
Jun 22, 2026
Merged

perf(render_images): stream multi-channel composite (avoid O(n_channels) RGBA cube)#736
timtreis merged 2 commits into
mainfrom
perf/issue-734-image-composite

Conversation

@timtreis

Copy link
Copy Markdown
Member

Closes #734.

Problem

Five multi-channel composite branches in _render_images build the full (n_channels, H, W, 4) float64 cube via np.stack([cmap(layers[ch]) for ch in channels], 0).sum(0) before reducing — peak ≈ 64·n·H·W bytes (GB-scale on large multiplex images).

Fix

A streaming helper _composite_channels accumulates per-channel RGB into a single (H, W, 3) buffer (O(1) full buffers), mirroring the existing n>3 branch.

Byte-identical

numpy.sum(axis=0) over the stacked outer axis reduces sequentially, matching acc += rgb — so the result is bit-for-bit identical to the old stack-and-sum (incl. >128 channels, past numpy's pairwise threshold). Verified end-to-end main-vs-branch across 8 render cases (max|Δ| = 0) and locked by a regression test.

Impact

  • Peak memory 3357 MB → 26 MB (129×) at 200 channels @512².
  • The n>3 premultiplied-alpha branch and the RGB-direct branch keep their own math and are untouched.

Tests

TestCompositeChannels: asserts the helper equals np.stack(...).sum(0)[:, :, :3] across channel counts (2, 3, 7, 129, 200) and that it returns an owned C-contiguous float64 (H,W,3) buffer.

@codecov-commenter

codecov-commenter commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.90909% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 79.27%. Comparing base (55f4970) to head (15c6c90).

Files with missing lines Patch % Lines
src/spatialdata_plot/pl/render.py 90.90% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #736      +/-   ##
==========================================
+ Coverage   79.26%   79.27%   +0.01%     
==========================================
  Files          17       17              
  Lines        4596     4594       -2     
  Branches     1028     1029       +1     
==========================================
- Hits         3643     3642       -1     
+ Misses        603      602       -1     
  Partials      350      350              
Files with missing lines Coverage Δ
src/spatialdata_plot/pl/render.py 89.63% <90.90%> (+0.08%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Five multi-channel composite branches built the full (n_channels, H, W, 4)
float64 cube via np.stack([...], 0).sum(0) before reducing (peak ~64*n*H*W
bytes; GB-scale on large multiplex images). Replace with a streaming helper
_composite_channels that accumulates per-channel RGB into one (H, W, 3)
buffer (O(1) full buffers), mirroring the existing n>3 branch.

Byte-identical: numpy sum over the stacked outer axis reduces sequentially,
matching acc += rgb. Verified end-to-end main-vs-branch (8 cases, max|delta|=0)
and via the regression test across channel counts incl. >128. Peak memory
3357MB -> 26MB (129x) at 200 channels @512x512.

The n>3 premultiplied-alpha branch and the RGB-direct branch keep their own
math and are left untouched.
@timtreis timtreis force-pushed the perf/issue-734-image-composite branch from cd6db7b to 942be7b Compare June 22, 2026 01:08
`table` was assigned (None or sdata_filt[table_name]) but never read —
color resolution goes through sdata_filt + table_name, not this local.
Drop both assignments, keep the _check_instance_ids_overlap validation,
and invert the guard. Clears a pre-existing ruff F841.
@timtreis timtreis merged commit edf3f76 into main Jun 22, 2026
7 of 8 checks passed
@timtreis timtreis deleted the perf/issue-734-image-composite branch June 22, 2026 08:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf: multi-channel image composite materializes O(n_channels) full-res RGBA cubes

2 participants