Skip to content

Set slope output units to 'degrees' instead of leaking input units#2904

Merged
brendancol merged 3 commits into
mainfrom
issue-2894
Jun 3, 2026
Merged

Set slope output units to 'degrees' instead of leaking input units#2904
brendancol merged 3 commits into
mainfrom
issue-2894

Conversation

@brendancol
Copy link
Copy Markdown
Contributor

Closes #2894

slope() returns degrees but copied the input DataArray's attrs verbatim, so a DEM with units='m' produced a slope array still labelled units='m'. _infer_vertical_unit_type reads that label and treated the slope output as elevation rather than an angle.

Changes

  • Override attrs['units'] to 'degrees' in the shared public wrapper, so the fix applies to all backends and to Dataset inputs. All other input attrs carry through unchanged, and the input array is not mutated.
  • Update the docstring Returns note to state the units override.
  • Add a verify_attrs passthrough to the cross-backend equality helpers in general_checks.py; the slope tests whose attrs now legitimately differ pass verify_attrs=False.
  • Add tests asserting the degrees override on numpy, cupy, dask+numpy, dask+cupy, the no-input-units case, and the geodesic path.

Backend coverage

numpy, cupy, dask+numpy, dask+cupy (attrs are set once in the wrapper).

Test plan

  • pytest xrspatial/tests/test_slope.py xrspatial/tests/test_geodesic_slope.py (121 passed)
  • Regression check on aspect/curvature/hillshade/terrain_metrics/northness_eastness which share the helpers (565 passed)

…2894)

slope() returned degrees but copied the input DataArray's attrs verbatim,
so a DEM with units='m' produced a slope array still labelled 'm'. That
stale label made _infer_vertical_unit_type misclassify slope output as
elevation. Override attrs['units'] to 'degrees' in the shared public
wrapper (covers numpy, cupy, dask+numpy, dask+cupy and Dataset inputs),
preserving all other attrs.

Add a verify_attrs passthrough to the cross-backend equality helpers and
use it in the slope tests whose attrs now legitimately differ. Add tests
asserting the degrees override on every backend and the geodesic path.
@github-actions github-actions Bot added the performance PR touches performance-sensitive code label Jun 3, 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: Set slope output units to 'degrees' instead of leaking input units

Blockers (must fix before merge)

None.

Suggestions (should fix, not blocking)

  • xrspatial/tests/test_slope.py: flipping the existing tests to verify_attrs=False means they no longer confirm that the other input attrs (res, crs) survive slope(). Only test_units_overridden_to_degrees_numpy checks res/crs propagation, and only on numpy. Worth having that numpy test assert the non-units attrs explicitly so the propagation contract stays covered now that the blanket attrs check is off.

Nits (optional improvements)

  • None.

What looks good

  • The override lives in the single shared wrapper, so all four backends and the Dataset path inherit it without per-backend edits. numpy/cupy/dask+numpy/dask+cupy and Dataset all report 'degrees'.
  • dict(agg.attrs) copies before mutating, so the input DataArray's attrs aren't touched; a test asserts the input still has units='m'.
  • The geodesic path is covered.
  • The verify_attrs passthrough on the shared equality helpers defaults to True, so no other module's tests change behavior.

Checklist

  • slope is degrees, units now say degrees
  • All implemented backends produce consistent results
  • NaN handling unaffected by this change
  • Edge cases covered (no-input-units case, geodesic path)
  • Dask chunk boundaries unaffected
  • No premature materialization or extra copies (one dict copy of attrs)
  • Benchmark not needed
  • README feature matrix not applicable (no new function)
  • Docstring updated to note the units override

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

The one suggestion from the previous pass is addressed: test_units_overridden_to_degrees_dask_numpy now asserts res and crs survive slope() on the dask path, in addition to the numpy test. No blockers, suggestions, or nits remain.

@brendancol brendancol merged commit 63da895 into main Jun 3, 2026
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.

slope() output advertises stale elevation units instead of degrees

1 participant