Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
- name: Set Up Hatch Env
run: |
hatch env create test.py${{ matrix.python-version }}
hatch env run -e test.py${{ matrix.python-version }} list-env
hatch env run --env test.py${{ matrix.python-version }} list-env
- name: Run Tests
run: |
hatch env run --env test.py${{ matrix.python-version }} run-coverage
Expand Down
31 changes: 16 additions & 15 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,6 @@ dynamic=["version"]
dask = ["dask-geopandas"]
rasterize = ["rasterio"]
exactextract = ["exactextract", "sparse"]
test = [
"geodatasets",
"pooch",
"dask-geopandas",
"rasterio",
"exactextract",
"sparse",
"netCDF4",
"hypothesis",
"xarray @ git+https://github.com/dcherian/xarray.git@fix-coord-transform-indexing",
]
docs = [
"geodatasets",
"pooch",
Expand Down Expand Up @@ -91,14 +80,26 @@ exclude = [
"doc",
]

[tool.hatch.envs.test]
dependencies = [
[dependency-groups]
test = [
"coverage",
"dask-geopandas",
"exactextract",
"geodatasets",
"hypothesis",
"netCDF4",
"pooch",
"pytest",
"pytest",
"pytest-cov",
"pytest-xdist"
"pytest-xdist",
"rasterio",
"sparse",
"xarray @ git+https://github.com/pydata/xarray.git@26ccc7f8f014f29c551fd566a04d6e9f878c0b0b", # https://github.com/pydata/xarray/pull/10980
]
features = ["test"]

[tool.hatch.envs.test]
dependency-groups = ["test"]

[[tool.hatch.envs.test.matrix]]
python = ["3.11", "3.13"]
Expand Down
19 changes: 18 additions & 1 deletion src/rasterix/raster_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from xarray.core.coordinate_transform import CoordinateTransform

# TODO: import from public API once it is available
from xarray.core.indexes import CoordinateTransformIndex
from xarray.core.indexes import CoordinateTransformIndex, PandasIndex
from xarray.core.indexing import IndexSelResult, merge_sel_results
from xarray.core.types import JoinOptions
from xproj.typing import CRSAwareIndex
Expand Down Expand Up @@ -840,6 +840,23 @@ def center_transform(self) -> Affine:
y = self._xy_indexes[YAXIS].axis_transform.affine
return Affine(x.a, x.b, x.c, y.d, y.e, y.f)

def _as_pandas_index(self) -> dict[str, PandasIndex]:
"""Convert RasterIndex to equivalent PandasIndex objects.

Returns a dict mapping dimension names to PandasIndex instances.
For internal/testing use.
"""
result = {}
if self._axis_independent:
for idx in self._xy_indexes:
dim = idx.axis_transform.dim
values = idx.to_pandas_index()
result[dim] = PandasIndex(values, dim)
else:
raise NotImplementedError("_as_pandas_index not supported for non-rectilinear grids")

return result

@property
def bbox(self) -> BoundingBox:
"""Bounding Box for index.
Expand Down
42 changes: 27 additions & 15 deletions tests/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@
)


def assert_identical(actual: xr.DataArray, expected: xr.DataArray):
"""Assert DataArrays are identical, comparing RasterIndex to equivalent PandasIndex."""
xr.testing.assert_equal(actual, expected)

for idx in actual.xindexes.get_unique():
if isinstance(idx, RasterIndex):
pandas_indexes = idx._as_pandas_index()
for dim, pandas_idx in pandas_indexes.items():
expected_idx = expected.xindexes[dim]
assert pandas_idx.equals(expected_idx)


@pytest.fixture
def raster_da():
"""Create a DataArray with RasterIndex coordinates."""
Expand Down Expand Up @@ -72,7 +84,7 @@ def test_isel_basic_indexing_equivalence(data, raster_da, pandas_da):
indexers = data.draw(basic_indexers(sizes=sizes))
result_raster = raster_da.isel(indexers)
result_pandas = pandas_da.isel(indexers)
xr.testing.assert_identical(result_raster, result_pandas)
assert_identical(result_raster, result_pandas)


@given(data=st.data())
Expand All @@ -81,7 +93,7 @@ def test_isel_basic_indexing_equivalence(data, raster_da, pandas_da):
suppress_health_check=[HealthCheck.function_scoped_fixture],
)
def test_sel_basic_indexing_equivalence(data, raster_da, pandas_da):
"""Test that isel produces identical results for RasterIndex and PandasIndex."""
"""Test that sel produces identical results for RasterIndex and PandasIndex."""
indexers = data.draw(basic_label_indexers(indexes=pandas_da.xindexes))

result_raster = raster_da.sel(
Expand All @@ -93,27 +105,27 @@ def test_sel_basic_indexing_equivalence(data, raster_da, pandas_da):
if all(isinstance(idxr, slice) for idxr in indexers.values()):
assert all(isinstance(idx, RasterIndex) for idx in result_raster.xindexes.get_unique())

xr.testing.assert_identical(result_raster, result_pandas)
assert_identical(result_raster, result_pandas)


def test_simple_isel(raster_da, pandas_da):
"""Sanity check: simple indexing operations."""
# Scalar indexing
xr.testing.assert_identical(raster_da.isel(x=0), pandas_da.isel(x=0))
xr.testing.assert_identical(raster_da.isel(y=0), pandas_da.isel(y=0))
xr.testing.assert_identical(raster_da.isel(x=0, y=0), pandas_da.isel(x=0, y=0))
assert_identical(raster_da.isel(x=0), pandas_da.isel(x=0))
assert_identical(raster_da.isel(y=0), pandas_da.isel(y=0))
assert_identical(raster_da.isel(x=0, y=0), pandas_da.isel(x=0, y=0))

# Slice indexing
xr.testing.assert_identical(raster_da.isel(x=slice(2, 5)), pandas_da.isel(x=slice(2, 5)))
xr.testing.assert_identical(raster_da.isel(y=slice(1, 4)), pandas_da.isel(y=slice(1, 4)))
xr.testing.assert_identical(
assert_identical(raster_da.isel(x=slice(2, 5)), pandas_da.isel(x=slice(2, 5)))
assert_identical(raster_da.isel(y=slice(1, 4)), pandas_da.isel(y=slice(1, 4)))
assert_identical(
raster_da.isel(x=slice(2, 5), y=slice(1, 4)),
pandas_da.isel(x=slice(2, 5), y=slice(1, 4)),
)

# Array indexing
xr.testing.assert_identical(raster_da.isel(x=[0, 2, 4]), pandas_da.isel(x=[0, 2, 4]))
xr.testing.assert_identical(raster_da.isel(y=[1, 3]), pandas_da.isel(y=[1, 3]))
assert_identical(raster_da.isel(x=[0, 2, 4]), pandas_da.isel(x=[0, 2, 4]))
assert_identical(raster_da.isel(y=[1, 3]), pandas_da.isel(y=[1, 3]))


@given(data=st.data())
Expand All @@ -126,7 +138,7 @@ def test_outer_array_indexing(data, raster_da, pandas_da):
result_raster = raster_da.isel(indexers)
result_pandas = pandas_da.isel(indexers)

xr.testing.assert_identical(result_raster, result_pandas)
assert_identical(result_raster, result_pandas)


@given(data=st.data())
Expand All @@ -139,7 +151,7 @@ def test_outer_array_label_indexing(data, raster_da, pandas_da):
indexers = data.draw(outer_array_label_indexers(indexes=pandas_da.xindexes))
result_raster = raster_da.sel(indexers, method="nearest")
result_pandas = pandas_da.sel(indexers, method="nearest")
xr.testing.assert_identical(result_raster, result_pandas)
assert_identical(result_raster, result_pandas)


@given(data=st.data())
Expand All @@ -150,7 +162,7 @@ def test_vectorized_indexing(data, raster_da, pandas_da):
indexers = data.draw(vectorized_indexers(sizes=sizes))
result_raster = raster_da.isel(indexers)
result_pandas = pandas_da.isel(indexers)
xr.testing.assert_identical(result_raster, result_pandas)
assert_identical(result_raster, result_pandas)


@given(data=st.data())
Expand All @@ -163,4 +175,4 @@ def test_vectorized_label_indexing(data, raster_da, pandas_da):
indexers = data.draw(vectorized_label_indexers(indexes=pandas_da.xindexes))
result_raster = raster_da.sel(indexers, method="nearest")
result_pandas = pandas_da.sel(indexers, method="nearest")
xr.testing.assert_identical(result_raster, result_pandas)
assert_identical(result_raster, result_pandas)
Loading