From 74ec7c9820bccdca09adebf25a1852827405019d Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Fri, 18 Nov 2022 02:07:41 +0100 Subject: [PATCH 01/28] add GeoVectorIndex As replacement of ShapelySTRTreeIndex. --- xvec/__init__.py | 1 + xvec/index.py | 165 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 xvec/index.py diff --git a/xvec/__init__.py b/xvec/__init__.py index 5aca488..08d35c5 100644 --- a/xvec/__init__.py +++ b/xvec/__init__.py @@ -1,5 +1,6 @@ from importlib.metadata import PackageNotFoundError, version +from .index import GeoVectorIndex # noqa from .strtree import ShapelySTRTreeIndex # noqa try: diff --git a/xvec/index.py b/xvec/index.py new file mode 100644 index 0000000..0190d05 --- /dev/null +++ b/xvec/index.py @@ -0,0 +1,165 @@ +from __future__ import annotations + +from typing import Any, Hashable, Iterable, Mapping, Sequence + +import shapely +import numpy as np +import pandas as pd +from pyproj import CRS +from xarray import DataArray, Variable +from xarray.core.indexing import IndexSelResult +from xarray.indexes import Index, PandasIndex + + +class GeoVectorIndex(Index): + + _index: PandasIndex + _sindex: shapely.STRtree | None + _crs: CRS + + def __init__(self, index: PandasIndex, crs: CRS): + if not np.all(shapely.is_geometry(index.index)): + raise ValueError("array must contain shapely.Geometry objects") + + self._crs = crs + self._index = index + self._sindex = None + + @property + def crs(self) -> CRS: + return self._crs + + @property + def sindex(self): + if self._sindex is None: + self._sindex = shapely.STRtree(self._index.index) + return self._sindex + + @classmethod + def from_variables( + cls, + variables: Mapping[Any, Variable], + *, + options: Mapping[str, Any], + ): + # TODO: get CRS from coordinate attrs or GeometryArray + if "crs" not in options: + raise ValueError("A CRS must be provided") + + crs = CRS.from_user_input(options["crs"]) + + index = PandasIndex.from_variables(variables, options={}) + return cls(index, crs=crs) + + @classmethod + def concat( + cls, + indexes: Sequence[GeoVectorIndex], + dim: Hashable, + positions: Iterable[Iterable[int]] | None = None, + ) -> GeoVectorIndex: + crss = [idx.crs for idx in indexes] + + if any([s != crss[0] for s in crss]): + raise ValueError("conflicting CRS for coordinates to concat") + + indexes_ = [idx._index for idx in indexes] + index = PandasIndex.concat(indexes_, dim, positions) + return cls(index, crss[0]) + + def create_variables( + self, variables: Mapping[Any, Variable] | None = None + ) -> dict[Hashable, Variable]: + return self._index.create_variables(variables) + + def to_pandas_index(self) -> pd.Index: + return self._index.index + + def isel(self, indexers: Mapping[Any, Any]): + index = self._index.isel(indexers) + + if index is not None: + return type(self)(index, self.crs) + else: + return None + + def _sel_sindex(self, labels, method, tolerance): + # only one coordinate supported + assert len(labels) == 1 + label = next(iter(labels.values())) + + if method is not None and method != "nearest": + if not isinstance(label, shapely.Geometry): + raise ValueError( + "selection with another method than nearest only supports " + "a single geometry as input label." + ) + + if isinstance(label, DataArray): + label_array = label._variable._data + elif isinstance(label, Variable): + label_array = label._data + elif isinstance(label, shapely.Geometry): + label_array = np.array([label]) + else: + label_array = np.array(label) + + # check for possible CRS of geometry labels + # (by default assume same CRS than the index) + if hasattr(label_array, "crs") and label_array.crs != self.crs: + raise ValueError("conflicting CRS for input geometries") + + assert np.all(shapely.is_geometry(label_array)) + + if method == "nearest": + indices = self.sindex.nearest(label_array) + else: + indices = self.sindex.query(label, predicate=method, distance=tolerance) + + # attach dimension names and/or coordinates to positional indexer + if isinstance(label, Variable): + indices = Variable(label.dims, indices) + elif isinstance(label, DataArray): + indices = DataArray(indices, coords=label._coords, dims=label.dims) + + return IndexSelResult({self._index.dim: indices}) + + def sel(self, labels: dict[Any, Any], method=None, tolerance=None) -> IndexSelResult: + if method is None: + return self._index.sel(labels) + else: + # We reuse here `method` and `tolerance` options of + # `xarray.indexes.PandasIndex` as `predicate` and `distance` + # options when `labels` is a single geometry. + # Xarray currently doesn't support custom options + # (see https://github.com/pydata/xarray/issues/7099) + return self._sel_sindex(labels, method, tolerance) + + def equals(self, other: Index) -> bool: + if not isinstance(other, GeoVectorIndex): + return False + if other.crs != self.crs: + return False + return self._index.equals(other._index) + + def join( + self: GeoVectorIndex, other: GeoVectorIndex, how: str = "inner" + ) -> GeoVectorIndex: + index = self._index.join(other._index, how=how) + return type(self)(index, self.crs) + + def reindex_like( + self, other: GeoVectorIndex, method=None, tolerance=None + ) -> dict[Hashable, Any]: + return self._index.reindex_like(other._index, method=method, tolerance=tolerance) + + def roll(self, shifts: Mapping[Any, int]) -> GeoVectorIndex: + index = self._index.roll(shifts) + return type(self)(index, self.crs) + + def rename(self, name_dict, dims_dict): + index = self._index.rename(name_dict, dims_dict) + return type(self)(index, self.crs) + + def _repr_inline_(self, max_width): + return f"{self.__class__.__name__}(crs={self.crs.to_string()})" From 5acb0b2fccb609a2b9a135854d974df2b42a2ca5 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Fri, 18 Nov 2022 09:02:44 +0100 Subject: [PATCH 02/28] update quickstart notebook --- doc/source/quickstart.ipynb | 1722 ++++++++++++++++++++++++----------- 1 file changed, 1172 insertions(+), 550 deletions(-) diff --git a/doc/source/quickstart.ipynb b/doc/source/quickstart.ipynb index d1b2068..f95802a 100644 --- a/doc/source/quickstart.ipynb +++ b/doc/source/quickstart.ipynb @@ -30,7 +30,7 @@ "import xarray\n", "import numpy\n", "\n", - "from xvec import ShapelySTRTreeIndex" + "from xvec import GeoVectorIndex" ] }, { @@ -465,93 +465,93 @@ " fill: currentColor;\n", "}\n", "
<xarray.DataArray (mode: 3, day: 100, time: 24, origin: 100, destination: 100)>\n",
-       "array([[[[[96, 29, 64, ..., 47, 80, 71],\n",
-       "          [79, 79, 96, ..., 92, 12, 90],\n",
-       "          [19, 85, 60, ..., 43, 28, 53],\n",
+       "array([[[[[ 3, 20, 86, ..., 47, 18,  4],\n",
+       "          [60, 27, 15, ..., 54,  1, 23],\n",
+       "          [65, 21, 14, ..., 70, 97, 71],\n",
        "          ...,\n",
-       "          [96,  8, 35, ..., 39,  7, 62],\n",
-       "          [82, 87, 18, ...,  1, 77, 38],\n",
-       "          [99, 94, 20, ..., 92, 16, 42]],\n",
+       "          [75, 34, 41, ..., 79,  7, 68],\n",
+       "          [31, 64, 18, ..., 44,  9, 37],\n",
+       "          [35, 71, 59, ..., 66, 71,  1]],\n",
        "\n",
-       "         [[79, 53, 28, ..., 30, 56, 14],\n",
-       "          [21, 88, 91, ..., 92, 73, 14],\n",
-       "          [74, 49, 88, ..., 30, 23, 28],\n",
+       "         [[ 8, 54, 27, ..., 79, 20, 93],\n",
+       "          [ 9, 94, 80, ..., 69, 25, 78],\n",
+       "          [78, 86, 59, ..., 24, 68, 13],\n",
        "          ...,\n",
-       "          [56, 76, 91, ..., 36, 94, 16],\n",
-       "          [80, 83,  4, ..., 91, 38,  3],\n",
-       "          [69, 61, 10, ..., 79, 15, 94]],\n",
+       "          [92, 73, 72, ..., 55, 75, 86],\n",
+       "          [39, 40, 55, ..., 63, 24, 64],\n",
+       "          [63, 85, 17, ..., 44, 75, 68]],\n",
        "\n",
-       "         [[91, 22, 13, ..., 45, 31, 17],\n",
-       "          [86, 48, 23, ..., 88, 55, 94],\n",
-       "          [56,  8, 55, ..., 68, 15, 48],\n",
+       "         [[24, 54, 24, ..., 99, 40, 89],\n",
+       "          [32, 39, 46, ..., 38, 21,  3],\n",
+       "          [39, 63, 90, ..., 54,  5, 84],\n",
        "          ...,\n",
        "...\n",
        "          ...,\n",
-       "          [27,  8, 29, ..., 96, 80, 60],\n",
-       "          [ 1, 98, 63, ...,  1, 73, 98],\n",
-       "          [77, 22, 88, ...,  6, 60,  7]],\n",
+       "          [91, 56, 61, ..., 91, 73, 25],\n",
+       "          [37, 91, 54, ..., 47, 72, 37],\n",
+       "          [72, 81, 93, ..., 59, 84, 68]],\n",
        "\n",
-       "         [[22, 40, 31, ..., 84, 62, 61],\n",
-       "          [27, 83, 95, ..., 81, 15, 54],\n",
-       "          [43, 45, 67, ..., 52,  2, 28],\n",
+       "         [[59, 76, 62, ..., 84, 38, 60],\n",
+       "          [11, 41, 61, ..., 70, 50, 98],\n",
+       "          [66, 59, 55, ..., 19, 21, 86],\n",
        "          ...,\n",
-       "          [91, 75, 49, ...,  1, 76, 65],\n",
-       "          [ 4, 78, 43, ..., 82, 20, 95],\n",
-       "          [16, 65, 36, ..., 27, 92, 43]],\n",
+       "          [41, 49, 95, ..., 28, 87, 23],\n",
+       "          [25, 52,  4, ..., 18, 78, 90],\n",
+       "          [93,  1, 48, ..., 22, 48, 45]],\n",
        "\n",
-       "         [[11, 54, 89, ..., 64, 56, 78],\n",
-       "          [ 1, 29, 49, ..., 46, 22, 95],\n",
-       "          [99,  4, 33, ..., 89, 48, 60],\n",
+       "         [[96, 94, 67, ..., 72, 32, 20],\n",
+       "          [59, 71, 78, ..., 92, 29, 23],\n",
+       "          [19, 56, 11, ..., 34, 30, 82],\n",
        "          ...,\n",
-       "          [18, 62, 84, ..., 12, 87, 52],\n",
-       "          [42, 79, 90, ...,  5, 24, 57],\n",
-       "          [51, 35, 71, ..., 55, 29, 11]]]]])\n",
+       "          [86, 83, 55, ..., 66, 67, 17],\n",
+       "          [27, 19, 10, ..., 42, 55, 73],\n",
+       "          [11, 25, 62, ..., 40, 84, 95]]]]])\n",
        "Coordinates:\n",
        "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
        "  * day          (day) datetime64[ns] 2015-01-01 2015-01-02 ... 2015-04-10\n",
        "  * time         (time) int64 0 1 2 3 4 5 6 7 8 9 ... 15 16 17 18 19 20 21 22 23\n",
        "  * origin       (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n",
