Describe the bug
to_geotiff silently strips georef from any DataArray whose x and y coords are contiguous int64 step-1 arrays. _is_no_georef_sentinel (xrspatial/geotiff/_coords.py:39-77) accepts every ascending step-1 int64 coord array as the read-side no-georef placeholder, but real user grids match that exact shape.
Reproducer
import numpy as np, xarray as xr
from xrspatial.geotiff import to_geotiff, open_geotiff
x = np.array([500, 501, 502], dtype=np.int64)
y = np.array([1000, 1001], dtype=np.int64)
da = xr.DataArray(np.zeros((2, 3), dtype=np.float32),
coords={'y': y, 'x': x}, dims=('y', 'x'),
attrs={'crs': 4326})
to_geotiff(da, '/tmp/repro.tif')
out = open_geotiff('/tmp/repro.tif')
print(out.x.values) # -> [0, 1, 2] georef silently lost
Expected behaviour
The output should round-trip with the original coords, or to_geotiff should raise so the user can supply attrs['transform'] explicitly. Silent metadata loss in a foundational IO path is worse than a noisy error.
Root cause
_is_no_georef_sentinel was tightened in #2087 from "any integer dtype" to "exact arange pattern" to fix an earlier silent-strip bug. The new check is still purely shape-based. The docstring at lines 63-68 admits the trade-off: a user-authored int64 step-1 grid still matches.
Fix sketch
Require an explicit no-georef marker instead of inferring from coord shape. Two options:
- (a)
attrs['_xrspatial_no_georef'] = True. The reader stamps it when emitting placeholder coords; the writer checks it before treating coords as no-georef.
- (b) Stamp a private flag on the coord variable (
coord.attrs) that the reader sets and the writer checks. Survives ops that preserve coord attrs.
With either fix, int64 coords without the marker should fall through to the normal coords_to_transform path: synthesise a real transform, or raise NonUniformCoordsError on irregular spacing.
Environment
- xrspatial
main (commit 22aa43c)
- python 3.11, numpy 2.x
Describe the bug
to_geotiffsilently strips georef from any DataArray whosexandycoords are contiguous int64 step-1 arrays._is_no_georef_sentinel(xrspatial/geotiff/_coords.py:39-77) accepts every ascending step-1 int64 coord array as the read-side no-georef placeholder, but real user grids match that exact shape.Reproducer
Expected behaviour
The output should round-trip with the original coords, or
to_geotiffshould raise so the user can supplyattrs['transform']explicitly. Silent metadata loss in a foundational IO path is worse than a noisy error.Root cause
_is_no_georef_sentinelwas tightened in #2087 from "any integer dtype" to "exact arange pattern" to fix an earlier silent-strip bug. The new check is still purely shape-based. The docstring at lines 63-68 admits the trade-off: a user-authored int64 step-1 grid still matches.Fix sketch
Require an explicit no-georef marker instead of inferring from coord shape. Two options:
attrs['_xrspatial_no_georef'] = True. The reader stamps it when emitting placeholder coords; the writer checks it before treating coords as no-georef.coord.attrs) that the reader sets and the writer checks. Survives ops that preserve coord attrs.With either fix, int64 coords without the marker should fall through to the normal
coords_to_transformpath: synthesise a real transform, or raiseNonUniformCoordsErroron irregular spacing.Environment
main(commit 22aa43c)