reproject() reads nodata from attrs['_FillValue'], attrs['nodata'], attrs['missing_value'] (via _detect_nodata in _crs_utils.py), but skips the rasterio convention key attrs['nodatavals'].
When rioxarray is installed the raster.rio.nodata accessor picks up nodatavals and the fall-through never matters. Without rioxarray, a raster carrying only nodatavals is treated as if nodata is NaN, so the user-provided sentinel pixels survive resampling as if they were real data. The output then carries the old nodatavals attr alongside a fresh nodata of NaN -- two contradictory keys for the same concept.
resample.py already handles nodatavals (lines 1389-1396), so the convention is recognised elsewhere in xrspatial; the inconsistency is local to reproject.
Reproduction
# Without rioxarray installed:
import numpy as np
import xarray as xr
from xrspatial.reproject import reproject
r = xr.DataArray(
np.full((16, 16), -9999, dtype=np.int32),
dims=['y', 'x'],
coords={'y': np.linspace(50, 40, 16), 'x': np.linspace(-5, 5, 16)},
attrs={'crs': 'EPSG:4326', 'nodatavals': (-9999,)},
)
out = reproject(r, 'EPSG:3857')
# out.attrs['nodata'] == nan (-9999 sentinel was ignored)
# out.attrs['nodatavals'] == (-9999,) (stale, carried forward)
# Data was resampled treating -9999 as a real value.
Expected behaviour
_detect_nodata should consult attrs['nodatavals'] after _FillValue / nodata / missing_value.
- On output, if input carried
nodatavals, replace its value with the resolved nodata to keep both keys consistent (or drop nodatavals after the nodata key is set authoritatively).
Suggested fix
- In
_crs_utils.py::_detect_nodata, add nodatavals to the attrs scan (handle the tuple shape: take element 0).
- In
reproject.__init__::reproject (around line 715-727 where out_attrs is built), if nodatavals is present in input attrs, update it to a tuple of the resolved nodata (or drop it so only the canonical nodata remains).
- Same fix for
merge() (around line 1629-1641).
reproject()reads nodata fromattrs['_FillValue'],attrs['nodata'],attrs['missing_value'](via_detect_nodatain_crs_utils.py), but skips the rasterio convention keyattrs['nodatavals'].When rioxarray is installed the
raster.rio.nodataaccessor picks upnodatavalsand the fall-through never matters. Without rioxarray, a raster carrying onlynodatavalsis treated as if nodata isNaN, so the user-provided sentinel pixels survive resampling as if they were real data. The output then carries the oldnodatavalsattr alongside a freshnodataofNaN-- two contradictory keys for the same concept.resample.pyalready handlesnodatavals(lines 1389-1396), so the convention is recognised elsewhere in xrspatial; the inconsistency is local to reproject.Reproduction
Expected behaviour
_detect_nodatashould consultattrs['nodatavals']after_FillValue/nodata/missing_value.nodatavals, replace its value with the resolved nodata to keep both keys consistent (or dropnodatavalsafter thenodatakey is set authoritatively).Suggested fix
_crs_utils.py::_detect_nodata, addnodatavalsto the attrs scan (handle the tuple shape: take element 0).reproject.__init__::reproject(around line 715-727 whereout_attrsis built), ifnodatavalsis present in input attrs, update it to a tuple of the resolved nodata (or drop it so only the canonicalnodataremains).merge()(around line 1629-1641).