-       "  * destination  (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...
  • " ], "text/plain": [ "\n", - "array([[[[[96, 29, 64, ..., 47, 80, 71],\n", - " [79, 79, 96, ..., 92, 12, 90],\n", - " [19, 85, 60, ..., 43, 28, 53],\n", + "array([[[[[ 3, 20, 86, ..., 47, 18, 4],\n", + " [60, 27, 15, ..., 54, 1, 23],\n", + " [65, 21, 14, ..., 70, 97, 71],\n", " ...,\n", - " [96, 8, 35, ..., 39, 7, 62],\n", - " [82, 87, 18, ..., 1, 77, 38],\n", - " [99, 94, 20, ..., 92, 16, 42]],\n", + " [75, 34, 41, ..., 79, 7, 68],\n", + " [31, 64, 18, ..., 44, 9, 37],\n", + " [35, 71, 59, ..., 66, 71, 1]],\n", "\n", - " [[79, 53, 28, ..., 30, 56, 14],\n", - " [21, 88, 91, ..., 92, 73, 14],\n", - " [74, 49, 88, ..., 30, 23, 28],\n", + " [[ 8, 54, 27, ..., 79, 20, 93],\n", + " [ 9, 94, 80, ..., 69, 25, 78],\n", + " [78, 86, 59, ..., 24, 68, 13],\n", " ...,\n", - " [56, 76, 91, ..., 36, 94, 16],\n", - " [80, 83, 4, ..., 91, 38, 3],\n", - " [69, 61, 10, ..., 79, 15, 94]],\n", + " [92, 73, 72, ..., 55, 75, 86],\n", + " [39, 40, 55, ..., 63, 24, 64],\n", + " [63, 85, 17, ..., 44, 75, 68]],\n", "\n", - " [[91, 22, 13, ..., 45, 31, 17],\n", - " [86, 48, 23, ..., 88, 55, 94],\n", - " [56, 8, 55, ..., 68, 15, 48],\n", + " [[24, 54, 24, ..., 99, 40, 89],\n", + " [32, 39, 46, ..., 38, 21, 3],\n", + " [39, 63, 90, ..., 54, 5, 84],\n", " ...,\n", "...\n", " ...,\n", - " [27, 8, 29, ..., 96, 80, 60],\n", - " [ 1, 98, 63, ..., 1, 73, 98],\n", - " [77, 22, 88, ..., 6, 60, 7]],\n", + " [91, 56, 61, ..., 91, 73, 25],\n", + " [37, 91, 54, ..., 47, 72, 37],\n", + " [72, 81, 93, ..., 59, 84, 68]],\n", "\n", - " [[22, 40, 31, ..., 84, 62, 61],\n", - " [27, 83, 95, ..., 81, 15, 54],\n", - " [43, 45, 67, ..., 52, 2, 28],\n", + " [[59, 76, 62, ..., 84, 38, 60],\n", + " [11, 41, 61, ..., 70, 50, 98],\n", + " [66, 59, 55, ..., 19, 21, 86],\n", " ...,\n", - " [91, 75, 49, ..., 1, 76, 65],\n", - " [ 4, 78, 43, ..., 82, 20, 95],\n", - " [16, 65, 36, ..., 27, 92, 43]],\n", + " [41, 49, 95, ..., 28, 87, 23],\n", + " [25, 52, 4, ..., 18, 78, 90],\n", + " [93, 1, 48, ..., 22, 48, 45]],\n", "\n", - " [[11, 54, 89, ..., 64, 56, 78],\n", - " [ 1, 29, 49, ..., 46, 22, 95],\n", - " [99, 4, 33, ..., 89, 48, 60],\n", + " [[96, 94, 67, ..., 72, 32, 20],\n", + " [59, 71, 78, ..., 92, 29, 23],\n", + " [19, 56, 11, ..., 34, 30, 82],\n", " ...,\n", - " [18, 62, 84, ..., 12, 87, 52],\n", - " [42, 79, 90, ..., 5, 24, 57],\n", - " [51, 35, 71, ..., 55, 29, 11]]]]])\n", + " [86, 83, 55, ..., 66, 67, 17],\n", + " [27, 19, 10, ..., 42, 55, 73],\n", + " [11, 25, 62, ..., 40, 84, 95]]]]])\n", "Coordinates:\n", " * mode (mode)
    <xarray.DataArray (mode: 3, day: 100, time: 24, origin: 100, destination: 100)>\n",
    -       "array([[[[[96, 29, 64, ..., 47, 80, 71],\n",
    -       "          [79, 79, 96, ..., 92, 12, 90],\n",
    -       "          [19, 85, 60, ..., 43, 28, 53],\n",
    +       "array([[[[[ 3, 20, 86, ..., 47, 18,  4],\n",
    +       "          [60, 27, 15, ..., 54,  1, 23],\n",
    +       "          [65, 21, 14, ..., 70, 97, 71],\n",
            "          ...,\n",
    -       "          [96,  8, 35, ..., 39,  7, 62],\n",
    -       "          [82, 87, 18, ...,  1, 77, 38],\n",
    -       "          [99, 94, 20, ..., 92, 16, 42]],\n",
    +       "          [75, 34, 41, ..., 79,  7, 68],\n",
    +       "          [31, 64, 18, ..., 44,  9, 37],\n",
    +       "          [35, 71, 59, ..., 66, 71,  1]],\n",
            "\n",
    -       "         [[79, 53, 28, ..., 30, 56, 14],\n",
    -       "          [21, 88, 91, ..., 92, 73, 14],\n",
    -       "          [74, 49, 88, ..., 30, 23, 28],\n",
    +       "         [[ 8, 54, 27, ..., 79, 20, 93],\n",
    +       "          [ 9, 94, 80, ..., 69, 25, 78],\n",
    +       "          [78, 86, 59, ..., 24, 68, 13],\n",
            "          ...,\n",
    -       "          [56, 76, 91, ..., 36, 94, 16],\n",
    -       "          [80, 83,  4, ..., 91, 38,  3],\n",
    -       "          [69, 61, 10, ..., 79, 15, 94]],\n",
    +       "          [92, 73, 72, ..., 55, 75, 86],\n",
    +       "          [39, 40, 55, ..., 63, 24, 64],\n",
    +       "          [63, 85, 17, ..., 44, 75, 68]],\n",
            "\n",
    -       "         [[91, 22, 13, ..., 45, 31, 17],\n",
    -       "          [86, 48, 23, ..., 88, 55, 94],\n",
    -       "          [56,  8, 55, ..., 68, 15, 48],\n",
    +       "         [[24, 54, 24, ..., 99, 40, 89],\n",
    +       "          [32, 39, 46, ..., 38, 21,  3],\n",
    +       "          [39, 63, 90, ..., 54,  5, 84],\n",
            "          ...,\n",
            "...\n",
            "          ...,\n",
    -       "          [27,  8, 29, ..., 96, 80, 60],\n",
    -       "          [ 1, 98, 63, ...,  1, 73, 98],\n",
    -       "          [77, 22, 88, ...,  6, 60,  7]],\n",
    +       "          [91, 56, 61, ..., 91, 73, 25],\n",
    +       "          [37, 91, 54, ..., 47, 72, 37],\n",
    +       "          [72, 81, 93, ..., 59, 84, 68]],\n",
            "\n",
    -       "         [[22, 40, 31, ..., 84, 62, 61],\n",
    -       "          [27, 83, 95, ..., 81, 15, 54],\n",
    -       "          [43, 45, 67, ..., 52,  2, 28],\n",
    +       "         [[59, 76, 62, ..., 84, 38, 60],\n",
    +       "          [11, 41, 61, ..., 70, 50, 98],\n",
    +       "          [66, 59, 55, ..., 19, 21, 86],\n",
            "          ...,\n",
    -       "          [91, 75, 49, ...,  1, 76, 65],\n",
    -       "          [ 4, 78, 43, ..., 82, 20, 95],\n",
    -       "          [16, 65, 36, ..., 27, 92, 43]],\n",
    +       "          [41, 49, 95, ..., 28, 87, 23],\n",
    +       "          [25, 52,  4, ..., 18, 78, 90],\n",
    +       "          [93,  1, 48, ..., 22, 48, 45]],\n",
            "\n",
    -       "         [[11, 54, 89, ..., 64, 56, 78],\n",
    -       "          [ 1, 29, 49, ..., 46, 22, 95],\n",
    -       "          [99,  4, 33, ..., 89, 48, 60],\n",
    +       "         [[96, 94, 67, ..., 72, 32, 20],\n",
    +       "          [59, 71, 78, ..., 92, 29, 23],\n",
    +       "          [19, 56, 11, ..., 34, 30, 82],\n",
            "          ...,\n",
    -       "          [18, 62, 84, ..., 12, 87, 52],\n",
    -       "          [42, 79, 90, ...,  5, 24, 57],\n",
    -       "          [51, 35, 71, ..., 55, 29, 11]]]]])\n",
    +       "          [86, 83, 55, ..., 66, 67, 17],\n",
    +       "          [27, 19, 10, ..., 42, 55, 73],\n",
    +       "          [11, 25, 62, ..., 40, 84, 95]]]]])\n",
            "Coordinates:\n",
            "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
            "  * day          (day) datetime64[ns] 2015-01-01 2015-01-02 ... 2015-04-10\n",
    @@ -1519,48 +1519,48 @@
            "  * origin       (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n",
            "  * destination  (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n",
            "Indexes:\n",
    -       "    origin       ShapelySTRTreeIndex\n",
    -       "    destination  ShapelySTRTreeIndex
  • " ], "text/plain": [ "\n", - "array([[[[[96, 29, 64, ..., 47, 80, 71],\n", - " [79, 79, 96, ..., 92, 12, 90],\n", - " [19, 85, 60, ..., 43, 28, 53],\n", + "array([[[[[ 3, 20, 86, ..., 47, 18, 4],\n", + " [60, 27, 15, ..., 54, 1, 23],\n", + " [65, 21, 14, ..., 70, 97, 71],\n", " ...,\n", - " [96, 8, 35, ..., 39, 7, 62],\n", - " [82, 87, 18, ..., 1, 77, 38],\n", - " [99, 94, 20, ..., 92, 16, 42]],\n", + " [75, 34, 41, ..., 79, 7, 68],\n", + " [31, 64, 18, ..., 44, 9, 37],\n", + " [35, 71, 59, ..., 66, 71, 1]],\n", "\n", - " [[79, 53, 28, ..., 30, 56, 14],\n", - " [21, 88, 91, ..., 92, 73, 14],\n", - " [74, 49, 88, ..., 30, 23, 28],\n", + " [[ 8, 54, 27, ..., 79, 20, 93],\n", + " [ 9, 94, 80, ..., 69, 25, 78],\n", + " [78, 86, 59, ..., 24, 68, 13],\n", " ...,\n", - " [56, 76, 91, ..., 36, 94, 16],\n", - " [80, 83, 4, ..., 91, 38, 3],\n", - " [69, 61, 10, ..., 79, 15, 94]],\n", + " [92, 73, 72, ..., 55, 75, 86],\n", + " [39, 40, 55, ..., 63, 24, 64],\n", + " [63, 85, 17, ..., 44, 75, 68]],\n", "\n", - " [[91, 22, 13, ..., 45, 31, 17],\n", - " [86, 48, 23, ..., 88, 55, 94],\n", - " [56, 8, 55, ..., 68, 15, 48],\n", + " [[24, 54, 24, ..., 99, 40, 89],\n", + " [32, 39, 46, ..., 38, 21, 3],\n", + " [39, 63, 90, ..., 54, 5, 84],\n", " ...,\n", "...\n", " ...,\n", - " [27, 8, 29, ..., 96, 80, 60],\n", - " [ 1, 98, 63, ..., 1, 73, 98],\n", - " [77, 22, 88, ..., 6, 60, 7]],\n", + " [91, 56, 61, ..., 91, 73, 25],\n", + " [37, 91, 54, ..., 47, 72, 37],\n", + " [72, 81, 93, ..., 59, 84, 68]],\n", "\n", - " [[22, 40, 31, ..., 84, 62, 61],\n", - " [27, 83, 95, ..., 81, 15, 54],\n", - " [43, 45, 67, ..., 52, 2, 28],\n", + " [[59, 76, 62, ..., 84, 38, 60],\n", + " [11, 41, 61, ..., 70, 50, 98],\n", + " [66, 59, 55, ..., 19, 21, 86],\n", " ...,\n", - " [91, 75, 49, ..., 1, 76, 65],\n", - " [ 4, 78, 43, ..., 82, 20, 95],\n", - " [16, 65, 36, ..., 27, 92, 43]],\n", + " [41, 49, 95, ..., 28, 87, 23],\n", + " [25, 52, 4, ..., 18, 78, 90],\n", + " [93, 1, 48, ..., 22, 48, 45]],\n", "\n", - " [[11, 54, 89, ..., 64, 56, 78],\n", - " [ 1, 29, 49, ..., 46, 22, 95],\n", - " [99, 4, 33, ..., 89, 48, 60],\n", + " [[96, 94, 67, ..., 72, 32, 20],\n", + " [59, 71, 78, ..., 92, 29, 23],\n", + " [19, 56, 11, ..., 34, 30, 82],\n", " ...,\n", - " [18, 62, 84, ..., 12, 87, 52],\n", - " [42, 79, 90, ..., 5, 24, 57],\n", - " [51, 35, 71, ..., 55, 29, 11]]]]])\n", + " [86, 83, 55, ..., 66, 67, 17],\n", + " [27, 19, 10, ..., 42, 55, 73],\n", + " [11, 25, 62, ..., 40, 84, 95]]]]])\n", "Coordinates:\n", " * mode (mode)
    <xarray.DataArray (mode: 3, origin: 2, destination: 2)>\n",
    -       "array([[[14, 88],\n",
    -       "        [ 9, 22]],\n",
    +       "array([[[40, 72],\n",
    +       "        [95, 66]],\n",
            "\n",
    -       "       [[99, 46],\n",
    -       "        [25, 62]],\n",
    +       "       [[66, 79],\n",
    +       "        [81, 33]],\n",
            "\n",
    -       "       [[20, 54],\n",
    -       "        [44, 17]]])\n",
    +       "       [[80, 42],\n",
    +       "        [56, 11]]])\n",
            "Coordinates:\n",
            "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
            "    day          datetime64[ns] 2015-01-01\n",
            "    time         int64 0\n",
    -       "    origin       (origin) object MULTIPOLYGON (((-79.91995239257812 34.807918...\n",
    -       "    destination  (destination) object MULTIPOLYGON (((-80.72651672363281 35.5...
    • mode
      PandasIndex
      PandasIndex(Index(['car', 'bike', 'foot'], dtype='object', name='mode'))
    • origin
      GeoVectorIndex(crs=EPSG:4267)
      <xvec.index.GeoVectorIndex object at 0x16311a390>
    • destination
      GeoVectorIndex(crs=EPSG:4267)
      <xvec.index.GeoVectorIndex object at 0x16311d1d0>
  • " ], "text/plain": [ "\n", - "array([[[14, 88],\n", - " [ 9, 22]],\n", + "array([[[40, 72],\n", + " [95, 66]],\n", "\n", - " [[99, 46],\n", - " [25, 62]],\n", + " [[66, 79],\n", + " [81, 33]],\n", "\n", - " [[20, 54],\n", - " [44, 17]]])\n", + " [[80, 42],\n", + " [56, 11]]])\n", "Coordinates:\n", " * mode (mode)
    <xarray.DataArray (mode: 3, day: 100, time: 24, origin: 41, destination: 100)>\n",
    -       "array([[[[[41, 61, 90, ..., 86, 69, 39],\n",
    -       "          [38, 45, 93, ..., 95, 53, 80],\n",
    -       "          [53, 31,  5, ..., 74, 48, 96],\n",
    +       "array([[[[[63,  4, 52, ..., 94, 53, 42],\n",
    +       "          [60, 43, 49, ..., 98, 60, 21],\n",
    +       "          [60, 58, 57, ..., 46, 75, 81],\n",
            "          ...,\n",
    -       "          [98, 48, 42, ..., 41, 81, 69],\n",
    -       "          [87, 18, 10, ..., 97, 15, 33],\n",
    -       "          [38, 68, 19, ..., 71,  9, 70]],\n",
    +       "          [82,  6, 34, ..., 72, 90, 61],\n",
    +       "          [87, 53, 91, ..., 80, 47, 39],\n",
    +       "          [24, 77, 60, ...,  3, 95, 81]],\n",
            "\n",
    -       "         [[30,  3, 51, ..., 60, 70,  6],\n",
    -       "          [40,  3, 36, ..., 32, 22, 32],\n",
    -       "          [74,  8, 25, ..., 91, 65, 71],\n",
    +       "         [[84, 17, 14, ..., 78, 62, 16],\n",
    +       "          [82, 90, 50, ..., 70, 78, 60],\n",
    +       "          [57, 43, 52, ...,  5, 15, 11],\n",
            "          ...,\n",
    -       "          [72, 63, 10, ..., 54, 84, 63],\n",
    -       "          [12, 77, 74, ..., 10, 30, 32],\n",
    -       "          [27, 73, 36, ..., 63, 16, 57]],\n",
    +       "          [58, 55, 49, ..., 99, 88, 42],\n",
    +       "          [ 2, 47, 44, ..., 78, 25, 75],\n",
    +       "          [10,  8, 35, ..., 26, 60, 50]],\n",
            "\n",
    -       "         [[68, 46, 26, ..., 71, 71, 33],\n",
    -       "          [21, 92, 65, ..., 94, 44, 88],\n",
    -       "          [62, 13, 97, ..., 10, 42,  2],\n",
    +       "         [[46, 29, 56, ..., 65, 28, 10],\n",
    +       "          [67, 50, 25, ..., 30, 18, 60],\n",
    +       "          [45, 87, 92, ..., 19, 41, 79],\n",
            "          ...,\n",
            "...\n",
            "          ...,\n",
    -       "          [53, 77, 85, ...,  9, 56, 44],\n",
    -       "          [17, 72, 69, ..., 34, 63, 43],\n",
    -       "          [17,  3,  1, ..., 40, 55, 74]],\n",
    +       "          [30, 28, 32, ...,  4, 11, 23],\n",
    +       "          [92, 91, 99, ..., 79, 56, 52],\n",
    +       "          [10, 94, 41, ...,  8, 26, 88]],\n",
            "\n",
    -       "         [[ 1, 27, 55, ..., 74, 12, 45],\n",
    -       "          [88, 31, 98, ..., 24,  4, 54],\n",
    -       "          [25, 94, 82, ..., 44,  6, 42],\n",
    +       "         [[27, 89, 88, ..., 96, 13, 41],\n",
    +       "          [25, 36, 66, ..., 91, 92, 45],\n",
    +       "          [13, 94, 11, ..., 94, 22, 83],\n",
            "          ...,\n",
    -       "          [97, 21, 97, ..., 25, 99, 15],\n",
    -       "          [49, 44,  3, ..., 83, 13, 14],\n",
    -       "          [57, 69, 97, ..., 27, 32, 77]],\n",
    +       "          [53, 51, 69, ..., 27, 17, 89],\n",
    +       "          [37, 14, 40, ..., 46, 46, 93],\n",
    +       "          [89, 15,  9, ..., 46, 49, 71]],\n",
            "\n",
    -       "         [[76, 34, 34, ..., 62, 81, 11],\n",
    -       "          [59, 57, 36, ..., 86, 47, 48],\n",
    -       "          [71, 58, 18, ..., 26, 33, 70],\n",
    +       "         [[70, 43, 47, ..., 99, 28, 59],\n",
    +       "          [35, 68, 47, ..., 91,  1, 38],\n",
    +       "          [90, 12, 13, ..., 54, 55, 69],\n",
            "          ...,\n",
    -       "          [55,  9, 44, ..., 63, 60,  5],\n",
    -       "          [44, 28,  3, ..., 61, 81,  9],\n",
    -       "          [51, 19,  7, ..., 39, 92, 50]]]]])\n",
    +       "          [93, 27, 67, ..., 96, 80, 67],\n",
    +       "          [16,  9, 21, ..., 53, 59, 72],\n",
    +       "          [14, 67, 89, ..., 22, 23, 36]]]]])\n",
            "Coordinates:\n",
            "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
            "  * day          (day) datetime64[ns] 2015-01-01 2015-01-02 ... 2015-04-10\n",
            "  * time         (time) int64 0 1 2 3 4 5 6 7 8 9 ... 15 16 17 18 19 20 21 22 23\n",
    -       "    origin       (origin) object MULTIPOLYGON (((-78.11376953125 34.720985412...\n",
    +       "  * origin       (origin) object MULTIPOLYGON (((-78.11376953125 34.720985412...\n",
            "  * destination  (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n",
            "Indexes:\n",
    -       "    destination  ShapelySTRTreeIndex
  • " ], "text/plain": [ "\n", - "array([[[[[41, 61, 90, ..., 86, 69, 39],\n", - " [38, 45, 93, ..., 95, 53, 80],\n", - " [53, 31, 5, ..., 74, 48, 96],\n", + "array([[[[[63, 4, 52, ..., 94, 53, 42],\n", + " [60, 43, 49, ..., 98, 60, 21],\n", + " [60, 58, 57, ..., 46, 75, 81],\n", " ...,\n", - " [98, 48, 42, ..., 41, 81, 69],\n", - " [87, 18, 10, ..., 97, 15, 33],\n", - " [38, 68, 19, ..., 71, 9, 70]],\n", + " [82, 6, 34, ..., 72, 90, 61],\n", + " [87, 53, 91, ..., 80, 47, 39],\n", + " [24, 77, 60, ..., 3, 95, 81]],\n", "\n", - " [[30, 3, 51, ..., 60, 70, 6],\n", - " [40, 3, 36, ..., 32, 22, 32],\n", - " [74, 8, 25, ..., 91, 65, 71],\n", + " [[84, 17, 14, ..., 78, 62, 16],\n", + " [82, 90, 50, ..., 70, 78, 60],\n", + " [57, 43, 52, ..., 5, 15, 11],\n", " ...,\n", - " [72, 63, 10, ..., 54, 84, 63],\n", - " [12, 77, 74, ..., 10, 30, 32],\n", - " [27, 73, 36, ..., 63, 16, 57]],\n", + " [58, 55, 49, ..., 99, 88, 42],\n", + " [ 2, 47, 44, ..., 78, 25, 75],\n", + " [10, 8, 35, ..., 26, 60, 50]],\n", "\n", - " [[68, 46, 26, ..., 71, 71, 33],\n", - " [21, 92, 65, ..., 94, 44, 88],\n", - " [62, 13, 97, ..., 10, 42, 2],\n", + " [[46, 29, 56, ..., 65, 28, 10],\n", + " [67, 50, 25, ..., 30, 18, 60],\n", + " [45, 87, 92, ..., 19, 41, 79],\n", " ...,\n", "...\n", " ...,\n", - " [53, 77, 85, ..., 9, 56, 44],\n", - " [17, 72, 69, ..., 34, 63, 43],\n", - " [17, 3, 1, ..., 40, 55, 74]],\n", + " [30, 28, 32, ..., 4, 11, 23],\n", + " [92, 91, 99, ..., 79, 56, 52],\n", + " [10, 94, 41, ..., 8, 26, 88]],\n", "\n", - " [[ 1, 27, 55, ..., 74, 12, 45],\n", - " [88, 31, 98, ..., 24, 4, 54],\n", - " [25, 94, 82, ..., 44, 6, 42],\n", + " [[27, 89, 88, ..., 96, 13, 41],\n", + " [25, 36, 66, ..., 91, 92, 45],\n", + " [13, 94, 11, ..., 94, 22, 83],\n", " ...,\n", - " [97, 21, 97, ..., 25, 99, 15],\n", - " [49, 44, 3, ..., 83, 13, 14],\n", - " [57, 69, 97, ..., 27, 32, 77]],\n", + " [53, 51, 69, ..., 27, 17, 89],\n", + " [37, 14, 40, ..., 46, 46, 93],\n", + " [89, 15, 9, ..., 46, 49, 71]],\n", "\n", - " [[76, 34, 34, ..., 62, 81, 11],\n", - " [59, 57, 36, ..., 86, 47, 48],\n", - " [71, 58, 18, ..., 26, 33, 70],\n", + " [[70, 43, 47, ..., 99, 28, 59],\n", + " [35, 68, 47, ..., 91, 1, 38],\n", + " [90, 12, 13, ..., 54, 55, 69],\n", " ...,\n", - " [55, 9, 44, ..., 63, 60, 5],\n", - " [44, 28, 3, ..., 61, 81, 9],\n", - " [51, 19, 7, ..., 39, 92, 50]]]]])\n", + " [93, 27, 67, ..., 96, 80, 67],\n", + " [16, 9, 21, ..., 53, 59, 72],\n", + " [14, 67, 89, ..., 22, 23, 36]]]]])\n", "Coordinates:\n", " * mode (mode) 1\u001b[0m \u001b[43marr\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msel\u001b[49m\u001b[43m(\u001b[49m\u001b[43morigin\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[43mshapely\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mPoint\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m80\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m35\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mshapely\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mPoint\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m76\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m35.6\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mintersects\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/miniconda3/envs/xvec_dev/lib/python3.11/site-packages/xarray/core/dataarray.py:1526\u001b[0m, in \u001b[0;36mDataArray.sel\u001b[0;34m(self, indexers, method, tolerance, drop, **indexers_kwargs)\u001b[0m\n\u001b[1;32m 1416\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21msel\u001b[39m(\n\u001b[1;32m 1417\u001b[0m \u001b[38;5;28mself\u001b[39m: T_DataArray,\n\u001b[1;32m 1418\u001b[0m indexers: Mapping[Any, Any] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1422\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mindexers_kwargs: Any,\n\u001b[1;32m 1423\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m T_DataArray:\n\u001b[1;32m 1424\u001b[0m \u001b[38;5;124;03m\"\"\"Return a new DataArray whose data is given by selecting index\u001b[39;00m\n\u001b[1;32m 1425\u001b[0m \u001b[38;5;124;03m labels along the specified dimension(s).\u001b[39;00m\n\u001b[1;32m 1426\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1524\u001b[0m \u001b[38;5;124;03m Dimensions without coordinates: points\u001b[39;00m\n\u001b[1;32m 1525\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m-> 1526\u001b[0m ds \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_to_temp_dataset\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msel\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1527\u001b[0m \u001b[43m \u001b[49m\u001b[43mindexers\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mindexers\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1528\u001b[0m \u001b[43m \u001b[49m\u001b[43mdrop\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdrop\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1529\u001b[0m \u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1530\u001b[0m \u001b[43m \u001b[49m\u001b[43mtolerance\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtolerance\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1531\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mindexers_kwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1532\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1533\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_from_temp_dataset(ds)\n", + "File \u001b[0;32m~/miniconda3/envs/xvec_dev/lib/python3.11/site-packages/xarray/core/dataset.py:2554\u001b[0m, in \u001b[0;36mDataset.sel\u001b[0;34m(self, indexers, method, tolerance, drop, **indexers_kwargs)\u001b[0m\n\u001b[1;32m 2493\u001b[0m \u001b[38;5;124;03m\"\"\"Returns a new dataset with each array indexed by tick labels\u001b[39;00m\n\u001b[1;32m 2494\u001b[0m \u001b[38;5;124;03malong the specified dimension(s).\u001b[39;00m\n\u001b[1;32m 2495\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 2551\u001b[0m \u001b[38;5;124;03mDataArray.sel\u001b[39;00m\n\u001b[1;32m 2552\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 2553\u001b[0m indexers \u001b[38;5;241m=\u001b[39m either_dict_or_kwargs(indexers, indexers_kwargs, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msel\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m-> 2554\u001b[0m query_results \u001b[38;5;241m=\u001b[39m \u001b[43mmap_index_queries\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 2555\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mindexers\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mindexers\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtolerance\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtolerance\u001b[49m\n\u001b[1;32m 2556\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2558\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m drop:\n\u001b[1;32m 2559\u001b[0m no_scalar_variables \u001b[38;5;241m=\u001b[39m {}\n", + "File \u001b[0;32m~/miniconda3/envs/xvec_dev/lib/python3.11/site-packages/xarray/core/indexing.py:183\u001b[0m, in \u001b[0;36mmap_index_queries\u001b[0;34m(obj, indexers, method, tolerance, **indexers_kwargs)\u001b[0m\n\u001b[1;32m 181\u001b[0m results\u001b[38;5;241m.\u001b[39mappend(IndexSelResult(labels))\n\u001b[1;32m 182\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 183\u001b[0m results\u001b[38;5;241m.\u001b[39mappend(\u001b[43mindex\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msel\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43moptions\u001b[49m\u001b[43m)\u001b[49m) \u001b[38;5;66;03m# type: ignore[call-arg]\u001b[39;00m\n\u001b[1;32m 185\u001b[0m merged \u001b[38;5;241m=\u001b[39m merge_sel_results(results)\n\u001b[1;32m 187\u001b[0m \u001b[38;5;66;03m# drop dimension coordinates found in dimension indexers\u001b[39;00m\n\u001b[1;32m 188\u001b[0m \u001b[38;5;66;03m# (also drop multi-index if any)\u001b[39;00m\n\u001b[1;32m 189\u001b[0m \u001b[38;5;66;03m# (.sel() already ensures alignment)\u001b[39;00m\n", + "File \u001b[0;32m~/Git/github/benbovy/xvec/xvec/index.py:136\u001b[0m, in \u001b[0;36mGeoVectorIndex.sel\u001b[0;34m(self, labels, method, tolerance)\u001b[0m\n\u001b[1;32m 129\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_index\u001b[38;5;241m.\u001b[39msel(labels)\n\u001b[1;32m 130\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 131\u001b[0m \u001b[38;5;66;03m# We reuse here `method` and `tolerance` options of\u001b[39;00m\n\u001b[1;32m 132\u001b[0m \u001b[38;5;66;03m# `xarray.indexes.PandasIndex` as `predicate` and `distance`\u001b[39;00m\n\u001b[1;32m 133\u001b[0m \u001b[38;5;66;03m# options when `labels` is a single geometry.\u001b[39;00m\n\u001b[1;32m 134\u001b[0m \u001b[38;5;66;03m# Xarray currently doesn't support custom options\u001b[39;00m\n\u001b[1;32m 135\u001b[0m \u001b[38;5;66;03m# (see https://github.com/pydata/xarray/issues/7099)\u001b[39;00m\n\u001b[0;32m--> 136\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_sel_sindex\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtolerance\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Git/github/benbovy/xvec/xvec/index.py:93\u001b[0m, in \u001b[0;36mGeoVectorIndex._sel_sindex\u001b[0;34m(self, labels, method, tolerance)\u001b[0m\n\u001b[1;32m 91\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m method \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m method \u001b[38;5;241m!=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnearest\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m 92\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(label, shapely\u001b[38;5;241m.\u001b[39mGeometry):\n\u001b[0;32m---> 93\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 94\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mselection with another method than nearest only supports \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 95\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124ma single geometry as input label.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 96\u001b[0m )\n\u001b[1;32m 98\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(label, DataArray):\n\u001b[1;32m 99\u001b[0m label_array \u001b[38;5;241m=\u001b[39m label\u001b[38;5;241m.\u001b[39m_variable\u001b[38;5;241m.\u001b[39m_data\n", + "\u001b[0;31mValueError\u001b[0m: selection with another method than nearest only supports a single geometry as input label." + ] + } + ], + "source": [ + "arr.sel(origin=[shapely.Point(-80, 35), shapely.Point(-76, 35.6)], method=\"intersects\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Other operations like `isel`, `concat` and alignment work just like with any default (pandas) index:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, "outputs": [ { "data": { @@ -3539,97 +3579,97 @@ " stroke: currentColor;\n", " fill: currentColor;\n", "}\n", - "
    <xarray.DataArray (mode: 3, day: 100, time: 24, points: 2, destination: 100)>\n",
    -       "array([[[[[31, 69, 46, ..., 85, 87, 41],\n",
    -       "          [63, 34, 15, ..., 62, 36, 23]],\n",
    +       "
    <xarray.DataArray (mode: 3, day: 100, time: 24, origin: 2, destination: 2)>\n",
    +       "array([[[[[ 36,   8],\n",
    +       "          [  2,  46]],\n",
            "\n",
    -       "         [[79, 46, 26, ..., 75, 89, 12],\n",
    -       "          [99, 67, 18, ..., 93, 63,  9]],\n",
    +       "         [[ 40, 186],\n",
    +       "          [ 50, 156]],\n",
            "\n",
    -       "         [[ 7, 22, 63, ..., 78, 89, 64],\n",
    -       "          [60, 33, 13, ..., 39, 54, 33]],\n",
    +       "         [[ 80, 178],\n",
    +       "          [ 42,   6]],\n",
            "\n",
            "         ...,\n",
            "\n",
    -       "         [[22, 59, 96, ..., 54, 84, 18],\n",
    -       "          [39, 52, 31, ..., 40, 45, 43]],\n",
    +       "         [[192,  20],\n",
    +       "          [ 78,  68]],\n",
            "\n",
    -       "         [[15, 37, 54, ..., 30,  2, 57],\n",
    -       "          [29, 90,  1, ..., 60, 21, 29]],\n",
    +       "         [[ 58, 102],\n",
    +       "          [112,  90]],\n",
            "\n",
    -       "         [[97, 47, 98, ..., 29, 76, 77],\n",
    -       "          [43, 42, 23, ..., 68, 56, 42]]],\n",
    +       "         [[ 62, 106],\n",
    +       "          [138,  64]]],\n",
            "\n",
            "...\n",
            "\n",
    -       "        [[[53, 70, 33, ...,  6, 78, 35],\n",
    -       "          [62, 58, 58, ..., 35, 88, 12]],\n",
    +       "        [[[  4, 166],\n",
    +       "          [146,  80]],\n",
            "\n",
    -       "         [[27, 77,  3, ..., 62, 44, 34],\n",
    -       "          [95, 88, 66, ..., 67, 63, 83]],\n",
    +       "         [[ 70, 166],\n",
    +       "          [138, 166]],\n",
            "\n",
    -       "         [[43, 78, 66, ..., 22, 16, 56],\n",
    -       "          [15, 82, 12, ..., 20, 26, 43]],\n",
    +       "         [[128, 108],\n",
    +       "          [150, 178]],\n",
            "\n",
            "         ...,\n",
            "\n",
    -       "         [[ 6, 65, 35, ..., 46, 17, 12],\n",
    -       "          [21, 22, 69, ..., 45, 58, 11]],\n",
    +       "         [[186,  68],\n",
    +       "          [ 58, 132]],\n",
            "\n",
    -       "         [[75, 78, 24, ..., 13, 37, 66],\n",
    -       "          [12, 90, 93, ..., 17, 52, 47]],\n",
    +       "         [[ 76, 120],\n",
    +       "          [100, 196]],\n",
            "\n",
    -       "         [[49, 62, 62, ..., 74, 70, 19],\n",
    -       "          [32,  8, 19, ..., 79, 16, 87]]]]])\n",
    +       "         [[ 64,  40],\n",
    +       "          [ 58,  46]]]]])\n",
            "Coordinates:\n",
            "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
            "  * day          (day) datetime64[ns] 2015-01-01 2015-01-02 ... 2015-04-10\n",
            "  * time         (time) int64 0 1 2 3 4 5 6 7 8 9 ... 15 16 17 18 19 20 21 22 23\n",
    -       "    origin       (points) object MULTIPOLYGON (((-79.91995239257812 34.807918...\n",
    -       "  * destination  (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n",
    -       "Dimensions without coordinates: points\n",
    +       "  * origin       (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n",
    +       "  * destination  (destination) object MULTIPOLYGON (((-77.96073150634766 34.1...\n",
            "Indexes:\n",
    -       "    destination  ShapelySTRTreeIndex
  • origin
    GeoVectorIndex(crs=EPSG:4267)
    <xvec.index.GeoVectorIndex object at 0x16afdd710>
  • destination
    GeoVectorIndex(crs=EPSG:4267)
    <xvec.index.GeoVectorIndex object at 0x16304f9d0>
  • " ], "text/plain": [ - "\n", - "array([[[[[31, 69, 46, ..., 85, 87, 41],\n", - " [63, 34, 15, ..., 62, 36, 23]],\n", + "\n", + "array([[[[[ 36, 8],\n", + " [ 2, 46]],\n", "\n", - " [[79, 46, 26, ..., 75, 89, 12],\n", - " [99, 67, 18, ..., 93, 63, 9]],\n", + " [[ 40, 186],\n", + " [ 50, 156]],\n", "\n", - " [[ 7, 22, 63, ..., 78, 89, 64],\n", - " [60, 33, 13, ..., 39, 54, 33]],\n", + " [[ 80, 178],\n", + " [ 42, 6]],\n", "\n", " ...,\n", "\n", - " [[22, 59, 96, ..., 54, 84, 18],\n", - " [39, 52, 31, ..., 40, 45, 43]],\n", + " [[192, 20],\n", + " [ 78, 68]],\n", "\n", - " [[15, 37, 54, ..., 30, 2, 57],\n", - " [29, 90, 1, ..., 60, 21, 29]],\n", + " [[ 58, 102],\n", + " [112, 90]],\n", "\n", - " [[97, 47, 98, ..., 29, 76, 77],\n", - " [43, 42, 23, ..., 68, 56, 42]]],\n", + " [[ 62, 106],\n", + " [138, 64]]],\n", "\n", "...\n", "\n", - " [[[53, 70, 33, ..., 6, 78, 35],\n", - " [62, 58, 58, ..., 35, 88, 12]],\n", + " [[[ 4, 166],\n", + " [146, 80]],\n", "\n", - " [[27, 77, 3, ..., 62, 44, 34],\n", - " [95, 88, 66, ..., 67, 63, 83]],\n", + " [[ 70, 166],\n", + " [138, 166]],\n", "\n", - " [[43, 78, 66, ..., 22, 16, 56],\n", - " [15, 82, 12, ..., 20, 26, 43]],\n", + " [[128, 108],\n", + " [150, 178]],\n", "\n", " ...,\n", "\n", - " [[ 6, 65, 35, ..., 46, 17, 12],\n", - " [21, 22, 69, ..., 45, 58, 11]],\n", + " [[186, 68],\n", + " [ 58, 132]],\n", "\n", - " [[75, 78, 24, ..., 13, 37, 66],\n", - " [12, 90, 93, ..., 17, 52, 47]],\n", + " [[ 76, 120],\n", + " [100, 196]],\n", "\n", - " [[49, 62, 62, ..., 74, 70, 19],\n", - " [32, 8, 19, ..., 79, 16, 87]]]]])\n", + " [[ 64, 40],\n", + " [ 58, 46]]]]])\n", "Coordinates:\n", " * mode (mode) 1\u001b[0m arr\u001b[39m.\u001b[39;49msel(origin\u001b[39m=\u001b[39;49m[shapely\u001b[39m.\u001b[39;49mPoint(\u001b[39m-\u001b[39;49m\u001b[39m80\u001b[39;49m, \u001b[39m35\u001b[39;49m), shapely\u001b[39m.\u001b[39;49mPoint(\u001b[39m-\u001b[39;49m\u001b[39m76\u001b[39;49m, \u001b[39m35.6\u001b[39;49m)], method\u001b[39m=\u001b[39;49m\u001b[39m\"\u001b[39;49m\u001b[39mintersects\u001b[39;49m\u001b[39m\"\u001b[39;49m)\n", - "File \u001b[0;32m~/mambaforge/envs/xvec_dev/lib/python3.10/site-packages/xarray/core/dataarray.py:1526\u001b[0m, in \u001b[0;36mDataArray.sel\u001b[0;34m(self, indexers, method, tolerance, drop, **indexers_kwargs)\u001b[0m\n\u001b[1;32m 1416\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39msel\u001b[39m(\n\u001b[1;32m 1417\u001b[0m \u001b[39mself\u001b[39m: T_DataArray,\n\u001b[1;32m 1418\u001b[0m indexers: Mapping[Any, Any] \u001b[39m=\u001b[39m \u001b[39mNone\u001b[39;00m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1422\u001b[0m \u001b[39m*\u001b[39m\u001b[39m*\u001b[39mindexers_kwargs: Any,\n\u001b[1;32m 1423\u001b[0m ) \u001b[39m-\u001b[39m\u001b[39m>\u001b[39m T_DataArray:\n\u001b[1;32m 1424\u001b[0m \u001b[39m\"\"\"Return a new DataArray whose data is given by selecting index\u001b[39;00m\n\u001b[1;32m 1425\u001b[0m \u001b[39m labels along the specified dimension(s).\u001b[39;00m\n\u001b[1;32m 1426\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1524\u001b[0m \u001b[39m Dimensions without coordinates: points\u001b[39;00m\n\u001b[1;32m 1525\u001b[0m \u001b[39m \"\"\"\u001b[39;00m\n\u001b[0;32m-> 1526\u001b[0m ds \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_to_temp_dataset()\u001b[39m.\u001b[39;49msel(\n\u001b[1;32m 1527\u001b[0m indexers\u001b[39m=\u001b[39;49mindexers,\n\u001b[1;32m 1528\u001b[0m drop\u001b[39m=\u001b[39;49mdrop,\n\u001b[1;32m 1529\u001b[0m method\u001b[39m=\u001b[39;49mmethod,\n\u001b[1;32m 1530\u001b[0m tolerance\u001b[39m=\u001b[39;49mtolerance,\n\u001b[1;32m 1531\u001b[0m \u001b[39m*\u001b[39;49m\u001b[39m*\u001b[39;49mindexers_kwargs,\n\u001b[1;32m 1532\u001b[0m )\n\u001b[1;32m 1533\u001b[0m \u001b[39mreturn\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_from_temp_dataset(ds)\n", - "File \u001b[0;32m~/mambaforge/envs/xvec_dev/lib/python3.10/site-packages/xarray/core/dataset.py:2554\u001b[0m, in \u001b[0;36mDataset.sel\u001b[0;34m(self, indexers, method, tolerance, drop, **indexers_kwargs)\u001b[0m\n\u001b[1;32m 2493\u001b[0m \u001b[39m\"\"\"Returns a new dataset with each array indexed by tick labels\u001b[39;00m\n\u001b[1;32m 2494\u001b[0m \u001b[39malong the specified dimension(s).\u001b[39;00m\n\u001b[1;32m 2495\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 2551\u001b[0m \u001b[39mDataArray.sel\u001b[39;00m\n\u001b[1;32m 2552\u001b[0m \u001b[39m\"\"\"\u001b[39;00m\n\u001b[1;32m 2553\u001b[0m indexers \u001b[39m=\u001b[39m either_dict_or_kwargs(indexers, indexers_kwargs, \u001b[39m\"\u001b[39m\u001b[39msel\u001b[39m\u001b[39m\"\u001b[39m)\n\u001b[0;32m-> 2554\u001b[0m query_results \u001b[39m=\u001b[39m map_index_queries(\n\u001b[1;32m 2555\u001b[0m \u001b[39mself\u001b[39;49m, indexers\u001b[39m=\u001b[39;49mindexers, method\u001b[39m=\u001b[39;49mmethod, tolerance\u001b[39m=\u001b[39;49mtolerance\n\u001b[1;32m 2556\u001b[0m )\n\u001b[1;32m 2558\u001b[0m \u001b[39mif\u001b[39;00m drop:\n\u001b[1;32m 2559\u001b[0m no_scalar_variables \u001b[39m=\u001b[39m {}\n", - "File \u001b[0;32m~/mambaforge/envs/xvec_dev/lib/python3.10/site-packages/xarray/core/indexing.py:183\u001b[0m, in \u001b[0;36mmap_index_queries\u001b[0;34m(obj, indexers, method, tolerance, **indexers_kwargs)\u001b[0m\n\u001b[1;32m 181\u001b[0m results\u001b[39m.\u001b[39mappend(IndexSelResult(labels))\n\u001b[1;32m 182\u001b[0m \u001b[39melse\u001b[39;00m:\n\u001b[0;32m--> 183\u001b[0m results\u001b[39m.\u001b[39mappend(index\u001b[39m.\u001b[39;49msel(labels, \u001b[39m*\u001b[39;49m\u001b[39m*\u001b[39;49moptions)) \u001b[39m# type: ignore[call-arg]\u001b[39;00m\n\u001b[1;32m 185\u001b[0m merged \u001b[39m=\u001b[39m merge_sel_results(results)\n\u001b[1;32m 187\u001b[0m \u001b[39m# drop dimension coordinates found in dimension indexers\u001b[39;00m\n\u001b[1;32m 188\u001b[0m \u001b[39m# (also drop multi-index if any)\u001b[39;00m\n\u001b[1;32m 189\u001b[0m \u001b[39m# (.sel() already ensures alignment)\u001b[39;00m\n", - "File \u001b[0;32m~/Git/xvec/xvec/strtree.py:40\u001b[0m, in \u001b[0;36mShapelySTRTreeIndex.sel\u001b[0;34m(self, labels, method, tolerance)\u001b[0m\n\u001b[1;32m 38\u001b[0m \u001b[39mif\u001b[39;00m method \u001b[39mis\u001b[39;00m \u001b[39mnot\u001b[39;00m \u001b[39mNone\u001b[39;00m \u001b[39mand\u001b[39;00m method \u001b[39m!=\u001b[39m \u001b[39m\"\u001b[39m\u001b[39mnearest\u001b[39m\u001b[39m\"\u001b[39m:\n\u001b[1;32m 39\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mnot\u001b[39;00m \u001b[39misinstance\u001b[39m(label, shapely\u001b[39m.\u001b[39mGeometry):\n\u001b[0;32m---> 40\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mValueError\u001b[39;00m(\n\u001b[1;32m 41\u001b[0m \u001b[39m\"\u001b[39m\u001b[39mselection with another method than nearest only supports \u001b[39m\u001b[39m\"\u001b[39m\n\u001b[1;32m 42\u001b[0m \u001b[39m\"\u001b[39m\u001b[39ma single geometry as input label.\u001b[39m\u001b[39m\"\u001b[39m\n\u001b[1;32m 43\u001b[0m )\n\u001b[1;32m 45\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39misinstance\u001b[39m(label, xarray\u001b[39m.\u001b[39mDataArray):\n\u001b[1;32m 46\u001b[0m label_array \u001b[39m=\u001b[39m label\u001b[39m.\u001b[39m_variable\u001b[39m.\u001b[39m_data\n", - "\u001b[0;31mValueError\u001b[0m: selection with another method than nearest only supports a single geometry as input label." - ] - } - ], - "source": [ - "arr.sel(origin=[shapely.Point(-80, 35), shapely.Point(-76, 35.6)], method=\"intersects\")" - ] + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
    <xarray.DataArray (mode: 3, day: 100, time: 24, origin: 4, destination: 100)>\n",
    +       "array([[[[[ 3, 20, 86, ..., 47, 18,  4],\n",
    +       "          [60, 27, 15, ..., 54,  1, 23],\n",
    +       "          [31, 64, 18, ..., 44,  9, 37],\n",
    +       "          [35, 71, 59, ..., 66, 71,  1]],\n",
    +       "\n",
    +       "         [[ 8, 54, 27, ..., 79, 20, 93],\n",
    +       "          [ 9, 94, 80, ..., 69, 25, 78],\n",
    +       "          [39, 40, 55, ..., 63, 24, 64],\n",
    +       "          [63, 85, 17, ..., 44, 75, 68]],\n",
    +       "\n",
    +       "         [[24, 54, 24, ..., 99, 40, 89],\n",
    +       "          [32, 39, 46, ..., 38, 21,  3],\n",
    +       "          [55, 69, 74, ..., 54, 53, 68],\n",
    +       "          [30, 21, 44, ..., 36, 31, 62]],\n",
    +       "\n",
    +       "         ...,\n",
    +       "\n",
    +       "         [[38, 39, 62, ..., 80, 96, 10],\n",
    +       "          [39, 92, 83, ..., 50, 39, 34],\n",
    +       "          [70, 31, 68, ..., 91, 32, 15],\n",
    +       "...\n",
    +       "          [67,  4, 40, ..., 36, 75, 89],\n",
    +       "          [ 8, 27, 47, ..., 46, 60,  6],\n",
    +       "          [94,  4, 66, ...,  1, 72, 94]],\n",
    +       "\n",
    +       "         ...,\n",
    +       "\n",
    +       "         [[59, 95, 17, ...,  2, 93, 34],\n",
    +       "          [56, 54, 73, ..., 81, 29, 66],\n",
    +       "          [37, 91, 54, ..., 47, 72, 37],\n",
    +       "          [72, 81, 93, ..., 59, 84, 68]],\n",
    +       "\n",
    +       "         [[59, 76, 62, ..., 84, 38, 60],\n",
    +       "          [11, 41, 61, ..., 70, 50, 98],\n",
    +       "          [25, 52,  4, ..., 18, 78, 90],\n",
    +       "          [93,  1, 48, ..., 22, 48, 45]],\n",
    +       "\n",
    +       "         [[96, 94, 67, ..., 72, 32, 20],\n",
    +       "          [59, 71, 78, ..., 92, 29, 23],\n",
    +       "          [27, 19, 10, ..., 42, 55, 73],\n",
    +       "          [11, 25, 62, ..., 40, 84, 95]]]]])\n",
    +       "Coordinates:\n",
    +       "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
    +       "  * day          (day) datetime64[ns] 2015-01-01 2015-01-02 ... 2015-04-10\n",
    +       "  * time         (time) int64 0 1 2 3 4 5 6 7 8 9 ... 15 16 17 18 19 20 21 22 23\n",
    +       "  * origin       (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n",
    +       "  * destination  (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n",
    +       "Indexes:\n",
    +       "    origin       GeoVectorIndex(crs=EPSG:4267)\n",
    +       "    destination  GeoVectorIndex(crs=EPSG:4267)
    " + ], + "text/plain": [ + "\n", + "array([[[[[ 3, 20, 86, ..., 47, 18, 4],\n", + " [60, 27, 15, ..., 54, 1, 23],\n", + " [31, 64, 18, ..., 44, 9, 37],\n", + " [35, 71, 59, ..., 66, 71, 1]],\n", + "\n", + " [[ 8, 54, 27, ..., 79, 20, 93],\n", + " [ 9, 94, 80, ..., 69, 25, 78],\n", + " [39, 40, 55, ..., 63, 24, 64],\n", + " [63, 85, 17, ..., 44, 75, 68]],\n", + "\n", + " [[24, 54, 24, ..., 99, 40, 89],\n", + " [32, 39, 46, ..., 38, 21, 3],\n", + " [55, 69, 74, ..., 54, 53, 68],\n", + " [30, 21, 44, ..., 36, 31, 62]],\n", + "\n", + " ...,\n", + "\n", + " [[38, 39, 62, ..., 80, 96, 10],\n", + " [39, 92, 83, ..., 50, 39, 34],\n", + " [70, 31, 68, ..., 91, 32, 15],\n", + "...\n", + " [67, 4, 40, ..., 36, 75, 89],\n", + " [ 8, 27, 47, ..., 46, 60, 6],\n", + " [94, 4, 66, ..., 1, 72, 94]],\n", + "\n", + " ...,\n", + "\n", + " [[59, 95, 17, ..., 2, 93, 34],\n", + " [56, 54, 73, ..., 81, 29, 66],\n", + " [37, 91, 54, ..., 47, 72, 37],\n", + " [72, 81, 93, ..., 59, 84, 68]],\n", + "\n", + " [[59, 76, 62, ..., 84, 38, 60],\n", + " [11, 41, 61, ..., 70, 50, 98],\n", + " [25, 52, 4, ..., 18, 78, 90],\n", + " [93, 1, 48, ..., 22, 48, 45]],\n", + "\n", + " [[96, 94, 67, ..., 72, 32, 20],\n", + " [59, 71, 78, ..., 92, 29, 23],\n", + " [27, 19, 10, ..., 42, 55, 73],\n", + " [11, 25, 62, ..., 40, 84, 95]]]]])\n", + "Coordinates:\n", + " * mode (mode) Date: Fri, 18 Nov 2022 09:05:42 +0100 Subject: [PATCH 03/28] fix __version__ --- xvec/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xvec/__init__.py b/xvec/__init__.py index 08d35c5..862e488 100644 --- a/xvec/__init__.py +++ b/xvec/__init__.py @@ -4,7 +4,7 @@ from .strtree import ShapelySTRTreeIndex # noqa try: - __version__ = version("package-name") + __version__ = version("xvec") except PackageNotFoundError: # noqa # package is not installed pass From 3b7e0207bf0678f09df5c7b282a67ef674fe9950 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Fri, 18 Nov 2022 09:06:01 +0100 Subject: [PATCH 04/28] remove ShapelySTRTreeIndex --- xvec/__init__.py | 1 - xvec/strtree.py | 72 ------------------------------------------------ 2 files changed, 73 deletions(-) delete mode 100644 xvec/strtree.py diff --git a/xvec/__init__.py b/xvec/__init__.py index 862e488..bca5ee9 100644 --- a/xvec/__init__.py +++ b/xvec/__init__.py @@ -1,7 +1,6 @@ from importlib.metadata import PackageNotFoundError, version from .index import GeoVectorIndex # noqa -from .strtree import ShapelySTRTreeIndex # noqa try: __version__ = version("xvec") diff --git a/xvec/strtree.py b/xvec/strtree.py deleted file mode 100644 index 592e8e1..0000000 --- a/xvec/strtree.py +++ /dev/null @@ -1,72 +0,0 @@ -import numpy -import shapely -import xarray -from xarray.core.indexes import IndexSelResult -from xarray.indexes import Index - - -class ShapelySTRTreeIndex(Index): - def __init__(self, array, dim, crs): - assert numpy.all(shapely.is_geometry(array)) - - # only support 1-d coordinate for now - assert len(array.shape) == 1 - - self._tree = shapely.STRtree(numpy.ravel(array)) - self.dim = dim - self.crs = crs - - @classmethod - def from_variables(cls, variables, *, options): - # only supports one coordinate of shapely geometries - assert len(variables) == 1 - var = next(iter(variables.values())) - - return cls(var._data, var.dims[0], options["crs"]) - - def sel(self, labels, method=None, tolerance=None): - # We reuse here `method` and `tolerance` options of - # `xarray.indexes.PandasIndex` as `predicate` and `distance` - # options when `labels` is a single geometry. - # Xarray currently doesn't support custom options - # (see https://github.com/pydata/xarray/issues/7099) - - # only one coordinate supported - assert len(labels) == 1 - label = next(iter(labels.values())) - - if method is not None and method != "nearest": - if not isinstance(label, shapely.Geometry): - raise ValueError( - "selection with another method than nearest only supports " - "a single geometry as input label." - ) - - if isinstance(label, xarray.DataArray): - label_array = label._variable._data - elif isinstance(label, xarray.Variable): - label_array = label._data - elif isinstance(label, shapely.Geometry): - label_array = numpy.array([label]) - else: - label_array = numpy.array(label) - - # check for possible CRS of geometry labels - # (by default assume same CRS than the index) - if hasattr(label_array, "crs") and label_array.crs != self.crs: - raise ValueError("conflicting CRS for input geometries") - - assert numpy.all(shapely.is_geometry(label_array)) - - if method is None or method == "nearest": - indices = self._tree.nearest(label_array) - else: - indices = self._tree.query(label, predicate=method, distance=tolerance) - - # attach dimension names and/or coordinates to positional indexer - if isinstance(label, xarray.Variable): - indices = xarray.Variable(label.dims, indices) - elif isinstance(label, xarray.DataArray): - indices = xarray.DataArray(indices, coords=label._coords, dims=label.dims) - - return IndexSelResult({self.dim: indices}) From 2f21e564698f53595f0dcc3ca11d736a5cb1aea7 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Fri, 18 Nov 2022 09:23:18 +0100 Subject: [PATCH 05/28] tweaks --- xvec/index.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xvec/index.py b/xvec/index.py index 0190d05..e069345 100644 --- a/xvec/index.py +++ b/xvec/index.py @@ -88,7 +88,7 @@ def _sel_sindex(self, labels, method, tolerance): assert len(labels) == 1 label = next(iter(labels.values())) - if method is not None and method != "nearest": + if method != "nearest": if not isinstance(label, shapely.Geometry): raise ValueError( "selection with another method than nearest only supports " From 604f5fd606d791da4dc8a82e1e8fb4a4b6b4eb9e Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Fri, 18 Nov 2022 09:49:50 +0100 Subject: [PATCH 06/28] add some docstrings --- xvec/index.py | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/xvec/index.py b/xvec/index.py index e069345..3d42f71 100644 --- a/xvec/index.py +++ b/xvec/index.py @@ -12,7 +12,25 @@ class GeoVectorIndex(Index): + """An CRS-aware, Xarray-compatible index for vector geometries. + This index can be set from any 1-dimensional coordinate of + (shapely 2.0) :class:`shapely.Geometry` elements. + + It provides all the basic functionality of an + :class:`xarray.indexes.PandasIndex`. In addition, it allows spatial + filtering based on geometries (powered by :class:`shapely.STRtree`). + + Parameters + ---------- + index : :class:`xarray.indexes.PandasIndex` + An Xarray (pandas) index built from an array-like of + :class:`shapely.Geometry` objects. + crs : object + The coordinate reference system. Any value accepted by + :meth:`pyproj.crs.CRS.from_user_input`. + + """ _index: PandasIndex _sindex: shapely.STRtree | None _crs: CRS @@ -21,16 +39,23 @@ def __init__(self, index: PandasIndex, crs: CRS): if not np.all(shapely.is_geometry(index.index)): raise ValueError("array must contain shapely.Geometry objects") - self._crs = crs + self._crs = CRS.from_user_input(crs) self._index = index self._sindex = None @property def crs(self) -> CRS: + """Returns the coordinate reference system of the index as a + :class:`pyproj.crs.CRS` object. + """ return self._crs @property - def sindex(self): + def sindex(self) -> shapely.STRtree: + """Returns the spatial index, i.e., a :class:`shapely.STRtree` object. + + It may build the index before returning it. + """ if self._sindex is None: self._sindex = shapely.STRtree(self._index.index) return self._sindex @@ -42,14 +67,12 @@ def from_variables( *, options: Mapping[str, Any], ): - # TODO: get CRS from coordinate attrs or GeometryArray + # TODO: try getting CRS from coordinate attrs or GeometryArray if "crs" not in options: raise ValueError("A CRS must be provided") - crs = CRS.from_user_input(options["crs"]) - index = PandasIndex.from_variables(variables, options={}) - return cls(index, crs=crs) + return cls(index, crs=options["crs"]) @classmethod def concat( From 5be917a8e79df67568bba8ce9875a9ecdb8fd554 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Fri, 18 Nov 2022 09:49:59 +0100 Subject: [PATCH 07/28] add pyproj to the dependencies --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index b14b7de..36bf964 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,7 @@ classifiers = [ requires-python = ">=3.8" dependencies = [ "xarray >= 2022.11.0", + "pyproj >= 2.6.1.post1", "shapely >= 2.0b1", ] From 32569922d18faa7221063d0937009f2bd1d733bd Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Fri, 18 Nov 2022 09:53:23 +0100 Subject: [PATCH 08/28] add strict selection example to notebook --- doc/source/quickstart.ipynb | 1707 +++++++++++++++++++++++++---------- 1 file changed, 1210 insertions(+), 497 deletions(-) diff --git a/doc/source/quickstart.ipynb b/doc/source/quickstart.ipynb index f95802a..845bce3 100644 --- a/doc/source/quickstart.ipynb +++ b/doc/source/quickstart.ipynb @@ -465,93 +465,93 @@ " fill: currentColor;\n", "}\n", "
    <xarray.DataArray (mode: 3, day: 100, time: 24, origin: 100, destination: 100)>\n",
    -       "array([[[[[ 3, 20, 86, ..., 47, 18,  4],\n",
    -       "          [60, 27, 15, ..., 54,  1, 23],\n",
    -       "          [65, 21, 14, ..., 70, 97, 71],\n",
    +       "array([[[[[93, 38,  9, ...,  4, 45, 31],\n",
    +       "          [49, 62, 40, ...,  5,  9, 59],\n",
    +       "          [26, 14, 86, ..., 36, 55, 70],\n",
            "          ...,\n",
    -       "          [75, 34, 41, ..., 79,  7, 68],\n",
    -       "          [31, 64, 18, ..., 44,  9, 37],\n",
    -       "          [35, 71, 59, ..., 66, 71,  1]],\n",
    +       "          [63, 22, 82, ..., 28, 16, 27],\n",
    +       "          [51, 52, 33, ..., 79, 51, 57],\n",
    +       "          [34, 19, 14, ...,  6, 25, 67]],\n",
            "\n",
    -       "         [[ 8, 54, 27, ..., 79, 20, 93],\n",
    -       "          [ 9, 94, 80, ..., 69, 25, 78],\n",
    -       "          [78, 86, 59, ..., 24, 68, 13],\n",
    +       "         [[10, 48, 23, ..., 95, 97,  3],\n",
    +       "          [67, 99, 47, ..., 26, 82, 10],\n",
    +       "          [66, 49,  3, ..., 11, 79, 32],\n",
            "          ...,\n",
    -       "          [92, 73, 72, ..., 55, 75, 86],\n",
    -       "          [39, 40, 55, ..., 63, 24, 64],\n",
    -       "          [63, 85, 17, ..., 44, 75, 68]],\n",
    +       "          [79, 55, 51, ..., 16, 95, 83],\n",
    +       "          [50,  1, 75, ..., 57, 34, 30],\n",
    +       "          [32, 44, 56, ..., 12, 42, 96]],\n",
            "\n",
    -       "         [[24, 54, 24, ..., 99, 40, 89],\n",
    -       "          [32, 39, 46, ..., 38, 21,  3],\n",
    -       "          [39, 63, 90, ..., 54,  5, 84],\n",
    +       "         [[25, 65, 47, ..., 72, 83, 55],\n",
    +       "          [ 5, 97, 93, ..., 60,  7, 98],\n",
    +       "          [58, 44, 38, ..., 27, 72, 14],\n",
            "          ...,\n",
            "...\n",
            "          ...,\n",
    -       "          [91, 56, 61, ..., 91, 73, 25],\n",
    -       "          [37, 91, 54, ..., 47, 72, 37],\n",
    -       "          [72, 81, 93, ..., 59, 84, 68]],\n",
    +       "          [23, 19, 82, ..., 91,  4, 90],\n",
    +       "          [ 7, 86, 98, ..., 81, 13, 97],\n",
    +       "          [67, 57, 39, ..., 25, 50, 91]],\n",
            "\n",
    -       "         [[59, 76, 62, ..., 84, 38, 60],\n",
    -       "          [11, 41, 61, ..., 70, 50, 98],\n",
    -       "          [66, 59, 55, ..., 19, 21, 86],\n",
    +       "         [[95, 85, 50, ..., 55, 78, 57],\n",
    +       "          [14,  7, 16, ..., 54,  7, 62],\n",
    +       "          [54, 23, 15, ..., 39, 80, 91],\n",
            "          ...,\n",
    -       "          [41, 49, 95, ..., 28, 87, 23],\n",
    -       "          [25, 52,  4, ..., 18, 78, 90],\n",
    -       "          [93,  1, 48, ..., 22, 48, 45]],\n",
    +       "          [81, 54,  2, ..., 76, 24, 99],\n",
    +       "          [25, 95, 66, ..., 81, 32, 35],\n",
    +       "          [29, 45,  1, ..., 25, 83, 20]],\n",
            "\n",
    -       "         [[96, 94, 67, ..., 72, 32, 20],\n",
    -       "          [59, 71, 78, ..., 92, 29, 23],\n",
    -       "          [19, 56, 11, ..., 34, 30, 82],\n",
    +       "         [[ 4, 59,  6, ..., 17, 69, 19],\n",
    +       "          [82, 93,  9, ...,  5, 11, 90],\n",
    +       "          [11, 53, 15, ..., 13, 64, 82],\n",
            "          ...,\n",
    -       "          [86, 83, 55, ..., 66, 67, 17],\n",
    -       "          [27, 19, 10, ..., 42, 55, 73],\n",
    -       "          [11, 25, 62, ..., 40, 84, 95]]]]])\n",
    +       "          [75, 48, 33, ..., 80, 45, 13],\n",
    +       "          [50, 61,  4, ..., 45, 70, 74],\n",
    +       "          [67, 36, 29, ..., 41, 58, 38]]]]])\n",
            "Coordinates:\n",
            "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
            "  * day          (day) datetime64[ns] 2015-01-01 2015-01-02 ... 2015-04-10\n",
            "  * time         (time) int64 0 1 2 3 4 5 6 7 8 9 ... 15 16 17 18 19 20 21 22 23\n",
            "  * origin       (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n",
    -       "  * destination  (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...
  • " ], "text/plain": [ "\n", - "array([[[[[ 3, 20, 86, ..., 47, 18, 4],\n", - " [60, 27, 15, ..., 54, 1, 23],\n", - " [65, 21, 14, ..., 70, 97, 71],\n", + "array([[[[[93, 38, 9, ..., 4, 45, 31],\n", + " [49, 62, 40, ..., 5, 9, 59],\n", + " [26, 14, 86, ..., 36, 55, 70],\n", " ...,\n", - " [75, 34, 41, ..., 79, 7, 68],\n", - " [31, 64, 18, ..., 44, 9, 37],\n", - " [35, 71, 59, ..., 66, 71, 1]],\n", + " [63, 22, 82, ..., 28, 16, 27],\n", + " [51, 52, 33, ..., 79, 51, 57],\n", + " [34, 19, 14, ..., 6, 25, 67]],\n", "\n", - " [[ 8, 54, 27, ..., 79, 20, 93],\n", - " [ 9, 94, 80, ..., 69, 25, 78],\n", - " [78, 86, 59, ..., 24, 68, 13],\n", + " [[10, 48, 23, ..., 95, 97, 3],\n", + " [67, 99, 47, ..., 26, 82, 10],\n", + " [66, 49, 3, ..., 11, 79, 32],\n", " ...,\n", - " [92, 73, 72, ..., 55, 75, 86],\n", - " [39, 40, 55, ..., 63, 24, 64],\n", - " [63, 85, 17, ..., 44, 75, 68]],\n", + " [79, 55, 51, ..., 16, 95, 83],\n", + " [50, 1, 75, ..., 57, 34, 30],\n", + " [32, 44, 56, ..., 12, 42, 96]],\n", "\n", - " [[24, 54, 24, ..., 99, 40, 89],\n", - " [32, 39, 46, ..., 38, 21, 3],\n", - " [39, 63, 90, ..., 54, 5, 84],\n", + " [[25, 65, 47, ..., 72, 83, 55],\n", + " [ 5, 97, 93, ..., 60, 7, 98],\n", + " [58, 44, 38, ..., 27, 72, 14],\n", " ...,\n", "...\n", " ...,\n", - " [91, 56, 61, ..., 91, 73, 25],\n", - " [37, 91, 54, ..., 47, 72, 37],\n", - " [72, 81, 93, ..., 59, 84, 68]],\n", + " [23, 19, 82, ..., 91, 4, 90],\n", + " [ 7, 86, 98, ..., 81, 13, 97],\n", + " [67, 57, 39, ..., 25, 50, 91]],\n", "\n", - " [[59, 76, 62, ..., 84, 38, 60],\n", - " [11, 41, 61, ..., 70, 50, 98],\n", - " [66, 59, 55, ..., 19, 21, 86],\n", + " [[95, 85, 50, ..., 55, 78, 57],\n", + " [14, 7, 16, ..., 54, 7, 62],\n", + " [54, 23, 15, ..., 39, 80, 91],\n", " ...,\n", - " [41, 49, 95, ..., 28, 87, 23],\n", - " [25, 52, 4, ..., 18, 78, 90],\n", - " [93, 1, 48, ..., 22, 48, 45]],\n", + " [81, 54, 2, ..., 76, 24, 99],\n", + " [25, 95, 66, ..., 81, 32, 35],\n", + " [29, 45, 1, ..., 25, 83, 20]],\n", "\n", - " [[96, 94, 67, ..., 72, 32, 20],\n", - " [59, 71, 78, ..., 92, 29, 23],\n", - " [19, 56, 11, ..., 34, 30, 82],\n", + " [[ 4, 59, 6, ..., 17, 69, 19],\n", + " [82, 93, 9, ..., 5, 11, 90],\n", + " [11, 53, 15, ..., 13, 64, 82],\n", " ...,\n", - " [86, 83, 55, ..., 66, 67, 17],\n", - " [27, 19, 10, ..., 42, 55, 73],\n", - " [11, 25, 62, ..., 40, 84, 95]]]]])\n", + " [75, 48, 33, ..., 80, 45, 13],\n", + " [50, 61, 4, ..., 45, 70, 74],\n", + " [67, 36, 29, ..., 41, 58, 38]]]]])\n", "Coordinates:\n", " * mode (mode)
    <xarray.DataArray (mode: 3, day: 100, time: 24, origin: 100, destination: 100)>\n",
    -       "array([[[[[ 3, 20, 86, ..., 47, 18,  4],\n",
    -       "          [60, 27, 15, ..., 54,  1, 23],\n",
    -       "          [65, 21, 14, ..., 70, 97, 71],\n",
    +       "array([[[[[93, 38,  9, ...,  4, 45, 31],\n",
    +       "          [49, 62, 40, ...,  5,  9, 59],\n",
    +       "          [26, 14, 86, ..., 36, 55, 70],\n",
            "          ...,\n",
    -       "          [75, 34, 41, ..., 79,  7, 68],\n",
    -       "          [31, 64, 18, ..., 44,  9, 37],\n",
    -       "          [35, 71, 59, ..., 66, 71,  1]],\n",
    +       "          [63, 22, 82, ..., 28, 16, 27],\n",
    +       "          [51, 52, 33, ..., 79, 51, 57],\n",
    +       "          [34, 19, 14, ...,  6, 25, 67]],\n",
            "\n",
    -       "         [[ 8, 54, 27, ..., 79, 20, 93],\n",
    -       "          [ 9, 94, 80, ..., 69, 25, 78],\n",
    -       "          [78, 86, 59, ..., 24, 68, 13],\n",
    +       "         [[10, 48, 23, ..., 95, 97,  3],\n",
    +       "          [67, 99, 47, ..., 26, 82, 10],\n",
    +       "          [66, 49,  3, ..., 11, 79, 32],\n",
            "          ...,\n",
    -       "          [92, 73, 72, ..., 55, 75, 86],\n",
    -       "          [39, 40, 55, ..., 63, 24, 64],\n",
    -       "          [63, 85, 17, ..., 44, 75, 68]],\n",
    +       "          [79, 55, 51, ..., 16, 95, 83],\n",
    +       "          [50,  1, 75, ..., 57, 34, 30],\n",
    +       "          [32, 44, 56, ..., 12, 42, 96]],\n",
            "\n",
    -       "         [[24, 54, 24, ..., 99, 40, 89],\n",
    -       "          [32, 39, 46, ..., 38, 21,  3],\n",
    -       "          [39, 63, 90, ..., 54,  5, 84],\n",
    +       "         [[25, 65, 47, ..., 72, 83, 55],\n",
    +       "          [ 5, 97, 93, ..., 60,  7, 98],\n",
    +       "          [58, 44, 38, ..., 27, 72, 14],\n",
            "          ...,\n",
            "...\n",
            "          ...,\n",
    -       "          [91, 56, 61, ..., 91, 73, 25],\n",
    -       "          [37, 91, 54, ..., 47, 72, 37],\n",
    -       "          [72, 81, 93, ..., 59, 84, 68]],\n",
    +       "          [23, 19, 82, ..., 91,  4, 90],\n",
    +       "          [ 7, 86, 98, ..., 81, 13, 97],\n",
    +       "          [67, 57, 39, ..., 25, 50, 91]],\n",
            "\n",
    -       "         [[59, 76, 62, ..., 84, 38, 60],\n",
    -       "          [11, 41, 61, ..., 70, 50, 98],\n",
    -       "          [66, 59, 55, ..., 19, 21, 86],\n",
    +       "         [[95, 85, 50, ..., 55, 78, 57],\n",
    +       "          [14,  7, 16, ..., 54,  7, 62],\n",
    +       "          [54, 23, 15, ..., 39, 80, 91],\n",
            "          ...,\n",
    -       "          [41, 49, 95, ..., 28, 87, 23],\n",
    -       "          [25, 52,  4, ..., 18, 78, 90],\n",
    -       "          [93,  1, 48, ..., 22, 48, 45]],\n",
    +       "          [81, 54,  2, ..., 76, 24, 99],\n",
    +       "          [25, 95, 66, ..., 81, 32, 35],\n",
    +       "          [29, 45,  1, ..., 25, 83, 20]],\n",
            "\n",
    -       "         [[96, 94, 67, ..., 72, 32, 20],\n",
    -       "          [59, 71, 78, ..., 92, 29, 23],\n",
    -       "          [19, 56, 11, ..., 34, 30, 82],\n",
    +       "         [[ 4, 59,  6, ..., 17, 69, 19],\n",
    +       "          [82, 93,  9, ...,  5, 11, 90],\n",
    +       "          [11, 53, 15, ..., 13, 64, 82],\n",
            "          ...,\n",
    -       "          [86, 83, 55, ..., 66, 67, 17],\n",
    -       "          [27, 19, 10, ..., 42, 55, 73],\n",
    -       "          [11, 25, 62, ..., 40, 84, 95]]]]])\n",
    +       "          [75, 48, 33, ..., 80, 45, 13],\n",
    +       "          [50, 61,  4, ..., 45, 70, 74],\n",
    +       "          [67, 36, 29, ..., 41, 58, 38]]]]])\n",
            "Coordinates:\n",
            "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
            "  * day          (day) datetime64[ns] 2015-01-01 2015-01-02 ... 2015-04-10\n",
    @@ -1520,47 +1520,47 @@
            "  * destination  (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n",
            "Indexes:\n",
            "    origin       GeoVectorIndex(crs=EPSG:4267)\n",
    -       "    destination  GeoVectorIndex(crs=EPSG:4267)
  • " ], "text/plain": [ "\n", - "array([[[[[ 3, 20, 86, ..., 47, 18, 4],\n", - " [60, 27, 15, ..., 54, 1, 23],\n", - " [65, 21, 14, ..., 70, 97, 71],\n", + "array([[[[[93, 38, 9, ..., 4, 45, 31],\n", + " [49, 62, 40, ..., 5, 9, 59],\n", + " [26, 14, 86, ..., 36, 55, 70],\n", " ...,\n", - " [75, 34, 41, ..., 79, 7, 68],\n", - " [31, 64, 18, ..., 44, 9, 37],\n", - " [35, 71, 59, ..., 66, 71, 1]],\n", + " [63, 22, 82, ..., 28, 16, 27],\n", + " [51, 52, 33, ..., 79, 51, 57],\n", + " [34, 19, 14, ..., 6, 25, 67]],\n", "\n", - " [[ 8, 54, 27, ..., 79, 20, 93],\n", - " [ 9, 94, 80, ..., 69, 25, 78],\n", - " [78, 86, 59, ..., 24, 68, 13],\n", + " [[10, 48, 23, ..., 95, 97, 3],\n", + " [67, 99, 47, ..., 26, 82, 10],\n", + " [66, 49, 3, ..., 11, 79, 32],\n", " ...,\n", - " [92, 73, 72, ..., 55, 75, 86],\n", - " [39, 40, 55, ..., 63, 24, 64],\n", - " [63, 85, 17, ..., 44, 75, 68]],\n", + " [79, 55, 51, ..., 16, 95, 83],\n", + " [50, 1, 75, ..., 57, 34, 30],\n", + " [32, 44, 56, ..., 12, 42, 96]],\n", "\n", - " [[24, 54, 24, ..., 99, 40, 89],\n", - " [32, 39, 46, ..., 38, 21, 3],\n", - " [39, 63, 90, ..., 54, 5, 84],\n", + " [[25, 65, 47, ..., 72, 83, 55],\n", + " [ 5, 97, 93, ..., 60, 7, 98],\n", + " [58, 44, 38, ..., 27, 72, 14],\n", " ...,\n", "...\n", " ...,\n", - " [91, 56, 61, ..., 91, 73, 25],\n", - " [37, 91, 54, ..., 47, 72, 37],\n", - " [72, 81, 93, ..., 59, 84, 68]],\n", + " [23, 19, 82, ..., 91, 4, 90],\n", + " [ 7, 86, 98, ..., 81, 13, 97],\n", + " [67, 57, 39, ..., 25, 50, 91]],\n", "\n", - " [[59, 76, 62, ..., 84, 38, 60],\n", - " [11, 41, 61, ..., 70, 50, 98],\n", - " [66, 59, 55, ..., 19, 21, 86],\n", + " [[95, 85, 50, ..., 55, 78, 57],\n", + " [14, 7, 16, ..., 54, 7, 62],\n", + " [54, 23, 15, ..., 39, 80, 91],\n", " ...,\n", - " [41, 49, 95, ..., 28, 87, 23],\n", - " [25, 52, 4, ..., 18, 78, 90],\n", - " [93, 1, 48, ..., 22, 48, 45]],\n", + " [81, 54, 2, ..., 76, 24, 99],\n", + " [25, 95, 66, ..., 81, 32, 35],\n", + " [29, 45, 1, ..., 25, 83, 20]],\n", "\n", - " [[96, 94, 67, ..., 72, 32, 20],\n", - " [59, 71, 78, ..., 92, 29, 23],\n", - " [19, 56, 11, ..., 34, 30, 82],\n", + " [[ 4, 59, 6, ..., 17, 69, 19],\n", + " [82, 93, 9, ..., 5, 11, 90],\n", + " [11, 53, 15, ..., 13, 64, 82],\n", " ...,\n", - " [86, 83, 55, ..., 66, 67, 17],\n", - " [27, 19, 10, ..., 42, 55, 73],\n", - " [11, 25, 62, ..., 40, 84, 95]]]]])\n", + " [75, 48, 33, ..., 80, 45, 13],\n", + " [50, 61, 4, ..., 45, 70, 74],\n", + " [67, 36, 29, ..., 41, 58, 38]]]]])\n", "Coordinates:\n", " * mode (mode)
    <xarray.DataArray (mode: 3, day: 100, time: 24, origin: 2, destination: 100)>\n",
    +       "array([[[[[93, 38,  9, ...,  4, 45, 31],\n",
    +       "          [13, 77, 81, ..., 92, 13, 54]],\n",
    +       "\n",
    +       "         [[10, 48, 23, ..., 95, 97,  3],\n",
    +       "          [30, 38, 56, ..., 84, 91, 44]],\n",
    +       "\n",
    +       "         [[25, 65, 47, ..., 72, 83, 55],\n",
    +       "          [90, 97, 52, ..., 16, 33, 80]],\n",
    +       "\n",
    +       "         ...,\n",
    +       "\n",
    +       "         [[65, 98, 32, ..., 13, 88, 39],\n",
    +       "          [36, 70, 20, ..., 55, 91, 27]],\n",
    +       "\n",
    +       "         [[56, 57, 14, ..., 81, 96, 11],\n",
    +       "          [30, 12, 56, ..., 84, 63, 69]],\n",
    +       "\n",
    +       "         [[69, 12, 89, ..., 77, 89, 70],\n",
    +       "          [94, 93,  4, ..., 88, 26, 77]]],\n",
    +       "\n",
    +       "...\n",
    +       "\n",
    +       "        [[[60, 66, 58, ..., 96, 79, 16],\n",
    +       "          [67, 14, 14, ..., 44, 85, 86]],\n",
    +       "\n",
    +       "         [[52, 99, 50, ..., 65, 88, 48],\n",
    +       "          [76, 38, 54, ..., 62, 23, 33]],\n",
    +       "\n",
    +       "         [[84,  2, 57, ..., 59, 13, 10],\n",
    +       "          [42, 88, 42, ..., 52, 36, 95]],\n",
    +       "\n",
    +       "         ...,\n",
    +       "\n",
    +       "         [[61, 31, 53, ..., 92, 83, 21],\n",
    +       "          [11, 87, 17, ...,  7, 37, 32]],\n",
    +       "\n",
    +       "         [[95, 85, 50, ..., 55, 78, 57],\n",
    +       "          [38, 48, 13, ...,  3, 70, 19]],\n",
    +       "\n",
    +       "         [[ 4, 59,  6, ..., 17, 69, 19],\n",
    +       "          [90, 83, 77, ..., 88, 42, 31]]]]])\n",
    +       "Coordinates:\n",
    +       "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
    +       "  * day          (day) datetime64[ns] 2015-01-01 2015-01-02 ... 2015-04-10\n",
    +       "  * time         (time) int64 0 1 2 3 4 5 6 7 8 9 ... 15 16 17 18 19 20 21 22 23\n",
    +       "  * origin       (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n",
    +       "  * destination  (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n",
    +       "Indexes:\n",
    +       "    origin       GeoVectorIndex(crs=EPSG:4267)\n",
    +       "    destination  GeoVectorIndex(crs=EPSG:4267)
    " + ], + "text/plain": [ + "\n", + "array([[[[[93, 38, 9, ..., 4, 45, 31],\n", + " [13, 77, 81, ..., 92, 13, 54]],\n", + "\n", + " [[10, 48, 23, ..., 95, 97, 3],\n", + " [30, 38, 56, ..., 84, 91, 44]],\n", + "\n", + " [[25, 65, 47, ..., 72, 83, 55],\n", + " [90, 97, 52, ..., 16, 33, 80]],\n", + "\n", + " ...,\n", + "\n", + " [[65, 98, 32, ..., 13, 88, 39],\n", + " [36, 70, 20, ..., 55, 91, 27]],\n", + "\n", + " [[56, 57, 14, ..., 81, 96, 11],\n", + " [30, 12, 56, ..., 84, 63, 69]],\n", + "\n", + " [[69, 12, 89, ..., 77, 89, 70],\n", + " [94, 93, 4, ..., 88, 26, 77]]],\n", + "\n", + "...\n", + "\n", + " [[[60, 66, 58, ..., 96, 79, 16],\n", + " [67, 14, 14, ..., 44, 85, 86]],\n", + "\n", + " [[52, 99, 50, ..., 65, 88, 48],\n", + " [76, 38, 54, ..., 62, 23, 33]],\n", + "\n", + " [[84, 2, 57, ..., 59, 13, 10],\n", + " [42, 88, 42, ..., 52, 36, 95]],\n", + "\n", + " ...,\n", + "\n", + " [[61, 31, 53, ..., 92, 83, 21],\n", + " [11, 87, 17, ..., 7, 37, 32]],\n", + "\n", + " [[95, 85, 50, ..., 55, 78, 57],\n", + " [38, 48, 13, ..., 3, 70, 19]],\n", + "\n", + " [[ 4, 59, 6, ..., 17, 69, 19],\n", + " [90, 83, 77, ..., 88, 42, 31]]]]])\n", + "Coordinates:\n", + " * mode (mode) \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
    <xarray.DataArray (mode: 3, origin: 2, destination: 2)>\n",
    -       "array([[[40, 72],\n",
    -       "        [95, 66]],\n",
    +       "array([[[52, 62],\n",
    +       "        [66, 29]],\n",
            "\n",
    -       "       [[66, 79],\n",
    -       "        [81, 33]],\n",
    +       "       [[41, 97],\n",
    +       "        [30, 54]],\n",
            "\n",
    -       "       [[80, 42],\n",
    -       "        [56, 11]]])\n",
    +       "       [[73, 10],\n",
    +       "        [65, 86]]])\n",
            "Coordinates:\n",
            "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
            "    day          datetime64[ns] 2015-01-01\n",
    @@ -2367,29 +3080,29 @@
            "  * destination  (destination) object MULTIPOLYGON (((-80.72651672363281 35.5...\n",
            "Indexes:\n",
            "    origin       GeoVectorIndex(crs=EPSG:4267)\n",
    -       "    destination  GeoVectorIndex(crs=EPSG:4267)
    • mode
      PandasIndex
      PandasIndex(Index(['car', 'bike', 'foot'], dtype='object', name='mode'))
    • origin
      GeoVectorIndex(crs=EPSG:4267)
      <xvec.index.GeoVectorIndex object at 0x16a7fee90>
    • destination
      GeoVectorIndex(crs=EPSG:4267)
      <xvec.index.GeoVectorIndex object at 0x16a810ad0>
  • " ], "text/plain": [ "\n", - "array([[[40, 72],\n", - " [95, 66]],\n", + "array([[[52, 62],\n", + " [66, 29]],\n", "\n", - " [[66, 79],\n", - " [81, 33]],\n", + " [[41, 97],\n", + " [30, 54]],\n", "\n", - " [[80, 42],\n", - " [56, 11]]])\n", + " [[73, 10],\n", + " [65, 86]]])\n", "Coordinates:\n", " * mode (mode)
    <xarray.DataArray (mode: 3, day: 100, time: 24, origin: 41, destination: 100)>\n",
    -       "array([[[[[63,  4, 52, ..., 94, 53, 42],\n",
    -       "          [60, 43, 49, ..., 98, 60, 21],\n",
    -       "          [60, 58, 57, ..., 46, 75, 81],\n",
    +       "array([[[[[78, 29, 75, ..., 39, 93, 97],\n",
    +       "          [84, 21, 64, ...,  7, 67,  5],\n",
    +       "          [20, 96, 69, ..., 51, 96, 44],\n",
            "          ...,\n",
    -       "          [82,  6, 34, ..., 72, 90, 61],\n",
    -       "          [87, 53, 91, ..., 80, 47, 39],\n",
    -       "          [24, 77, 60, ...,  3, 95, 81]],\n",
    +       "          [ 9,  9, 51, ..., 22, 29, 87],\n",
    +       "          [79, 63, 20, ..., 37, 85, 63],\n",
    +       "          [60, 50, 35, ..., 67, 91, 44]],\n",
            "\n",
    -       "         [[84, 17, 14, ..., 78, 62, 16],\n",
    -       "          [82, 90, 50, ..., 70, 78, 60],\n",
    -       "          [57, 43, 52, ...,  5, 15, 11],\n",
    +       "         [[88, 85, 29, ..., 34, 38,  4],\n",
    +       "          [94, 70, 54, ..., 24, 97, 53],\n",
    +       "          [35, 15, 35, ..., 46, 35, 51],\n",
            "          ...,\n",
    -       "          [58, 55, 49, ..., 99, 88, 42],\n",
    -       "          [ 2, 47, 44, ..., 78, 25, 75],\n",
    -       "          [10,  8, 35, ..., 26, 60, 50]],\n",
    +       "          [76, 75, 34, ..., 29, 84, 27],\n",
    +       "          [32, 42, 60, ..., 21, 29, 53],\n",
    +       "          [61, 76, 63, ..., 55, 11, 72]],\n",
            "\n",
    -       "         [[46, 29, 56, ..., 65, 28, 10],\n",
    -       "          [67, 50, 25, ..., 30, 18, 60],\n",
    -       "          [45, 87, 92, ..., 19, 41, 79],\n",
    +       "         [[52, 64, 89, ..., 76, 62, 18],\n",
    +       "          [34, 25, 76, ..., 88,  7, 41],\n",
    +       "          [37, 48, 85, ..., 81, 99, 48],\n",
            "          ...,\n",
            "...\n",
            "          ...,\n",
    -       "          [30, 28, 32, ...,  4, 11, 23],\n",
    -       "          [92, 91, 99, ..., 79, 56, 52],\n",
    -       "          [10, 94, 41, ...,  8, 26, 88]],\n",
    +       "          [76, 79, 94, ..., 84, 85, 79],\n",
    +       "          [41, 59, 54, ..., 77, 15, 37],\n",
    +       "          [57, 75,  9, ..., 76, 73, 16]],\n",
            "\n",
    -       "         [[27, 89, 88, ..., 96, 13, 41],\n",
    -       "          [25, 36, 66, ..., 91, 92, 45],\n",
    -       "          [13, 94, 11, ..., 94, 22, 83],\n",
    +       "         [[82, 18, 39, ..., 52, 11, 70],\n",
    +       "          [74, 20, 85, ..., 41, 14, 77],\n",
    +       "          [42, 60, 43, ..., 10, 13,  4],\n",
            "          ...,\n",
    -       "          [53, 51, 69, ..., 27, 17, 89],\n",
    -       "          [37, 14, 40, ..., 46, 46, 93],\n",
    -       "          [89, 15,  9, ..., 46, 49, 71]],\n",
    +       "          [84, 84, 81, ...,  7, 45, 27],\n",
    +       "          [68, 68, 35, ..., 51, 66, 81],\n",
    +       "          [41, 32, 97, ..., 17, 76, 14]],\n",
            "\n",
    -       "         [[70, 43, 47, ..., 99, 28, 59],\n",
    -       "          [35, 68, 47, ..., 91,  1, 38],\n",
    -       "          [90, 12, 13, ..., 54, 55, 69],\n",
    +       "         [[49,  2, 91, ..., 36, 88, 82],\n",
    +       "          [70, 43, 16, ..., 47, 41, 37],\n",
    +       "          [87, 26, 78, ..., 28, 67, 76],\n",
            "          ...,\n",
    -       "          [93, 27, 67, ..., 96, 80, 67],\n",
    -       "          [16,  9, 21, ..., 53, 59, 72],\n",
    -       "          [14, 67, 89, ..., 22, 23, 36]]]]])\n",
    +       "          [20, 92, 47, ..., 22, 65, 80],\n",
    +       "          [15, 14, 42, ..., 76, 27, 94],\n",
    +       "          [79,  4, 49, ..., 84,  8, 73]]]]])\n",
            "Coordinates:\n",
            "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
            "  * day          (day) datetime64[ns] 2015-01-01 2015-01-02 ... 2015-04-10\n",
    @@ -2844,47 +3557,47 @@
            "  * destination  (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n",
            "Indexes:\n",
            "    origin       GeoVectorIndex(crs=EPSG:4267)\n",
    -       "    destination  GeoVectorIndex(crs=EPSG:4267)
  • " ], "text/plain": [ "\n", - "array([[[[[63, 4, 52, ..., 94, 53, 42],\n", - " [60, 43, 49, ..., 98, 60, 21],\n", - " [60, 58, 57, ..., 46, 75, 81],\n", + "array([[[[[78, 29, 75, ..., 39, 93, 97],\n", + " [84, 21, 64, ..., 7, 67, 5],\n", + " [20, 96, 69, ..., 51, 96, 44],\n", " ...,\n", - " [82, 6, 34, ..., 72, 90, 61],\n", - " [87, 53, 91, ..., 80, 47, 39],\n", - " [24, 77, 60, ..., 3, 95, 81]],\n", + " [ 9, 9, 51, ..., 22, 29, 87],\n", + " [79, 63, 20, ..., 37, 85, 63],\n", + " [60, 50, 35, ..., 67, 91, 44]],\n", "\n", - " [[84, 17, 14, ..., 78, 62, 16],\n", - " [82, 90, 50, ..., 70, 78, 60],\n", - " [57, 43, 52, ..., 5, 15, 11],\n", + " [[88, 85, 29, ..., 34, 38, 4],\n", + " [94, 70, 54, ..., 24, 97, 53],\n", + " [35, 15, 35, ..., 46, 35, 51],\n", " ...,\n", - " [58, 55, 49, ..., 99, 88, 42],\n", - " [ 2, 47, 44, ..., 78, 25, 75],\n", - " [10, 8, 35, ..., 26, 60, 50]],\n", + " [76, 75, 34, ..., 29, 84, 27],\n", + " [32, 42, 60, ..., 21, 29, 53],\n", + " [61, 76, 63, ..., 55, 11, 72]],\n", "\n", - " [[46, 29, 56, ..., 65, 28, 10],\n", - " [67, 50, 25, ..., 30, 18, 60],\n", - " [45, 87, 92, ..., 19, 41, 79],\n", + " [[52, 64, 89, ..., 76, 62, 18],\n", + " [34, 25, 76, ..., 88, 7, 41],\n", + " [37, 48, 85, ..., 81, 99, 48],\n", " ...,\n", "...\n", " ...,\n", - " [30, 28, 32, ..., 4, 11, 23],\n", - " [92, 91, 99, ..., 79, 56, 52],\n", - " [10, 94, 41, ..., 8, 26, 88]],\n", + " [76, 79, 94, ..., 84, 85, 79],\n", + " [41, 59, 54, ..., 77, 15, 37],\n", + " [57, 75, 9, ..., 76, 73, 16]],\n", "\n", - " [[27, 89, 88, ..., 96, 13, 41],\n", - " [25, 36, 66, ..., 91, 92, 45],\n", - " [13, 94, 11, ..., 94, 22, 83],\n", + " [[82, 18, 39, ..., 52, 11, 70],\n", + " [74, 20, 85, ..., 41, 14, 77],\n", + " [42, 60, 43, ..., 10, 13, 4],\n", " ...,\n", - " [53, 51, 69, ..., 27, 17, 89],\n", - " [37, 14, 40, ..., 46, 46, 93],\n", - " [89, 15, 9, ..., 46, 49, 71]],\n", + " [84, 84, 81, ..., 7, 45, 27],\n", + " [68, 68, 35, ..., 51, 66, 81],\n", + " [41, 32, 97, ..., 17, 76, 14]],\n", "\n", - " [[70, 43, 47, ..., 99, 28, 59],\n", - " [35, 68, 47, ..., 91, 1, 38],\n", - " [90, 12, 13, ..., 54, 55, 69],\n", + " [[49, 2, 91, ..., 36, 88, 82],\n", + " [70, 43, 16, ..., 47, 41, 37],\n", + " [87, 26, 78, ..., 28, 67, 76],\n", " ...,\n", - " [93, 27, 67, ..., 96, 80, 67],\n", - " [16, 9, 21, ..., 53, 59, 72],\n", - " [14, 67, 89, ..., 22, 23, 36]]]]])\n", + " [20, 92, 47, ..., 22, 65, 80],\n", + " [15, 14, 42, ..., 76, 27, 94],\n", + " [79, 4, 49, ..., 84, 8, 73]]]]])\n", "Coordinates:\n", " * mode (mode) 1\u001b[0m \u001b[43marr\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msel\u001b[49m\u001b[43m(\u001b[49m\u001b[43morigin\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[43mshapely\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mPoint\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m80\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m35\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mshapely\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mPoint\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m76\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m35.6\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mintersects\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[0;32mIn [12], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43marr\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msel\u001b[49m\u001b[43m(\u001b[49m\u001b[43morigin\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[43mshapely\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mPoint\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m80\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m35\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mshapely\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mPoint\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m76\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m35.6\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mintersects\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m~/miniconda3/envs/xvec_dev/lib/python3.11/site-packages/xarray/core/dataarray.py:1526\u001b[0m, in \u001b[0;36mDataArray.sel\u001b[0;34m(self, indexers, method, tolerance, drop, **indexers_kwargs)\u001b[0m\n\u001b[1;32m 1416\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21msel\u001b[39m(\n\u001b[1;32m 1417\u001b[0m \u001b[38;5;28mself\u001b[39m: T_DataArray,\n\u001b[1;32m 1418\u001b[0m indexers: Mapping[Any, Any] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1422\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mindexers_kwargs: Any,\n\u001b[1;32m 1423\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m T_DataArray:\n\u001b[1;32m 1424\u001b[0m \u001b[38;5;124;03m\"\"\"Return a new DataArray whose data is given by selecting index\u001b[39;00m\n\u001b[1;32m 1425\u001b[0m \u001b[38;5;124;03m labels along the specified dimension(s).\u001b[39;00m\n\u001b[1;32m 1426\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1524\u001b[0m \u001b[38;5;124;03m Dimensions without coordinates: points\u001b[39;00m\n\u001b[1;32m 1525\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m-> 1526\u001b[0m ds \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_to_temp_dataset\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msel\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1527\u001b[0m \u001b[43m \u001b[49m\u001b[43mindexers\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mindexers\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1528\u001b[0m \u001b[43m \u001b[49m\u001b[43mdrop\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdrop\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1529\u001b[0m \u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1530\u001b[0m \u001b[43m \u001b[49m\u001b[43mtolerance\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtolerance\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1531\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mindexers_kwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1532\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1533\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_from_temp_dataset(ds)\n", "File \u001b[0;32m~/miniconda3/envs/xvec_dev/lib/python3.11/site-packages/xarray/core/dataset.py:2554\u001b[0m, in \u001b[0;36mDataset.sel\u001b[0;34m(self, indexers, method, tolerance, drop, **indexers_kwargs)\u001b[0m\n\u001b[1;32m 2493\u001b[0m \u001b[38;5;124;03m\"\"\"Returns a new dataset with each array indexed by tick labels\u001b[39;00m\n\u001b[1;32m 2494\u001b[0m \u001b[38;5;124;03malong the specified dimension(s).\u001b[39;00m\n\u001b[1;32m 2495\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 2551\u001b[0m \u001b[38;5;124;03mDataArray.sel\u001b[39;00m\n\u001b[1;32m 2552\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 2553\u001b[0m indexers \u001b[38;5;241m=\u001b[39m either_dict_or_kwargs(indexers, indexers_kwargs, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msel\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m-> 2554\u001b[0m query_results \u001b[38;5;241m=\u001b[39m \u001b[43mmap_index_queries\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 2555\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mindexers\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mindexers\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtolerance\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtolerance\u001b[49m\n\u001b[1;32m 2556\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2558\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m drop:\n\u001b[1;32m 2559\u001b[0m no_scalar_variables \u001b[38;5;241m=\u001b[39m {}\n", "File \u001b[0;32m~/miniconda3/envs/xvec_dev/lib/python3.11/site-packages/xarray/core/indexing.py:183\u001b[0m, in \u001b[0;36mmap_index_queries\u001b[0;34m(obj, indexers, method, tolerance, **indexers_kwargs)\u001b[0m\n\u001b[1;32m 181\u001b[0m results\u001b[38;5;241m.\u001b[39mappend(IndexSelResult(labels))\n\u001b[1;32m 182\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 183\u001b[0m results\u001b[38;5;241m.\u001b[39mappend(\u001b[43mindex\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msel\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43moptions\u001b[49m\u001b[43m)\u001b[49m) \u001b[38;5;66;03m# type: ignore[call-arg]\u001b[39;00m\n\u001b[1;32m 185\u001b[0m merged \u001b[38;5;241m=\u001b[39m merge_sel_results(results)\n\u001b[1;32m 187\u001b[0m \u001b[38;5;66;03m# drop dimension coordinates found in dimension indexers\u001b[39;00m\n\u001b[1;32m 188\u001b[0m \u001b[38;5;66;03m# (also drop multi-index if any)\u001b[39;00m\n\u001b[1;32m 189\u001b[0m \u001b[38;5;66;03m# (.sel() already ensures alignment)\u001b[39;00m\n", - "File \u001b[0;32m~/Git/github/benbovy/xvec/xvec/index.py:136\u001b[0m, in \u001b[0;36mGeoVectorIndex.sel\u001b[0;34m(self, labels, method, tolerance)\u001b[0m\n\u001b[1;32m 129\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_index\u001b[38;5;241m.\u001b[39msel(labels)\n\u001b[1;32m 130\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 131\u001b[0m \u001b[38;5;66;03m# We reuse here `method` and `tolerance` options of\u001b[39;00m\n\u001b[1;32m 132\u001b[0m \u001b[38;5;66;03m# `xarray.indexes.PandasIndex` as `predicate` and `distance`\u001b[39;00m\n\u001b[1;32m 133\u001b[0m \u001b[38;5;66;03m# options when `labels` is a single geometry.\u001b[39;00m\n\u001b[1;32m 134\u001b[0m \u001b[38;5;66;03m# Xarray currently doesn't support custom options\u001b[39;00m\n\u001b[1;32m 135\u001b[0m \u001b[38;5;66;03m# (see https://github.com/pydata/xarray/issues/7099)\u001b[39;00m\n\u001b[0;32m--> 136\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_sel_sindex\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtolerance\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Git/github/benbovy/xvec/xvec/index.py:93\u001b[0m, in \u001b[0;36mGeoVectorIndex._sel_sindex\u001b[0;34m(self, labels, method, tolerance)\u001b[0m\n\u001b[1;32m 91\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m method \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m method \u001b[38;5;241m!=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnearest\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m 92\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(label, shapely\u001b[38;5;241m.\u001b[39mGeometry):\n\u001b[0;32m---> 93\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 94\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mselection with another method than nearest only supports \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 95\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124ma single geometry as input label.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 96\u001b[0m )\n\u001b[1;32m 98\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(label, DataArray):\n\u001b[1;32m 99\u001b[0m label_array \u001b[38;5;241m=\u001b[39m label\u001b[38;5;241m.\u001b[39m_variable\u001b[38;5;241m.\u001b[39m_data\n", + "File \u001b[0;32m~/Git/github/benbovy/xvec/xvec/index.py:159\u001b[0m, in \u001b[0;36mGeoVectorIndex.sel\u001b[0;34m(self, labels, method, tolerance)\u001b[0m\n\u001b[1;32m 152\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_index\u001b[38;5;241m.\u001b[39msel(labels)\n\u001b[1;32m 153\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 154\u001b[0m \u001b[38;5;66;03m# We reuse here `method` and `tolerance` options of\u001b[39;00m\n\u001b[1;32m 155\u001b[0m \u001b[38;5;66;03m# `xarray.indexes.PandasIndex` as `predicate` and `distance`\u001b[39;00m\n\u001b[1;32m 156\u001b[0m \u001b[38;5;66;03m# options when `labels` is a single geometry.\u001b[39;00m\n\u001b[1;32m 157\u001b[0m \u001b[38;5;66;03m# Xarray currently doesn't support custom options\u001b[39;00m\n\u001b[1;32m 158\u001b[0m \u001b[38;5;66;03m# (see https://github.com/pydata/xarray/issues/7099)\u001b[39;00m\n\u001b[0;32m--> 159\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_sel_sindex\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtolerance\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Git/github/benbovy/xvec/xvec/index.py:116\u001b[0m, in \u001b[0;36mGeoVectorIndex._sel_sindex\u001b[0;34m(self, labels, method, tolerance)\u001b[0m\n\u001b[1;32m 114\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m method \u001b[38;5;241m!=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnearest\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m 115\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(label, shapely\u001b[38;5;241m.\u001b[39mGeometry):\n\u001b[0;32m--> 116\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 117\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mselection with another method than nearest only supports \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 118\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124ma single geometry as input label.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 119\u001b[0m )\n\u001b[1;32m 121\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(label, DataArray):\n\u001b[1;32m 122\u001b[0m label_array \u001b[38;5;241m=\u001b[39m label\u001b[38;5;241m.\u001b[39m_variable\u001b[38;5;241m.\u001b[39m_data\n", "\u001b[0;31mValueError\u001b[0m: selection with another method than nearest only supports a single geometry as input label." ] } @@ -3210,7 +3923,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "metadata": {}, "outputs": [ { @@ -3580,47 +4293,47 @@ " fill: currentColor;\n", "}\n", "
    <xarray.DataArray (mode: 3, day: 100, time: 24, origin: 2, destination: 2)>\n",
    -       "array([[[[[ 36,   8],\n",
    -       "          [  2,  46]],\n",
    +       "array([[[[[ 90,  62],\n",
    +       "          [ 18, 118]],\n",
            "\n",
    -       "         [[ 40, 186],\n",
    -       "          [ 50, 156]],\n",
    +       "         [[194,   6],\n",
    +       "          [164,  20]],\n",
            "\n",
    -       "         [[ 80, 178],\n",
    -       "          [ 42,   6]],\n",
    +       "         [[166, 110],\n",
    +       "          [ 14, 196]],\n",
            "\n",
            "         ...,\n",
            "\n",
    -       "         [[192,  20],\n",
    -       "          [ 78,  68]],\n",
    +       "         [[176,  78],\n",
    +       "          [ 32, 136]],\n",
            "\n",
    -       "         [[ 58, 102],\n",
    -       "          [112,  90]],\n",
    +       "         [[192,  22],\n",
    +       "          [ 62,  40]],\n",
            "\n",
    -       "         [[ 62, 106],\n",
    -       "          [138,  64]]],\n",
    +       "         [[178, 140],\n",
    +       "          [ 80,  86]]],\n",
            "\n",
            "...\n",
            "\n",
    -       "        [[[  4, 166],\n",
    -       "          [146,  80]],\n",
    +       "        [[[158,  32],\n",
    +       "          [  8, 156]],\n",
            "\n",
    -       "         [[ 70, 166],\n",
    -       "          [138, 166]],\n",
    +       "         [[176,  96],\n",
    +       "          [ 58, 176]],\n",
            "\n",
    -       "         [[128, 108],\n",
    -       "          [150, 178]],\n",
    +       "         [[ 26,  20],\n",
    +       "          [ 68, 152]],\n",
            "\n",
            "         ...,\n",
            "\n",
    -       "         [[186,  68],\n",
    -       "          [ 58, 132]],\n",
    +       "         [[166,  42],\n",
    +       "          [ 70, 186]],\n",
            "\n",
    -       "         [[ 76, 120],\n",
    -       "          [100, 196]],\n",
    +       "         [[156, 114],\n",
    +       "          [ 14, 124]],\n",
            "\n",
    -       "         [[ 64,  40],\n",
    -       "          [ 58,  46]]]]])\n",
    +       "         [[138,  38],\n",
    +       "          [ 22, 180]]]]])\n",
            "Coordinates:\n",
            "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
            "  * day          (day) datetime64[ns] 2015-01-01 2015-01-02 ... 2015-04-10\n",
    @@ -3629,47 +4342,47 @@
            "  * destination  (destination) object MULTIPOLYGON (((-77.96073150634766 34.1...\n",
            "Indexes:\n",
            "    origin       GeoVectorIndex(crs=EPSG:4267)\n",
    -       "    destination  GeoVectorIndex(crs=EPSG:4267)
  • " ], "text/plain": [ "\n", - "array([[[[[ 36, 8],\n", - " [ 2, 46]],\n", + "array([[[[[ 90, 62],\n", + " [ 18, 118]],\n", "\n", - " [[ 40, 186],\n", - " [ 50, 156]],\n", + " [[194, 6],\n", + " [164, 20]],\n", "\n", - " [[ 80, 178],\n", - " [ 42, 6]],\n", + " [[166, 110],\n", + " [ 14, 196]],\n", "\n", " ...,\n", "\n", - " [[192, 20],\n", - " [ 78, 68]],\n", + " [[176, 78],\n", + " [ 32, 136]],\n", "\n", - " [[ 58, 102],\n", - " [112, 90]],\n", + " [[192, 22],\n", + " [ 62, 40]],\n", "\n", - " [[ 62, 106],\n", - " [138, 64]]],\n", + " [[178, 140],\n", + " [ 80, 86]]],\n", "\n", "...\n", "\n", - " [[[ 4, 166],\n", - " [146, 80]],\n", + " [[[158, 32],\n", + " [ 8, 156]],\n", "\n", - " [[ 70, 166],\n", - " [138, 166]],\n", + " [[176, 96],\n", + " [ 58, 176]],\n", "\n", - " [[128, 108],\n", - " [150, 178]],\n", + " [[ 26, 20],\n", + " [ 68, 152]],\n", "\n", " ...,\n", "\n", - " [[186, 68],\n", - " [ 58, 132]],\n", + " [[166, 42],\n", + " [ 70, 186]],\n", "\n", - " [[ 76, 120],\n", - " [100, 196]],\n", + " [[156, 114],\n", + " [ 14, 124]],\n", "\n", - " [[ 64, 40],\n", - " [ 58, 46]]]]])\n", + " [[138, 38],\n", + " [ 22, 180]]]]])\n", "Coordinates:\n", " * mode (mode)
    <xarray.DataArray (mode: 3, day: 100, time: 24, origin: 4, destination: 100)>\n",
    -       "array([[[[[ 3, 20, 86, ..., 47, 18,  4],\n",
    -       "          [60, 27, 15, ..., 54,  1, 23],\n",
    -       "          [31, 64, 18, ..., 44,  9, 37],\n",
    -       "          [35, 71, 59, ..., 66, 71,  1]],\n",
    +       "array([[[[[93, 38,  9, ...,  4, 45, 31],\n",
    +       "          [49, 62, 40, ...,  5,  9, 59],\n",
    +       "          [51, 52, 33, ..., 79, 51, 57],\n",
    +       "          [34, 19, 14, ...,  6, 25, 67]],\n",
            "\n",
    -       "         [[ 8, 54, 27, ..., 79, 20, 93],\n",
    -       "          [ 9, 94, 80, ..., 69, 25, 78],\n",
    -       "          [39, 40, 55, ..., 63, 24, 64],\n",
    -       "          [63, 85, 17, ..., 44, 75, 68]],\n",
    +       "         [[10, 48, 23, ..., 95, 97,  3],\n",
    +       "          [67, 99, 47, ..., 26, 82, 10],\n",
    +       "          [50,  1, 75, ..., 57, 34, 30],\n",
    +       "          [32, 44, 56, ..., 12, 42, 96]],\n",
            "\n",
    -       "         [[24, 54, 24, ..., 99, 40, 89],\n",
    -       "          [32, 39, 46, ..., 38, 21,  3],\n",
    -       "          [55, 69, 74, ..., 54, 53, 68],\n",
    -       "          [30, 21, 44, ..., 36, 31, 62]],\n",
    +       "         [[25, 65, 47, ..., 72, 83, 55],\n",
    +       "          [ 5, 97, 93, ..., 60,  7, 98],\n",
    +       "          [74, 74, 53, ..., 85, 30, 84],\n",
    +       "          [15, 12, 84, ...,  1, 33, 97]],\n",
            "\n",
            "         ...,\n",
            "\n",
    -       "         [[38, 39, 62, ..., 80, 96, 10],\n",
    -       "          [39, 92, 83, ..., 50, 39, 34],\n",
    -       "          [70, 31, 68, ..., 91, 32, 15],\n",
    +       "         [[65, 98, 32, ..., 13, 88, 39],\n",
    +       "          [20, 36, 74, ..., 52, 16, 68],\n",
    +       "          [24, 53, 24, ..., 43, 32, 43],\n",
            "...\n",
    -       "          [67,  4, 40, ..., 36, 75, 89],\n",
    -       "          [ 8, 27, 47, ..., 46, 60,  6],\n",
    -       "          [94,  4, 66, ...,  1, 72, 94]],\n",
    +       "          [99, 52, 72, ..., 47, 34, 76],\n",
    +       "          [25, 38, 67, ...,  1, 76, 25],\n",
    +       "          [50, 41, 15, ..., 28, 50, 12]],\n",
            "\n",
            "         ...,\n",
            "\n",
    -       "         [[59, 95, 17, ...,  2, 93, 34],\n",
    -       "          [56, 54, 73, ..., 81, 29, 66],\n",
    -       "          [37, 91, 54, ..., 47, 72, 37],\n",
    -       "          [72, 81, 93, ..., 59, 84, 68]],\n",
    +       "         [[61, 31, 53, ..., 92, 83, 21],\n",
    +       "          [72, 96, 48, ..., 89, 35, 93],\n",
    +       "          [ 7, 86, 98, ..., 81, 13, 97],\n",
    +       "          [67, 57, 39, ..., 25, 50, 91]],\n",
            "\n",
    -       "         [[59, 76, 62, ..., 84, 38, 60],\n",
    -       "          [11, 41, 61, ..., 70, 50, 98],\n",
    -       "          [25, 52,  4, ..., 18, 78, 90],\n",
    -       "          [93,  1, 48, ..., 22, 48, 45]],\n",
    +       "         [[95, 85, 50, ..., 55, 78, 57],\n",
    +       "          [14,  7, 16, ..., 54,  7, 62],\n",
    +       "          [25, 95, 66, ..., 81, 32, 35],\n",
    +       "          [29, 45,  1, ..., 25, 83, 20]],\n",
            "\n",
    -       "         [[96, 94, 67, ..., 72, 32, 20],\n",
    -       "          [59, 71, 78, ..., 92, 29, 23],\n",
    -       "          [27, 19, 10, ..., 42, 55, 73],\n",
    -       "          [11, 25, 62, ..., 40, 84, 95]]]]])\n",
    +       "         [[ 4, 59,  6, ..., 17, 69, 19],\n",
    +       "          [82, 93,  9, ...,  5, 11, 90],\n",
    +       "          [50, 61,  4, ..., 45, 70, 74],\n",
    +       "          [67, 36, 29, ..., 41, 58, 38]]]]])\n",
            "Coordinates:\n",
            "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
            "  * day          (day) datetime64[ns] 2015-01-01 2015-01-02 ... 2015-04-10\n",
    @@ -4237,47 +4950,47 @@
            "  * destination  (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n",
            "Indexes:\n",
            "    origin       GeoVectorIndex(crs=EPSG:4267)\n",
    -       "    destination  GeoVectorIndex(crs=EPSG:4267)
  • " ], "text/plain": [ "\n", - "array([[[[[ 3, 20, 86, ..., 47, 18, 4],\n", - " [60, 27, 15, ..., 54, 1, 23],\n", - " [31, 64, 18, ..., 44, 9, 37],\n", - " [35, 71, 59, ..., 66, 71, 1]],\n", + "array([[[[[93, 38, 9, ..., 4, 45, 31],\n", + " [49, 62, 40, ..., 5, 9, 59],\n", + " [51, 52, 33, ..., 79, 51, 57],\n", + " [34, 19, 14, ..., 6, 25, 67]],\n", "\n", - " [[ 8, 54, 27, ..., 79, 20, 93],\n", - " [ 9, 94, 80, ..., 69, 25, 78],\n", - " [39, 40, 55, ..., 63, 24, 64],\n", - " [63, 85, 17, ..., 44, 75, 68]],\n", + " [[10, 48, 23, ..., 95, 97, 3],\n", + " [67, 99, 47, ..., 26, 82, 10],\n", + " [50, 1, 75, ..., 57, 34, 30],\n", + " [32, 44, 56, ..., 12, 42, 96]],\n", "\n", - " [[24, 54, 24, ..., 99, 40, 89],\n", - " [32, 39, 46, ..., 38, 21, 3],\n", - " [55, 69, 74, ..., 54, 53, 68],\n", - " [30, 21, 44, ..., 36, 31, 62]],\n", + " [[25, 65, 47, ..., 72, 83, 55],\n", + " [ 5, 97, 93, ..., 60, 7, 98],\n", + " [74, 74, 53, ..., 85, 30, 84],\n", + " [15, 12, 84, ..., 1, 33, 97]],\n", "\n", " ...,\n", "\n", - " [[38, 39, 62, ..., 80, 96, 10],\n", - " [39, 92, 83, ..., 50, 39, 34],\n", - " [70, 31, 68, ..., 91, 32, 15],\n", + " [[65, 98, 32, ..., 13, 88, 39],\n", + " [20, 36, 74, ..., 52, 16, 68],\n", + " [24, 53, 24, ..., 43, 32, 43],\n", "...\n", - " [67, 4, 40, ..., 36, 75, 89],\n", - " [ 8, 27, 47, ..., 46, 60, 6],\n", - " [94, 4, 66, ..., 1, 72, 94]],\n", + " [99, 52, 72, ..., 47, 34, 76],\n", + " [25, 38, 67, ..., 1, 76, 25],\n", + " [50, 41, 15, ..., 28, 50, 12]],\n", "\n", " ...,\n", "\n", - " [[59, 95, 17, ..., 2, 93, 34],\n", - " [56, 54, 73, ..., 81, 29, 66],\n", - " [37, 91, 54, ..., 47, 72, 37],\n", - " [72, 81, 93, ..., 59, 84, 68]],\n", + " [[61, 31, 53, ..., 92, 83, 21],\n", + " [72, 96, 48, ..., 89, 35, 93],\n", + " [ 7, 86, 98, ..., 81, 13, 97],\n", + " [67, 57, 39, ..., 25, 50, 91]],\n", "\n", - " [[59, 76, 62, ..., 84, 38, 60],\n", - " [11, 41, 61, ..., 70, 50, 98],\n", - " [25, 52, 4, ..., 18, 78, 90],\n", - " [93, 1, 48, ..., 22, 48, 45]],\n", + " [[95, 85, 50, ..., 55, 78, 57],\n", + " [14, 7, 16, ..., 54, 7, 62],\n", + " [25, 95, 66, ..., 81, 32, 35],\n", + " [29, 45, 1, ..., 25, 83, 20]],\n", "\n", - " [[96, 94, 67, ..., 72, 32, 20],\n", - " [59, 71, 78, ..., 92, 29, 23],\n", - " [27, 19, 10, ..., 42, 55, 73],\n", - " [11, 25, 62, ..., 40, 84, 95]]]]])\n", + " [[ 4, 59, 6, ..., 17, 69, 19],\n", + " [82, 93, 9, ..., 5, 11, 90],\n", + " [50, 61, 4, ..., 45, 70, 74],\n", + " [67, 36, 29, ..., 41, 58, 38]]]]])\n", "Coordinates:\n", " * mode (mode) Date: Fri, 18 Nov 2022 09:58:25 +0100 Subject: [PATCH 09/28] fix tests --- xvec/tests/test_index.py | 2 ++ xvec/tests/test_strtree.py | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 xvec/tests/test_index.py delete mode 100644 xvec/tests/test_strtree.py diff --git a/xvec/tests/test_index.py b/xvec/tests/test_index.py new file mode 100644 index 0000000..9a056a7 --- /dev/null +++ b/xvec/tests/test_index.py @@ -0,0 +1,2 @@ +def test_import_dummy(): + from xvec import GeoVectorIndex # noqa diff --git a/xvec/tests/test_strtree.py b/xvec/tests/test_strtree.py deleted file mode 100644 index 7e5d728..0000000 --- a/xvec/tests/test_strtree.py +++ /dev/null @@ -1,2 +0,0 @@ -def test_import_dummy(): - from xvec import ShapelySTRTreeIndex # noqa From 97c90f5ae90b6e7ad4106b811defddcf2d510a3d Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Fri, 18 Nov 2022 10:05:09 +0100 Subject: [PATCH 10/28] pre-commit --- xvec/index.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/xvec/index.py b/xvec/index.py index 3d42f71..396c5e5 100644 --- a/xvec/index.py +++ b/xvec/index.py @@ -2,9 +2,9 @@ from typing import Any, Hashable, Iterable, Mapping, Sequence -import shapely import numpy as np import pandas as pd +import shapely from pyproj import CRS from xarray import DataArray, Variable from xarray.core.indexing import IndexSelResult @@ -31,6 +31,7 @@ class GeoVectorIndex(Index): :meth:`pyproj.crs.CRS.from_user_input`. """ + _index: PandasIndex _sindex: shapely.STRtree | None _crs: CRS @@ -147,7 +148,9 @@ def _sel_sindex(self, labels, method, tolerance): return IndexSelResult({self._index.dim: indices}) - def sel(self, labels: dict[Any, Any], method=None, tolerance=None) -> IndexSelResult: + def sel( + self, labels: dict[Any, Any], method=None, tolerance=None + ) -> IndexSelResult: if method is None: return self._index.sel(labels) else: @@ -174,7 +177,9 @@ def join( def reindex_like( self, other: GeoVectorIndex, method=None, tolerance=None ) -> dict[Hashable, Any]: - return self._index.reindex_like(other._index, method=method, tolerance=tolerance) + return self._index.reindex_like( + other._index, method=method, tolerance=tolerance + ) def roll(self, shifts: Mapping[Any, int]) -> GeoVectorIndex: index = self._index.roll(shifts) From 7b35e6c56605aca11385ec26631edb8c51cce35f Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Fri, 18 Nov 2022 10:14:19 +0100 Subject: [PATCH 11/28] fix API docs Remove Index API that is meant to be only used via Xarray internals. --- doc/source/api.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/source/api.rst b/doc/source/api.rst index 64bad58..e44776e 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -12,6 +12,6 @@ Indexing .. autosummary:: :toctree: generated/ - ShapelySTRTreeIndex.__init__ - ShapelySTRTreeIndex.from_variables - ShapelySTRTreeIndex.sel + GeoVectorIndex + GeoVectorIndex.crs + GeoVectorIndex.sindex From be351e1007feb9817c48617dbf5501c7b000c3a8 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Fri, 18 Nov 2022 14:18:06 +0100 Subject: [PATCH 12/28] add tests --- xvec/index.py | 2 +- xvec/tests/test_index.py | 143 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 142 insertions(+), 3 deletions(-) diff --git a/xvec/index.py b/xvec/index.py index 396c5e5..f8d6ab5 100644 --- a/xvec/index.py +++ b/xvec/index.py @@ -70,7 +70,7 @@ def from_variables( ): # TODO: try getting CRS from coordinate attrs or GeometryArray if "crs" not in options: - raise ValueError("A CRS must be provided") + raise ValueError("a CRS must be provided") index = PandasIndex.from_variables(variables, options={}) return cls(index, crs=options["crs"]) diff --git a/xvec/tests/test_index.py b/xvec/tests/test_index.py index 9a056a7..6a5bb39 100644 --- a/xvec/tests/test_index.py +++ b/xvec/tests/test_index.py @@ -1,2 +1,141 @@ -def test_import_dummy(): - from xvec import GeoVectorIndex # noqa +import numpy as np +import pytest +import shapely +import xarray as xr +from pyproj import CRS + +from xvec import GeoVectorIndex + + +@pytest.fixture(scope="session") +def geom_array(): + return np.array([shapely.Point(1, 2), shapely.Point(3, 4)]) + + +@pytest.fixture(scope="session") +def geom_dataset_no_index(geom_array): + # a dataset with a geometry coordinate but no index + ds = xr.Dataset(coords={"geom": geom_array}) + return ds.drop_indexes("geom") + + +@pytest.fixture(scope="session") +def geom_dataset(geom_dataset_no_index): + # a dataset with a geometry coordinate baked by a GeoVectorIndex + crs = CRS.from_user_input(26915) + return geom_dataset_no_index.set_xindex("geom", GeoVectorIndex, crs=crs) + + +@pytest.fixture(scope="session") +def first_geom_dataset(geom_dataset, geom_array): + return ( + xr.Dataset(coords={"geom": [geom_array[0]]}) + .drop_indexes("geom") + .set_xindex("geom", GeoVectorIndex, crs=geom_dataset.xindexes["geom"].crs) + ) + + +def test_set_index(geom_dataset_no_index): + crs = CRS.from_user_input(26915) + ds = geom_dataset_no_index.set_xindex("geom", GeoVectorIndex, crs=crs) + + # test properties + assert isinstance(ds.xindexes["geom"], GeoVectorIndex) + assert ds.xindexes["geom"].crs == crs + np.testing.assert_array_equal(ds.xindexes["geom"].sindex.geometries, ds.geom.values) + + # test `GeoVectorIndex.create_variables` + assert ds.geom.variable._data.array is ds.xindexes["geom"]._index.index + + with pytest.raises(ValueError, match="a CRS must be provided"): + geom_dataset_no_index.set_xindex("geom", GeoVectorIndex) + + no_geom_ds = xr.Dataset(coords={"no_geom": ("x", [0, 1, 2])}) + with pytest.raises(ValueError, match="array must contain shapely.Geometry objects"): + no_geom_ds.set_xindex("no_geom", GeoVectorIndex, crs=crs) + + +def test_concat(geom_dataset, geom_array): + expected = ( + xr.Dataset(coords={"geom": np.concatenate([geom_array, geom_array])}) + .drop_indexes("geom") + .set_xindex("geom", GeoVectorIndex, crs=geom_dataset.xindexes["geom"].crs) + ) + actual = xr.concat([geom_dataset, geom_dataset], "geom") + xr.testing.assert_identical(actual, expected) + + +def test_to_pandas_index(geom_dataset): + index = geom_dataset.xindexes["geom"] + assert index.to_pandas_index() is index._index.index + + +def test_isel(geom_dataset, first_geom_dataset): + actual = geom_dataset.isel(geom=[0]) + xr.testing.assert_identical(actual, first_geom_dataset) + + +def test_sel_strict(geom_dataset, geom_array, first_geom_dataset): + actual = geom_dataset.sel(geom=[geom_array[0]]) + xr.testing.assert_identical(actual, first_geom_dataset) + + +@pytest.mark.parametrize( + "label", + [ + shapely.Point(1, 1), + [shapely.Point(1, 1)], + xr.Variable("geom", [shapely.Point(1, 1)]), + xr.DataArray([shapely.Point(1, 1)], dims="geom"), + ], +) +def test_sel_nearest(geom_dataset, geom_array, first_geom_dataset, label): + actual = geom_dataset.sel(geom=label, method="nearest") + xr.testing.assert_identical(actual, first_geom_dataset) + + +def test_sel_query(geom_dataset, first_geom_dataset): + actual = geom_dataset.sel(geom=shapely.box(0, 0, 2, 2), method="intersects") + xr.testing.assert_identical(actual, first_geom_dataset) + + +def test_equals(geom_dataset, geom_dataset_no_index, first_geom_dataset): + # different index types + other = xr.Dataset(coords={"geom": [0, 1]}) + assert not geom_dataset.xindexes["geom"].equals(other.xindexes["geom"]) + + # different CRS + crs = CRS.from_user_input(4267) + other = geom_dataset_no_index.set_xindex("geom", GeoVectorIndex, crs=crs) + assert not geom_dataset.xindexes["geom"].equals(other.xindexes["geom"]) + + # different geometries + assert not geom_dataset.xindexes["geom"].equals(first_geom_dataset.xindexes["geom"]) + + +def test_align(geom_dataset, first_geom_dataset): + # test GeoVectorIndex's `join` and `reindex_like` + aligned = xr.align(geom_dataset, first_geom_dataset, join="inner") + assert all(ds.identical(first_geom_dataset) for ds in aligned) + + +def test_roll(geom_dataset, geom_array): + expected = ( + xr.Dataset(coords={"geom": np.roll(geom_array, 1)}) + .drop_indexes("geom") + .set_xindex("geom", GeoVectorIndex, crs=geom_dataset.xindexes["geom"].crs) + ) + actual = geom_dataset.roll(geom=1, roll_coords=True) + xr.testing.assert_identical(actual, expected) + + +def test_rename(geom_dataset): + ds = geom_dataset.rename_vars(geom="renamed") + assert ds.xindexes["renamed"]._index.index.name == "renamed" + assert ds.xindexes["renamed"]._index.dim == "geom" + + +def test_repr_inline(geom_dataset): + actual = geom_dataset.xindexes["geom"]._repr_inline_(70) + expected = "GeoVectorIndex(crs=EPSG:26915)" + assert actual == expected From 6cc503d78b6205ac89660bdd5a367016aeb85b01 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Tue, 22 Nov 2022 13:25:52 +0100 Subject: [PATCH 13/28] Update xvec/index.py Co-authored-by: Martin Fleischmann --- xvec/index.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xvec/index.py b/xvec/index.py index f8d6ab5..56813ba 100644 --- a/xvec/index.py +++ b/xvec/index.py @@ -55,7 +55,7 @@ def crs(self) -> CRS: def sindex(self) -> shapely.STRtree: """Returns the spatial index, i.e., a :class:`shapely.STRtree` object. - It may build the index before returning it. + It may build the index before returning it if it hasn't been built before. """ if self._sindex is None: self._sindex = shapely.STRtree(self._index.index) From 90aaf1ad239c30ab771973739e6b24e1d6ab7b70 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Tue, 22 Nov 2022 13:26:27 +0100 Subject: [PATCH 14/28] Update xvec/index.py Co-authored-by: Martin Fleischmann --- xvec/index.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xvec/index.py b/xvec/index.py index 56813ba..2b375e0 100644 --- a/xvec/index.py +++ b/xvec/index.py @@ -68,7 +68,7 @@ def from_variables( *, options: Mapping[str, Any], ): - # TODO: try getting CRS from coordinate attrs or GeometryArray + # TODO: try getting CRS from coordinate attrs or GeometryArray or SRID if "crs" not in options: raise ValueError("a CRS must be provided") From 8c0f83ddb535f722584f9562d0627709e4336b60 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Tue, 22 Nov 2022 13:51:50 +0100 Subject: [PATCH 15/28] Update xvec/index.py Co-authored-by: Martin Fleischmann --- xvec/index.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xvec/index.py b/xvec/index.py index 2b375e0..f02993f 100644 --- a/xvec/index.py +++ b/xvec/index.py @@ -190,4 +190,4 @@ def rename(self, name_dict, dims_dict): return type(self)(index, self.crs) def _repr_inline_(self, max_width): - return f"{self.__class__.__name__}(crs={self.crs.to_string()})" + return f"{self.__class__.__name__} (crs={self.crs.to_string()})" From dbf3c7dd5dcfd22a7da8225222656f069eb89a60 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Tue, 22 Nov 2022 15:27:12 +0100 Subject: [PATCH 16/28] fix _repr_inline_ test --- xvec/tests/test_index.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xvec/tests/test_index.py b/xvec/tests/test_index.py index 6a5bb39..cd5cfed 100644 --- a/xvec/tests/test_index.py +++ b/xvec/tests/test_index.py @@ -137,5 +137,5 @@ def test_rename(geom_dataset): def test_repr_inline(geom_dataset): actual = geom_dataset.xindexes["geom"]._repr_inline_(70) - expected = "GeoVectorIndex(crs=EPSG:26915)" + expected = "GeoVectorIndex (crs=EPSG:26915)" assert actual == expected From 531e4cf2cf6ce22f192c5ce42ca90a299e78fbef Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Tue, 22 Nov 2022 15:28:07 +0100 Subject: [PATCH 17/28] make index crs optional --- xvec/index.py | 28 ++++++++++++++++++---------- xvec/tests/test_index.py | 27 +++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/xvec/index.py b/xvec/index.py index f02993f..55bc1a3 100644 --- a/xvec/index.py +++ b/xvec/index.py @@ -26,7 +26,7 @@ class GeoVectorIndex(Index): index : :class:`xarray.indexes.PandasIndex` An Xarray (pandas) index built from an array-like of :class:`shapely.Geometry` objects. - crs : object + crs : object, optional The coordinate reference system. Any value accepted by :meth:`pyproj.crs.CRS.from_user_input`. @@ -34,18 +34,21 @@ class GeoVectorIndex(Index): _index: PandasIndex _sindex: shapely.STRtree | None - _crs: CRS + _crs: CRS | None - def __init__(self, index: PandasIndex, crs: CRS): + def __init__(self, index: PandasIndex, crs: CRS | None = None): if not np.all(shapely.is_geometry(index.index)): raise ValueError("array must contain shapely.Geometry objects") - self._crs = CRS.from_user_input(crs) + if crs is not None: + crs = CRS.from_user_input(crs) + + self._crs = crs self._index = index self._sindex = None @property - def crs(self) -> CRS: + def crs(self) -> CRS | None: """Returns the coordinate reference system of the index as a :class:`pyproj.crs.CRS` object. """ @@ -69,11 +72,9 @@ def from_variables( options: Mapping[str, Any], ): # TODO: try getting CRS from coordinate attrs or GeometryArray or SRID - if "crs" not in options: - raise ValueError("a CRS must be provided") index = PandasIndex.from_variables(variables, options={}) - return cls(index, crs=options["crs"]) + return cls(index, crs=options.get("crs")) @classmethod def concat( @@ -84,7 +85,7 @@ def concat( ) -> GeoVectorIndex: crss = [idx.crs for idx in indexes] - if any([s != crss[0] for s in crss]): + if any([s is not None and s != crss[0] for s in crss]): raise ValueError("conflicting CRS for coordinates to concat") indexes_ = [idx._index for idx in indexes] @@ -130,7 +131,8 @@ def _sel_sindex(self, labels, method, tolerance): # check for possible CRS of geometry labels # (by default assume same CRS than the index) - if hasattr(label_array, "crs") and label_array.crs != self.crs: + label_crs = getattr(label_array, "crs", None) + if label_crs is not None and label_crs != self.crs: raise ValueError("conflicting CRS for input geometries") assert np.all(shapely.is_geometry(label_array)) @@ -171,12 +173,18 @@ def equals(self, other: Index) -> bool: def join( self: GeoVectorIndex, other: GeoVectorIndex, how: str = "inner" ) -> GeoVectorIndex: + if other.crs is not None and other.crs != self.crs: + raise ValueError("conflicting CRS for left and right indexes to join") + index = self._index.join(other._index, how=how) return type(self)(index, self.crs) def reindex_like( self, other: GeoVectorIndex, method=None, tolerance=None ) -> dict[Hashable, Any]: + if other.crs is not None and other.crs != self.crs: + raise ValueError("conflicting CRS between the current and new indexes") + return self._index.reindex_like( other._index, method=method, tolerance=tolerance ) diff --git a/xvec/tests/test_index.py b/xvec/tests/test_index.py index cd5cfed..f4a6279 100644 --- a/xvec/tests/test_index.py +++ b/xvec/tests/test_index.py @@ -47,15 +47,15 @@ def test_set_index(geom_dataset_no_index): # test `GeoVectorIndex.create_variables` assert ds.geom.variable._data.array is ds.xindexes["geom"]._index.index - with pytest.raises(ValueError, match="a CRS must be provided"): - geom_dataset_no_index.set_xindex("geom", GeoVectorIndex) + no_crs_ds = geom_dataset_no_index.set_xindex("geom", GeoVectorIndex) + assert no_crs_ds.xindexes["geom"].crs is None no_geom_ds = xr.Dataset(coords={"no_geom": ("x", [0, 1, 2])}) with pytest.raises(ValueError, match="array must contain shapely.Geometry objects"): no_geom_ds.set_xindex("no_geom", GeoVectorIndex, crs=crs) -def test_concat(geom_dataset, geom_array): +def test_concat(geom_dataset, geom_array, geom_dataset_no_index): expected = ( xr.Dataset(coords={"geom": np.concatenate([geom_array, geom_array])}) .drop_indexes("geom") @@ -64,6 +64,13 @@ def test_concat(geom_dataset, geom_array): actual = xr.concat([geom_dataset, geom_dataset], "geom") xr.testing.assert_identical(actual, expected) + # different CRS + crs = CRS.from_user_input(4267) + geom_dataset_alt = geom_dataset_no_index.set_xindex("geom", GeoVectorIndex, crs=crs) + + with pytest.raises(ValueError, match="conflicting CRS for coordinates to concat"): + xr.concat([geom_dataset, geom_dataset_alt], "geom") + def test_to_pandas_index(geom_dataset): index = geom_dataset.xindexes["geom"] @@ -113,11 +120,23 @@ def test_equals(geom_dataset, geom_dataset_no_index, first_geom_dataset): assert not geom_dataset.xindexes["geom"].equals(first_geom_dataset.xindexes["geom"]) -def test_align(geom_dataset, first_geom_dataset): +def test_align(geom_dataset, first_geom_dataset, geom_dataset_no_index): # test GeoVectorIndex's `join` and `reindex_like` aligned = xr.align(geom_dataset, first_geom_dataset, join="inner") assert all(ds.identical(first_geom_dataset) for ds in aligned) + # test conflicting CRS + crs = CRS.from_user_input(4267) + geom_dataset_alt = geom_dataset_no_index.set_xindex("geom", GeoVectorIndex, crs=crs) + + with pytest.raises(ValueError, match="conflicting CRS for left and right indexes"): + xr.align(geom_dataset_alt, first_geom_dataset, join="inner") + + with pytest.raises( + ValueError, match="conflicting CRS between the current and new index" + ): + first_geom_dataset.reindex_like(geom_dataset_alt) + def test_roll(geom_dataset, geom_array): expected = ( From cbcaa5101b5e24af8cc7725a70ced86f466273e4 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Tue, 22 Nov 2022 16:01:51 +0100 Subject: [PATCH 18/28] assert -> raise --- xvec/index.py | 5 +++-- xvec/tests/test_index.py | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/xvec/index.py b/xvec/index.py index 55bc1a3..827744f 100644 --- a/xvec/index.py +++ b/xvec/index.py @@ -109,7 +109,7 @@ def isel(self, indexers: Mapping[Any, Any]): return None def _sel_sindex(self, labels, method, tolerance): - # only one coordinate supported + # only one entry expected assert len(labels) == 1 label = next(iter(labels.values())) @@ -135,7 +135,8 @@ def _sel_sindex(self, labels, method, tolerance): if label_crs is not None and label_crs != self.crs: raise ValueError("conflicting CRS for input geometries") - assert np.all(shapely.is_geometry(label_array)) + if not np.all(shapely.is_geometry(label_array)): + raise ValueError("labels must be shapely.Geometry objects") if method == "nearest": indices = self.sindex.nearest(label_array) diff --git a/xvec/tests/test_index.py b/xvec/tests/test_index.py index f4a6279..4d822f1 100644 --- a/xvec/tests/test_index.py +++ b/xvec/tests/test_index.py @@ -101,6 +101,11 @@ def test_sel_nearest(geom_dataset, geom_array, first_geom_dataset, label): xr.testing.assert_identical(actual, first_geom_dataset) +def test_sel_nearest_error(geom_dataset): + with pytest.raises(ValueError, match="labels must be shapely.Geometry objects"): + geom_dataset.sel(geom=[0], method="nearest") + + def test_sel_query(geom_dataset, first_geom_dataset): actual = geom_dataset.sel(geom=shapely.box(0, 0, 2, 2), method="intersects") xr.testing.assert_identical(actual, first_geom_dataset) From fe1dada2c75439bdbce2406bc4e9d6bde6328f17 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Tue, 22 Nov 2022 16:03:43 +0100 Subject: [PATCH 19/28] update pyproj min required version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 36bf964..1333517 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ classifiers = [ requires-python = ">=3.8" dependencies = [ "xarray >= 2022.11.0", - "pyproj >= 2.6.1.post1", + "pyproj >= 3.0.0", "shapely >= 2.0b1", ] From c53956255ea6820d205c32fdaf79ee4b6c093a7f Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Tue, 22 Nov 2022 16:09:03 +0100 Subject: [PATCH 20/28] enable intersphinx --- doc/source/conf.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/source/conf.py b/doc/source/conf.py index da50322..c12bc21 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -17,6 +17,7 @@ "sphinx.ext.autodoc", "numpydoc", "sphinx.ext.autosummary", + "sphinx.ext.intersphinx", "myst_nb", "sphinx_copybutton", ] @@ -24,6 +25,11 @@ templates_path = ["_templates"] exclude_patterns = [] +intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), + "shapely": ("https://shapely.readthedocs.io/en/latest/", None), + "pyproj": ("https://pyproj4.github.io/pyproj/latest/", None), +} # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output From 1a84c23bc1c2540a54a8157e0b57d5aa73b95520 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Tue, 22 Nov 2022 16:33:32 +0100 Subject: [PATCH 21/28] doc tweaks --- doc/source/conf.py | 1 + xvec/index.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index c12bc21..a49b0da 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -29,6 +29,7 @@ "python": ("https://docs.python.org/3", None), "shapely": ("https://shapely.readthedocs.io/en/latest/", None), "pyproj": ("https://pyproj4.github.io/pyproj/latest/", None), + "xarray": ("https://docs.xarray.dev/en/latest/", None), } # -- Options for HTML output ------------------------------------------------- diff --git a/xvec/index.py b/xvec/index.py index 827744f..5425fca 100644 --- a/xvec/index.py +++ b/xvec/index.py @@ -26,7 +26,7 @@ class GeoVectorIndex(Index): index : :class:`xarray.indexes.PandasIndex` An Xarray (pandas) index built from an array-like of :class:`shapely.Geometry` objects. - crs : object, optional + crs : :class:`pyproj.crs.CRS` or any, optional The coordinate reference system. Any value accepted by :meth:`pyproj.crs.CRS.from_user_input`. @@ -36,7 +36,7 @@ class GeoVectorIndex(Index): _sindex: shapely.STRtree | None _crs: CRS | None - def __init__(self, index: PandasIndex, crs: CRS | None = None): + def __init__(self, index: PandasIndex, crs: CRS | Any | None = None): if not np.all(shapely.is_geometry(index.index)): raise ValueError("array must contain shapely.Geometry objects") From 1e945b7798a5649871de75ace1e75d206811e6f3 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Tue, 22 Nov 2022 17:02:11 +0100 Subject: [PATCH 22/28] rename GeoVectorIndex -> GeometryIndex --- doc/source/api.rst | 6 +-- doc/source/quickstart.ipynb | 76 ++++++++++++++++++------------------- xvec/__init__.py | 2 +- xvec/index.py | 16 ++++---- xvec/tests/test_index.py | 32 ++++++++-------- 5 files changed, 66 insertions(+), 66 deletions(-) diff --git a/doc/source/api.rst b/doc/source/api.rst index e44776e..0d27ae4 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -12,6 +12,6 @@ Indexing .. autosummary:: :toctree: generated/ - GeoVectorIndex - GeoVectorIndex.crs - GeoVectorIndex.sindex + GeometryIndex + GeometryIndex.crs + GeometryIndex.sindex diff --git a/doc/source/quickstart.ipynb b/doc/source/quickstart.ipynb index 845bce3..d4f9c46 100644 --- a/doc/source/quickstart.ipynb +++ b/doc/source/quickstart.ipynb @@ -30,7 +30,7 @@ "import xarray\n", "import numpy\n", "\n", - "from xvec import GeoVectorIndex" + "from xvec import GeometryIndex" ] }, { @@ -1096,7 +1096,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Set two `GeoVectorIndex` instances for the `origin` and `destination` coordinates, respectively (first drop the two `pandas.Index` objects that were set by default for these two dimension coordinates)." + "Set two `GeometryIndex` instances for the `origin` and `destination` coordinates, respectively (first drop the two `pandas.Index` objects that were set by default for these two dimension coordinates)." ] }, { @@ -1519,8 +1519,8 @@ " * origin (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n", " * destination (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n", "Indexes:\n", - " origin GeoVectorIndex(crs=EPSG:4267)\n", - " destination GeoVectorIndex(crs=EPSG:4267)" + " dtype='int64', name='time'))
  • origin
    GeometryIndex(crs=EPSG:4267)
    <xvec.index.GeometryIndex object at 0x16a7efe50>
  • destination
    GeometryIndex(crs=EPSG:4267)
    <xvec.index.GeometryIndex object at 0x16a7fd8d0>
  • " ], "text/plain": [ "\n", @@ -1890,8 +1890,8 @@ " * origin (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n", " * destination (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n", "Indexes:\n", - " origin GeoVectorIndex(crs=EPSG:4267)\n", - " destination GeoVectorIndex(crs=EPSG:4267)" + " origin GeometryIndex(crs=EPSG:4267)\n", + " destination GeometryIndex(crs=EPSG:4267)" ] }, "execution_count": 6, @@ -1903,8 +1903,8 @@ "arr = (\n", " arr\n", " .drop_indexes([\"origin\", \"destination\"])\n", - " .set_xindex(\"origin\", GeoVectorIndex, crs=origin.crs)\n", - " .set_xindex(\"destination\", GeoVectorIndex, crs=destination.crs)\n", + " .set_xindex(\"origin\", GeometryIndex, crs=origin.crs)\n", + " .set_xindex(\"destination\", GeometryIndex, crs=destination.crs)\n", ")\n", "\n", "arr" @@ -1922,8 +1922,8 @@ " mode PandasIndex\n", " day PandasIndex\n", " time PandasIndex\n", - " origin GeoVectorIndex(crs=EPSG:4267)\n", - " destination GeoVectorIndex(crs=EPSG:4267)" + " origin GeometryIndex(crs=EPSG:4267)\n", + " destination GeometryIndex(crs=EPSG:4267)" ] }, "execution_count": 7, @@ -2399,8 +2399,8 @@ " * origin (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n", " * destination (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n", "Indexes:\n", - " origin GeoVectorIndex(crs=EPSG:4267)\n", - " destination GeoVectorIndex(crs=EPSG:4267)" + " dtype='int64', name='time'))
  • origin
    GeometryIndex(crs=EPSG:4267)
    <xvec.index.GeometryIndex object at 0x16a808bd0>
  • destination
    GeometryIndex(crs=EPSG:4267)
    <xvec.index.GeometryIndex object at 0x16a7fd8d0>
  • " ], "text/plain": [ "\n", @@ -2672,8 +2672,8 @@ " * origin (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n", " * destination (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n", "Indexes:\n", - " origin GeoVectorIndex(crs=EPSG:4267)\n", - " destination GeoVectorIndex(crs=EPSG:4267)" + " origin GeometryIndex(crs=EPSG:4267)\n", + " destination GeometryIndex(crs=EPSG:4267)" ] }, "execution_count": 9, @@ -3079,8 +3079,8 @@ " * origin (origin) object MULTIPOLYGON (((-79.91995239257812 34.807918...\n", " * destination (destination) object MULTIPOLYGON (((-80.72651672363281 35.5...\n", "Indexes:\n", - " origin GeoVectorIndex(crs=EPSG:4267)\n", - " destination GeoVectorIndex(crs=EPSG:4267)" + " dtype=object)
    • mode
      PandasIndex
      PandasIndex(Index(['car', 'bike', 'foot'], dtype='object', name='mode'))
    • origin
      GeometryIndex(crs=EPSG:4267)
      <xvec.index.GeometryIndex object at 0x16a7fee90>
    • destination
      GeometryIndex(crs=EPSG:4267)
      <xvec.index.GeometryIndex object at 0x16a810ad0>
  • " ], "text/plain": [ "\n", @@ -3110,8 +3110,8 @@ " * origin (origin) object MULTIPOLYGON (((-79.91995239257812 34.807918...\n", " * destination (destination) object MULTIPOLYGON (((-80.72651672363281 35.5...\n", "Indexes:\n", - " origin GeoVectorIndex(crs=EPSG:4267)\n", - " destination GeoVectorIndex(crs=EPSG:4267)" + " origin GeometryIndex(crs=EPSG:4267)\n", + " destination GeometryIndex(crs=EPSG:4267)" ] }, "execution_count": 10, @@ -3556,8 +3556,8 @@ " * origin (origin) object MULTIPOLYGON (((-78.11376953125 34.720985412...\n", " * destination (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n", "Indexes:\n", - " origin GeoVectorIndex(crs=EPSG:4267)\n", - " destination GeoVectorIndex(crs=EPSG:4267)" + " dtype='int64', name='time'))
  • origin
    GeometryIndex(crs=EPSG:4267)
    <xvec.index.GeometryIndex object at 0x16a7fd1d0>
  • destination
    GeometryIndex(crs=EPSG:4267)
    <xvec.index.GeometryIndex object at 0x16a7fd8d0>
  • " ], "text/plain": [ "\n", @@ -3868,8 +3868,8 @@ " * origin (origin) object MULTIPOLYGON (((-78.11376953125 34.720985412...\n", " * destination (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n", "Indexes:\n", - " origin GeoVectorIndex(crs=EPSG:4267)\n", - " destination GeoVectorIndex(crs=EPSG:4267)" + " origin GeometryIndex(crs=EPSG:4267)\n", + " destination GeometryIndex(crs=EPSG:4267)" ] }, "execution_count": 11, @@ -3904,8 +3904,8 @@ "File \u001b[0;32m~/miniconda3/envs/xvec_dev/lib/python3.11/site-packages/xarray/core/dataarray.py:1526\u001b[0m, in \u001b[0;36mDataArray.sel\u001b[0;34m(self, indexers, method, tolerance, drop, **indexers_kwargs)\u001b[0m\n\u001b[1;32m 1416\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21msel\u001b[39m(\n\u001b[1;32m 1417\u001b[0m \u001b[38;5;28mself\u001b[39m: T_DataArray,\n\u001b[1;32m 1418\u001b[0m indexers: Mapping[Any, Any] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1422\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mindexers_kwargs: Any,\n\u001b[1;32m 1423\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m T_DataArray:\n\u001b[1;32m 1424\u001b[0m \u001b[38;5;124;03m\"\"\"Return a new DataArray whose data is given by selecting index\u001b[39;00m\n\u001b[1;32m 1425\u001b[0m \u001b[38;5;124;03m labels along the specified dimension(s).\u001b[39;00m\n\u001b[1;32m 1426\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1524\u001b[0m \u001b[38;5;124;03m Dimensions without coordinates: points\u001b[39;00m\n\u001b[1;32m 1525\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m-> 1526\u001b[0m ds \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_to_temp_dataset\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msel\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1527\u001b[0m \u001b[43m \u001b[49m\u001b[43mindexers\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mindexers\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1528\u001b[0m \u001b[43m \u001b[49m\u001b[43mdrop\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdrop\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1529\u001b[0m \u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1530\u001b[0m \u001b[43m \u001b[49m\u001b[43mtolerance\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtolerance\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1531\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mindexers_kwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1532\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1533\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_from_temp_dataset(ds)\n", "File \u001b[0;32m~/miniconda3/envs/xvec_dev/lib/python3.11/site-packages/xarray/core/dataset.py:2554\u001b[0m, in \u001b[0;36mDataset.sel\u001b[0;34m(self, indexers, method, tolerance, drop, **indexers_kwargs)\u001b[0m\n\u001b[1;32m 2493\u001b[0m \u001b[38;5;124;03m\"\"\"Returns a new dataset with each array indexed by tick labels\u001b[39;00m\n\u001b[1;32m 2494\u001b[0m \u001b[38;5;124;03malong the specified dimension(s).\u001b[39;00m\n\u001b[1;32m 2495\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 2551\u001b[0m \u001b[38;5;124;03mDataArray.sel\u001b[39;00m\n\u001b[1;32m 2552\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 2553\u001b[0m indexers \u001b[38;5;241m=\u001b[39m either_dict_or_kwargs(indexers, indexers_kwargs, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msel\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m-> 2554\u001b[0m query_results \u001b[38;5;241m=\u001b[39m \u001b[43mmap_index_queries\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 2555\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mindexers\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mindexers\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtolerance\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtolerance\u001b[49m\n\u001b[1;32m 2556\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2558\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m drop:\n\u001b[1;32m 2559\u001b[0m no_scalar_variables \u001b[38;5;241m=\u001b[39m {}\n", "File \u001b[0;32m~/miniconda3/envs/xvec_dev/lib/python3.11/site-packages/xarray/core/indexing.py:183\u001b[0m, in \u001b[0;36mmap_index_queries\u001b[0;34m(obj, indexers, method, tolerance, **indexers_kwargs)\u001b[0m\n\u001b[1;32m 181\u001b[0m results\u001b[38;5;241m.\u001b[39mappend(IndexSelResult(labels))\n\u001b[1;32m 182\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 183\u001b[0m results\u001b[38;5;241m.\u001b[39mappend(\u001b[43mindex\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msel\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43moptions\u001b[49m\u001b[43m)\u001b[49m) \u001b[38;5;66;03m# type: ignore[call-arg]\u001b[39;00m\n\u001b[1;32m 185\u001b[0m merged \u001b[38;5;241m=\u001b[39m merge_sel_results(results)\n\u001b[1;32m 187\u001b[0m \u001b[38;5;66;03m# drop dimension coordinates found in dimension indexers\u001b[39;00m\n\u001b[1;32m 188\u001b[0m \u001b[38;5;66;03m# (also drop multi-index if any)\u001b[39;00m\n\u001b[1;32m 189\u001b[0m \u001b[38;5;66;03m# (.sel() already ensures alignment)\u001b[39;00m\n", - "File \u001b[0;32m~/Git/github/benbovy/xvec/xvec/index.py:159\u001b[0m, in \u001b[0;36mGeoVectorIndex.sel\u001b[0;34m(self, labels, method, tolerance)\u001b[0m\n\u001b[1;32m 152\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_index\u001b[38;5;241m.\u001b[39msel(labels)\n\u001b[1;32m 153\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 154\u001b[0m \u001b[38;5;66;03m# We reuse here `method` and `tolerance` options of\u001b[39;00m\n\u001b[1;32m 155\u001b[0m \u001b[38;5;66;03m# `xarray.indexes.PandasIndex` as `predicate` and `distance`\u001b[39;00m\n\u001b[1;32m 156\u001b[0m \u001b[38;5;66;03m# options when `labels` is a single geometry.\u001b[39;00m\n\u001b[1;32m 157\u001b[0m \u001b[38;5;66;03m# Xarray currently doesn't support custom options\u001b[39;00m\n\u001b[1;32m 158\u001b[0m \u001b[38;5;66;03m# (see https://github.com/pydata/xarray/issues/7099)\u001b[39;00m\n\u001b[0;32m--> 159\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_sel_sindex\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtolerance\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Git/github/benbovy/xvec/xvec/index.py:116\u001b[0m, in \u001b[0;36mGeoVectorIndex._sel_sindex\u001b[0;34m(self, labels, method, tolerance)\u001b[0m\n\u001b[1;32m 114\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m method \u001b[38;5;241m!=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnearest\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m 115\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(label, shapely\u001b[38;5;241m.\u001b[39mGeometry):\n\u001b[0;32m--> 116\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 117\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mselection with another method than nearest only supports \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 118\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124ma single geometry as input label.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 119\u001b[0m )\n\u001b[1;32m 121\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(label, DataArray):\n\u001b[1;32m 122\u001b[0m label_array \u001b[38;5;241m=\u001b[39m label\u001b[38;5;241m.\u001b[39m_variable\u001b[38;5;241m.\u001b[39m_data\n", + "File \u001b[0;32m~/Git/github/benbovy/xvec/xvec/index.py:159\u001b[0m, in \u001b[0;36mGeometryIndex.sel\u001b[0;34m(self, labels, method, tolerance)\u001b[0m\n\u001b[1;32m 152\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_index\u001b[38;5;241m.\u001b[39msel(labels)\n\u001b[1;32m 153\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 154\u001b[0m \u001b[38;5;66;03m# We reuse here `method` and `tolerance` options of\u001b[39;00m\n\u001b[1;32m 155\u001b[0m \u001b[38;5;66;03m# `xarray.indexes.PandasIndex` as `predicate` and `distance`\u001b[39;00m\n\u001b[1;32m 156\u001b[0m \u001b[38;5;66;03m# options when `labels` is a single geometry.\u001b[39;00m\n\u001b[1;32m 157\u001b[0m \u001b[38;5;66;03m# Xarray currently doesn't support custom options\u001b[39;00m\n\u001b[1;32m 158\u001b[0m \u001b[38;5;66;03m# (see https://github.com/pydata/xarray/issues/7099)\u001b[39;00m\n\u001b[0;32m--> 159\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_sel_sindex\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtolerance\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Git/github/benbovy/xvec/xvec/index.py:116\u001b[0m, in \u001b[0;36mGeometryIndex._sel_sindex\u001b[0;34m(self, labels, method, tolerance)\u001b[0m\n\u001b[1;32m 114\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m method \u001b[38;5;241m!=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnearest\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m 115\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(label, shapely\u001b[38;5;241m.\u001b[39mGeometry):\n\u001b[0;32m--> 116\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 117\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mselection with another method than nearest only supports \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 118\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124ma single geometry as input label.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 119\u001b[0m )\n\u001b[1;32m 121\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(label, DataArray):\n\u001b[1;32m 122\u001b[0m label_array \u001b[38;5;241m=\u001b[39m label\u001b[38;5;241m.\u001b[39m_variable\u001b[38;5;241m.\u001b[39m_data\n", "\u001b[0;31mValueError\u001b[0m: selection with another method than nearest only supports a single geometry as input label." ] } @@ -4341,8 +4341,8 @@ " * origin (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n", " * destination (destination) object MULTIPOLYGON (((-77.96073150634766 34.1...\n", "Indexes:\n", - " origin GeoVectorIndex(crs=EPSG:4267)\n", - " destination GeoVectorIndex(crs=EPSG:4267)" + " dtype='int64', name='time'))
  • origin
    GeometryIndex(crs=EPSG:4267)
    <xvec.index.GeometryIndex object at 0x16a816250>
  • destination
    GeometryIndex(crs=EPSG:4267)
    <xvec.index.GeometryIndex object at 0x16a8103d0>
  • " ], "text/plain": [ "\n", @@ -4516,8 +4516,8 @@ " * origin (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n", " * destination (destination) object MULTIPOLYGON (((-77.96073150634766 34.1...\n", "Indexes:\n", - " origin GeoVectorIndex(crs=EPSG:4267)\n", - " destination GeoVectorIndex(crs=EPSG:4267)" + " origin GeometryIndex(crs=EPSG:4267)\n", + " destination GeometryIndex(crs=EPSG:4267)" ] }, "execution_count": 13, @@ -4949,8 +4949,8 @@ " * origin (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n", " * destination (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n", "Indexes:\n", - " origin GeoVectorIndex(crs=EPSG:4267)\n", - " destination GeoVectorIndex(crs=EPSG:4267)" + " dtype='int64', name='time'))
  • origin
    GeometryIndex(crs=EPSG:4267)
    <xvec.index.GeometryIndex object at 0x16bfa9550>
  • destination
    GeometryIndex(crs=EPSG:4267)
    <xvec.index.GeometryIndex object at 0x16bfabfd0>
  • " ], "text/plain": [ "\n", @@ -5224,8 +5224,8 @@ " * origin (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n", " * destination (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n", "Indexes:\n", - " origin GeoVectorIndex(crs=EPSG:4267)\n", - " destination GeoVectorIndex(crs=EPSG:4267)" + " origin GeometryIndex(crs=EPSG:4267)\n", + " destination GeometryIndex(crs=EPSG:4267)" ] }, "execution_count": 14, diff --git a/xvec/__init__.py b/xvec/__init__.py index bca5ee9..15ad2cb 100644 --- a/xvec/__init__.py +++ b/xvec/__init__.py @@ -1,6 +1,6 @@ from importlib.metadata import PackageNotFoundError, version -from .index import GeoVectorIndex # noqa +from .index import GeometryIndex # noqa try: __version__ = version("xvec") diff --git a/xvec/index.py b/xvec/index.py index 5425fca..8b5df94 100644 --- a/xvec/index.py +++ b/xvec/index.py @@ -11,7 +11,7 @@ from xarray.indexes import Index, PandasIndex -class GeoVectorIndex(Index): +class GeometryIndex(Index): """An CRS-aware, Xarray-compatible index for vector geometries. This index can be set from any 1-dimensional coordinate of @@ -79,10 +79,10 @@ def from_variables( @classmethod def concat( cls, - indexes: Sequence[GeoVectorIndex], + indexes: Sequence[GeometryIndex], dim: Hashable, positions: Iterable[Iterable[int]] | None = None, - ) -> GeoVectorIndex: + ) -> GeometryIndex: crss = [idx.crs for idx in indexes] if any([s is not None and s != crss[0] for s in crss]): @@ -165,15 +165,15 @@ def sel( return self._sel_sindex(labels, method, tolerance) def equals(self, other: Index) -> bool: - if not isinstance(other, GeoVectorIndex): + if not isinstance(other, GeometryIndex): return False if other.crs != self.crs: return False return self._index.equals(other._index) def join( - self: GeoVectorIndex, other: GeoVectorIndex, how: str = "inner" - ) -> GeoVectorIndex: + self: GeometryIndex, other: GeometryIndex, how: str = "inner" + ) -> GeometryIndex: if other.crs is not None and other.crs != self.crs: raise ValueError("conflicting CRS for left and right indexes to join") @@ -181,7 +181,7 @@ def join( return type(self)(index, self.crs) def reindex_like( - self, other: GeoVectorIndex, method=None, tolerance=None + self, other: GeometryIndex, method=None, tolerance=None ) -> dict[Hashable, Any]: if other.crs is not None and other.crs != self.crs: raise ValueError("conflicting CRS between the current and new indexes") @@ -190,7 +190,7 @@ def reindex_like( other._index, method=method, tolerance=tolerance ) - def roll(self, shifts: Mapping[Any, int]) -> GeoVectorIndex: + def roll(self, shifts: Mapping[Any, int]) -> GeometryIndex: index = self._index.roll(shifts) return type(self)(index, self.crs) diff --git a/xvec/tests/test_index.py b/xvec/tests/test_index.py index 4d822f1..17cd64d 100644 --- a/xvec/tests/test_index.py +++ b/xvec/tests/test_index.py @@ -4,7 +4,7 @@ import xarray as xr from pyproj import CRS -from xvec import GeoVectorIndex +from xvec import GeometryIndex @pytest.fixture(scope="session") @@ -21,9 +21,9 @@ def geom_dataset_no_index(geom_array): @pytest.fixture(scope="session") def geom_dataset(geom_dataset_no_index): - # a dataset with a geometry coordinate baked by a GeoVectorIndex + # a dataset with a geometry coordinate baked by a GeometryIndex crs = CRS.from_user_input(26915) - return geom_dataset_no_index.set_xindex("geom", GeoVectorIndex, crs=crs) + return geom_dataset_no_index.set_xindex("geom", GeometryIndex, crs=crs) @pytest.fixture(scope="session") @@ -31,42 +31,42 @@ def first_geom_dataset(geom_dataset, geom_array): return ( xr.Dataset(coords={"geom": [geom_array[0]]}) .drop_indexes("geom") - .set_xindex("geom", GeoVectorIndex, crs=geom_dataset.xindexes["geom"].crs) + .set_xindex("geom", GeometryIndex, crs=geom_dataset.xindexes["geom"].crs) ) def test_set_index(geom_dataset_no_index): crs = CRS.from_user_input(26915) - ds = geom_dataset_no_index.set_xindex("geom", GeoVectorIndex, crs=crs) + ds = geom_dataset_no_index.set_xindex("geom", GeometryIndex, crs=crs) # test properties - assert isinstance(ds.xindexes["geom"], GeoVectorIndex) + assert isinstance(ds.xindexes["geom"], GeometryIndex) assert ds.xindexes["geom"].crs == crs np.testing.assert_array_equal(ds.xindexes["geom"].sindex.geometries, ds.geom.values) - # test `GeoVectorIndex.create_variables` + # test `GeometryIndex.create_variables` assert ds.geom.variable._data.array is ds.xindexes["geom"]._index.index - no_crs_ds = geom_dataset_no_index.set_xindex("geom", GeoVectorIndex) + no_crs_ds = geom_dataset_no_index.set_xindex("geom", GeometryIndex) assert no_crs_ds.xindexes["geom"].crs is None no_geom_ds = xr.Dataset(coords={"no_geom": ("x", [0, 1, 2])}) with pytest.raises(ValueError, match="array must contain shapely.Geometry objects"): - no_geom_ds.set_xindex("no_geom", GeoVectorIndex, crs=crs) + no_geom_ds.set_xindex("no_geom", GeometryIndex, crs=crs) def test_concat(geom_dataset, geom_array, geom_dataset_no_index): expected = ( xr.Dataset(coords={"geom": np.concatenate([geom_array, geom_array])}) .drop_indexes("geom") - .set_xindex("geom", GeoVectorIndex, crs=geom_dataset.xindexes["geom"].crs) + .set_xindex("geom", GeometryIndex, crs=geom_dataset.xindexes["geom"].crs) ) actual = xr.concat([geom_dataset, geom_dataset], "geom") xr.testing.assert_identical(actual, expected) # different CRS crs = CRS.from_user_input(4267) - geom_dataset_alt = geom_dataset_no_index.set_xindex("geom", GeoVectorIndex, crs=crs) + geom_dataset_alt = geom_dataset_no_index.set_xindex("geom", GeometryIndex, crs=crs) with pytest.raises(ValueError, match="conflicting CRS for coordinates to concat"): xr.concat([geom_dataset, geom_dataset_alt], "geom") @@ -118,7 +118,7 @@ def test_equals(geom_dataset, geom_dataset_no_index, first_geom_dataset): # different CRS crs = CRS.from_user_input(4267) - other = geom_dataset_no_index.set_xindex("geom", GeoVectorIndex, crs=crs) + other = geom_dataset_no_index.set_xindex("geom", GeometryIndex, crs=crs) assert not geom_dataset.xindexes["geom"].equals(other.xindexes["geom"]) # different geometries @@ -126,13 +126,13 @@ def test_equals(geom_dataset, geom_dataset_no_index, first_geom_dataset): def test_align(geom_dataset, first_geom_dataset, geom_dataset_no_index): - # test GeoVectorIndex's `join` and `reindex_like` + # test GeometryIndex's `join` and `reindex_like` aligned = xr.align(geom_dataset, first_geom_dataset, join="inner") assert all(ds.identical(first_geom_dataset) for ds in aligned) # test conflicting CRS crs = CRS.from_user_input(4267) - geom_dataset_alt = geom_dataset_no_index.set_xindex("geom", GeoVectorIndex, crs=crs) + geom_dataset_alt = geom_dataset_no_index.set_xindex("geom", GeometryIndex, crs=crs) with pytest.raises(ValueError, match="conflicting CRS for left and right indexes"): xr.align(geom_dataset_alt, first_geom_dataset, join="inner") @@ -147,7 +147,7 @@ def test_roll(geom_dataset, geom_array): expected = ( xr.Dataset(coords={"geom": np.roll(geom_array, 1)}) .drop_indexes("geom") - .set_xindex("geom", GeoVectorIndex, crs=geom_dataset.xindexes["geom"].crs) + .set_xindex("geom", GeometryIndex, crs=geom_dataset.xindexes["geom"].crs) ) actual = geom_dataset.roll(geom=1, roll_coords=True) xr.testing.assert_identical(actual, expected) @@ -161,5 +161,5 @@ def test_rename(geom_dataset): def test_repr_inline(geom_dataset): actual = geom_dataset.xindexes["geom"]._repr_inline_(70) - expected = "GeoVectorIndex (crs=EPSG:26915)" + expected = "GeometryIndex (crs=EPSG:26915)" assert actual == expected From cd1cb4e195b3bcc278ebf76bd772cc7939096c27 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Tue, 22 Nov 2022 18:19:39 +0100 Subject: [PATCH 23/28] review CRS check and error vs. warning Try being consistent with geopandas. --- xvec/index.py | 90 +++++++++++++++++++++++++++++++++------- xvec/tests/test_index.py | 15 ++++--- 2 files changed, 82 insertions(+), 23 deletions(-) diff --git a/xvec/index.py b/xvec/index.py index 8b5df94..251022c 100644 --- a/xvec/index.py +++ b/xvec/index.py @@ -1,5 +1,6 @@ from __future__ import annotations +import warnings from typing import Any, Hashable, Iterable, Mapping, Sequence import numpy as np @@ -11,6 +12,38 @@ from xarray.indexes import Index, PandasIndex +def _format_crs(crs: CRS | None, max_width: int = 50) -> str: + if crs is not None: + srs = crs.to_string() + else: + srs = "None" + + return srs if len(srs) <= max_width else " ".join([srs[:max_width], "..."]) + + +def _get_common_crs(crs_set: set[CRS | None]): + # code taken from geopandas (BSD-3 Licence) + + crs_not_none = [crs for crs in crs_set if crs is not None] + names = [crs.name for crs in crs_not_none] + + if len(crs_not_none) == 0: + return None + if len(crs_not_none) == 1: + if len(crs_set) != 1: + warnings.warn( + "CRS not set for some of the concatenation inputs. " + f"Setting output's CRS as {names[0]} " + "(the single non-null crs provided)." + ) + return crs_not_none[0] + + raise ValueError( + f"cannot determine common CRS for concatenation inputs, got {names}. " + # "Use `to_crs()` to transform geometries to the same CRS before merging." + ) + + class GeometryIndex(Index): """An CRS-aware, Xarray-compatible index for vector geometries. @@ -64,6 +97,32 @@ def sindex(self) -> shapely.STRtree: self._sindex = shapely.STRtree(self._index.index) return self._sindex + def _check_crs(self, other_crs: CRS | None, allow_none: bool = False) -> bool: + """Check if the index's projection is the same than the given one. + If allow_none is True, empty CRS is treated as the same. + """ + if allow_none: + if self.crs is None or other_crs is None: + return True + if not self.crs == other_crs: + return False + return True + + def _crs_mismatch_warn(self, other_crs: CRS | None, stacklevel: int = 3): + """Raise a CRS mismatch warning with the information on the assigned CRS.""" + srs = _format_crs(self.crs, max_width=50) + other_srs = _format_crs(other_crs, max_width=50) + + # TODO: expand warning message with reproject suggestion + warnings.warn( + "CRS mismatch between the CRS of index geometries " + "and the CRS of input geometries.\n" + f"Index CRS: {srs}\n" + f"Input CRS: {other_srs}\n", + UserWarning, + stacklevel=stacklevel, + ) + @classmethod def from_variables( cls, @@ -83,14 +142,12 @@ def concat( dim: Hashable, positions: Iterable[Iterable[int]] | None = None, ) -> GeometryIndex: - crss = [idx.crs for idx in indexes] - - if any([s is not None and s != crss[0] for s in crss]): - raise ValueError("conflicting CRS for coordinates to concat") + crs_set = {idx.crs for idx in indexes} + crs = _get_common_crs(crs_set) indexes_ = [idx._index for idx in indexes] index = PandasIndex.concat(indexes_, dim, positions) - return cls(index, crss[0]) + return cls(index, crs) def create_variables( self, variables: Mapping[Any, Variable] | None = None @@ -132,8 +189,8 @@ def _sel_sindex(self, labels, method, tolerance): # check for possible CRS of geometry labels # (by default assume same CRS than the index) label_crs = getattr(label_array, "crs", None) - if label_crs is not None and label_crs != self.crs: - raise ValueError("conflicting CRS for input geometries") + if label_crs is not None and not self._check_crs(label_crs, allow_none=True): + self._crs_mismatch_warn(label_crs, stacklevel=4) if not np.all(shapely.is_geometry(label_array)): raise ValueError("labels must be shapely.Geometry objects") @@ -167,15 +224,17 @@ def sel( def equals(self, other: Index) -> bool: if not isinstance(other, GeometryIndex): return False - if other.crs != self.crs: - return False + + if not self._check_crs(other.crs, allow_none=True): + self._crs_mismatch_warn(other.crs) + return self._index.equals(other._index) def join( self: GeometryIndex, other: GeometryIndex, how: str = "inner" ) -> GeometryIndex: - if other.crs is not None and other.crs != self.crs: - raise ValueError("conflicting CRS for left and right indexes to join") + if not self._check_crs(other.crs, allow_none=True): + self._crs_mismatch_warn(other.crs) index = self._index.join(other._index, how=how) return type(self)(index, self.crs) @@ -183,8 +242,8 @@ def join( def reindex_like( self, other: GeometryIndex, method=None, tolerance=None ) -> dict[Hashable, Any]: - if other.crs is not None and other.crs != self.crs: - raise ValueError("conflicting CRS between the current and new indexes") + if not self._check_crs(other.crs, allow_none=True): + self._crs_mismatch_warn(other.crs) return self._index.reindex_like( other._index, method=method, tolerance=tolerance @@ -198,5 +257,6 @@ def rename(self, name_dict, dims_dict): index = self._index.rename(name_dict, dims_dict) return type(self)(index, self.crs) - def _repr_inline_(self, max_width): - return f"{self.__class__.__name__} (crs={self.crs.to_string()})" + def _repr_inline_(self, max_width: int): + srs = _format_crs(self.crs, max_width=max_width) + return f"{self.__class__.__name__} (crs={srs})" diff --git a/xvec/tests/test_index.py b/xvec/tests/test_index.py index 17cd64d..2beff74 100644 --- a/xvec/tests/test_index.py +++ b/xvec/tests/test_index.py @@ -68,7 +68,7 @@ def test_concat(geom_dataset, geom_array, geom_dataset_no_index): crs = CRS.from_user_input(4267) geom_dataset_alt = geom_dataset_no_index.set_xindex("geom", GeometryIndex, crs=crs) - with pytest.raises(ValueError, match="conflicting CRS for coordinates to concat"): + with pytest.raises(ValueError, match="cannot determine common CRS"): xr.concat([geom_dataset, geom_dataset_alt], "geom") @@ -116,17 +116,18 @@ def test_equals(geom_dataset, geom_dataset_no_index, first_geom_dataset): other = xr.Dataset(coords={"geom": [0, 1]}) assert not geom_dataset.xindexes["geom"].equals(other.xindexes["geom"]) - # different CRS + # different CRS (just a warning) crs = CRS.from_user_input(4267) other = geom_dataset_no_index.set_xindex("geom", GeometryIndex, crs=crs) - assert not geom_dataset.xindexes["geom"].equals(other.xindexes["geom"]) + with pytest.warns(UserWarning, match="CRS mismatch"): + assert geom_dataset.xindexes["geom"].equals(other.xindexes["geom"]) # different geometries assert not geom_dataset.xindexes["geom"].equals(first_geom_dataset.xindexes["geom"]) def test_align(geom_dataset, first_geom_dataset, geom_dataset_no_index): - # test GeometryIndex's `join` and `reindex_like` + # test both GeometryIndex's `join` and `reindex_like` aligned = xr.align(geom_dataset, first_geom_dataset, join="inner") assert all(ds.identical(first_geom_dataset) for ds in aligned) @@ -134,12 +135,10 @@ def test_align(geom_dataset, first_geom_dataset, geom_dataset_no_index): crs = CRS.from_user_input(4267) geom_dataset_alt = geom_dataset_no_index.set_xindex("geom", GeometryIndex, crs=crs) - with pytest.raises(ValueError, match="conflicting CRS for left and right indexes"): + with pytest.warns(UserWarning, match="CRS mismatch"): xr.align(geom_dataset_alt, first_geom_dataset, join="inner") - with pytest.raises( - ValueError, match="conflicting CRS between the current and new index" - ): + with pytest.warns(UserWarning, match="CRS mismatch"): first_geom_dataset.reindex_like(geom_dataset_alt) From dcc4a327e37613a7c0e9980f256683c3837593a3 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Wed, 23 Nov 2022 09:34:52 +0100 Subject: [PATCH 24/28] raise error for alignment when CRS mismatch --- xvec/index.py | 33 +++++++++++++++++++-------------- xvec/tests/test_index.py | 27 ++++++++++++++++++++------- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/xvec/index.py b/xvec/index.py index 251022c..13f1e99 100644 --- a/xvec/index.py +++ b/xvec/index.py @@ -34,7 +34,7 @@ def _get_common_crs(crs_set: set[CRS | None]): warnings.warn( "CRS not set for some of the concatenation inputs. " f"Setting output's CRS as {names[0]} " - "(the single non-null crs provided)." + "(the single non-null CRS provided)." ) return crs_not_none[0] @@ -108,21 +108,28 @@ def _check_crs(self, other_crs: CRS | None, allow_none: bool = False) -> bool: return False return True - def _crs_mismatch_warn(self, other_crs: CRS | None, stacklevel: int = 3): - """Raise a CRS mismatch warning with the information on the assigned CRS.""" + def _crs_mismatch_raise( + self, other_crs: CRS | None, warn: bool = False, stacklevel: int = 3 + ): + """Raise a CRS mismatch error or warning with the information + on the assigned CRS. + """ srs = _format_crs(self.crs, max_width=50) other_srs = _format_crs(other_crs, max_width=50) - # TODO: expand warning message with reproject suggestion - warnings.warn( + # TODO: expand message with reproject suggestion + msg = ( "CRS mismatch between the CRS of index geometries " "and the CRS of input geometries.\n" f"Index CRS: {srs}\n" - f"Input CRS: {other_srs}\n", - UserWarning, - stacklevel=stacklevel, + f"Input CRS: {other_srs}\n" ) + if warn: + warnings.warn(msg, UserWarning, stacklevel=stacklevel) + else: + raise ValueError(msg) + @classmethod def from_variables( cls, @@ -190,7 +197,7 @@ def _sel_sindex(self, labels, method, tolerance): # (by default assume same CRS than the index) label_crs = getattr(label_array, "crs", None) if label_crs is not None and not self._check_crs(label_crs, allow_none=True): - self._crs_mismatch_warn(label_crs, stacklevel=4) + self._crs_mismatch_raise(label_crs, warn=True, stacklevel=4) if not np.all(shapely.is_geometry(label_array)): raise ValueError("labels must be shapely.Geometry objects") @@ -224,17 +231,15 @@ def sel( def equals(self, other: Index) -> bool: if not isinstance(other, GeometryIndex): return False - if not self._check_crs(other.crs, allow_none=True): - self._crs_mismatch_warn(other.crs) - + return False return self._index.equals(other._index) def join( self: GeometryIndex, other: GeometryIndex, how: str = "inner" ) -> GeometryIndex: if not self._check_crs(other.crs, allow_none=True): - self._crs_mismatch_warn(other.crs) + self._crs_mismatch_raise(other.crs) index = self._index.join(other._index, how=how) return type(self)(index, self.crs) @@ -243,7 +248,7 @@ def reindex_like( self, other: GeometryIndex, method=None, tolerance=None ) -> dict[Hashable, Any]: if not self._check_crs(other.crs, allow_none=True): - self._crs_mismatch_warn(other.crs) + self._crs_mismatch_raise(other.crs) return self._index.reindex_like( other._index, method=method, tolerance=tolerance diff --git a/xvec/tests/test_index.py b/xvec/tests/test_index.py index 2beff74..6cd63b1 100644 --- a/xvec/tests/test_index.py +++ b/xvec/tests/test_index.py @@ -96,7 +96,7 @@ def test_sel_strict(geom_dataset, geom_array, first_geom_dataset): xr.DataArray([shapely.Point(1, 1)], dims="geom"), ], ) -def test_sel_nearest(geom_dataset, geom_array, first_geom_dataset, label): +def test_sel_nearest(geom_dataset, first_geom_dataset, label): actual = geom_dataset.sel(geom=label, method="nearest") xr.testing.assert_identical(actual, first_geom_dataset) @@ -112,15 +112,22 @@ def test_sel_query(geom_dataset, first_geom_dataset): def test_equals(geom_dataset, geom_dataset_no_index, first_geom_dataset): + assert geom_dataset.xindexes["geom"].equals(geom_dataset.xindexes["geom"]) + # different index types other = xr.Dataset(coords={"geom": [0, 1]}) assert not geom_dataset.xindexes["geom"].equals(other.xindexes["geom"]) - # different CRS (just a warning) + # different CRS crs = CRS.from_user_input(4267) other = geom_dataset_no_index.set_xindex("geom", GeometryIndex, crs=crs) - with pytest.warns(UserWarning, match="CRS mismatch"): - assert geom_dataset.xindexes["geom"].equals(other.xindexes["geom"]) + assert not geom_dataset.xindexes["geom"].equals(other.xindexes["geom"]) + + # no CRS + geom_dataset_no_crs = geom_dataset_no_index.set_xindex("geom", GeometryIndex) + assert geom_dataset_no_crs.xindexes["geom"].equals( + geom_dataset_no_crs.xindexes["geom"] + ) # different geometries assert not geom_dataset.xindexes["geom"].equals(first_geom_dataset.xindexes["geom"]) @@ -129,18 +136,24 @@ def test_equals(geom_dataset, geom_dataset_no_index, first_geom_dataset): def test_align(geom_dataset, first_geom_dataset, geom_dataset_no_index): # test both GeometryIndex's `join` and `reindex_like` aligned = xr.align(geom_dataset, first_geom_dataset, join="inner") - assert all(ds.identical(first_geom_dataset) for ds in aligned) + assert all([ds.identical(first_geom_dataset) for ds in aligned]) # test conflicting CRS crs = CRS.from_user_input(4267) geom_dataset_alt = geom_dataset_no_index.set_xindex("geom", GeometryIndex, crs=crs) - with pytest.warns(UserWarning, match="CRS mismatch"): + with pytest.raises(ValueError, match="CRS mismatch"): xr.align(geom_dataset_alt, first_geom_dataset, join="inner") - with pytest.warns(UserWarning, match="CRS mismatch"): + with pytest.raises(ValueError, match="CRS mismatch"): first_geom_dataset.reindex_like(geom_dataset_alt) + # no CRS + geom_dataset_no_crs = geom_dataset_no_index.set_xindex("geom", GeometryIndex) + first_geom_dataset_no_crs = geom_dataset_no_crs.isel(geom=[0]) + aligned = xr.align(geom_dataset_no_crs, first_geom_dataset_no_crs, join="inner") + assert all([ds.identical(first_geom_dataset_no_crs) for ds in aligned]) + def test_roll(geom_dataset, geom_array): expected = ( From b8fbbd068b01a0c7bfde84e0709d94d64f64b3dd Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Wed, 23 Nov 2022 09:51:19 +0100 Subject: [PATCH 25/28] max_width temp fix --- xvec/index.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/xvec/index.py b/xvec/index.py index 13f1e99..68ffff3 100644 --- a/xvec/index.py +++ b/xvec/index.py @@ -7,7 +7,7 @@ import pandas as pd import shapely from pyproj import CRS -from xarray import DataArray, Variable +from xarray import DataArray, Variable, get_options from xarray.core.indexing import IndexSelResult from xarray.indexes import Index, PandasIndex @@ -263,5 +263,9 @@ def rename(self, name_dict, dims_dict): return type(self)(index, self.crs) def _repr_inline_(self, max_width: int): + # TODO: remove when fixed in XArray + if max_width is None: + max_width = get_options()["display_width"] + srs = _format_crs(self.crs, max_width=max_width) return f"{self.__class__.__name__} (crs={srs})" From 4da5b8522502a1bf60aa18e6c68084792174f360 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Wed, 23 Nov 2022 09:52:06 +0100 Subject: [PATCH 26/28] quickstart notebook: fixed seed to generate data Prevent long diffs. --- doc/source/quickstart.ipynb | 1227 ++++++++++++++++++----------------- 1 file changed, 619 insertions(+), 608 deletions(-) diff --git a/doc/source/quickstart.ipynb b/doc/source/quickstart.ipynb index d4f9c46..9c9ec83 100644 --- a/doc/source/quickstart.ipynb +++ b/doc/source/quickstart.ipynb @@ -82,8 +82,19 @@ "source": [ "mode = [\"car\", \"bike\", \"foot\"]\n", "day = pandas.date_range(\"2015-01-01\", periods=100)\n", - "hours = range(24)\n", - "data = numpy.random.randint(1, 100, size=(3, 100, 24, 100, 100))" + "hours = range(24)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "from numpy.random import default_rng\n", + "\n", + "rng = default_rng(1)\n", + "data = rng.integers(1, 100, size=(3, 100, 24, 100, 100))" ] }, { @@ -95,7 +106,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -465,93 +476,93 @@ " fill: currentColor;\n", "}\n", "
    <xarray.DataArray (mode: 3, day: 100, time: 24, origin: 100, destination: 100)>\n",
    -       "array([[[[[93, 38,  9, ...,  4, 45, 31],\n",
    -       "          [49, 62, 40, ...,  5,  9, 59],\n",
    -       "          [26, 14, 86, ..., 36, 55, 70],\n",
    +       "array([[[[[47, 51, 75, ..., 15, 54, 82],\n",
    +       "          [ 7, 68, 76, ..., 38,  3, 72],\n",
    +       "          [50, 65, 16, ..., 53, 91, 15],\n",
            "          ...,\n",
    -       "          [63, 22, 82, ..., 28, 16, 27],\n",
    -       "          [51, 52, 33, ..., 79, 51, 57],\n",
    -       "          [34, 19, 14, ...,  6, 25, 67]],\n",
    +       "          [30,  1, 15, ...,  6, 36, 46],\n",
    +       "          [19, 47,  3, ..., 75, 42, 69],\n",
    +       "          [48, 94, 34, ..., 47, 54, 86]],\n",
            "\n",
    -       "         [[10, 48, 23, ..., 95, 97,  3],\n",
    -       "          [67, 99, 47, ..., 26, 82, 10],\n",
    -       "          [66, 49,  3, ..., 11, 79, 32],\n",
    +       "         [[67,  5, 73, ..., 95, 34, 44],\n",
    +       "          [80, 22, 89, ..., 93,  5, 41],\n",
    +       "          [47, 70, 65, ..., 44, 82, 54],\n",
            "          ...,\n",
    -       "          [79, 55, 51, ..., 16, 95, 83],\n",
    -       "          [50,  1, 75, ..., 57, 34, 30],\n",
    -       "          [32, 44, 56, ..., 12, 42, 96]],\n",
    +       "          [91, 33, 38, ..., 24, 40,  5],\n",
    +       "          [78, 49,  9, ..., 45,  3,  9],\n",
    +       "          [87, 73, 52, ..., 32, 58, 48]],\n",
            "\n",
    -       "         [[25, 65, 47, ..., 72, 83, 55],\n",
    -       "          [ 5, 97, 93, ..., 60,  7, 98],\n",
    -       "          [58, 44, 38, ..., 27, 72, 14],\n",
    +       "         [[22, 57, 42, ..., 24, 60,  1],\n",
    +       "          [ 4,  3, 94, ..., 66, 40, 17],\n",
    +       "          [87, 55, 87, ..., 41, 26, 55],\n",
            "          ...,\n",
            "...\n",
            "          ...,\n",
    -       "          [23, 19, 82, ..., 91,  4, 90],\n",
    -       "          [ 7, 86, 98, ..., 81, 13, 97],\n",
    -       "          [67, 57, 39, ..., 25, 50, 91]],\n",
    +       "          [67, 50, 96, ..., 28, 89, 55],\n",
    +       "          [83, 98,  3, ..., 91, 25, 14],\n",
    +       "          [81,  7, 45, ..., 18, 78,  9]],\n",
            "\n",
    -       "         [[95, 85, 50, ..., 55, 78, 57],\n",
    -       "          [14,  7, 16, ..., 54,  7, 62],\n",
    -       "          [54, 23, 15, ..., 39, 80, 91],\n",
    +       "         [[29, 94, 53, ...,  3, 52, 47],\n",
    +       "          [93, 43, 11, ..., 94, 71, 37],\n",
    +       "          [80, 34, 29, ..., 12, 67, 48],\n",
            "          ...,\n",
    -       "          [81, 54,  2, ..., 76, 24, 99],\n",
    -       "          [25, 95, 66, ..., 81, 32, 35],\n",
    -       "          [29, 45,  1, ..., 25, 83, 20]],\n",
    +       "          [31, 96, 58, ..., 71, 85, 90],\n",
    +       "          [72, 95, 55, ..., 83, 17, 97],\n",
    +       "          [72, 77, 15, ..., 42, 62,  9]],\n",
            "\n",
    -       "         [[ 4, 59,  6, ..., 17, 69, 19],\n",
    -       "          [82, 93,  9, ...,  5, 11, 90],\n",
    -       "          [11, 53, 15, ..., 13, 64, 82],\n",
    +       "         [[26, 76, 23, ..., 21, 92, 42],\n",
    +       "          [60, 80, 37, ..., 49, 91, 88],\n",
    +       "          [55, 64, 94, ..., 99, 91, 43],\n",
            "          ...,\n",
    -       "          [75, 48, 33, ..., 80, 45, 13],\n",
    -       "          [50, 61,  4, ..., 45, 70, 74],\n",
    -       "          [67, 36, 29, ..., 41, 58, 38]]]]])\n",
    +       "          [80, 85, 15, ..., 23, 42, 52],\n",
    +       "          [66, 91, 73, ..., 10, 44, 22],\n",
    +       "          [75, 27, 89, ..., 37, 57, 20]]]]])\n",
            "Coordinates:\n",
            "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
            "  * day          (day) datetime64[ns] 2015-01-01 2015-01-02 ... 2015-04-10\n",
            "  * time         (time) int64 0 1 2 3 4 5 6 7 8 9 ... 15 16 17 18 19 20 21 22 23\n",
            "  * origin       (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n",
    -       "  * destination  (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...
  • " ], "text/plain": [ "\n", - "array([[[[[93, 38, 9, ..., 4, 45, 31],\n", - " [49, 62, 40, ..., 5, 9, 59],\n", - " [26, 14, 86, ..., 36, 55, 70],\n", + "array([[[[[47, 51, 75, ..., 15, 54, 82],\n", + " [ 7, 68, 76, ..., 38, 3, 72],\n", + " [50, 65, 16, ..., 53, 91, 15],\n", " ...,\n", - " [63, 22, 82, ..., 28, 16, 27],\n", - " [51, 52, 33, ..., 79, 51, 57],\n", - " [34, 19, 14, ..., 6, 25, 67]],\n", + " [30, 1, 15, ..., 6, 36, 46],\n", + " [19, 47, 3, ..., 75, 42, 69],\n", + " [48, 94, 34, ..., 47, 54, 86]],\n", "\n", - " [[10, 48, 23, ..., 95, 97, 3],\n", - " [67, 99, 47, ..., 26, 82, 10],\n", - " [66, 49, 3, ..., 11, 79, 32],\n", + " [[67, 5, 73, ..., 95, 34, 44],\n", + " [80, 22, 89, ..., 93, 5, 41],\n", + " [47, 70, 65, ..., 44, 82, 54],\n", " ...,\n", - " [79, 55, 51, ..., 16, 95, 83],\n", - " [50, 1, 75, ..., 57, 34, 30],\n", - " [32, 44, 56, ..., 12, 42, 96]],\n", + " [91, 33, 38, ..., 24, 40, 5],\n", + " [78, 49, 9, ..., 45, 3, 9],\n", + " [87, 73, 52, ..., 32, 58, 48]],\n", "\n", - " [[25, 65, 47, ..., 72, 83, 55],\n", - " [ 5, 97, 93, ..., 60, 7, 98],\n", - " [58, 44, 38, ..., 27, 72, 14],\n", + " [[22, 57, 42, ..., 24, 60, 1],\n", + " [ 4, 3, 94, ..., 66, 40, 17],\n", + " [87, 55, 87, ..., 41, 26, 55],\n", " ...,\n", "...\n", " ...,\n", - " [23, 19, 82, ..., 91, 4, 90],\n", - " [ 7, 86, 98, ..., 81, 13, 97],\n", - " [67, 57, 39, ..., 25, 50, 91]],\n", + " [67, 50, 96, ..., 28, 89, 55],\n", + " [83, 98, 3, ..., 91, 25, 14],\n", + " [81, 7, 45, ..., 18, 78, 9]],\n", "\n", - " [[95, 85, 50, ..., 55, 78, 57],\n", - " [14, 7, 16, ..., 54, 7, 62],\n", - " [54, 23, 15, ..., 39, 80, 91],\n", + " [[29, 94, 53, ..., 3, 52, 47],\n", + " [93, 43, 11, ..., 94, 71, 37],\n", + " [80, 34, 29, ..., 12, 67, 48],\n", " ...,\n", - " [81, 54, 2, ..., 76, 24, 99],\n", - " [25, 95, 66, ..., 81, 32, 35],\n", - " [29, 45, 1, ..., 25, 83, 20]],\n", + " [31, 96, 58, ..., 71, 85, 90],\n", + " [72, 95, 55, ..., 83, 17, 97],\n", + " [72, 77, 15, ..., 42, 62, 9]],\n", "\n", - " [[ 4, 59, 6, ..., 17, 69, 19],\n", - " [82, 93, 9, ..., 5, 11, 90],\n", - " [11, 53, 15, ..., 13, 64, 82],\n", + " [[26, 76, 23, ..., 21, 92, 42],\n", + " [60, 80, 37, ..., 49, 91, 88],\n", + " [55, 64, 94, ..., 99, 91, 43],\n", " ...,\n", - " [75, 48, 33, ..., 80, 45, 13],\n", - " [50, 61, 4, ..., 45, 70, 74],\n", - " [67, 36, 29, ..., 41, 58, 38]]]]])\n", + " [80, 85, 15, ..., 23, 42, 52],\n", + " [66, 91, 73, ..., 10, 44, 22],\n", + " [75, 27, 89, ..., 37, 57, 20]]]]])\n", "Coordinates:\n", " * mode (mode)
    <xarray.DataArray (mode: 3, day: 100, time: 24, origin: 100, destination: 100)>\n",
    -       "array([[[[[93, 38,  9, ...,  4, 45, 31],\n",
    -       "          [49, 62, 40, ...,  5,  9, 59],\n",
    -       "          [26, 14, 86, ..., 36, 55, 70],\n",
    +       "array([[[[[47, 51, 75, ..., 15, 54, 82],\n",
    +       "          [ 7, 68, 76, ..., 38,  3, 72],\n",
    +       "          [50, 65, 16, ..., 53, 91, 15],\n",
            "          ...,\n",
    -       "          [63, 22, 82, ..., 28, 16, 27],\n",
    -       "          [51, 52, 33, ..., 79, 51, 57],\n",
    -       "          [34, 19, 14, ...,  6, 25, 67]],\n",
    +       "          [30,  1, 15, ...,  6, 36, 46],\n",
    +       "          [19, 47,  3, ..., 75, 42, 69],\n",
    +       "          [48, 94, 34, ..., 47, 54, 86]],\n",
            "\n",
    -       "         [[10, 48, 23, ..., 95, 97,  3],\n",
    -       "          [67, 99, 47, ..., 26, 82, 10],\n",
    -       "          [66, 49,  3, ..., 11, 79, 32],\n",
    +       "         [[67,  5, 73, ..., 95, 34, 44],\n",
    +       "          [80, 22, 89, ..., 93,  5, 41],\n",
    +       "          [47, 70, 65, ..., 44, 82, 54],\n",
            "          ...,\n",
    -       "          [79, 55, 51, ..., 16, 95, 83],\n",
    -       "          [50,  1, 75, ..., 57, 34, 30],\n",
    -       "          [32, 44, 56, ..., 12, 42, 96]],\n",
    +       "          [91, 33, 38, ..., 24, 40,  5],\n",
    +       "          [78, 49,  9, ..., 45,  3,  9],\n",
    +       "          [87, 73, 52, ..., 32, 58, 48]],\n",
            "\n",
    -       "         [[25, 65, 47, ..., 72, 83, 55],\n",
    -       "          [ 5, 97, 93, ..., 60,  7, 98],\n",
    -       "          [58, 44, 38, ..., 27, 72, 14],\n",
    +       "         [[22, 57, 42, ..., 24, 60,  1],\n",
    +       "          [ 4,  3, 94, ..., 66, 40, 17],\n",
    +       "          [87, 55, 87, ..., 41, 26, 55],\n",
            "          ...,\n",
            "...\n",
            "          ...,\n",
    -       "          [23, 19, 82, ..., 91,  4, 90],\n",
    -       "          [ 7, 86, 98, ..., 81, 13, 97],\n",
    -       "          [67, 57, 39, ..., 25, 50, 91]],\n",
    +       "          [67, 50, 96, ..., 28, 89, 55],\n",
    +       "          [83, 98,  3, ..., 91, 25, 14],\n",
    +       "          [81,  7, 45, ..., 18, 78,  9]],\n",
            "\n",
    -       "         [[95, 85, 50, ..., 55, 78, 57],\n",
    -       "          [14,  7, 16, ..., 54,  7, 62],\n",
    -       "          [54, 23, 15, ..., 39, 80, 91],\n",
    +       "         [[29, 94, 53, ...,  3, 52, 47],\n",
    +       "          [93, 43, 11, ..., 94, 71, 37],\n",
    +       "          [80, 34, 29, ..., 12, 67, 48],\n",
            "          ...,\n",
    -       "          [81, 54,  2, ..., 76, 24, 99],\n",
    -       "          [25, 95, 66, ..., 81, 32, 35],\n",
    -       "          [29, 45,  1, ..., 25, 83, 20]],\n",
    +       "          [31, 96, 58, ..., 71, 85, 90],\n",
    +       "          [72, 95, 55, ..., 83, 17, 97],\n",
    +       "          [72, 77, 15, ..., 42, 62,  9]],\n",
            "\n",
    -       "         [[ 4, 59,  6, ..., 17, 69, 19],\n",
    -       "          [82, 93,  9, ...,  5, 11, 90],\n",
    -       "          [11, 53, 15, ..., 13, 64, 82],\n",
    +       "         [[26, 76, 23, ..., 21, 92, 42],\n",
    +       "          [60, 80, 37, ..., 49, 91, 88],\n",
    +       "          [55, 64, 94, ..., 99, 91, 43],\n",
            "          ...,\n",
    -       "          [75, 48, 33, ..., 80, 45, 13],\n",
    -       "          [50, 61,  4, ..., 45, 70, 74],\n",
    -       "          [67, 36, 29, ..., 41, 58, 38]]]]])\n",
    +       "          [80, 85, 15, ..., 23, 42, 52],\n",
    +       "          [66, 91, 73, ..., 10, 44, 22],\n",
    +       "          [75, 27, 89, ..., 37, 57, 20]]]]])\n",
            "Coordinates:\n",
            "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
            "  * day          (day) datetime64[ns] 2015-01-01 2015-01-02 ... 2015-04-10\n",
    @@ -1519,48 +1530,48 @@
            "  * origin       (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n",
            "  * destination  (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n",
            "Indexes:\n",
    -       "    origin       GeometryIndex(crs=EPSG:4267)\n",
    -       "    destination  GeometryIndex(crs=EPSG:4267)
  • " ], "text/plain": [ "\n", - "array([[[[[93, 38, 9, ..., 4, 45, 31],\n", - " [49, 62, 40, ..., 5, 9, 59],\n", - " [26, 14, 86, ..., 36, 55, 70],\n", + "array([[[[[47, 51, 75, ..., 15, 54, 82],\n", + " [ 7, 68, 76, ..., 38, 3, 72],\n", + " [50, 65, 16, ..., 53, 91, 15],\n", " ...,\n", - " [63, 22, 82, ..., 28, 16, 27],\n", - " [51, 52, 33, ..., 79, 51, 57],\n", - " [34, 19, 14, ..., 6, 25, 67]],\n", + " [30, 1, 15, ..., 6, 36, 46],\n", + " [19, 47, 3, ..., 75, 42, 69],\n", + " [48, 94, 34, ..., 47, 54, 86]],\n", "\n", - " [[10, 48, 23, ..., 95, 97, 3],\n", - " [67, 99, 47, ..., 26, 82, 10],\n", - " [66, 49, 3, ..., 11, 79, 32],\n", + " [[67, 5, 73, ..., 95, 34, 44],\n", + " [80, 22, 89, ..., 93, 5, 41],\n", + " [47, 70, 65, ..., 44, 82, 54],\n", " ...,\n", - " [79, 55, 51, ..., 16, 95, 83],\n", - " [50, 1, 75, ..., 57, 34, 30],\n", - " [32, 44, 56, ..., 12, 42, 96]],\n", + " [91, 33, 38, ..., 24, 40, 5],\n", + " [78, 49, 9, ..., 45, 3, 9],\n", + " [87, 73, 52, ..., 32, 58, 48]],\n", "\n", - " [[25, 65, 47, ..., 72, 83, 55],\n", - " [ 5, 97, 93, ..., 60, 7, 98],\n", - " [58, 44, 38, ..., 27, 72, 14],\n", + " [[22, 57, 42, ..., 24, 60, 1],\n", + " [ 4, 3, 94, ..., 66, 40, 17],\n", + " [87, 55, 87, ..., 41, 26, 55],\n", " ...,\n", "...\n", " ...,\n", - " [23, 19, 82, ..., 91, 4, 90],\n", - " [ 7, 86, 98, ..., 81, 13, 97],\n", - " [67, 57, 39, ..., 25, 50, 91]],\n", + " [67, 50, 96, ..., 28, 89, 55],\n", + " [83, 98, 3, ..., 91, 25, 14],\n", + " [81, 7, 45, ..., 18, 78, 9]],\n", "\n", - " [[95, 85, 50, ..., 55, 78, 57],\n", - " [14, 7, 16, ..., 54, 7, 62],\n", - " [54, 23, 15, ..., 39, 80, 91],\n", + " [[29, 94, 53, ..., 3, 52, 47],\n", + " [93, 43, 11, ..., 94, 71, 37],\n", + " [80, 34, 29, ..., 12, 67, 48],\n", " ...,\n", - " [81, 54, 2, ..., 76, 24, 99],\n", - " [25, 95, 66, ..., 81, 32, 35],\n", - " [29, 45, 1, ..., 25, 83, 20]],\n", + " [31, 96, 58, ..., 71, 85, 90],\n", + " [72, 95, 55, ..., 83, 17, 97],\n", + " [72, 77, 15, ..., 42, 62, 9]],\n", "\n", - " [[ 4, 59, 6, ..., 17, 69, 19],\n", - " [82, 93, 9, ..., 5, 11, 90],\n", - " [11, 53, 15, ..., 13, 64, 82],\n", + " [[26, 76, 23, ..., 21, 92, 42],\n", + " [60, 80, 37, ..., 49, 91, 88],\n", + " [55, 64, 94, ..., 99, 91, 43],\n", " ...,\n", - " [75, 48, 33, ..., 80, 45, 13],\n", - " [50, 61, 4, ..., 45, 70, 74],\n", - " [67, 36, 29, ..., 41, 58, 38]]]]])\n", + " [80, 85, 15, ..., 23, 42, 52],\n", + " [66, 91, 73, ..., 10, 44, 22],\n", + " [75, 27, 89, ..., 37, 57, 20]]]]])\n", "Coordinates:\n", " * mode (mode)
    <xarray.DataArray (mode: 3, day: 100, time: 24, origin: 2, destination: 100)>\n",
    -       "array([[[[[93, 38,  9, ...,  4, 45, 31],\n",
    -       "          [13, 77, 81, ..., 92, 13, 54]],\n",
    +       "array([[[[[47, 51, 75, ..., 15, 54, 82],\n",
    +       "          [ 7, 61, 46, ...,  7, 65, 17]],\n",
            "\n",
    -       "         [[10, 48, 23, ..., 95, 97,  3],\n",
    -       "          [30, 38, 56, ..., 84, 91, 44]],\n",
    +       "         [[67,  5, 73, ..., 95, 34, 44],\n",
    +       "          [62, 80,  2, ..., 56, 38, 33]],\n",
            "\n",
    -       "         [[25, 65, 47, ..., 72, 83, 55],\n",
    -       "          [90, 97, 52, ..., 16, 33, 80]],\n",
    +       "         [[22, 57, 42, ..., 24, 60,  1],\n",
    +       "          [47,  3, 82, ..., 52, 56, 23]],\n",
            "\n",
            "         ...,\n",
            "\n",
    -       "         [[65, 98, 32, ..., 13, 88, 39],\n",
    -       "          [36, 70, 20, ..., 55, 91, 27]],\n",
    +       "         [[ 6, 83, 84, ..., 50, 77, 13],\n",
    +       "          [66, 67, 24, ..., 60, 14, 91]],\n",
            "\n",
    -       "         [[56, 57, 14, ..., 81, 96, 11],\n",
    -       "          [30, 12, 56, ..., 84, 63, 69]],\n",
    +       "         [[55, 85, 99, ..., 28, 13, 39],\n",
    +       "          [76, 92, 33, ..., 18, 31, 75]],\n",
            "\n",
    -       "         [[69, 12, 89, ..., 77, 89, 70],\n",
    -       "          [94, 93,  4, ..., 88, 26, 77]]],\n",
    +       "         [[86, 47, 79, ..., 70, 99, 93],\n",
    +       "          [86, 87, 78, ..., 66, 26, 80]]],\n",
            "\n",
            "...\n",
            "\n",
    -       "        [[[60, 66, 58, ..., 96, 79, 16],\n",
    -       "          [67, 14, 14, ..., 44, 85, 86]],\n",
    +       "        [[[52, 34, 75, ...,  7, 84, 13],\n",
    +       "          [34, 11, 38, ..., 70, 89, 56]],\n",
            "\n",
    -       "         [[52, 99, 50, ..., 65, 88, 48],\n",
    -       "          [76, 38, 54, ..., 62, 23, 33]],\n",
    +       "         [[ 9, 52, 95, ..., 82, 89, 44],\n",
    +       "          [84, 94, 76, ..., 54, 34, 49]],\n",
            "\n",
    -       "         [[84,  2, 57, ..., 59, 13, 10],\n",
    -       "          [42, 88, 42, ..., 52, 36, 95]],\n",
    +       "         [[ 9, 64, 85, ..., 28, 44, 22],\n",
    +       "          [15, 18, 14, ..., 47, 81, 18]],\n",
            "\n",
            "         ...,\n",
            "\n",
    -       "         [[61, 31, 53, ..., 92, 83, 21],\n",
    -       "          [11, 87, 17, ...,  7, 37, 32]],\n",
    +       "         [[ 9, 82, 60, ..., 64, 56, 98],\n",
    +       "          [30, 70, 34, ..., 17, 34, 86]],\n",
            "\n",
    -       "         [[95, 85, 50, ..., 55, 78, 57],\n",
    -       "          [38, 48, 13, ...,  3, 70, 19]],\n",
    +       "         [[29, 94, 53, ...,  3, 52, 47],\n",
    +       "          [56, 99, 33, ..., 81, 88, 85]],\n",
            "\n",
    -       "         [[ 4, 59,  6, ..., 17, 69, 19],\n",
    -       "          [90, 83, 77, ..., 88, 42, 31]]]]])\n",
    +       "         [[26, 76, 23, ..., 21, 92, 42],\n",
    +       "          [44, 47, 95, ..., 84,  5, 86]]]]])\n",
            "Coordinates:\n",
            "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
            "  * day          (day) datetime64[ns] 2015-01-01 2015-01-02 ... 2015-04-10\n",
    @@ -2399,48 +2410,48 @@
            "  * origin       (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n",
            "  * destination  (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n",
            "Indexes:\n",
    -       "    origin       GeometryIndex(crs=EPSG:4267)\n",
    -       "    destination  GeometryIndex(crs=EPSG:4267)
  • " ], "text/plain": [ "\n", - "array([[[[[93, 38, 9, ..., 4, 45, 31],\n", - " [13, 77, 81, ..., 92, 13, 54]],\n", + "array([[[[[47, 51, 75, ..., 15, 54, 82],\n", + " [ 7, 61, 46, ..., 7, 65, 17]],\n", "\n", - " [[10, 48, 23, ..., 95, 97, 3],\n", - " [30, 38, 56, ..., 84, 91, 44]],\n", + " [[67, 5, 73, ..., 95, 34, 44],\n", + " [62, 80, 2, ..., 56, 38, 33]],\n", "\n", - " [[25, 65, 47, ..., 72, 83, 55],\n", - " [90, 97, 52, ..., 16, 33, 80]],\n", + " [[22, 57, 42, ..., 24, 60, 1],\n", + " [47, 3, 82, ..., 52, 56, 23]],\n", "\n", " ...,\n", "\n", - " [[65, 98, 32, ..., 13, 88, 39],\n", - " [36, 70, 20, ..., 55, 91, 27]],\n", + " [[ 6, 83, 84, ..., 50, 77, 13],\n", + " [66, 67, 24, ..., 60, 14, 91]],\n", "\n", - " [[56, 57, 14, ..., 81, 96, 11],\n", - " [30, 12, 56, ..., 84, 63, 69]],\n", + " [[55, 85, 99, ..., 28, 13, 39],\n", + " [76, 92, 33, ..., 18, 31, 75]],\n", "\n", - " [[69, 12, 89, ..., 77, 89, 70],\n", - " [94, 93, 4, ..., 88, 26, 77]]],\n", + " [[86, 47, 79, ..., 70, 99, 93],\n", + " [86, 87, 78, ..., 66, 26, 80]]],\n", "\n", "...\n", "\n", - " [[[60, 66, 58, ..., 96, 79, 16],\n", - " [67, 14, 14, ..., 44, 85, 86]],\n", + " [[[52, 34, 75, ..., 7, 84, 13],\n", + " [34, 11, 38, ..., 70, 89, 56]],\n", "\n", - " [[52, 99, 50, ..., 65, 88, 48],\n", - " [76, 38, 54, ..., 62, 23, 33]],\n", + " [[ 9, 52, 95, ..., 82, 89, 44],\n", + " [84, 94, 76, ..., 54, 34, 49]],\n", "\n", - " [[84, 2, 57, ..., 59, 13, 10],\n", - " [42, 88, 42, ..., 52, 36, 95]],\n", + " [[ 9, 64, 85, ..., 28, 44, 22],\n", + " [15, 18, 14, ..., 47, 81, 18]],\n", "\n", " ...,\n", "\n", - " [[61, 31, 53, ..., 92, 83, 21],\n", - " [11, 87, 17, ..., 7, 37, 32]],\n", + " [[ 9, 82, 60, ..., 64, 56, 98],\n", + " [30, 70, 34, ..., 17, 34, 86]],\n", "\n", - " [[95, 85, 50, ..., 55, 78, 57],\n", - " [38, 48, 13, ..., 3, 70, 19]],\n", + " [[29, 94, 53, ..., 3, 52, 47],\n", + " [56, 99, 33, ..., 81, 88, 85]],\n", "\n", - " [[ 4, 59, 6, ..., 17, 69, 19],\n", - " [90, 83, 77, ..., 88, 42, 31]]]]])\n", + " [[26, 76, 23, ..., 21, 92, 42],\n", + " [44, 47, 95, ..., 84, 5, 86]]]]])\n", "Coordinates:\n", " * mode (mode)
    <xarray.DataArray (mode: 3, origin: 2, destination: 2)>\n",
    -       "array([[[52, 62],\n",
    -       "        [66, 29]],\n",
    +       "array([[[47, 23],\n",
    +       "        [93, 84]],\n",
            "\n",
    -       "       [[41, 97],\n",
    -       "        [30, 54]],\n",
    +       "       [[35, 46],\n",
    +       "        [18, 68]],\n",
            "\n",
    -       "       [[73, 10],\n",
    -       "        [65, 86]]])\n",
    +       "       [[62, 69],\n",
    +       "        [49, 32]]])\n",
            "Coordinates:\n",
            "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
            "    day          datetime64[ns] 2015-01-01\n",
    @@ -3079,30 +3090,30 @@
            "  * origin       (origin) object MULTIPOLYGON (((-79.91995239257812 34.807918...\n",
            "  * destination  (destination) object MULTIPOLYGON (((-80.72651672363281 35.5...\n",
            "Indexes:\n",
    -       "    origin       GeometryIndex(crs=EPSG:4267)\n",
    -       "    destination  GeometryIndex(crs=EPSG:4267)
    • mode
      PandasIndex
      PandasIndex(Index(['car', 'bike', 'foot'], dtype='object', name='mode'))
    • origin
      GeometryIndex (crs=EPSG:4267)
      <xvec.index.GeometryIndex object at 0x16ab7f3d0>
    • destination
      GeometryIndex (crs=EPSG:4267)
      <xvec.index.GeometryIndex object at 0x16ab7de10>
  • " ], "text/plain": [ "\n", - "array([[[52, 62],\n", - " [66, 29]],\n", + "array([[[47, 23],\n", + " [93, 84]],\n", "\n", - " [[41, 97],\n", - " [30, 54]],\n", + " [[35, 46],\n", + " [18, 68]],\n", "\n", - " [[73, 10],\n", - " [65, 86]]])\n", + " [[62, 69],\n", + " [49, 32]]])\n", "Coordinates:\n", " * mode (mode)
    <xarray.DataArray (mode: 3, day: 100, time: 24, origin: 41, destination: 100)>\n",
    -       "array([[[[[78, 29, 75, ..., 39, 93, 97],\n",
    -       "          [84, 21, 64, ...,  7, 67,  5],\n",
    -       "          [20, 96, 69, ..., 51, 96, 44],\n",
    +       "array([[[[[77, 84, 80, ..., 31, 71, 18],\n",
    +       "          [30, 62, 58, ..., 26,  9, 61],\n",
    +       "          [96, 86, 84, ..., 31, 69, 57],\n",
            "          ...,\n",
    -       "          [ 9,  9, 51, ..., 22, 29, 87],\n",
    -       "          [79, 63, 20, ..., 37, 85, 63],\n",
    -       "          [60, 50, 35, ..., 67, 91, 44]],\n",
    +       "          [98, 86, 56, ..., 94, 22, 75],\n",
    +       "          [85, 42, 89, ..., 23, 69, 10],\n",
    +       "          [98, 90, 56, ..., 35, 26, 39]],\n",
            "\n",
    -       "         [[88, 85, 29, ..., 34, 38,  4],\n",
    -       "          [94, 70, 54, ..., 24, 97, 53],\n",
    -       "          [35, 15, 35, ..., 46, 35, 51],\n",
    +       "         [[ 7, 45, 63, ..., 82, 61, 99],\n",
    +       "          [88, 96, 84, ...,  7, 87, 18],\n",
    +       "          [67, 72, 77, ..., 27, 54,  5],\n",
            "          ...,\n",
    -       "          [76, 75, 34, ..., 29, 84, 27],\n",
    -       "          [32, 42, 60, ..., 21, 29, 53],\n",
    -       "          [61, 76, 63, ..., 55, 11, 72]],\n",
    +       "          [86, 52, 62, ..., 50, 51, 28],\n",
    +       "          [50,  8, 17, ..., 63, 93, 77],\n",
    +       "          [95, 50, 26, ..., 56, 85, 46]],\n",
            "\n",
    -       "         [[52, 64, 89, ..., 76, 62, 18],\n",
    -       "          [34, 25, 76, ..., 88,  7, 41],\n",
    -       "          [37, 48, 85, ..., 81, 99, 48],\n",
    +       "         [[27, 67, 87, ..., 88, 63, 37],\n",
    +       "          [27, 46, 96, ..., 26, 29, 10],\n",
    +       "          [60, 86, 15, ...,  9, 51, 29],\n",
            "          ...,\n",
            "...\n",
            "          ...,\n",
    -       "          [76, 79, 94, ..., 84, 85, 79],\n",
    -       "          [41, 59, 54, ..., 77, 15, 37],\n",
    -       "          [57, 75,  9, ..., 76, 73, 16]],\n",
    +       "          [86,  7, 13, ..., 66, 74, 38],\n",
    +       "          [59, 33, 37, ..., 85, 92, 18],\n",
    +       "          [90, 87, 39, ..., 15, 99, 71]],\n",
            "\n",
    -       "         [[82, 18, 39, ..., 52, 11, 70],\n",
    -       "          [74, 20, 85, ..., 41, 14, 77],\n",
    -       "          [42, 60, 43, ..., 10, 13,  4],\n",
    +       "         [[28, 62,  2, ..., 41,  2, 84],\n",
    +       "          [70, 99,  7, ..., 55, 28, 78],\n",
    +       "          [27, 78, 16, ..., 73, 89, 24],\n",
            "          ...,\n",
    -       "          [84, 84, 81, ...,  7, 45, 27],\n",
    -       "          [68, 68, 35, ..., 51, 66, 81],\n",
    -       "          [41, 32, 97, ..., 17, 76, 14]],\n",
    +       "          [15, 80, 70, ..., 20, 12, 10],\n",
    +       "          [77,  7, 58, ..., 90, 12, 78],\n",
    +       "          [67, 89, 62, ..., 39,  8, 68]],\n",
            "\n",
    -       "         [[49,  2, 91, ..., 36, 88, 82],\n",
    -       "          [70, 43, 16, ..., 47, 41, 37],\n",
    -       "          [87, 26, 78, ..., 28, 67, 76],\n",
    +       "         [[87, 17, 38, ..., 41, 73, 36],\n",
    +       "          [58, 93, 31, ..., 13, 78, 28],\n",
    +       "          [30, 47, 25, ..., 92, 47, 74],\n",
            "          ...,\n",
    -       "          [20, 92, 47, ..., 22, 65, 80],\n",
    -       "          [15, 14, 42, ..., 76, 27, 94],\n",
    -       "          [79,  4, 49, ..., 84,  8, 73]]]]])\n",
    +       "          [12,  8, 60, ..., 86, 25, 44],\n",
    +       "          [88, 56, 41, ..., 39, 19, 93],\n",
    +       "          [29, 88, 17, ..., 54, 93, 57]]]]])\n",
            "Coordinates:\n",
            "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
            "  * day          (day) datetime64[ns] 2015-01-01 2015-01-02 ... 2015-04-10\n",
    @@ -3556,48 +3567,48 @@
            "  * origin       (origin) object MULTIPOLYGON (((-78.11376953125 34.720985412...\n",
            "  * destination  (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n",
            "Indexes:\n",
    -       "    origin       GeometryIndex(crs=EPSG:4267)\n",
    -       "    destination  GeometryIndex(crs=EPSG:4267)
  • " ], "text/plain": [ "\n", - "array([[[[[78, 29, 75, ..., 39, 93, 97],\n", - " [84, 21, 64, ..., 7, 67, 5],\n", - " [20, 96, 69, ..., 51, 96, 44],\n", + "array([[[[[77, 84, 80, ..., 31, 71, 18],\n", + " [30, 62, 58, ..., 26, 9, 61],\n", + " [96, 86, 84, ..., 31, 69, 57],\n", " ...,\n", - " [ 9, 9, 51, ..., 22, 29, 87],\n", - " [79, 63, 20, ..., 37, 85, 63],\n", - " [60, 50, 35, ..., 67, 91, 44]],\n", + " [98, 86, 56, ..., 94, 22, 75],\n", + " [85, 42, 89, ..., 23, 69, 10],\n", + " [98, 90, 56, ..., 35, 26, 39]],\n", "\n", - " [[88, 85, 29, ..., 34, 38, 4],\n", - " [94, 70, 54, ..., 24, 97, 53],\n", - " [35, 15, 35, ..., 46, 35, 51],\n", + " [[ 7, 45, 63, ..., 82, 61, 99],\n", + " [88, 96, 84, ..., 7, 87, 18],\n", + " [67, 72, 77, ..., 27, 54, 5],\n", " ...,\n", - " [76, 75, 34, ..., 29, 84, 27],\n", - " [32, 42, 60, ..., 21, 29, 53],\n", - " [61, 76, 63, ..., 55, 11, 72]],\n", + " [86, 52, 62, ..., 50, 51, 28],\n", + " [50, 8, 17, ..., 63, 93, 77],\n", + " [95, 50, 26, ..., 56, 85, 46]],\n", "\n", - " [[52, 64, 89, ..., 76, 62, 18],\n", - " [34, 25, 76, ..., 88, 7, 41],\n", - " [37, 48, 85, ..., 81, 99, 48],\n", + " [[27, 67, 87, ..., 88, 63, 37],\n", + " [27, 46, 96, ..., 26, 29, 10],\n", + " [60, 86, 15, ..., 9, 51, 29],\n", " ...,\n", "...\n", " ...,\n", - " [76, 79, 94, ..., 84, 85, 79],\n", - " [41, 59, 54, ..., 77, 15, 37],\n", - " [57, 75, 9, ..., 76, 73, 16]],\n", + " [86, 7, 13, ..., 66, 74, 38],\n", + " [59, 33, 37, ..., 85, 92, 18],\n", + " [90, 87, 39, ..., 15, 99, 71]],\n", "\n", - " [[82, 18, 39, ..., 52, 11, 70],\n", - " [74, 20, 85, ..., 41, 14, 77],\n", - " [42, 60, 43, ..., 10, 13, 4],\n", + " [[28, 62, 2, ..., 41, 2, 84],\n", + " [70, 99, 7, ..., 55, 28, 78],\n", + " [27, 78, 16, ..., 73, 89, 24],\n", " ...,\n", - " [84, 84, 81, ..., 7, 45, 27],\n", - " [68, 68, 35, ..., 51, 66, 81],\n", - " [41, 32, 97, ..., 17, 76, 14]],\n", + " [15, 80, 70, ..., 20, 12, 10],\n", + " [77, 7, 58, ..., 90, 12, 78],\n", + " [67, 89, 62, ..., 39, 8, 68]],\n", "\n", - " [[49, 2, 91, ..., 36, 88, 82],\n", - " [70, 43, 16, ..., 47, 41, 37],\n", - " [87, 26, 78, ..., 28, 67, 76],\n", + " [[87, 17, 38, ..., 41, 73, 36],\n", + " [58, 93, 31, ..., 13, 78, 28],\n", + " [30, 47, 25, ..., 92, 47, 74],\n", " ...,\n", - " [20, 92, 47, ..., 22, 65, 80],\n", - " [15, 14, 42, ..., 76, 27, 94],\n", - " [79, 4, 49, ..., 84, 8, 73]]]]])\n", + " [12, 8, 60, ..., 86, 25, 44],\n", + " [88, 56, 41, ..., 39, 19, 93],\n", + " [29, 88, 17, ..., 54, 93, 57]]]]])\n", "Coordinates:\n", " * mode (mode) 1\u001b[0m \u001b[43marr\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msel\u001b[49m\u001b[43m(\u001b[49m\u001b[43morigin\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[43mshapely\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mPoint\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m80\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m35\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mshapely\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mPoint\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m76\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m35.6\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mintersects\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[0;32mIn [13], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43marr\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msel\u001b[49m\u001b[43m(\u001b[49m\u001b[43morigin\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[43mshapely\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mPoint\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m80\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m35\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mshapely\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mPoint\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m76\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m35.6\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mintersects\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m~/miniconda3/envs/xvec_dev/lib/python3.11/site-packages/xarray/core/dataarray.py:1526\u001b[0m, in \u001b[0;36mDataArray.sel\u001b[0;34m(self, indexers, method, tolerance, drop, **indexers_kwargs)\u001b[0m\n\u001b[1;32m 1416\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21msel\u001b[39m(\n\u001b[1;32m 1417\u001b[0m \u001b[38;5;28mself\u001b[39m: T_DataArray,\n\u001b[1;32m 1418\u001b[0m indexers: Mapping[Any, Any] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1422\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mindexers_kwargs: Any,\n\u001b[1;32m 1423\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m T_DataArray:\n\u001b[1;32m 1424\u001b[0m \u001b[38;5;124;03m\"\"\"Return a new DataArray whose data is given by selecting index\u001b[39;00m\n\u001b[1;32m 1425\u001b[0m \u001b[38;5;124;03m labels along the specified dimension(s).\u001b[39;00m\n\u001b[1;32m 1426\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1524\u001b[0m \u001b[38;5;124;03m Dimensions without coordinates: points\u001b[39;00m\n\u001b[1;32m 1525\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m-> 1526\u001b[0m ds \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_to_temp_dataset\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msel\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1527\u001b[0m \u001b[43m \u001b[49m\u001b[43mindexers\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mindexers\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1528\u001b[0m \u001b[43m \u001b[49m\u001b[43mdrop\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdrop\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1529\u001b[0m \u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1530\u001b[0m \u001b[43m \u001b[49m\u001b[43mtolerance\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtolerance\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1531\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mindexers_kwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1532\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1533\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_from_temp_dataset(ds)\n", "File \u001b[0;32m~/miniconda3/envs/xvec_dev/lib/python3.11/site-packages/xarray/core/dataset.py:2554\u001b[0m, in \u001b[0;36mDataset.sel\u001b[0;34m(self, indexers, method, tolerance, drop, **indexers_kwargs)\u001b[0m\n\u001b[1;32m 2493\u001b[0m \u001b[38;5;124;03m\"\"\"Returns a new dataset with each array indexed by tick labels\u001b[39;00m\n\u001b[1;32m 2494\u001b[0m \u001b[38;5;124;03malong the specified dimension(s).\u001b[39;00m\n\u001b[1;32m 2495\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 2551\u001b[0m \u001b[38;5;124;03mDataArray.sel\u001b[39;00m\n\u001b[1;32m 2552\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 2553\u001b[0m indexers \u001b[38;5;241m=\u001b[39m either_dict_or_kwargs(indexers, indexers_kwargs, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msel\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m-> 2554\u001b[0m query_results \u001b[38;5;241m=\u001b[39m \u001b[43mmap_index_queries\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 2555\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mindexers\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mindexers\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtolerance\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtolerance\u001b[49m\n\u001b[1;32m 2556\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2558\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m drop:\n\u001b[1;32m 2559\u001b[0m no_scalar_variables \u001b[38;5;241m=\u001b[39m {}\n", "File \u001b[0;32m~/miniconda3/envs/xvec_dev/lib/python3.11/site-packages/xarray/core/indexing.py:183\u001b[0m, in \u001b[0;36mmap_index_queries\u001b[0;34m(obj, indexers, method, tolerance, **indexers_kwargs)\u001b[0m\n\u001b[1;32m 181\u001b[0m results\u001b[38;5;241m.\u001b[39mappend(IndexSelResult(labels))\n\u001b[1;32m 182\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 183\u001b[0m results\u001b[38;5;241m.\u001b[39mappend(\u001b[43mindex\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msel\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43moptions\u001b[49m\u001b[43m)\u001b[49m) \u001b[38;5;66;03m# type: ignore[call-arg]\u001b[39;00m\n\u001b[1;32m 185\u001b[0m merged \u001b[38;5;241m=\u001b[39m merge_sel_results(results)\n\u001b[1;32m 187\u001b[0m \u001b[38;5;66;03m# drop dimension coordinates found in dimension indexers\u001b[39;00m\n\u001b[1;32m 188\u001b[0m \u001b[38;5;66;03m# (also drop multi-index if any)\u001b[39;00m\n\u001b[1;32m 189\u001b[0m \u001b[38;5;66;03m# (.sel() already ensures alignment)\u001b[39;00m\n", - "File \u001b[0;32m~/Git/github/benbovy/xvec/xvec/index.py:159\u001b[0m, in \u001b[0;36mGeometryIndex.sel\u001b[0;34m(self, labels, method, tolerance)\u001b[0m\n\u001b[1;32m 152\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_index\u001b[38;5;241m.\u001b[39msel(labels)\n\u001b[1;32m 153\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 154\u001b[0m \u001b[38;5;66;03m# We reuse here `method` and `tolerance` options of\u001b[39;00m\n\u001b[1;32m 155\u001b[0m \u001b[38;5;66;03m# `xarray.indexes.PandasIndex` as `predicate` and `distance`\u001b[39;00m\n\u001b[1;32m 156\u001b[0m \u001b[38;5;66;03m# options when `labels` is a single geometry.\u001b[39;00m\n\u001b[1;32m 157\u001b[0m \u001b[38;5;66;03m# Xarray currently doesn't support custom options\u001b[39;00m\n\u001b[1;32m 158\u001b[0m \u001b[38;5;66;03m# (see https://github.com/pydata/xarray/issues/7099)\u001b[39;00m\n\u001b[0;32m--> 159\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_sel_sindex\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtolerance\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Git/github/benbovy/xvec/xvec/index.py:116\u001b[0m, in \u001b[0;36mGeometryIndex._sel_sindex\u001b[0;34m(self, labels, method, tolerance)\u001b[0m\n\u001b[1;32m 114\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m method \u001b[38;5;241m!=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnearest\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m 115\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(label, shapely\u001b[38;5;241m.\u001b[39mGeometry):\n\u001b[0;32m--> 116\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 117\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mselection with another method than nearest only supports \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 118\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124ma single geometry as input label.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 119\u001b[0m )\n\u001b[1;32m 121\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(label, DataArray):\n\u001b[1;32m 122\u001b[0m label_array \u001b[38;5;241m=\u001b[39m label\u001b[38;5;241m.\u001b[39m_variable\u001b[38;5;241m.\u001b[39m_data\n", + "File \u001b[0;32m~/Git/github/benbovy/xvec/xvec/index.py:229\u001b[0m, in \u001b[0;36mGeometryIndex.sel\u001b[0;34m(self, labels, method, tolerance)\u001b[0m\n\u001b[1;32m 222\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_index\u001b[38;5;241m.\u001b[39msel(labels)\n\u001b[1;32m 223\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 224\u001b[0m \u001b[38;5;66;03m# We reuse here `method` and `tolerance` options of\u001b[39;00m\n\u001b[1;32m 225\u001b[0m \u001b[38;5;66;03m# `xarray.indexes.PandasIndex` as `predicate` and `distance`\u001b[39;00m\n\u001b[1;32m 226\u001b[0m \u001b[38;5;66;03m# options when `labels` is a single geometry.\u001b[39;00m\n\u001b[1;32m 227\u001b[0m \u001b[38;5;66;03m# Xarray currently doesn't support custom options\u001b[39;00m\n\u001b[1;32m 228\u001b[0m \u001b[38;5;66;03m# (see https://github.com/pydata/xarray/issues/7099)\u001b[39;00m\n\u001b[0;32m--> 229\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_sel_sindex\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtolerance\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Git/github/benbovy/xvec/xvec/index.py:182\u001b[0m, in \u001b[0;36mGeometryIndex._sel_sindex\u001b[0;34m(self, labels, method, tolerance)\u001b[0m\n\u001b[1;32m 180\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m method \u001b[38;5;241m!=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnearest\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m 181\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(label, shapely\u001b[38;5;241m.\u001b[39mGeometry):\n\u001b[0;32m--> 182\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 183\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mselection with another method than nearest only supports \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 184\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124ma single geometry as input label.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 185\u001b[0m )\n\u001b[1;32m 187\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(label, DataArray):\n\u001b[1;32m 188\u001b[0m label_array \u001b[38;5;241m=\u001b[39m label\u001b[38;5;241m.\u001b[39m_variable\u001b[38;5;241m.\u001b[39m_data\n", "\u001b[0;31mValueError\u001b[0m: selection with another method than nearest only supports a single geometry as input label." ] } @@ -3923,7 +3934,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "metadata": {}, "outputs": [ { @@ -4293,47 +4304,47 @@ " fill: currentColor;\n", "}\n", "
    <xarray.DataArray (mode: 3, day: 100, time: 24, origin: 2, destination: 2)>\n",
    -       "array([[[[[ 90,  62],\n",
    -       "          [ 18, 118]],\n",
    +       "array([[[[[108, 164],\n",
    +       "          [  6, 144]],\n",
            "\n",
    -       "         [[194,   6],\n",
    -       "          [164,  20]],\n",
    +       "         [[ 68,  88],\n",
    +       "          [ 10,  82]],\n",
            "\n",
    -       "         [[166, 110],\n",
    -       "          [ 14, 196]],\n",
    +       "         [[120,   2],\n",
    +       "          [ 80,  34]],\n",
            "\n",
            "         ...,\n",
            "\n",
    -       "         [[176,  78],\n",
    -       "          [ 32, 136]],\n",
    +       "         [[154,  26],\n",
    +       "          [104,  94]],\n",
            "\n",
    -       "         [[192,  22],\n",
    -       "          [ 62,  40]],\n",
    +       "         [[ 26,  78],\n",
    +       "          [  8, 152]],\n",
            "\n",
    -       "         [[178, 140],\n",
    -       "          [ 80,  86]]],\n",
    +       "         [[198, 186],\n",
    +       "          [ 40, 114]]],\n",
            "\n",
            "...\n",
            "\n",
    -       "        [[[158,  32],\n",
    -       "          [  8, 156]],\n",
    +       "        [[[168,  26],\n",
    +       "          [ 78,  10]],\n",
            "\n",
    -       "         [[176,  96],\n",
    -       "          [ 58, 176]],\n",
    +       "         [[178,  88],\n",
    +       "          [114,  20]],\n",
            "\n",
    -       "         [[ 26,  20],\n",
    -       "          [ 68, 152]],\n",
    +       "         [[ 88,  44],\n",
    +       "          [192, 184]],\n",
            "\n",
            "         ...,\n",
            "\n",
    -       "         [[166,  42],\n",
    -       "          [ 70, 186]],\n",
    +       "         [[112, 196],\n",
    +       "          [168, 120]],\n",
            "\n",
    -       "         [[156, 114],\n",
    -       "          [ 14, 124]],\n",
    +       "         [[104,  94],\n",
    +       "          [142,  74]],\n",
            "\n",
    -       "         [[138,  38],\n",
    -       "          [ 22, 180]]]]])\n",
    +       "         [[184,  84],\n",
    +       "          [182, 176]]]]])\n",
            "Coordinates:\n",
            "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
            "  * day          (day) datetime64[ns] 2015-01-01 2015-01-02 ... 2015-04-10\n",
    @@ -4341,48 +4352,48 @@
            "  * origin       (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n",
            "  * destination  (destination) object MULTIPOLYGON (((-77.96073150634766 34.1...\n",
            "Indexes:\n",
    -       "    origin       GeometryIndex(crs=EPSG:4267)\n",
    -       "    destination  GeometryIndex(crs=EPSG:4267)
  • " ], "text/plain": [ "\n", - "array([[[[[ 90, 62],\n", - " [ 18, 118]],\n", + "array([[[[[108, 164],\n", + " [ 6, 144]],\n", "\n", - " [[194, 6],\n", - " [164, 20]],\n", + " [[ 68, 88],\n", + " [ 10, 82]],\n", "\n", - " [[166, 110],\n", - " [ 14, 196]],\n", + " [[120, 2],\n", + " [ 80, 34]],\n", "\n", " ...,\n", "\n", - " [[176, 78],\n", - " [ 32, 136]],\n", + " [[154, 26],\n", + " [104, 94]],\n", "\n", - " [[192, 22],\n", - " [ 62, 40]],\n", + " [[ 26, 78],\n", + " [ 8, 152]],\n", "\n", - " [[178, 140],\n", - " [ 80, 86]]],\n", + " [[198, 186],\n", + " [ 40, 114]]],\n", "\n", "...\n", "\n", - " [[[158, 32],\n", - " [ 8, 156]],\n", + " [[[168, 26],\n", + " [ 78, 10]],\n", "\n", - " [[176, 96],\n", - " [ 58, 176]],\n", + " [[178, 88],\n", + " [114, 20]],\n", "\n", - " [[ 26, 20],\n", - " [ 68, 152]],\n", + " [[ 88, 44],\n", + " [192, 184]],\n", "\n", " ...,\n", "\n", - " [[166, 42],\n", - " [ 70, 186]],\n", + " [[112, 196],\n", + " [168, 120]],\n", "\n", - " [[156, 114],\n", - " [ 14, 124]],\n", + " [[104, 94],\n", + " [142, 74]],\n", "\n", - " [[138, 38],\n", - " [ 22, 180]]]]])\n", + " [[184, 84],\n", + " [182, 176]]]]])\n", "Coordinates:\n", " * mode (mode)
    <xarray.DataArray (mode: 3, day: 100, time: 24, origin: 4, destination: 100)>\n",
    -       "array([[[[[93, 38,  9, ...,  4, 45, 31],\n",
    -       "          [49, 62, 40, ...,  5,  9, 59],\n",
    -       "          [51, 52, 33, ..., 79, 51, 57],\n",
    -       "          [34, 19, 14, ...,  6, 25, 67]],\n",
    +       "array([[[[[47, 51, 75, ..., 15, 54, 82],\n",
    +       "          [ 7, 68, 76, ..., 38,  3, 72],\n",
    +       "          [19, 47,  3, ..., 75, 42, 69],\n",
    +       "          [48, 94, 34, ..., 47, 54, 86]],\n",
            "\n",
    -       "         [[10, 48, 23, ..., 95, 97,  3],\n",
    -       "          [67, 99, 47, ..., 26, 82, 10],\n",
    -       "          [50,  1, 75, ..., 57, 34, 30],\n",
    -       "          [32, 44, 56, ..., 12, 42, 96]],\n",
    +       "         [[67,  5, 73, ..., 95, 34, 44],\n",
    +       "          [80, 22, 89, ..., 93,  5, 41],\n",
    +       "          [78, 49,  9, ..., 45,  3,  9],\n",
    +       "          [87, 73, 52, ..., 32, 58, 48]],\n",
            "\n",
    -       "         [[25, 65, 47, ..., 72, 83, 55],\n",
    -       "          [ 5, 97, 93, ..., 60,  7, 98],\n",
    -       "          [74, 74, 53, ..., 85, 30, 84],\n",
    -       "          [15, 12, 84, ...,  1, 33, 97]],\n",
    +       "         [[22, 57, 42, ..., 24, 60,  1],\n",
    +       "          [ 4,  3, 94, ..., 66, 40, 17],\n",
    +       "          [81, 36, 30, ...,  5, 51,  6],\n",
    +       "          [54, 70, 25, ..., 30, 18, 37]],\n",
            "\n",
            "         ...,\n",
            "\n",
    -       "         [[65, 98, 32, ..., 13, 88, 39],\n",
    -       "          [20, 36, 74, ..., 52, 16, 68],\n",
    -       "          [24, 53, 24, ..., 43, 32, 43],\n",
    +       "         [[ 6, 83, 84, ..., 50, 77, 13],\n",
    +       "          [44, 84, 52, ..., 38, 52, 47],\n",
    +       "          [65, 26, 50, ..., 12, 21, 25],\n",
            "...\n",
    -       "          [99, 52, 72, ..., 47, 34, 76],\n",
    -       "          [25, 38, 67, ...,  1, 76, 25],\n",
    -       "          [50, 41, 15, ..., 28, 50, 12]],\n",
    +       "          [44, 67, 26, ..., 29, 96, 92],\n",
    +       "          [38, 63, 87, ..., 32, 89, 62],\n",
    +       "          [ 1,  5, 28, ..., 88, 84, 58]],\n",
            "\n",
            "         ...,\n",
            "\n",
    -       "         [[61, 31, 53, ..., 92, 83, 21],\n",
    -       "          [72, 96, 48, ..., 89, 35, 93],\n",
    -       "          [ 7, 86, 98, ..., 81, 13, 97],\n",
    -       "          [67, 57, 39, ..., 25, 50, 91]],\n",
    +       "         [[ 9, 82, 60, ..., 64, 56, 98],\n",
    +       "          [79, 62, 12, ..., 47, 84, 60],\n",
    +       "          [83, 98,  3, ..., 91, 25, 14],\n",
    +       "          [81,  7, 45, ..., 18, 78,  9]],\n",
            "\n",
    -       "         [[95, 85, 50, ..., 55, 78, 57],\n",
    -       "          [14,  7, 16, ..., 54,  7, 62],\n",
    -       "          [25, 95, 66, ..., 81, 32, 35],\n",
    -       "          [29, 45,  1, ..., 25, 83, 20]],\n",
    +       "         [[29, 94, 53, ...,  3, 52, 47],\n",
    +       "          [93, 43, 11, ..., 94, 71, 37],\n",
    +       "          [72, 95, 55, ..., 83, 17, 97],\n",
    +       "          [72, 77, 15, ..., 42, 62,  9]],\n",
            "\n",
    -       "         [[ 4, 59,  6, ..., 17, 69, 19],\n",
    -       "          [82, 93,  9, ...,  5, 11, 90],\n",
    -       "          [50, 61,  4, ..., 45, 70, 74],\n",
    -       "          [67, 36, 29, ..., 41, 58, 38]]]]])\n",
    +       "         [[26, 76, 23, ..., 21, 92, 42],\n",
    +       "          [60, 80, 37, ..., 49, 91, 88],\n",
    +       "          [66, 91, 73, ..., 10, 44, 22],\n",
    +       "          [75, 27, 89, ..., 37, 57, 20]]]]])\n",
            "Coordinates:\n",
            "  * mode         (mode) <U4 'car' 'bike' 'foot'\n",
            "  * day          (day) datetime64[ns] 2015-01-01 2015-01-02 ... 2015-04-10\n",
    @@ -4949,48 +4960,48 @@
            "  * origin       (origin) object MULTIPOLYGON (((-81.4727554321289 36.2343559...\n",
            "  * destination  (destination) object MULTIPOLYGON (((-81.4727554321289 36.23...\n",
            "Indexes:\n",
    -       "    origin       GeometryIndex(crs=EPSG:4267)\n",
    -       "    destination  GeometryIndex(crs=EPSG:4267)
  • " ], "text/plain": [ "\n", - "array([[[[[93, 38, 9, ..., 4, 45, 31],\n", - " [49, 62, 40, ..., 5, 9, 59],\n", - " [51, 52, 33, ..., 79, 51, 57],\n", - " [34, 19, 14, ..., 6, 25, 67]],\n", + "array([[[[[47, 51, 75, ..., 15, 54, 82],\n", + " [ 7, 68, 76, ..., 38, 3, 72],\n", + " [19, 47, 3, ..., 75, 42, 69],\n", + " [48, 94, 34, ..., 47, 54, 86]],\n", "\n", - " [[10, 48, 23, ..., 95, 97, 3],\n", - " [67, 99, 47, ..., 26, 82, 10],\n", - " [50, 1, 75, ..., 57, 34, 30],\n", - " [32, 44, 56, ..., 12, 42, 96]],\n", + " [[67, 5, 73, ..., 95, 34, 44],\n", + " [80, 22, 89, ..., 93, 5, 41],\n", + " [78, 49, 9, ..., 45, 3, 9],\n", + " [87, 73, 52, ..., 32, 58, 48]],\n", "\n", - " [[25, 65, 47, ..., 72, 83, 55],\n", - " [ 5, 97, 93, ..., 60, 7, 98],\n", - " [74, 74, 53, ..., 85, 30, 84],\n", - " [15, 12, 84, ..., 1, 33, 97]],\n", + " [[22, 57, 42, ..., 24, 60, 1],\n", + " [ 4, 3, 94, ..., 66, 40, 17],\n", + " [81, 36, 30, ..., 5, 51, 6],\n", + " [54, 70, 25, ..., 30, 18, 37]],\n", "\n", " ...,\n", "\n", - " [[65, 98, 32, ..., 13, 88, 39],\n", - " [20, 36, 74, ..., 52, 16, 68],\n", - " [24, 53, 24, ..., 43, 32, 43],\n", + " [[ 6, 83, 84, ..., 50, 77, 13],\n", + " [44, 84, 52, ..., 38, 52, 47],\n", + " [65, 26, 50, ..., 12, 21, 25],\n", "...\n", - " [99, 52, 72, ..., 47, 34, 76],\n", - " [25, 38, 67, ..., 1, 76, 25],\n", - " [50, 41, 15, ..., 28, 50, 12]],\n", + " [44, 67, 26, ..., 29, 96, 92],\n", + " [38, 63, 87, ..., 32, 89, 62],\n", + " [ 1, 5, 28, ..., 88, 84, 58]],\n", "\n", " ...,\n", "\n", - " [[61, 31, 53, ..., 92, 83, 21],\n", - " [72, 96, 48, ..., 89, 35, 93],\n", - " [ 7, 86, 98, ..., 81, 13, 97],\n", - " [67, 57, 39, ..., 25, 50, 91]],\n", + " [[ 9, 82, 60, ..., 64, 56, 98],\n", + " [79, 62, 12, ..., 47, 84, 60],\n", + " [83, 98, 3, ..., 91, 25, 14],\n", + " [81, 7, 45, ..., 18, 78, 9]],\n", "\n", - " [[95, 85, 50, ..., 55, 78, 57],\n", - " [14, 7, 16, ..., 54, 7, 62],\n", - " [25, 95, 66, ..., 81, 32, 35],\n", - " [29, 45, 1, ..., 25, 83, 20]],\n", + " [[29, 94, 53, ..., 3, 52, 47],\n", + " [93, 43, 11, ..., 94, 71, 37],\n", + " [72, 95, 55, ..., 83, 17, 97],\n", + " [72, 77, 15, ..., 42, 62, 9]],\n", "\n", - " [[ 4, 59, 6, ..., 17, 69, 19],\n", - " [82, 93, 9, ..., 5, 11, 90],\n", - " [50, 61, 4, ..., 45, 70, 74],\n", - " [67, 36, 29, ..., 41, 58, 38]]]]])\n", + " [[26, 76, 23, ..., 21, 92, 42],\n", + " [60, 80, 37, ..., 49, 91, 88],\n", + " [66, 91, 73, ..., 10, 44, 22],\n", + " [75, 27, 89, ..., 37, 57, 20]]]]])\n", "Coordinates:\n", " * mode (mode) Date: Wed, 23 Nov 2022 10:05:37 +0100 Subject: [PATCH 27/28] sel (sindex): remove CRS check for now Let's address later the extraction of CRS info from various input types in a more general way? --- xvec/index.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/xvec/index.py b/xvec/index.py index 68ffff3..1c4eee6 100644 --- a/xvec/index.py +++ b/xvec/index.py @@ -193,12 +193,6 @@ def _sel_sindex(self, labels, method, tolerance): else: label_array = np.array(label) - # check for possible CRS of geometry labels - # (by default assume same CRS than the index) - label_crs = getattr(label_array, "crs", None) - if label_crs is not None and not self._check_crs(label_crs, allow_none=True): - self._crs_mismatch_raise(label_crs, warn=True, stacklevel=4) - if not np.all(shapely.is_geometry(label_array)): raise ValueError("labels must be shapely.Geometry objects") From 6d770d797642a9954e9c443d2bb1975a6c6c136b Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Wed, 23 Nov 2022 10:31:05 +0100 Subject: [PATCH 28/28] increase test coverage --- xvec/tests/test_index.py | 44 ++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/xvec/tests/test_index.py b/xvec/tests/test_index.py index 6cd63b1..efd9fdd 100644 --- a/xvec/tests/test_index.py +++ b/xvec/tests/test_index.py @@ -26,6 +26,12 @@ def geom_dataset(geom_dataset_no_index): return geom_dataset_no_index.set_xindex("geom", GeometryIndex, crs=crs) +@pytest.fixture(scope="session") +def geom_dataset_no_crs(geom_dataset_no_index): + # a dataset with a geometry coordinate baked by a GeometryIndex (no CRS) + return geom_dataset_no_index.set_xindex("geom", GeometryIndex) + + @pytest.fixture(scope="session") def first_geom_dataset(geom_dataset, geom_array): return ( @@ -55,7 +61,7 @@ def test_set_index(geom_dataset_no_index): no_geom_ds.set_xindex("no_geom", GeometryIndex, crs=crs) -def test_concat(geom_dataset, geom_array, geom_dataset_no_index): +def test_concat(geom_dataset, geom_array, geom_dataset_no_index, geom_dataset_no_crs): expected = ( xr.Dataset(coords={"geom": np.concatenate([geom_array, geom_array])}) .drop_indexes("geom") @@ -71,6 +77,21 @@ def test_concat(geom_dataset, geom_array, geom_dataset_no_index): with pytest.raises(ValueError, match="cannot determine common CRS"): xr.concat([geom_dataset, geom_dataset_alt], "geom") + # no CRS + expected = ( + xr.Dataset(coords={"geom": np.concatenate([geom_array, geom_array])}) + .drop_indexes("geom") + .set_xindex("geom", GeometryIndex) + ) + actual = xr.concat([geom_dataset_no_crs, geom_dataset_no_crs], "geom") + xr.testing.assert_identical(actual, expected) + + # mixed CRS / no CRS + with pytest.warns( + UserWarning, match="CRS not set for some of the concatenation inputs" + ): + xr.concat([geom_dataset, geom_dataset_no_crs], "geom") + def test_to_pandas_index(geom_dataset): index = geom_dataset.xindexes["geom"] @@ -81,6 +102,11 @@ def test_isel(geom_dataset, first_geom_dataset): actual = geom_dataset.isel(geom=[0]) xr.testing.assert_identical(actual, first_geom_dataset) + # scalar selection + actual = geom_dataset.isel(geom=0) + assert len(actual.geom.dims) == 0 + assert "geom" not in actual.xindexes + def test_sel_strict(geom_dataset, geom_array, first_geom_dataset): actual = geom_dataset.sel(geom=[geom_array[0]]) @@ -111,7 +137,9 @@ def test_sel_query(geom_dataset, first_geom_dataset): xr.testing.assert_identical(actual, first_geom_dataset) -def test_equals(geom_dataset, geom_dataset_no_index, first_geom_dataset): +def test_equals( + geom_dataset, geom_dataset_no_index, first_geom_dataset, geom_dataset_no_crs +): assert geom_dataset.xindexes["geom"].equals(geom_dataset.xindexes["geom"]) # different index types @@ -124,7 +152,6 @@ def test_equals(geom_dataset, geom_dataset_no_index, first_geom_dataset): assert not geom_dataset.xindexes["geom"].equals(other.xindexes["geom"]) # no CRS - geom_dataset_no_crs = geom_dataset_no_index.set_xindex("geom", GeometryIndex) assert geom_dataset_no_crs.xindexes["geom"].equals( geom_dataset_no_crs.xindexes["geom"] ) @@ -133,7 +160,9 @@ def test_equals(geom_dataset, geom_dataset_no_index, first_geom_dataset): assert not geom_dataset.xindexes["geom"].equals(first_geom_dataset.xindexes["geom"]) -def test_align(geom_dataset, first_geom_dataset, geom_dataset_no_index): +def test_align( + geom_dataset, first_geom_dataset, geom_dataset_no_index, geom_dataset_no_crs +): # test both GeometryIndex's `join` and `reindex_like` aligned = xr.align(geom_dataset, first_geom_dataset, join="inner") assert all([ds.identical(first_geom_dataset) for ds in aligned]) @@ -149,7 +178,6 @@ def test_align(geom_dataset, first_geom_dataset, geom_dataset_no_index): first_geom_dataset.reindex_like(geom_dataset_alt) # no CRS - geom_dataset_no_crs = geom_dataset_no_index.set_xindex("geom", GeometryIndex) first_geom_dataset_no_crs = geom_dataset_no_crs.isel(geom=[0]) aligned = xr.align(geom_dataset_no_crs, first_geom_dataset_no_crs, join="inner") assert all([ds.identical(first_geom_dataset_no_crs) for ds in aligned]) @@ -171,7 +199,11 @@ def test_rename(geom_dataset): assert ds.xindexes["renamed"]._index.dim == "geom" -def test_repr_inline(geom_dataset): +def test_repr_inline(geom_dataset, geom_dataset_no_crs): actual = geom_dataset.xindexes["geom"]._repr_inline_(70) expected = "GeometryIndex (crs=EPSG:26915)" assert actual == expected + + actual = geom_dataset_no_crs.xindexes["geom"]._repr_inline_(70) + expected = "GeometryIndex (crs=None)" + assert actual == expected