-
Hi, I've recently been poking around in the custom index stuff, and found some things to ask about. Say you have a dataset representing a structured grid with some data living on grid cells. Dimensions ds = xr.Dataset(
{
"a": (("rows", "cols"), np.zeros((3, 3))),
"b": (("cells",), np.ones((9,)))
},
coords={
"i": ("rows", [0, 1, 2]),
"j": ("cols", [0, 1, 2]),
"n": ("cells", np.arange(9)),
},
)
ds = ds\
.set_xindex("i", PandasIndex)\
.set_xindex("j", PandasIndex)\
.set_xindex("n", PandasIndex)
ds
>>> <xarray.Dataset> Size: 264B
Dimensions: (x: 3, y: 3, cells: 9)
Coordinates:
* i (x) int64 24B 0 1 2
* j (y) int64 24B 0 1 2
* n (cells) int64 72B 0 1 2 3 4 5 6 7 8
Dimensions without coordinates: x, y, cells
Data variables:
a (x, y) float64 72B 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
b (cells) float64 72B 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
print(ds.a.sel(i=0))
>>> <xarray.DataArray 'a' (y: 3)> Size: 24B
array([0., 0., 0.])
Coordinates:
i int64 8B 0
* j (y) int64 24B 0 1 2
Dimensions without coordinates: y
print(ds.b.sel(n=0))
>>> <xarray.DataArray 'b' ()> Size: 8B
array(1.)
Coordinates:
n int64 8B 0 You can write a meta-index to do this too (lifted from docs with some asserts removed) class MetaIndex(Index):
def __init__(self, indices):
self._indices = indices
@classmethod
def from_variables(cls, variables):
return {k: PandasIndex.from_variables({k: v}) for k, v in variables.items()}
def create_variables(self, variables=None):
idx_vars = {}
for index in self._indices.values():
idx_vars.update(index.create_variables(variables))
return idx_vars
def sel(self, labels):
results = []
for k, index in self._indices.items():
if k in labels:
results.append(index.sel({k: labels[k]}))
return merge_sel_results(results) As suggested by @benbovy here you can do def alias(dataset: xr.Dataset, old_name: str, new_name: str) -> PandasIndex:
size = dataset.sizes[old_name]
return PandasIndex(pd.RangeIndex(size, name=new_name), dim=old_name)
ds = ds.drop_indexes(["i", "j", "n"])
ds = ds.assign_coords(xr.Coordinates.from_xindex(MetaIndex(
{
"i": alias(ds, "x", "i"),
"j": alias(ds, "y", "j"),
}
))) And it works. ds.a.sel(i=0)
<xarray.DataArray 'a' (y: 3)> Size: 24B
array([0., 0., 0.])
Coordinates:
i int64 8B 0
j (y) int64 24B 0 1 2
Dimensions without coordinates: y Note the absence of the star before the ds.a._indexes
>>> {'i': <__main__.MetaIndex object at 0x148892850>, 'j': <__main__.MetaIndex object at 0x148892850>} Now, if I pass not 2 but 3 indexes to ds = ds.drop_indexes(["i", "j"])
ds = ds.assign_coords(xr.Coordinates.from_xindex(MetaIndex(
{
"i": alias(ds, "x", "i"),
"j": alias(ds, "y", "j"),
"n": alias(ds, "cells", "n"),
}
)))
print(ds.a.sel(i=0))
>>> Exception has occurred: KeyError
"no index found for coordinate 'i'"
print(ds.b.sel(n=0))
>>> Exception has occurred: KeyError
"no index found for coordinate 'n'" But if I remove the first two entries in the dict argument to I also saw this and wondered in general how to implement I know this is all under development. I am excited to take advantage of it. Just trying to wrap my head around it. Thanks! |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
The index is still in the input object but normally it is not in the result By default the index is dropped after the selection unless
It breaks down in your example because the selection is done on the DataArrays
A possible implementation of |
Beta Was this translation helpful? Give feedback.
-
Thank you @benbovy just to make sure I understand, if I am reading And after #10137 I could override Thank you for the heads up about |
Beta Was this translation helpful? Give feedback.
The index is still in the input object but normally it is not in the result
ds.a.sel(i=0)._indexes
.By default the index is dropped after the selection unless
MetaIndex.isel(...)
is implemented such that it returns a new index instance.It breaks down in your example because the selection is done on the DataArrays
ds.a
andds.b
and not on the Datasetds
. Each of those DataArrays have only a subset of the dimensions linked to the meta-index, which is by default droppe…