Skip to content

Fix datashader resolution collapse on cropped coordinate offsets#669

Merged
timtreis merged 3 commits into
mainfrom
fix/issue-668-datashader-cropped-offset
May 19, 2026
Merged

Fix datashader resolution collapse on cropped coordinate offsets#669
timtreis merged 3 commits into
mainfrom
fix/issue-668-datashader-cropped-offset

Conversation

@timtreis
Copy link
Copy Markdown
Member

@timtreis timtreis commented May 19, 2026

Summary

Fixes #668. After a bounding_box_query on a translated SpatialData, render_points(method=\"datashader\") and render_shapes(method=\"datashader\") silently collapsed the rasterization resolution — points collapsed into a handful of right-edge pixels.

Three entangled defects in the datashader pipeline forced the canvas to span [0, world_max] instead of [world_min, world_max], then masked the broken canvas extent with a Scale-only rgba transform that happens to align at world 0. Plus related resolution / empty-input issues surfaced by the investigation.

What changed

Datashader canvas pipeline (Bugs 1–5 from #668):

  • _datashader_canvas_from_dataframe / _get_extent_and_range_for_datashader_canvas use the real element extent (no min(0, ...) clamp).
  • _create_image_from_datashader_result accepts x_min/y_min and emits Sequence([Scale, Translation]) so the rgba lands at the element's actual world position.
  • _render_ds_image / _render_ds_outlines thread x_min/y_min through.
  • _compute_datashader_canvas_params no longer merges with ax.get_xlim() (which was read pre-correction and reflected intrinsic-pixel extent after an imshow draw).
  • The unused negative-only extent= shift branch in _ax_show_and_transform is removed.

Rasterize / empty input (Bugs 6 + 8 from #668):

  • _rasterize_if_necessary now computes target_unit_to_pixels against the world extent instead of intrinsic source dims; for Scale != 1 this changes the resulting pixel count by exactly the scale factor.
  • _datashader_canvas_from_dataframe short-circuits on empty input (NaN min() used to crash with cannot convert float NaN to integer). _render_points / _render_shapes skip the datashader pipeline when the element is empty.

timtreis added 2 commits May 19, 2026 19:01
After a ``bounding_box_query`` on a translated SpatialData,
``render_points(method="datashader")`` and ``render_shapes(method="datashader")``
silently collapsed the rasterization resolution. Three entangled defects in the
datashader canvas pipeline made the data range ``min(0, world_min)`` to
``world_max`` instead of the actual element bbox, then masked the broken canvas
extent with a ``Scale``-only rgba transform that happens to align at world 0.

Atomic fix:
- ``_datashader_canvas_from_dataframe`` and ``_get_extent_and_range_for_datashader_canvas``
  use the real element extent (no ``min(0, ...)`` clamp).
- ``_create_image_from_datashader_result`` accepts ``x_min``/``y_min`` and emits
  ``Sequence([Scale, Translation])`` so the rgba lands at the element's actual
  world position.
- ``_render_ds_image`` and ``_render_ds_outlines`` thread ``x_min``/``y_min``
  through from the caller.
- ``_compute_datashader_canvas_params`` no longer merges with ``ax.get_xlim()``
  (which was read pre-correction and returned intrinsic-pixel extent for an
  ``imshow``-rendered image).
- The unused negative-only ``extent=`` shift branch in
  ``_ax_show_and_transform`` is removed.

Also fix the related rasterize / empty-input bugs surfaced by the
investigation:
- ``_rasterize_if_necessary`` now computes ``target_unit_to_pixels`` against
  the world extent instead of intrinsic source dims; for Scale != 1 this
  changes pixel resolution by exactly the scale factor.
- ``_datashader_canvas_from_dataframe`` short-circuits on empty input (NaN
  ``min()`` used to crash with ``cannot convert float NaN to integer``).
- ``_render_points`` / ``_render_shapes`` skip the datashader pipeline when
  the element is empty.

Tests added (all non-visual):
- bbox_query points canvas factor matches no-offset baseline
- bbox_query points end-to-end render does not crash
- bbox_query shapes end-to-end render does not crash
- empty-input canvas helper does not crash
- rasterize target_unit_to_pixels uses world units under Scale=0.5
@timtreis timtreis changed the title Fix datashader resolution collapse on cropped coordinate offsets (#668) Fix datashader resolution collapse on cropped coordinate offsets May 19, 2026
…ization

Datashader shape outlines: pixel-level differences from the canvas extent
fix; visually the outlines are essentially identical to the previous
baselines (minor antialiasing only).

raccoon_scale: sharper rasterization output now that
_rasterize_if_necessary computes target_unit_to_pixels in world
units instead of intrinsic pixels.

Baselines pulled from CI run 26113431879.
@timtreis timtreis merged commit 2329522 into main May 19, 2026
7 of 8 checks passed
@timtreis timtreis deleted the fix/issue-668-datashader-cropped-offset branch May 19, 2026 17:44
@codecov-commenter
Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.56%. Comparing base (db17a4f) to head (e904be0).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #669      +/-   ##
==========================================
- Coverage   77.61%   77.56%   -0.06%     
==========================================
  Files          11       11              
  Lines        3610     3610              
  Branches      849      849              
==========================================
- Hits         2802     2800       -2     
- Misses        484      485       +1     
- Partials      324      325       +1     
Files with missing lines Coverage Δ
src/spatialdata_plot/pl/_datashader.py 90.25% <100.00%> (ø)
src/spatialdata_plot/pl/render.py 86.98% <100.00%> (-0.38%) ⬇️
src/spatialdata_plot/pl/utils.py 67.92% <100.00%> (-0.02%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

render_points(method="datashader") collapses resolution after bounding_box_query on a translated SpatialData

2 participants