Skip to content

Fix set_zero_in_cmap_to_transparent with datashader rendering#577

Merged
timtreis merged 10 commits intomainfrom
fix/issue-376-transparent-cmap-datashader
Apr 5, 2026
Merged

Fix set_zero_in_cmap_to_transparent with datashader rendering#577
timtreis merged 10 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 72.72727% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.42%. Comparing base (303140c) to head (7e68c38).

Files with missing lines Patch % Lines
src/spatialdata_plot/pl/utils.py 72.72% 4 Missing and 5 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #577      +/-   ##
==========================================
+ Coverage   75.36%   75.42%   +0.05%     
==========================================
  Files          10       10              
  Lines        2935     2966      +31     
  Branches      684      693       +9     
==========================================
+ Hits         2212     2237      +25     
- Misses        441      444       +3     
- Partials      282      285       +3     
Files with missing lines Coverage Δ
src/spatialdata_plot/pl/utils.py 65.89% <72.72%> (+0.29%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

timtreis and others added 9 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>
The points visual test failed because adding a column to the points
DataFrame requires table annotation. The shapes and clip=False tests
cover the same _datashader_map_aggregate_to_color code path. Updated
baselines with CI-generated images.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@timtreis timtreis merged commit bdc8405 into main Apr 5, 2026
8 checks passed
@timtreis timtreis deleted the fix/issue-376-transparent-cmap-datashader branch April 5, 2026 15:25
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