You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There have been a number of threads discussing possible improvements/extensions to xray indexing. The current indexing behavior for isel is orthogonal indexing - in other words, each coordinate is treated independently (see #214 and #411 for more discussion).
So the question: what is the best way to incorporate diagonal or pointwise indexing in xray? I see two main goals / applications:
support pointwise array indexing along coordinates via computation of nearest-neighbor indexes - I think this can also be thought of as a form of resampling.
So, the good news is that once we figure out the API for pointwise indexing, I think the nearest-neighbor part could be as simple as supplying method='nearest'.
The challenge is that we want to go from an DataArray that looks like this:
In [4]: arr = xray.DataArray([[1, 2], [3, 4]], dims=['x', 'y'])
In [5]: arr
Out[5]:
<xray.DataArray (x: 2, y: 2)>
array([[1, 2],
[3, 4]])
Coordinates:
* x (x) int64 0 1
* y (y) int64 0 1
To one that looks like that:
In [6]: xray.DataArray([1, 4], {'x': ('c', [0, 1]), 'y': ('c', [0, 1])}, dims='c')
Out[6]:
<xray.DataArray (c: 2)>
array([1, 4])
Coordinates:
y (c) int64 0 1
x (c) int64 0 1
* c (c) int64 0 1
Somehow, we need to figure out the name for the new dimension (c in this example).
My thought would be to have methods sel_points and isel_points that work similarly to sel and isel. This is straightforward if you already have xray 1D objects with a labeled dimension: arr.sel_points(x=x, y=y), where x and y are along the c dimension.
If you don't already have 1D xray objects, I suppose we could also allow arr.sel_points(x=('c', [0, 1]), y=('c', [0, 1])) or arr.sel_points('c', x=[0, 1], y=[0, 1]).
Seems like if your method is going to be named sel_points then points is a reasonable dimension name. Maybe support a name kwarg?
One thing to keep in mind is that for many of us the "nearest-neighbor" part isn't really method='nearest', but instead more like, method='ingridcell' where the grid cell might be roughly square or might be something pretty different. At least that's how I think of my data. Maybe what I really want is some other kind of more explicit support for gridded data, although my thoughts on this are too half-baked to clearly write down. I thought there was another issue related to this, but I couldn't find it.
Seems like if your method is going to be named sel_points then points is a reasonable dimension name.
Yes, this is a reasonable choice for the case of 1d indexers.
Maybe support a name kwarg?
This is also a good idea, though I would probably call the parameter dim, not name.
One thing to keep in mind is that for many of us the "nearest-neighbor" part isn't really method='nearest', but instead more like, method='ingridcell' where the grid cell might be roughly square or might be something pretty different.
Indeed. As a start, we should be able to do nearest neighbor lookups with a tolerance soon -- I have a pandas PR that should add some of that basic functionality (pandas-dev/pandas#10411). In the long term, it would be useful to have some sort of representation of grid cells in the index itself, possibly something similar to IntervalIndex (pandas-dev/pandas#8707).
How do we want to do the nearest-neighbor selection? The simplest case would be to follow the cKDTree example from #214. However, when you're using lat/lon coordinates, it is usually best to map these coordinates from the spherical coordinates to a Cartesian coordinates (see here for a simple example using cKDTree. Is that a road we want to go down here?
Further along that subject, but not directly relate - has anyone used pyresample.
Unidata also has a blog post benchmarking cKDTree and other methods and concludes "Your Mileage May Vary". I'd probably just go with a KDTree, but something to aware of.
There is a great kdtree-based geospatial resampling package you might want to consider building on: https://github.com/pytroll/pyresample
It is fast (multithreaded) and has support for different map projections.
Maybe this is off topic, but are the plans to support more general spatial resampling / regridding? Like if I have two DataArrays a and b with different spatial coords, it would be great to be able to do
c=a.regrid_like(b)
This is a pretty common practice in climate science, since different datasets are provided on different grids with different resolutions.
I agree that regridding and resample would be very nice, and pyresample looks like a decent option. I have no immediate plans to implement these features but contributions would be very welcome.
For n-dimensional indexing, kdtree seems sensible, especially if we can cache it on the coordinates. We probably want an explicit API for methods that add new coordinates -- something like ds.set_kdtree(['latitude', 'longitude']).
@jhamman it would be great if you could put together a PR for isel_points. The main complexity is that you'll want to write a version that also works with dask arrays. Let me know if that part is confusing, I can certainly help with that.
Good point on the dask array business. From the dask docs:
Dask.array supports most of the NumPy slicing syntax.
...
It does not currently support the following:
Slicing one dask.array with another x[x > 0] Slicing with lists in multiple axes x[[1, 2, 3], [3, 2, 1]]
Both of these are straightforward to add though. If you have a use case then raise an issue.
So, from browsing the closed dask issues, it seems like dask has similar support for multi-dimension slicing and indexing as xray. This throws a bit of a wrench in my plan for how I was going to implement isel_points as I had not fully considered the dask array complexities.
I'll have to put a bit more thought into this. Any suggestions on how to index the dask array without looping through individual points would be great.
Any suggestions on how to index the dask array without looping through individual points would be great.
For now, I actually think selecting individual points and then concatenating the resulting arrays together would be a reasonable start. Yes, it's kind of slow, but once you have a first draft put together that way with the right API we can optimize later.
Now that the isel_points method is implemented, I think it makes sense to discuss the sel_points method in a bit more detail. The main outstanding question is - do we want to support spherical nearest neighbor mapping. The use case is when you are searching for the nearest neighbor using longitudes and latitudes. This example shows an example of to do this by projecting the coordinates onto a sphere. If we go this route, which is probably the most common use case here, we are committing to the coordinates being latitudes and longitudes. Maybe it is better to use a method='spherical' keyword to fall into this path.
I would start with the easiest case -- lookups of 1d orthogonal arrays, e.g., grid.sel(latitude=stations.latitude, longitude=stations.longitude, method='nearest'). This would very straightforwardly leverage our current machinery.
For 2D lookups, we need a KDTree. Here are some API ideas, just tossing things around...
Thanks @jhamman, I'd love to contribute! I'm not that confident in my Python skills, but maybe with a little guidance? Let me know if or how I could help.
@stefanomattia - I'd be happy to provide guidance and even to contribute to some of the development. Based on your blog post, I think you may be well on your way.
That post must look a bit amateurish, I reckon, but if you guys think it could be a starting point for a KD-tree search implementation in xarray, I would be thrilled to contribute! There is no learning without trying, after all. I could start from #475 (comment). @jhamman maybe you could send me an email with a few requirements?
Note that it will probably be easier to implement such KDTreeIndex after having refactored indexes and multi-indexes in xarray (see #1603). I think this refactoring would represent a good amount of work, though, so maybe we can do it after if you don't want to wait too long for the KD-Tree feature?
Further to the comment I made in a related issue #486 comment I've now taken a simplified version of the collocation approach in CIS and created a stand-alone package which works with xarray objects: https://github.com/cistools/collocate.
This works essentially the same as the nice example shown in the above blog, with some key differences:
The points within a certain distance (tolerance) of each sample point can be aggregated or selected from using the built-in kernels, allowing fast operations over many sample points.
The horizontal distance constraint can be supplemented with constraints in other dimensions (such as time or altitude).
The transform from Cartesian to Eucledian coordinates is not needed as we use our own KD-Tree implementation which builds haversine rectangles. Depending on use cases this isn't always the fastest approach, but it does sidestep some nasty dateline issues.
In the case where only the nearest points in the horizontal is needed the collocation falls back the fast single point lookup.
The KD-Tree implementation is (relatively well) separated so could easily be switched out for cKDtree or pyresample implementations
There are a some tests too, although no docs yet.
I'll try and put together a notebook building on the above blogpost so that the similarities and differences are a bit clearer.
I'm not familiar enough with xarray indexing to be able to say how well this would fit inside xarray, but hopefully it will be useful before we're able to crack KD-MultiIndexes!
There hasn't been much activity here since quite some time.
Meanwhile, there has been the development of the xoak package that supports point-wise indexing of Xarray objects with various indexes (either generic like scipy.spatial.cKDTree or more specific like pys2index's S2PointIndex for lat/lon point data). xoak leverage Xarray's advanced indexing capabilities and supports selection using both coordinates and indexers with an arbitrary number of dimensions.
With the forthcoming Xarray release, it will be possible to create and assign custom indexes to DataArray / Dataset objects. The plan for xoak is then to just provide some custom indexes so that we can perform point-wise selection directly with Dataset.sel() instead of Dataset.xoak.sel().
Or is there still a need to extend Xarray's API for supporting pointwise indexing, i.e., something that cannot be done with .isel or with .sel + a custom Xarray index?
Activity
shoyer commentedon Jul 15, 2015
So, the good news is that once we figure out the API for pointwise indexing, I think the nearest-neighbor part could be as simple as supplying
method='nearest'.The challenge is that we want to go from an DataArray that looks like this:
To one that looks like that:
Somehow, we need to figure out the name for the new dimension (
cin this example).My thought would be to have methods
sel_pointsandisel_pointsthat work similarly toselandisel. This is straightforward if you already have xray 1D objects with a labeled dimension:arr.sel_points(x=x, y=y), wherexandyare along thecdimension.If you don't already have 1D xray objects, I suppose we could also allow
arr.sel_points(x=('c', [0, 1]), y=('c', [0, 1]))orarr.sel_points('c', x=[0, 1], y=[0, 1]).wholmgren commentedon Jul 15, 2015
Seems like if your method is going to be named
sel_pointsthenpointsis a reasonable dimension name. Maybe support anamekwarg?One thing to keep in mind is that for many of us the "nearest-neighbor" part isn't really
method='nearest', but instead more like,method='ingridcell'where the grid cell might be roughly square or might be something pretty different. At least that's how I think of my data. Maybe what I really want is some other kind of more explicit support for gridded data, although my thoughts on this are too half-baked to clearly write down. I thought there was another issue related to this, but I couldn't find it.shoyer commentedon Jul 15, 2015
Yes, this is a reasonable choice for the case of 1d indexers.
This is also a good idea, though I would probably call the parameter
dim, notname.Indeed. As a start, we should be able to do nearest neighbor lookups with a tolerance soon -- I have a pandas PR that should add some of that basic functionality (pandas-dev/pandas#10411). In the long term, it would be useful to have some sort of representation of grid cells in the index itself, possibly something similar to
IntervalIndex(pandas-dev/pandas#8707).[-]api design for pointwise indexing[/-][+]API design for pointwise indexing[/+]jhamman commentedon Jul 15, 2015
I like:
I also like the nearest-neighbor / resample API of:
How do we want to do the nearest-neighbor selection? The simplest case would be to follow the cKDTree example from #214. However, when you're using lat/lon coordinates, it is usually best to map these coordinates from the spherical coordinates to a Cartesian coordinates (see here for a simple example using cKDTree. Is that a road we want to go down here?
Further along that subject, but not directly relate - has anyone used pyresample.
wholmgren commentedon Jul 16, 2015
Unidata also has a blog post benchmarking cKDTree and other methods and concludes "Your Mileage May Vary". I'd probably just go with a KDTree, but something to aware of.
rabernat commentedon Jul 16, 2015
There is a great kdtree-based geospatial resampling package you might want to consider building on:
https://github.com/pytroll/pyresample
It is fast (multithreaded) and has support for different map projections.
rabernat commentedon Jul 16, 2015
Maybe this is off topic, but are the plans to support more general spatial resampling / regridding? Like if I have two DataArrays a and b with different spatial coords, it would be great to be able to do
This is a pretty common practice in climate science, since different datasets are provided on different grids with different resolutions.
shoyer commentedon Jul 16, 2015
I agree that regridding and resample would be very nice, and pyresample looks like a decent option. I have no immediate plans to implement these features but contributions would be very welcome.
For n-dimensional indexing, kdtree seems sensible, especially if we can cache it on the coordinates. We probably want an explicit API for methods that add new coordinates -- something like
ds.set_kdtree(['latitude', 'longitude']).jhamman commentedon Jul 16, 2015
As a first step, I'll volunteer (unless someone else is more keen on doing this work) to put together a pull request for
isel_points.After that, we'll want to add the
sel_pointsandkdtreeAPI, which will depend onisel_points.Later on, I'm also interested in regridding and resampling between grids - let's open another issue for that. Maybe we use
pyresamplefor that.shoyer commentedon Jul 16, 2015
@jhamman it would be great if you could put together a PR for
isel_points. The main complexity is that you'll want to write a version that also works with dask arrays. Let me know if that part is confusing, I can certainly help with that.As for
sel_points, we only need a kdtree if the underlying coordinates are 2D. Iflatitudeandlongitude(for example) are 1d, we can just use the existing machinery for remapping label based indexers to integers. This should be pretty straightforward, following the example ofisel:https://github.com/xray/xray/blob/v0.5.1/xray/core/dataset.py#L1024
https://github.com/xray/xray/blob/v0.5.1/xray/core/indexing.py#L157
jhamman commentedon Jul 17, 2015
Good point on the dask array business. From the dask docs:
So, from browsing the closed dask issues, it seems like dask has similar support for multi-dimension slicing and indexing as xray. This throws a bit of a wrench in my plan for how I was going to implement
isel_pointsas I had not fully considered the dask array complexities.I'll have to put a bit more thought into this. Any suggestions on how to index the dask array without looping through individual points would be great.
shoyer commentedon Jul 17, 2015
For now, I actually think selecting individual points and then concatenating the resulting arrays together would be a reasonable start. Yes, it's kind of slow, but once you have a first draft put together that way with the right API we can optimize later.
jhamman commentedon Jul 27, 2015
Now that the
isel_pointsmethod is implemented, I think it makes sense to discuss thesel_pointsmethod in a bit more detail. The main outstanding question is - do we want to support spherical nearest neighbor mapping. The use case is when you are searching for the nearest neighbor using longitudes and latitudes. This example shows an example of to do this by projecting the coordinates onto a sphere. If we go this route, which is probably the most common use case here, we are committing to the coordinates being latitudes and longitudes. Maybe it is better to use amethod='spherical'keyword to fall into this path.shoyer commentedon Jul 27, 2015
I would start with the easiest case -- lookups of 1d orthogonal arrays, e.g.,
grid.sel(latitude=stations.latitude, longitude=stations.longitude, method='nearest'). This would very straightforwardly leverage our current machinery.For 2D lookups, we need a KDTree. Here are some API ideas, just tossing things around...
15 remaining items
stefanomattia commentedon Jan 3, 2018
Thanks @jhamman, I'd love to contribute! I'm not that confident in my Python skills, but maybe with a little guidance? Let me know if or how I could help.
jhamman commentedon Jan 3, 2018
@stefanomattia - I'd be happy to provide guidance and even to contribute to some of the development. Based on your blog post, I think you may be well on your way.
shoyer commentedon Jan 3, 2018
@jhamman @stefanomattia can you share a link to this blog post? :)
jhamman commentedon Jan 3, 2018
http://notes.stefanomattia.net/2017/12/12/The-quest-to-find-the-closest-ground-pixel/
stefanomattia commentedon Jan 4, 2018
That post must look a bit amateurish, I reckon, but if you guys think it could be a starting point for a KD-tree search implementation in xarray, I would be thrilled to contribute! There is no learning without trying, after all. I could start from #475 (comment). @jhamman maybe you could send me an email with a few requirements?
benbovy commentedon Jan 5, 2018
Note that it will probably be easier to implement such KDTreeIndex after having refactored indexes and multi-indexes in xarray (see #1603). I think this refactoring would represent a good amount of work, though, so maybe we can do it after if you don't want to wait too long for the KD-Tree feature?
duncanwp commentedon Jan 9, 2018
Further to the comment I made in a related issue #486 comment I've now taken a simplified version of the collocation approach in CIS and created a stand-alone package which works with xarray objects: https://github.com/cistools/collocate.
This works essentially the same as the nice example shown in the above blog, with some key differences:
I'll try and put together a notebook building on the above blogpost so that the similarities and differences are a bit clearer.
I'm not familiar enough with xarray indexing to be able to say how well this would fit inside xarray, but hopefully it will be useful before we're able to crack KD-MultiIndexes!
stale commentedon Dec 10, 2019
In order to maintain a list of currently relevant issues, we mark issues as stale after a period of inactivity
If this issue remains relevant, please comment here or remove the
stalelabel; otherwise it will be marked as closed automaticallyshoyer commentedon May 24, 2020
@JimmyGao0204 I moved your comment to a new issue: #4090
benbovy commentedon Sep 28, 2022
There hasn't been much activity here since quite some time.
Meanwhile, there has been the development of the xoak package that supports point-wise indexing of Xarray objects with various indexes (either generic like
scipy.spatial.cKDTreeor more specific like pys2index'sS2PointIndexfor lat/lon point data).xoakleverage Xarray's advanced indexing capabilities and supports selection using both coordinates and indexers with an arbitrary number of dimensions.With the forthcoming Xarray release, it will be possible to create and assign custom indexes to DataArray / Dataset objects. The plan for
xoakis then to just provide some custom indexes so that we can perform point-wise selection directly withDataset.sel()instead ofDataset.xoak.sel().benbovy commentedon Aug 23, 2023
Can we close this issue and redirect the reader to https://github.com/xarray-contrib/xoak or #7041?
Or is there still a need to extend Xarray's API for supporting pointwise indexing, i.e., something that cannot be done with
.iselor with.sel+ a custom Xarray index?