Skip to content

rasterize: honor like.y orientation for ascending-y templates (#2170)#2181

Merged
brendancol merged 3 commits into
mainfrom
issue-2170
May 20, 2026
Merged

rasterize: honor like.y orientation for ascending-y templates (#2170)#2181
brendancol merged 3 commits into
mainfrom
issue-2170

Conversation

@brendancol
Copy link
Copy Markdown
Contributor

Summary

  • Detect like.y orientation once in _extract_grid_from_like().
  • Carry the flag through to the coord-assignment site and flip the burned array on axis 0 right before reusing the template's coords. After the fix, result.sel(y=...) lines up with the geometry whether like.y ascends or descends.
  • result.y still equals like.y byte-for-byte, so xr.align keeps working.

Closes #2170

Backend coverage

The flip is just out[::-1, :], which behaves the same on numpy, cupy, dask+numpy, and dask+cupy arrays.

Out of scope

There's a sibling issue for irregular like grids (non-uniform spacing). Not touched here.

Test plan

  • New TestLikeYOrientation2170 in xrspatial/tests/test_rasterize.py, covering polygons, lines, and points across all four backends (GPU cases skip when CUDA isn't available).
  • Regression test: result.sel(y=0.5, x=0.5) returns the burned value for both ascending and descending like.y.
  • Round-trip: result.y == like.y and xr.align(result, like) still works.
  • Explicit-bounds path still rebuilds descending coords (flip is correctly bypassed for any resized output).
  • Full test_rasterize.py passes locally (199 passed, 2 skipped).

…plates (#2170)

The rasterizer always burns row 0 = ymax (top-down image convention),
but the output reused like.y verbatim. When like.y was ascending,
result.sel(y=...) lined up against the wrong rows because the burned
array still pointed the wrong way.

Detect orientation once in _extract_grid_from_like, carry the flag
through to the coord-assignment site, and flip the burned array on
axis 0 right before assigning the template's coords. Works the same
way for numpy, cupy, dask+numpy, and dask+cupy outputs.

Closes #2170
@github-actions github-actions Bot added the performance PR touches performance-sensitive code label May 20, 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 honor like.y orientation for ascending-y templates (#2170)

Blockers

None.

Suggestions

  • xrspatial/rasterize.py:1968. y_ascending = height > 1 and float(y[-1]) > float(y[0]) only looks at the first and last samples. Fine for a monotonic 1D coord, but a non-monotonic or duplicate-valued like.y would be misclassified. The inline comment already defers the irregular-spacing case; a sentence noting monotonicity is assumed, or an np.all(np.diff(y) > 0) check, would make the contract explicit.
  • xrspatial/rasterize.py:1978. _extract_grid_from_like now returns a 9-tuple and the call site unpacks positionally. A NamedTuple or small dataclass would scale better as future grid attributes get added. Out of scope for this fix.

Nits

  • xrspatial/rasterize.py:2298. Descending-x templates would hit the same bug class as descending-y did before this fix. A short comment near the y-flip noting "x is assumed ascending; descending-x templates are not supported" would document the asymmetry for the next reader.
  • xrspatial/tests/test_rasterize.py:2244. test_numpy_explicit_bounds_skips_flip asserts result.y.values[0] > result.y.values[-1]. Tightening to exact expected values (e.g. [3.5, 2.5, 1.5, 0.5]) would catch a regression where the bounds path produces an off-by-one coord centre.

What looks good

One detection site, one flip site, with comments at both explaining the image-vs-world convention. out[::-1, :] is backend-agnostic by construction. Tests hit all four backends and three geometry types, plus the xr.align round-trip and the explicit-bounds bypass. World-y selection asserts (result.sel(y=0.5, x=0.5)) target the bug directly rather than checking array indices. result.y is preserved byte-for-byte against like.y, which is what xr.align depends on. The height == 1 edge case falls out for free: the height > 1 guard makes y_ascending=False so the flip is a no-op.

- Convert _extract_grid_from_like to return a _LikeGrid NamedTuple
  instead of a 9-tuple.  Positional unpacking was fragile.
- Document the monotonicity assumption on the y_ascending detection
  and the same-class assumption for x being ascending.
- Tighten test_numpy_explicit_bounds_skips_flip to lock the exact
  coord centres instead of only checking the order.

Refs #2181.
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 on 54fe792

All four findings from the first pass are addressed in the new commit.

Disposition

  • Suggestion 1 (monotonicity contract). Fixed. The comment on y_ascending now states that monotonicity is assumed and that the irregular-spacing case is out of scope.
  • Suggestion 2 (9-tuple unpacking). Fixed. _extract_grid_from_like returns a _LikeGrid NamedTuple. The call site in rasterize unpacks by attribute name.
  • Nit 1 (x-axis asymmetry). Fixed. The same comment block now flags the descending-x case as out of scope so the asymmetry is explicit.
  • Nit 2 (test assertion tightness). Fixed. test_numpy_explicit_bounds_skips_flip locks the exact y/x coord centres.

Verification

  • pytest xrspatial/tests/test_rasterize.py passes locally (199 passed, 2 skipped).

Remaining concerns

None.

# Conflicts:
#	xrspatial/rasterize.py
#	xrspatial/tests/test_rasterize.py
@brendancol brendancol merged commit d35cd69 into main May 20, 2026
4 of 5 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(like=...) silently flips spatial meaning when y coordinates ascend

1 participant