Skip to content

rasterize: support descending-x in like= templates (#2568)#2595

Merged
brendancol merged 4 commits into
mainfrom
issue-2568
May 28, 2026
Merged

rasterize: support descending-x in like= templates (#2568)#2595
brendancol merged 4 commits into
mainfrom
issue-2568

Conversation

@brendancol
Copy link
Copy Markdown
Contributor

Closes #2568.

Summary

  • rasterize(like=...) silently mislabelled output coords when the template's x axis was descending. The burner writes column 0 = xmin (image convention), but reuse_like_coords assigned the descending x-coord unchanged, so a polygon at world x=0.5 ended up under coord x=3.5.
  • Fix: detect descending x in _extract_grid_from_like, carry it on _LikeGrid, and flip the burned array along axis 1 in rasterize when reusing coords. Same shape as the existing ascending-y axis-0 flip.
  • Backend coverage: numpy, cupy, dask+numpy, dask+cupy. All four use the same slicing semantics, so one flip line covers everything.

Why "support" rather than "reject"

The y-axis already supports both ascending and descending transparently via the axis-0 flip (added for #2170). Treating x asymmetrically would be surprising for users who get a descending-x like from a pipeline that flipped a raster (e.g. negative-stride affine transforms). The fix is small and local, and it matches the existing pattern. Rejecting with ValueError was the other reasonable option; this PR picks the symmetric one.

Descending y was investigated while in the area and is already correctly handled (it is the default image convention -- the burner emits row 0 = ymax natively).

Test plan

  • New tests at xrspatial/tests/test_rasterize_descending_x_2568.py cover polygons, points, lines, world-coord round-trip with xr.align, and both axes flipped together.
  • Tests run against numpy, dask+numpy, cupy, and dask+cupy.
  • Existing xrspatial/tests/test_rasterize.py (215 tests) still passes.
  • Related coverage suites (test_rasterize_accuracy.py, test_rasterize_coverage_*.py) still pass.

The rasterizer always burns with column 0 = xmin (image convention).
When the template's x axis is descending (high-to-low), the burned
array now flips along axis 1 before assigning like.x, so
result.sel(x=...) lines up with the geometry in world coordinates.
Mirrors the existing ascending-y flip on axis 0.

Previously descending-x silently mislabelled coords: a polygon at
world x=0.5 ended up under coord x=3.5. No exception was raised.

Tests cover numpy, dask+numpy, cupy, and dask+cupy.
@github-actions github-actions Bot added the performance PR touches performance-sensitive code label May 28, 2026
Copy link
Copy Markdown
Contributor Author

@brendancol brendancol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review: rasterize: support descending-x in like= templates (#2568)

Blockers (must fix before merge)

None.

Suggestions (should fix, not blocking)

None.

Nits (optional improvements)

  • xrspatial/tests/test_rasterize_descending_x_2568.py:42: _like_2568 has a y_descending=True parameter that only gets flipped in one test (test_numpy_descending_x_and_ascending_y). The asymmetry is harmless. If you want fewer one-off helpers later, this could fold into a parameterized test pair.
  • xrspatial/rasterize.py:2940: x_descending = width > 1 and float(x[-1]) < float(x[0]) mirrors the y case. Both correctly treat width/height == 1 as "no flip needed," but a comment noting that single-column templates short-circuit would help the next reader.

What looks good

  • The fix is symmetric with the existing y-axis treatment: same comment shape, same _LikeGrid field pattern, same plumbing through rasterize, same slicing flip.
  • The reuse_like_coords gate is unchanged, so the flip only runs in the path where it matters (template grid reused bit-identically). When the caller passes explicit bounds/width/height/resolution, the linspace-rebuild path produces ascending coords as before. test_numpy_explicit_bounds_skips_flip covers that.
  • Slicing (out[:, ::-1]) works the same way for numpy, dask, cupy, and dask+cupy, so no per-backend code is needed.
  • Test matrix hits all four backends, plus polygon/point/line geometry types, plus xr.align round-trip, plus the combined ascending-y + descending-x case.

Checklist

  • Algorithm matches reference/paper (n/a, bug fix to existing internal logic)
  • All implemented backends produce consistent results (covered by tests)
  • NaN handling is correct (unchanged path; fill semantics preserved)
  • Edge cases are covered by tests
  • Dask chunk boundaries handled correctly (flip is a view, no chunk impact)
  • No premature materialization or unnecessary copies (slice view, lazy under dask)
  • Benchmark exists or is not needed (n/a for a coord-orientation fix)
  • README feature matrix updated (n/a, no new function)
  • Docstrings present and accurate (no new public API; existing docstrings unaffected)

…2568)

Address review nit on PR #2595: the ``> 1`` guard in the orientation
detection makes single-row / single-column templates short-circuit to
"no flip needed".  Clarifies for the next reader why a 1-cell template
is safe.
Copy link
Copy Markdown
Contributor Author

@brendancol brendancol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up review (after 2f5c8ce)

Disposition of the previous nits

  • Nit 1 (parameterize _like_2568 y_descending): dismissed. The current helper lets one test cover both-axes-flipped without bloating every other test signature. Folding it into a fixture would be more code for the same coverage.
  • Nit 2 (single-column short-circuit comment): fixed in 2f5c8ce. The detection comment now spells out that width/height > 1 is the short-circuit guard.

New findings

None. Follow-up is comment-only.

@brendancol brendancol merged commit 013b2ea into main May 28, 2026
6 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance PR touches performance-sensitive code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

rasterize: descending-x like silently mislabels output coords

1 participant