-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ Implement cog3pio xarray BackendEntrypoint (#14)
* ✨ Implement cog3pio xarray BackendEntrypoint Initial implementation of a 'cog3pio' xarray BackendEntrypoint for decoding GeoTIFF files! Following instructions at https://docs.xarray.dev/en/v2024.02.0/internals/how-to-add-new-backend.html on registering a backend. Only a minimal implementation for now to read the pixel array data, with dummy x and y coordinates. * ➕ Add xarray N-D labeled arrays and datasets in Python! * 🌐 Decode x and y coordinates from affine transform Work out the list of x and y coordinates for the raster grid from the Affine transformation matrix. Requires changes being developed at georust/geo#1159. * 👷 Disable CI builds on 32-bit Windows Getting an error with compiling pandas 2.2.1 on Windows x86 (32-bit), and pandas has moved away from providing 32-bit Windows wheels, see pandas-dev/pandas#54979, so might as well not build cog3pio wheels for 32-bit Windows since we can't test them properly. * ⚗️ Benchmark cog3pio engine against rioxarray Parametrized test to compare loading a GeoTIFF using cog3pio vs rioxarray via their respective xarray BackendEntrypoints. Made a new extras dependency group in pyproject.toml called 'benchmark', and listed both `pytest-codspeed` and `rioxarray` under it. * 🐛 Add half pixel offset to get centrepoint of top left pixel The affine transform from the GeoTIFF represents the top-left corner of the top-left pixel (gridline registration), but we need to convert that to the center of the top-left pixel (pixel registration) which is what xarray typically assumes. Added some more comments on how the xy_coords is calculated, and updated unit tests with new x/y min/max bounds. Commented out the mean value assertion for now as NaN handling is not implemented yet. * 📌 Pin to georust/geo at rev 481196b Getter methods on AffineTransform implemented in georust/geo#1159 has been merged into the main branch of georust/geo, so no longer need to point to my personal fork. Also fixed a mismatched type when accessing the x_res and y_res attributes. * 📝 Document usage of cog3pio xarray backend engine in main README.md Show how a GeoTIFF file can be read into an xarray.DataArray object by passing `engine="cog3pio"` to xarray.open_dataarray. * 👥 Push out multi-dtype feature in roadmap to Q2 The multiple dtype feature is a little trickier than expected, so will push this out as a medium term goal for Q2 2024. Likely will depend on how the georust/geotiff crate's progress is like.
- Loading branch information
Showing
10 changed files
with
181 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
""" | ||
An xarray backend for reading GeoTIFF files using the 'cog3pio' engine. | ||
""" | ||
|
||
import os | ||
|
||
import numpy as np | ||
import xarray as xr | ||
from xarray.backends import BackendEntrypoint | ||
|
||
from cog3pio import CogReader | ||
|
||
|
||
# %% | ||
class Cog3pioBackendEntrypoint(BackendEntrypoint): | ||
""" | ||
Xarray backend to read GeoTIFF files using 'cog3pio' engine. | ||
""" | ||
|
||
description = "Use .tif files in Xarray" | ||
open_dataset_parameters = ["filename_or_obj"] | ||
url = "https://github.com/weiji14/cog3pio" | ||
|
||
def open_dataset( | ||
self, | ||
filename_or_obj: str, | ||
*, | ||
drop_variables=None, | ||
# other backend specific keyword arguments | ||
# `chunks` and `cache` DO NOT go here, they are handled by xarray | ||
) -> xr.Dataset: | ||
reader = CogReader(path=filename_or_obj) | ||
|
||
array: np.ndarray = reader.to_numpy() | ||
x_coords, y_coords = reader.xy_coords() | ||
|
||
channels, height, width = array.shape | ||
dataarray: xr.DataArray = xr.DataArray( | ||
data=array, | ||
coords={ | ||
"band": np.arange(stop=channels, dtype=np.uint8), | ||
"y": y_coords, | ||
"x": x_coords, | ||
}, | ||
name=None, | ||
attrs=None, | ||
) | ||
|
||
return dataarray.to_dataset(name="raster") | ||
|
||
def guess_can_open(self, filename_or_obj): | ||
try: | ||
_, ext = os.path.splitext(filename_or_obj) | ||
except TypeError: | ||
return False | ||
return ext in {".tif", ".tiff"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
""" | ||
Tests for xarray 'cog3pio' backend engine. | ||
""" | ||
|
||
import numpy as np | ||
import pytest | ||
import xarray as xr | ||
|
||
try: | ||
import rioxarray | ||
|
||
HAS_RIOXARRAY = True | ||
except ImportError: | ||
HAS_RIOXARRAY = False | ||
|
||
|
||
# %% | ||
@pytest.mark.benchmark | ||
@pytest.mark.parametrize( | ||
"engine", | ||
[ | ||
"cog3pio", | ||
pytest.param( | ||
"rasterio", | ||
marks=pytest.mark.skipif( | ||
condition=not HAS_RIOXARRAY, reason="Could not import 'rioxarray'" | ||
), | ||
), | ||
], | ||
) | ||
def test_xarray_backend_open_dataarray(engine): | ||
""" | ||
Ensure that passing engine='cog3pio' to xarray.open_dataarray works, and benchmark | ||
against engine="rasterio" (rioxarray). | ||
""" | ||
with xr.open_dataarray( | ||
filename_or_obj="https://github.com/cogeotiff/rio-tiler/raw/6.4.1/tests/fixtures/cog_nodata_nan.tif", | ||
engine=engine, | ||
) as da: | ||
assert da.sizes == {'band': 1, 'y': 549, 'x': 549} | ||
assert da.x.min() == 500080.0 | ||
assert da.x.max() == 609680.0 | ||
assert da.y.min() == 5190340.0 | ||
assert da.y.max() == 5299940.0 | ||
assert da.dtype == "float32" | ||
# np.testing.assert_allclose(actual=da.mean(), desired=0.181176) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters