-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Flexible coordinate transform #9543
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
4a595df
0b545cf
8af6614
e9a11ef
0b3fd9e
acf1c47
e101585
09667c5
0a5b798
b6b9175
4c7ce28
5cfb1af
632c71b
ae8b318
1c425e3
952faa7
03fdc90
406b03b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
from xarray.core import formatting, nputils, utils | ||
from xarray.core.coordinate_transform import CoordinateTransform | ||
from xarray.core.indexing import ( | ||
CoordinateTransformIndexingAdapter, | ||
IndexSelResult, | ||
PandasIndexingAdapter, | ||
PandasMultiIndexingAdapter, | ||
|
@@ -25,6 +26,7 @@ | |
) | ||
|
||
if TYPE_CHECKING: | ||
from xarray.core.coordinate import Coordinates | ||
from xarray.core.types import ErrorOptions, JoinOptions, Self | ||
from xarray.core.variable import Variable | ||
|
||
|
@@ -1374,8 +1376,13 @@ def rename(self, name_dict, dims_dict): | |
|
||
|
||
class CoordinateTransformIndex(Index): | ||
"""Xarray index abstract class for transformation between "pixel" | ||
and "world" coordinates. | ||
"""Helper class for creating Xarray indexes based on coordinate transforms. | ||
|
||
- wraps a :py:class:`CoordinateTransform` instance | ||
- takes care of creating the index (lazy) coordinates | ||
- supports point-wise label-based selection | ||
- supports exact alignment only, by comparing indexes based on their transform | ||
(not on their explicit coordinate labels) | ||
|
||
""" | ||
|
||
|
@@ -1409,9 +1416,11 @@ def create_variables( | |
|
||
def create_coordinates(self) -> Coordinates: | ||
# TODO: move this in xarray.Index base class? | ||
from xarray.core.coordinates import Coordinates | ||
|
||
variables = self.create_variables() | ||
indexes = {name: self for name in variables} | ||
return xr.Coordinates(coords=variables, indexes=indexes) | ||
return Coordinates(coords=variables, indexes=indexes) | ||
|
||
def isel( | ||
self, indexers: Mapping[Any, int | slice | np.ndarray | Variable] | ||
|
@@ -1423,6 +1432,9 @@ def isel( | |
def sel( | ||
self, labels: dict[Any, Any], method=None, tolerance=None | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How hard would it be to support There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pretty tricky to support it here I think, probably better to handle it on a per case basis. For basic transformations I guess it could be possible to calculate a single, uniform tolerance value in decimal array index units and validate the selected elements using those units (cheap). In other cases we would need to compute the forward transformation of the extracted array indices and then validate the selected elements based on distances in physical units (more expensive). Also, there may be cases where the coordinates of a same transform object don’t have all the same physical units (e.g., both degrees and radians coordinates in an Astropy WCS object). Unless we forbid that in |
||
) -> IndexSelResult: | ||
from xarray.core.dataarray import DataArray | ||
from xarray.core.variable import Variable | ||
|
||
if method != "nearest": | ||
raise ValueError( | ||
"CoordinateTransformIndex only supports selection with method='nearest'" | ||
|
@@ -1433,15 +1445,14 @@ def sel( | |
|
||
missing_labels = coord_names_set - labels_set | ||
if missing_labels: | ||
raise ValueError( | ||
f"missing labels for coordinate(s): {','.join(missing_labels)}." | ||
) | ||
missing_labels_str = ",".join([f"{name}" for name in missing_labels]) | ||
raise ValueError(f"missing labels for coordinate(s): {missing_labels_str}.") | ||
|
||
label0_obj = next(iter(labels.values())) | ||
dim_size0 = getattr(label0_obj, "sizes", None) | ||
|
||
is_xr_obj = [ | ||
isinstance(label, (xr.DataArray, xr.Variable)) for label in labels.values() | ||
isinstance(label, DataArray | Variable) for label in labels.values() | ||
] | ||
if not all(is_xr_obj): | ||
raise TypeError( | ||
|
@@ -1461,13 +1472,14 @@ def sel( | |
dim_positions = self.transform.reverse(coord_labels) | ||
benbovy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
results = {} | ||
dims0 = tuple(dim_size0) | ||
for dim, pos in dim_positions.items(): | ||
if isinstance(label0_obj, Variable): | ||
xr_pos = Variable(label.dims, idx) | ||
xr_pos = Variable(dims0, pos) | ||
else: | ||
# dataarray | ||
xr_pos = DataArray(idx, dims=label.dims) | ||
results[dim] = idx | ||
xr_pos = DataArray(pos, dims=dims0) | ||
results[dim] = xr_pos | ||
|
||
return IndexSelResult(results) | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.