Summary
The .name of the DataArray returned by focal_stats and hotspots is not the same across the four backends. On the dask paths it leaks an internal dask graph token.
Details
focal_stats:
- numpy / dask+numpy:
'focal_apply' (inherited from the internal apply call)
- cupy:
None
- dask+cupy: a dask graph token, e.g.
'_trim-d142fa3d...'
hotspots:
- numpy / cupy:
None
- dask+numpy / dask+cupy: a dask graph token, e.g.
'_trim-b75965c2...'
Root cause: the dask paths build the output xr.DataArray without an explicit name=. When the backing array is a dask array, xarray adopts the dask array's internal graph-layer name as the public .name. That token changes from call to call and exposes an implementation detail. The numpy/cupy paths leave the name as None (or inherit a different value).
.name is user-visible: it shows in the repr, becomes the variable key in to_dataset(), and sets default plot labels. So a chained pipeline ends up with a different name depending on which backend ran.
Fix
Set a stable .name on the returned DataArray in both functions so all four backends agree. focal_stats keeps the 'focal_apply' name the numpy path already emits; hotspots uses 'hotspots'.
The rest of the metadata (attrs res/crs, coords, dims) is already preserved consistently across all four backends. Only .name was off.
Summary
The
.nameof the DataArray returned byfocal_statsandhotspotsis not the same across the four backends. On the dask paths it leaks an internal dask graph token.Details
focal_stats:'focal_apply'(inherited from the internalapplycall)None'_trim-d142fa3d...'hotspots:None'_trim-b75965c2...'Root cause: the dask paths build the output
xr.DataArraywithout an explicitname=. When the backing array is a dask array, xarray adopts the dask array's internal graph-layer name as the public.name. That token changes from call to call and exposes an implementation detail. The numpy/cupy paths leave the name asNone(or inherit a different value)..nameis user-visible: it shows in the repr, becomes the variable key into_dataset(), and sets default plot labels. So a chained pipeline ends up with a different name depending on which backend ran.Fix
Set a stable
.nameon the returned DataArray in both functions so all four backends agree.focal_statskeeps the'focal_apply'name the numpy path already emits;hotspotsuses'hotspots'.The rest of the metadata (attrs
res/crs, coords, dims) is already preserved consistently across all four backends. Only.namewas off.