Describe the bug
slope() returns its result in degrees, but it copies the input DataArray's attrs verbatim via attrs=agg.attrs (xrspatial/slope.py near line 432). If the input DEM has attrs={'units': 'm'}, the slope output values are in degrees while the attrs still say units='m'. The metadata no longer matches the data.
This bites because _infer_vertical_unit_type in xrspatial/utils.py reads attrs['units'] and treats 'degrees' as an angle and 'm' as elevation. A slope output carrying units='m' gets classified as elevation, so downstream diagnostics and users are misled about what the array holds.
Expected behavior
The slope output should report the angle unit it actually produces (units='degrees'), not the input elevation unit. Other input attrs should carry through unchanged.
Steps to reproduce
import numpy as np, xarray as xr
from xrspatial import slope
agg = xr.DataArray(np.random.rand(5, 5), attrs={'units': 'm'})
out = slope(agg)
print(out.attrs['units']) # prints 'm', should be 'degrees'
Additional context
Applies to all four backends (numpy, cupy, dask+numpy, dask+cupy) since the attrs are set in the shared public wrapper. aspect.py and curvature.py copy attrs the same way, but those are out of scope here.
Describe the bug
slope()returns its result in degrees, but it copies the input DataArray's attrs verbatim viaattrs=agg.attrs(xrspatial/slope.py near line 432). If the input DEM hasattrs={'units': 'm'}, the slope output values are in degrees while the attrs still sayunits='m'. The metadata no longer matches the data.This bites because
_infer_vertical_unit_typein xrspatial/utils.py readsattrs['units']and treats'degrees'as an angle and'm'as elevation. A slope output carryingunits='m'gets classified as elevation, so downstream diagnostics and users are misled about what the array holds.Expected behavior
The slope output should report the angle unit it actually produces (
units='degrees'), not the input elevation unit. Other input attrs should carry through unchanged.Steps to reproduce
Additional context
Applies to all four backends (numpy, cupy, dask+numpy, dask+cupy) since the attrs are set in the shared public wrapper. aspect.py and curvature.py copy attrs the same way, but those are out of scope here.