Skip to content

Commit 852d023

Browse files
committed
Rename read_geotiff/write_geotiff to open_geotiff/to_geotiff (#1045)
Aligns with the base branch rename (PR #1056) to match xarray conventions (open_* for readers, to_* for writers). Updated in: - xrspatial/geotiff/__init__.py (function defs, __all__) - xrspatial/reproject/_datum_grids.py, _vertical.py (grid loading) - README.md (all code examples and feature matrix) - benchmarks/reproject_benchmark.md - All geotiff test files (test_cog.py, test_edge_cases.py, test_features.py, bench_vs_rioxarray.py) All 343 tests pass (271 geotiff + 72 reproject).
1 parent 443de96 commit 852d023

File tree

9 files changed

+156
-156
lines changed

9 files changed

+156
-156
lines changed

README.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -141,23 +141,23 @@ Native GeoTIFF and Cloud Optimized GeoTIFF reader/writer. No GDAL required.
141141

142142
| Name | Description | NumPy | Dask | CuPy GPU | Dask+CuPy GPU | Cloud |
143143
|:-----|:------------|:-----:|:----:|:--------:|:-------------:|:-----:|
144-
| [read_geotiff](xrspatial/geotiff/__init__.py) | Read GeoTIFF / COG / VRT | ✅️ | ✅️ | ✅️ | ✅️ | ✅️ |
145-
| [write_geotiff](xrspatial/geotiff/__init__.py) | Write DataArray as GeoTIFF / COG | ✅️ | ✅️ | ✅️ | ✅️ | ✅️ |
144+
| [open_geotiff](xrspatial/geotiff/__init__.py) | Read GeoTIFF / COG / VRT | ✅️ | ✅️ | ✅️ | ✅️ | ✅️ |
145+
| [to_geotiff](xrspatial/geotiff/__init__.py) | Write DataArray as GeoTIFF / COG | ✅️ | ✅️ | ✅️ | ✅️ | ✅️ |
146146
| [write_vrt](xrspatial/geotiff/__init__.py) | Generate VRT mosaic from GeoTIFFs | ✅️ | | | | |
147147

148-
`read_geotiff` and `write_geotiff` auto-dispatch to the correct backend:
148+
`open_geotiff` and `to_geotiff` auto-dispatch to the correct backend:
149149

150150
```python
151-
read_geotiff('dem.tif') # NumPy
152-
read_geotiff('dem.tif', chunks=512) # Dask
153-
read_geotiff('dem.tif', gpu=True) # CuPy (nvCOMP + GDS)
154-
read_geotiff('dem.tif', gpu=True, chunks=512) # Dask + CuPy
155-
read_geotiff('https://example.com/cog.tif') # HTTP COG
156-
read_geotiff('s3://bucket/dem.tif') # Cloud (S3/GCS/Azure)
157-
read_geotiff('mosaic.vrt') # VRT mosaic (auto-detected)
158-
159-
write_geotiff(cupy_array, 'out.tif') # auto-detects GPU
160-
write_geotiff(data, 'out.tif', gpu=True) # force GPU compress
151+
open_geotiff('dem.tif') # NumPy
152+
open_geotiff('dem.tif', chunks=512) # Dask
153+
open_geotiff('dem.tif', gpu=True) # CuPy (nvCOMP + GDS)
154+
open_geotiff('dem.tif', gpu=True, chunks=512) # Dask + CuPy
155+
open_geotiff('https://example.com/cog.tif') # HTTP COG
156+
open_geotiff('s3://bucket/dem.tif') # Cloud (S3/GCS/Azure)
157+
open_geotiff('mosaic.vrt') # VRT mosaic (auto-detected)
158+
159+
to_geotiff(cupy_array, 'out.tif') # auto-detects GPU
160+
to_geotiff(data, 'out.tif', gpu=True) # force GPU compress
161161
write_vrt('mosaic.vrt', ['tile1.tif', 'tile2.tif']) # generate VRT
162162
```
163163

@@ -517,10 +517,10 @@ Importing `xrspatial` registers an `.xrs` accessor on DataArrays and Datasets, g
517517

518518
```python
519519
import xrspatial as xrs
520-
from xrspatial.geotiff import read_geotiff, write_geotiff
520+
from xrspatial.geotiff import open_geotiff, to_geotiff
521521

522522
# Read a GeoTIFF (no GDAL required)
523-
elevation = read_geotiff('dem.tif')
523+
elevation = open_geotiff('dem.tif')
524524

525525
# Surface analysis
526526
slope = elevation.xrs.slope()
@@ -529,7 +529,7 @@ aspect = elevation.xrs.aspect()
529529

530530
# Reproject and write as a Cloud Optimized GeoTIFF
531531
dem_wgs84 = elevation.xrs.reproject(target_crs='EPSG:4326')
532-
write_geotiff(dem_wgs84, 'output.tif', cog=True)
532+
to_geotiff(dem_wgs84, 'output.tif', cog=True)
533533

534534
# Classification
535535
classes = elevation.xrs.equal_interval(k=5)

benchmarks/reproject_benchmark.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ Python 3.14, NumPy, Numba, CuPy, Dask, pyproj, rioxarray (GDAL)
1313
Source file: Copernicus DEM COG (`Copernicus_DSM_COG_10_N40_00_W075_00_DEM.tif`), 3600x3600, WGS84, deflate+floating-point predictor. Reprojected to Web Mercator (EPSG:3857). Median of 3 runs after warmup.
1414

1515
```python
16-
from xrspatial.geotiff import read_geotiff, write_geotiff
16+
from xrspatial.geotiff import open_geotiff, to_geotiff
1717
from xrspatial.reproject import reproject
1818

19-
dem = read_geotiff('Copernicus_DSM_COG_10_N40_00_W075_00_DEM.tif')
19+
dem = open_geotiff('Copernicus_DSM_COG_10_N40_00_W075_00_DEM.tif')
2020
dem_merc = reproject(dem, 'EPSG:3857')
21-
write_geotiff(dem_merc, 'output.tif')
21+
to_geotiff(dem_merc, 'output.tif')
2222
```
2323

2424
All times measured with warm Numba/CUDA kernels (first call incurs ~4.5s JIT compilation).

xrspatial/geotiff/__init__.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
55
Public API
66
----------
7-
read_geotiff(source, ...)
7+
open_geotiff(source, ...)
88
Read a GeoTIFF file to an xarray.DataArray.
9-
write_geotiff(data, path, ...)
9+
to_geotiff(data, path, ...)
1010
Write an xarray.DataArray as a GeoTIFF or COG.
1111
open_cog(url, ...)
1212
Read a Cloud Optimized GeoTIFF from an HTTP URL.
@@ -20,7 +20,7 @@
2020
from ._reader import read_to_array
2121
from ._writer import write
2222

23-
__all__ = ['read_geotiff', 'write_geotiff', 'write_vrt']
23+
__all__ = ['open_geotiff', 'to_geotiff', 'write_vrt']
2424

2525

2626
def _wkt_to_epsg(wkt_or_proj: str) -> int | None:
@@ -98,7 +98,7 @@ def _coords_to_transform(da: xr.DataArray) -> GeoTransform | None:
9898
)
9999

100100

101-
def read_geotiff(source: str, *, window=None,
101+
def open_geotiff(source: str, *, window=None,
102102
overview_level: int | None = None,
103103
band: int | None = None,
104104
name: str | None = None,
@@ -285,7 +285,7 @@ def _is_gpu_data(data) -> bool:
285285
return isinstance(data, _cupy_type)
286286

287287

288-
def write_geotiff(data: xr.DataArray | np.ndarray, path: str, *,
288+
def to_geotiff(data: xr.DataArray | np.ndarray, path: str, *,
289289
crs: int | str | None = None,
290290
nodata=None,
291291
compression: str = 'zstd',
@@ -449,7 +449,7 @@ def write_geotiff(data: xr.DataArray | np.ndarray, path: str, *,
449449
def open_cog(url: str, **kwargs) -> xr.DataArray:
450450
"""Deprecated: use ``read_geotiff(url, ...)`` instead.
451451
452-
read_geotiff handles HTTP URLs, cloud URIs, and local files.
452+
open_geotiff handles HTTP URLs, cloud URIs, and local files.
453453
"""
454454
return read_geotiff(url, **kwargs)
455455

xrspatial/geotiff/tests/bench_vs_rioxarray.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ def _fmt_ms(seconds):
3636
def check_consistency(path):
3737
"""Compare pixel values and geo metadata between the two readers."""
3838
import rioxarray # noqa: F401
39-
from xrspatial.geotiff import read_geotiff
39+
from xrspatial.geotiff import open_geotiff
4040

4141
rio_da = xr.open_dataarray(path, engine='rasterio')
4242
rio_arr = rio_da.squeeze('band').values.astype(np.float64)
4343

44-
our_da = read_geotiff(path)
44+
our_da = open_geotiff(path)
4545
our_arr = our_da.values.astype(np.float64)
4646

4747
# Shape
@@ -96,7 +96,7 @@ def check_consistency(path):
9696
def bench_read(path, runs=10):
9797
"""Benchmark read performance."""
9898
import rioxarray # noqa: F401
99-
from xrspatial.geotiff import read_geotiff
99+
from xrspatial.geotiff import open_geotiff
100100

101101
def rio_read():
102102
da = xr.open_dataarray(path, engine='rasterio')
@@ -105,7 +105,7 @@ def rio_read():
105105
return da
106106

107107
def our_read():
108-
return read_geotiff(path)
108+
return open_geotiff(path)
109109

110110
rio_time, _ = _timer(rio_read, warmup=2, runs=runs)
111111
our_time, _ = _timer(our_read, warmup=2, runs=runs)
@@ -120,7 +120,7 @@ def our_read():
120120
def bench_write(shape=(512, 512), compression='deflate', runs=5):
121121
"""Benchmark write performance."""
122122
import rioxarray # noqa: F401
123-
from xrspatial.geotiff import write_geotiff
123+
from xrspatial.geotiff import to_geotiff
124124
from xrspatial.geotiff._geotags import GeoTransform
125125

126126
rng = np.random.RandomState(42)
@@ -150,7 +150,7 @@ def rio_write():
150150

151151
def our_write():
152152
p = os.path.join(tmpdir, 'our_out.tif')
153-
write_geotiff(da_ours, p, compression=compression, tiled=False)
153+
to_geotiff(da_ours, p, compression=compression, tiled=False)
154154
return os.path.getsize(p)
155155

156156
rio_time, rio_size = _timer(rio_write, warmup=1, runs=runs)
@@ -166,7 +166,7 @@ def our_write():
166166
def bench_round_trip(shape=(256, 256), compression='deflate'):
167167
"""Write with our module, read back with rioxarray, and vice versa."""
168168
import rioxarray # noqa: F401
169-
from xrspatial.geotiff import read_geotiff, write_geotiff
169+
from xrspatial.geotiff import open_geotiff, to_geotiff
170170

171171
rng = np.random.RandomState(99)
172172
arr = rng.rand(*shape).astype(np.float32)
@@ -179,7 +179,7 @@ def bench_round_trip(shape=(256, 256), compression='deflate'):
179179
our_path = os.path.join(tmpdir, 'ours.tif')
180180
da_ours = xr.DataArray(arr, dims=['y', 'x'], coords={'y': y, 'x': x},
181181
attrs={'crs': 4326})
182-
write_geotiff(da_ours, our_path, compression=compression, tiled=False)
182+
to_geotiff(da_ours, our_path, compression=compression, tiled=False)
183183

184184
rio_da = xr.open_dataarray(our_path, engine='rasterio')
185185
rio_arr = rio_da.squeeze('band').values if 'band' in rio_da.dims else rio_da.values
@@ -198,7 +198,7 @@ def bench_round_trip(shape=(256, 256), compression='deflate'):
198198
else:
199199
da_rio.rio.to_raster(rio_path)
200200

201-
our_da = read_geotiff(rio_path)
201+
our_da = open_geotiff(rio_path)
202202
our_arr = our_da.values
203203

204204
diff2 = float(np.nanmax(np.abs(arr - our_arr)))

xrspatial/geotiff/tests/test_cog.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import pytest
66
import xarray as xr
77

8-
from xrspatial.geotiff import read_geotiff, write_geotiff
8+
from xrspatial.geotiff import open_geotiff, to_geotiff
99
from xrspatial.geotiff._header import parse_header, parse_all_ifds
1010
from xrspatial.geotiff._writer import write
1111
from xrspatial.geotiff._geotags import GeoTransform, extract_geo_info
@@ -83,9 +83,9 @@ def test_read_write_round_trip(self, tmp_path):
8383
)
8484

8585
path = str(tmp_path / 'round_trip.tif')
86-
write_geotiff(da, path, compression='deflate', tiled=False)
86+
to_geotiff(da, path, compression='deflate', tiled=False)
8787

88-
result = read_geotiff(path)
88+
result = open_geotiff(path)
8989
np.testing.assert_array_almost_equal(result.values, data, decimal=5)
9090
assert result.attrs.get('crs') == 4326
9191

@@ -95,40 +95,40 @@ def test_read_geotiff_name(self, tmp_path):
9595
path = str(tmp_path / 'myfile.tif')
9696
write(arr, path, compression='none', tiled=False)
9797

98-
da = read_geotiff(path)
98+
da = open_geotiff(path)
9999
assert da.name == 'myfile'
100100

101101
def test_read_geotiff_custom_name(self, tmp_path):
102102
arr = np.zeros((4, 4), dtype=np.float32)
103103
path = str(tmp_path / 'test.tif')
104104
write(arr, path, compression='none', tiled=False)
105105

106-
da = read_geotiff(path, name='custom')
106+
da = open_geotiff(path, name='custom')
107107
assert da.name == 'custom'
108108

109109
def test_write_numpy_array(self, tmp_path):
110110
"""write_geotiff should accept raw numpy arrays too."""
111111
arr = np.arange(16, dtype=np.float32).reshape(4, 4)
112112
path = str(tmp_path / 'numpy.tif')
113-
write_geotiff(arr, path, compression='none')
113+
to_geotiff(arr, path, compression='none')
114114

115-
result = read_geotiff(path)
115+
result = open_geotiff(path)
116116
np.testing.assert_array_equal(result.values, arr)
117117

118118
def test_write_3d_rgb(self, tmp_path):
119119
"""3D arrays (height, width, bands) should write multi-band."""
120120
arr = np.zeros((4, 4, 3), dtype=np.uint8)
121121
arr[:, :, 0] = 255 # red channel
122122
path = str(tmp_path / 'rgb.tif')
123-
write_geotiff(arr, path, compression='none')
123+
to_geotiff(arr, path, compression='none')
124124

125-
result = read_geotiff(path)
125+
result = open_geotiff(path)
126126
np.testing.assert_array_equal(result.values, arr)
127127

128128
def test_write_rejects_4d(self, tmp_path):
129129
arr = np.zeros((2, 3, 4, 4), dtype=np.float32)
130130
with pytest.raises(ValueError, match="Expected 2D or 3D"):
131-
write_geotiff(arr, str(tmp_path / 'bad.tif'))
131+
to_geotiff(arr, str(tmp_path / 'bad.tif'))
132132

133133

134134
def read_to_array_local(path):

0 commit comments

Comments
 (0)