Skip to content

Fix set_zero_in_cmap_to_transparent with datashader rendering#577

Open
timtreis wants to merge 9 commits intomainfrom
fix/issue-376-transparent-cmap-datashader
Open

Fix set_zero_in_cmap_to_transparent with datashader rendering#577
timtreis wants to merge 9 commits intomainfrom
fix/issue-376-transparent-cmap-datashader

Conversation

@timtreis
Copy link
Copy Markdown
Member

@timtreis timtreis commented Apr 4, 2026

Summary

  • Fixes Issue with set_zero_in_cmap_to_transparent Function Not Making Zero Values Transparent in Spatial Data Plotting #376: set_zero_in_cmap_to_transparent produced opaque white shapes instead of transparent ones when rendering with datashader
  • ds.tf.shade() strips the alpha channel from matplotlib colormaps entirely — entries with alpha=0 were rendered as opaque white
  • Fix: mask aggregate values that map to transparent cmap entries to NaN before shading, which is datashader's native transparency mechanism
  • The matplotlib rendering path was already correct (preserves alpha=0 in _get_collection_shape)

Known limitation: when all aggregate values are identical and map to the transparent cmap entry, the upstream single-value path in _ds_shade_continuous converts the cmap to a hex string before reaching the masking logic. This is a pre-existing edge case.

Datashader's tf.shade() strips the alpha channel from matplotlib colormaps,
so entries with alpha=0 (from set_zero_in_cmap_to_transparent) rendered as
opaque white instead of transparent. Fix by masking aggregate values that
map to transparent cmap entries to NaN before shading — NaN is datashader's
native transparency mechanism.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 4, 2026

Codecov Report

❌ Patch coverage is 66.66667% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.25%. Comparing base (303140c) to head (783f54a).

Files with missing lines Patch % Lines
src/spatialdata_plot/pl/utils.py 66.66% 5 Missing and 6 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #577      +/-   ##
==========================================
- Coverage   75.36%   75.25%   -0.12%     
==========================================
  Files          10       10              
  Lines        2935     2966      +31     
  Branches      684      693       +9     
==========================================
+ Hits         2212     2232      +20     
- Misses        441      446       +5     
- Partials      282      288       +6     
Files with missing lines Coverage Δ
src/spatialdata_plot/pl/utils.py 65.57% <66.66%> (-0.03%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

timtreis and others added 8 commits April 4, 2026 21:46
Add test_plot_transparent_cmap_shapes_matplotlib and
test_plot_transparent_cmap_shapes_datashader to verify that shapes with
value=0 are rendered transparently over an image when using
set_zero_in_cmap_to_transparent, for both rendering backends.

Placeholder baselines included — CI will generate the real ones.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Each visual test now shows a side-by-side comparison with the standard
viridis cmap on the left and the transparent cmap on the right, making
the transparency effect clearly visible.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When span=None, datashader auto-scales from non-NaN values. After masking
zeros to NaN, the remaining minimum value (e.g. 2.0) would map to cmap(0.0)
— the transparent-white entry — and min_alpha would override the alpha,
producing opaque white.

Fix: _mask_transparent_cmap_entries now returns the pre-masking span so
ds.tf.shade uses the original data range, preventing re-scaling into the
transparent bin.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The NaN-masking approach was fundamentally flawed: masking values to NaN
caused datashader to auto-scale the remaining values, shifting other
shapes' colors and potentially making them white.

New approach: let datashader shade normally (preserving all colors and
spans), then post-process the RGBA output to apply the cmap's alpha
channel. This:
- Does not modify aggregate values or spans
- Preserves exact colors for all non-transparent shapes
- Works for any cmap with transparent entries at any position
- Handles span=None correctly (no auto-scaling issues)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cover additional datashader code paths:
- Points with transparent cmap (separate from shapes)
- Shapes with clip=False norm (3-part under/in/over shading)

Placeholder baselines — CI will generate real ones.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Issue with set_zero_in_cmap_to_transparent Function Not Making Zero Values Transparent in Spatial Data Plotting

2 participants