Add scanpy-style multi-panel color=[...] for render_shapes and render_labels#686
Add scanpy-style multi-panel color=[...] for render_shapes and render_labels#686timtreis wants to merge 6 commits into
color=[...] for render_shapes and render_labels#686Conversation
…_labels `render_shapes` and `render_labels` now accept a list of column/key names for `color`, producing one panel per key (like scanpy's `color=[...]`). A string list is expanded at render time into one set of render params per key, each tagged with a new `panel_key`; `show()` lays out one panel per key and draws scalar-colored render calls into every panel as a shared background. `show(ncols=...)` controls the grid width. Constraints: multi-panel color requires a single coordinate system, only one `render_*` call per figure may pass a list, duplicate keys are rejected, and invalid keys are reported together before drawing. Also shallow-copy `plotting_tree` in `_copy()` so appending a render step to one chain no longer mutates a sibling chain branched off the same object. Closes #611
…avioral tests Add `test_plot_*` image-comparison tests covering the scanpy-style `color=[...]` feature: multi-panel shapes (continuous + categorical), shared image background with `ncols` wrapping, and multi-panel labels. Baselines are generated on CI. Consolidate the multi-panel behavioral tests into a tight set: one structural test (panel count + titles + grid geometry), one parametrized scalar-forms test (length-1 list and RGB float list stay single-panel), one parametrized invalid-input test (empty/duplicate/mixed/bad-key/two-lists), and the branch-independence regression.
Generated from the CI visual_test_results artifact (py3.11-stable). Covers multi-panel shapes (continuous + categorical), shared image background with ncols wrapping, and multi-panel labels.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #686 +/- ##
==========================================
+ Coverage 75.98% 76.25% +0.26%
==========================================
Files 14 14
Lines 4156 4211 +55
Branches 964 982 +18
==========================================
+ Hits 3158 3211 +53
- Misses 647 648 +1
- Partials 351 352 +1
🚀 New features to boost your workflow:
|
`compare()` previously forced every figure into a single 5-inch canvas with constrained layout. For multi-panel figures (e.g. scanpy-style color=[...] or multiple coordinate systems) this crammed the panels together and pushed each panel's per-axis colorbar/legend into the neighbouring panel. Only normalize size + layout for single-panel figures (count gridspec-placed axes; colorbar/legend insets have no subplotspec). Multi-panel figures keep their own size and spacing; the thumbnail is produced by the existing resize step. Single-panel baselines are unaffected; multi-panel baselines are regenerated.
These baselines now reflect the figures' natural per-panel layout (colorbars and legends within each panel's column instead of overlapping neighbours). Includes the new multi-panel color baselines and existing multi-panel tests (group filtering, datashader reduction grid, multichannel normalization, frameon multi-panel, raccoon split, visium hex grid, transparent-cmap comparisons). Generated from the py3.11-stable CI artifact.
The compare() change traded dense-colorbar overlap for letterboxed whitespace and, in some cases, new legend overlap, regressing existing multi-panel baselines. The 400x300 comparison canvas fundamentally cannot render per-panel colorbars/legends without crowding, so visual baselines are a poor fit for the multi-panel color feature. Revert compare() to its original behavior, restore the existing multi-panel baselines, and drop the four overlapping multi-panel color baselines/visual tests. The feature stays covered by structural tests: panel count + titles + ncols geometry, per-panel categorical legends, shared scalar background, scalar-form fallbacks, error cases, and branch independence.
|
CCing @melonora, wasn't this feature available on a earlier version and then got refactored out because it was making linking parameters to color challenging? But I think having all the elements in |
|
Yeah, we removed it for type checking "elegance" but with the new The original plan was to upstream that ability to Squidpy, but there are so many plots you can only do with the non-wrapped |
Summary
Closes #611.
render_shapesandrender_labelsnow accept a list of column/key names forcolor, producing one panel per key — the scanpycolor=[...]convention.panel_key.show()lays out one panel per key; scalar-colored render calls (e.g. a background image) are drawn into every panel as a shared layer.show(ncols=...)controls the grid width; each panel is titled by its key.A
list[str]is statically distinct fromColorLike'slist[float], so the type surface stays clean (color: ColorLike | list[str] | None).Behavior & constraints
colorcalls are unchanged. A length-1 list normalizes to a scalar color.render_*call per figure may pass a list (others must be scalar).groups/palette/cmap/normare broadcast to every panel; each continuous panel auto-scales independently; colorbars/legends are per-panel.Drive-by fix
_copy()now shallow-copiesplotting_tree, so appending a render step to one chain no longer mutates a sibling chain branched off the same object (this previously also let branched chains bleed layers into each other).