Repository: developmentseed/titiler
Pull request #1134: refactor xarray dimension selection
Author: login: vincentsarago
Created: 2025-04-22T20:50:32Z | Merged: 2025-04-24T21:27:10Z

closes #1112, closes #1099

With the change in this PR a user could now do 

```
# select array for time = 2024-02-10 and with elevation=200
# Xarray: da.sel({"time": "2024-02-10", "elevation": 200}, method="nearest"})
# With Titiler:
{titiler endpoint}/info?url={netcdf.nc}&sel=time=2024-02-10&sel=elevation=200&method=nearest

# Create a 2 band array (for each time dim selection)
# Xarray: da.sel({"time": ["2024-02-10", "2024-02-11"], "elevation": 200}, method="nearest"})
# With Titiler:
{titiler endpoint}/info?url={netcdf.nc}&sel=time=2024-02-10&time=2024-02-11&sel=elevation=200&method=nearest
```



cc @j08lue @maxrjones @sharkinsspatial @hrodmn 

Linked issue #1112: [Xarray] Improve dimension selection
Right now the `dimension` selection in titiler-xarray is very limited. We have 2 options:
- `drop_dim={dimension}={value}` (select a value and drop the dimension)

https://github.com/developmentseed/titiler/blob/6d1519e9a289a1f1f8e15c04020920f82cf02c60/src/titiler/xarray/titiler/xarray/io.py#L156-L160
 
- `datetime={date}` 

https://github.com/developmentseed/titiler/blob/6d1519e9a289a1f1f8e15c04020920f82cf02c60/src/titiler/xarray/titiler/xarray/io.py#L175-L187


The `drop_dim` parameter feels kinda weird to me. We are using it to `select a slice` and `drop a dimension`, while the `datetime` is limited to the `time` dimension. 

I'm looking for opinions here but here are my though:

- `drop_dim` should only drop dimension (not select a slice)
- `datetime` should be deprecated
- we should add a `sel={dimension}={value}` option (https://docs.xarray.dev/en/latest/user-guide/indexing.html) 
- we could introduce a `band_dim={dimension}` which will let user select the dimension they want to appear as `bands` in titiler. Resulting in dropping all other dimensions (except X and Y)  

cc @sharkinsspatial @maxrjones @j08lue 
Linked issue comments: user: login: j08lue
created_at: 2025-03-28T12:41:19Z
body: > drop_dim should only drop dimension (not select a slice)

Yes, to conform with [`Xarray.Dataset.drop_dims`](https://docs.xarray.dev/en/latest/generated/xarray.Dataset.drop_dims.html).

> datetime should be deprecated

Yes!

Xarray / Pandas will actually parse and match keys automagically - you can pass a string to a float index and it will try to look it up as float, or pass datetime strings in various formats as keys for a datetime index.

It's kinda scary, but I think a highly appreciated feature of pandas we might as well expose to users. Check this out:

```python
import xarray as xr
import numpy as np
import pandas as pd

da = xr.DataArray(
    np.random.rand(4, 3),
    [
        ("time", pd.date_range("2000-01-01", periods=4)),
        ("space", ["IA", "IL", "IN"]),
    ],
)

# all of these work
da.sel(time="2000-01-01T00:00:00")
da.sel(time="2000-01-01")
da.sel(time="1st of January 2000")
da.sel(time="January 1, 2000")
```

We should drop the dimensions we select, though - the purpose of this parameter is to reduce the dimensionality of the data cube to the two spatial dimensions, nothing else. `reduce_dimensions`? Reduce means something else, though, often an operation, not just a selection...


> we could introduce a band_dim={dimension}

What is the advantage of defining a dimension as a "band" dimension?

The fact that rasters only have (unlabelled) "bands" and not named dimensions and explicit keys (coordinates) like CF datasets is a huge limitation of raster formats, IMO, since you always need to know which band index corresponds to what. This breaks down already when someone omits some of the canonical bands. Sure, you can store that info somewhere in GeoTIFF, but no driver really exposes it well.

We work around that by storing single-band **assets** in STAC to be able to reference them explicitly in TiTiler-PgSTAC (by asset key).

Let's not do more bands. Dimensions and explicit labels (i.e. Xarray Datasets) ftw!
author_association: MEMBER
user: login: vincentsarago
created_at: 2025-03-28T18:01:25Z
body: > Let's not do more bands. Dimensions and explicit labels (i.e. Xarray Datasets) ftw!

🙉 https://github.com/cogeotiff/rio-tiler/pull/764 

https://github.com/cogeotiff/rio-tiler/blob/main/CHANGES.md#740-2025-01-28

we already define `bands` for data array used by rio-tiler, to align all the APIs. It makes things easier once we integrate into titiler. 

> we could introduce a band_dim={dimension}

This means mostly that a user would select one dimension which will be used as band in rio-tiler/titiler by dropping all other dimension (except `x` and `y`), resulting in a 3D data array `({dim}, y, x)`
author_association: MEMBER
user: login: hrodmn
created_at: 2025-03-31T14:47:39Z
body: > we should add a sel={dimension}={value} option (https://docs.xarray.dev/en/latest/user-guide/indexing.html)

This could be very useful particularly if multiple values are allowed, e.g. `sel=time=2020-01-01&sel=space="IN"` would convert to `da.sel(time="2020-01-01").sel(space="IN")` or `da.sel(time="2020-01-01", space="IN")`

It would also be useful to add a `/info` endpoint to the xarray `Factory` that would describe the file in terms that could be used to help a user parameterize the right `sel` and `band_dim` values. We might even be able to use the `DataArray._repr_html_` method to return a html document that would look good in the browser like you get when you display a `DataArray` in a notebook.
author_association: CONTRIBUTOR
user: login: vincentsarago
created_at: 2025-03-31T14:57:58Z
body: > It would also be useful to add a /info endpoint to the xarray Factory that would describe the file in terms that could be used to help a user parameterize the right sel and band_dim values. We might even be able to use the DataArray._repr_html_ method to return a html document that would look good in the browser like you get when you display a DataArray in a notebook.

Yeah I mentioned that last week with Sean that the `/variables` extension https://github.com/developmentseed/titiler/blob/main/src/titiler/xarray/titiler/xarray/extensions.py#L16-L38 to have metadata about the available dimensions
author_association: MEMBER
user: login: j08lue
created_at: 2025-03-31T20:07:33Z
body: > It would also be useful to add a /info endpoint to the xarray Factory that would describe the file in terms that could be used to help a user parameterize the right sel and band_dim values

When available, clients can also get this information from the STAC Datacube extension. But does not hurt to put it on the tiler API as well.
author_association: MEMBER
user: login: vincentsarago
created_at: 2025-03-31T20:17:24Z
body: > Yeah I mentioned that last week with Sean that the /variables extension https://github.com/developmentseed/titiler/blob/main/src/titiler/xarray/titiler/xarray/extensions.py#L16-L38 to have metadata about the available dimensions

I've totally forget that in titiler-md-demo I've added a `dimension` extension 😅 

https://github.com/developmentseed/titiler-md-demo/blob/main/runtimes/titiler_md_demo/extensions.py#L23-L55

```
curl https://t4z3zffpeh.execute-api.us-east-1.amazonaws.com/md/dims\?url\=https://gws-access.jasmin.ac.uk/public/leicester/SENTINEL3A_SLSTR_L3C_0.01/4.00/2024/10/16/EOCIS_-LST-L3C-LST-SLSTRA-0.01deg_1DAILY_DAY-20241016000000-fv4.00.nc\&variable\=lst | jq

  "time": {
    "min": "2024-10-16T00:00:00.000000000",
    "max": "2024-10-16T00:00:00.000000000",
    "len": 1
  },
  "lat": {
    "min": "-89.995",
    "max": "89.99499",
    "len": 18000
  },
  "lon": {
    "min": "-179.995",
    "max": "179.995",
    "len": 36000
  }
}
```
author_association: MEMBER
user: login: vincentsarago
created_at: 2025-04-01T23:33:24Z
body: FYI here is how it's done in Xpublish 🙉 https://github.com/xpublish-community/xpublish-wms/blob/15aaa48ead7468f80d4794456b674a28bbc7dbe0/xpublish_wms/wms/get_map.py#L184-L280
author_association: MEMBER
user: login: j08lue
created_at: 2025-04-02T09:19:19Z
body: Right, xpublish is a relevant reference we should keep in mind. 💡 

They are doing the exact same thing in `select_custom_dim`, except that they do some dtype checking which, I think, is not actually needed since `xarray.Dataset.sel` handles that. And they allow for some fuzzy magic for selecting the first or last coordinate if you don't pass a value, which I think we should not do but keep it simple.

https://github.com/xpublish-community/xpublish-wms/blob/15aaa48ead7468f80d4794456b674a28bbc7dbe0/xpublish_wms/wms/get_map.py#L251-L269

If it turns out we need it, we could later add another way to drop a dimension by index (`.isel`) instead of key (`.sel`).
author_association: MEMBER

Diff:
diff --git a/CHANGES.md b/CHANGES.md
index f725e7e4e..f9e88bc1c 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -96,7 +96,27 @@
 
 ### titiler.xarray
 
-* change `get_variable.drop_dim` parameter type from `str` to `List[str]` **breaking change**
+* update `rio-tiler` requirement to `>=7.6.1`
+* add `sel` and `sel_method` options to select dimension
+
+    ```
+    # before
+    https://.../0/0/0.png?url=dataset.zarr&drop_dim=time=2023-01-01
+
+    # now
+    https://.../0/0/0.png?url=dataset.zarr&sel=time=2023-01-01
+
+    # method
+    https://.../0/0/0.png?url=dataset.zarr&sel=time=2023-01-02&sel_method=nearest
+
+    # Can use `slice` when providing 2 values
+    https://.../0/0/0.png?url=dataset.zarr&sel=time=2023-01-01&time=2023-01-31
+    ```
+* add support for `bidx` parameter
+* remove `first` **time** dim selection **breaking change**
+* add support for 3D dataset
+* remove `drop_dim` option **breaking change**
+* remove `datetime` option **breaking change**
 * deprecate `VariablesExtension` extension
 * add `DatasetMetadataExtension` extension (`/dataset/keys`, `/dataset/` and `/dataset/dict` endpoints)
 
diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml
index e1f3078c6..3b60a5648 100644
--- a/docs/mkdocs.yml
+++ b/docs/mkdocs.yml
@@ -161,7 +161,7 @@ plugins:
             signature_crossrefs: true
             extensions:
               - griffe_inherited_docstrings
-          import:
+          inventories:
             - https://docs.python.org/3/objects.inv
             - https://numpy.org/doc/stable/objects.inv
             - https://rasterio.readthedocs.io/en/stable/objects.inv
diff --git a/docs/src/advanced/Extensions.md b/docs/src/advanced/Extensions.md
index bc5f128c2..07f7ebc4c 100644
--- a/docs/src/advanced/Extensions.md
+++ b/docs/src/advanced/Extensions.md
@@ -33,32 +33,36 @@ class FactoryExtension(metaclass=abc.ABCMeta):
 
 ## Available extensions
 
-#### cogValidateExtension
+#### titiler.extensions.cogValidateExtension
 
 - Goal: adds a `/validate` endpoint which return the content of rio-cogeo `info` method
 - Additional requirements: `titiler.extensions["cogeo"]` (installs `rio-cogeo`)
 
-#### cogViewerExtension
+#### titiler.extensions.cogViewerExtension
 
 - Goal: adds a `/viewer` endpoint which return an HTML viewer for simple COGs
 
-#### stacViewerExtension
+#### titiler.extensions.stacViewerExtension
 
 - Goal: adds a `/viewer` endpoint which return an HTML viewer for STAC item
 
-#### stacExtension
+#### titiler.extensions.stacExtension
 
 - Goal: adds a `/stac` endpoint which return an HTML viewer for STAC item
 - Additional requirements: `titiler.extensions["stac"]` (installs `rio-stac`)
 
-#### wmsExtension
+#### titiler.extensions.wmsExtension
 
 - Goal: adds a `/wms` endpoint to support OGC WMS specification (`GetCapabilities` and `GetMap`)
 
-#### stacRenderExtenstion
+#### titiler.extensions.stacRenderExtenstion
 
 - Goal: adds `/render` and `/render/{render_id}` endpoints which return the contents of [STAC render extension](https://github.com/stac-extensions/render) and links to tileset.json and WMTS service
 
+#### titiler.xarray.DatasetMetadataExtension
+
+- Goal: adds `/dataset/`, `/dataset/keys` and `/datasets/dict` endpoints which return metadata about a multidimensional Dataset (not a DataArray)
+
 ## How To
 
 ### Use extensions
@@ -85,8 +89,6 @@ tiler = TilerFactory(
 app.include_router(tiler.router, prefix="/cog")
 ```
 
-See [titiler.application](../application) for a full example.
-
 ### Create your own
 
 ```python
diff --git a/docs/src/advanced/dependencies.md b/docs/src/advanced/dependencies.md
index b3b84ab51..1f87a851c 100644
--- a/docs/src/advanced/dependencies.md
+++ b/docs/src/advanced/dependencies.md
@@ -38,6 +38,8 @@ def preview(
 
     Using `titiler.core.dependencies.DefaultDependency`, we can use `.as_dict(exclude_none=True/False)` method to `unpack` the object parameters. This can be useful if method or reader do not take the same parameters.
 
+## titiler.core
+
 #### AssetsParams
 
 Define `assets`.
@@ -877,7 +879,7 @@ class StatisticsParams(DefaultDependency):
 
 #### TileParams
 
-Defile `buffer` and `padding` to apply at tile creation.
+Define `buffer` and `padding` to apply at tile creation.
 
 | Name      | Type      | Required | Default
 | ------    | ----------|----------|--------------
@@ -952,3 +954,205 @@ def post_process(
 
 </details>
 
+## titiler.xarray
+
+
+#### XarrayIOParams
+
+Define Xarray's `open_args` to `xarray.open_dataset`.
+
+| Name             | Type        | Required | Default
+| ------           | ----------  |----------|--------------
+| **group**        | Query (str) | No       | None
+| **decode_times** | Query (bool)| No       | None
+
+<details>
+
+```python
+@dataclass
+class XarrayIOParams(DefaultDependency):
+    """Dataset IO Options."""
+
+    group: Annotated[
+        Optional[str],
+        Query(
+            description="Select a specific zarr group from a zarr hierarchy. Could be associated with a zoom level or dataset."
+        ),
+    ] = None
+
+    decode_times: Annotated[
+        Optional[bool],
+        Query(
+            title="decode_times",
+            description="Whether to decode times",
+        ),
+    ] = None
+```
+
+</details>
+
+#### XarrayDsParams
+
+Define options to select a **variable** within a Xarray Dataset.
+
+| Name          | Type        | Required | Default
+| ------        | ----------  |----------|--------------
+| **variable**  | Query (str) | Yes      | None
+| **sel**       | Query (list of str) | No | None
+| **method**    | Query (str)| No       | None
+
+<details>
+
+```python
+@dataclass
+class XarrayDsParams(DefaultDependency):
+    """Xarray Dataset Options."""
+
+    variable: Annotated[str, Query(description="Xarray Variable name.")]
+
+    sel: Annotated[
+        Optional[List[SelDimStr]],
+        Query(
+            description="Xarray Indexing using dimension names `{dimension}={value}`.",
+        ),
+    ] = None
+
+    method: Annotated[
+        Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]],
+        Query(
+            alias="sel_method",
+            description="Xarray indexing method to use for inexact matches.",
+        ),
+    ] = None
+```
+
+</details>
+
+
+#### XarrayParams
+
+Combination of `XarrayIOParams` and `XarrayDsParams`
+
+| Name             | Type        | Required | Default
+| ------           | ----------  |----------|--------------
+| **group**        | Query (str) | No       | None
+| **decode_times** | Query (bool)| No       | None
+| **variable**     | Query (str) | Yes      | None
+| **sel**          | Query (list of str) | No | None
+| **method**       | Query (str)| No       | None
+
+<details>
+
+```python
+@dataclass
+class XarrayParams(XarrayIOParams, XarrayDsParams):
+    """Xarray Reader dependency."""
+
+    pass
+```
+
+</details>
+
+#### CompatXarrayParams
+
+same as `XarrayParams` but with optional `variable` option.
+
+| Name             | Type        | Required | Default
+| ------           | ----------  |----------|--------------
+| **group**        | Query (str) | No       | None
+| **decode_times** | Query (bool)| No       | None
+| **variable**     | Query (str) | No      | None
+| **sel**          | Query (list of str) | No | None
+| **method**       | Query (str)| No       | None
+
+<details>
+
+```python
+@dataclass
+class XarrayParams(XarrayIOParams, XarrayDsParams):
+    """Xarray Reader dependency."""
+
+    pass
+```
+
+</details>
+
+
+#### DatasetParams
+
+Same as `titiler.core.dependencies.DatasetParams` but with only `nodata` and `reproject`
+
+| Name      | Type      | Required | Default
+| ------    | ----------|----------|--------------
+| **nodata**  | Query (str, int, float)    | No       | None
+| **reproject** | Query (str) | No        | 'nearest'
+
+<details>
+
+```python
+@dataclass
+class DatasetParams(DefaultDependency):
+    """Low level WarpedVRT Optional parameters."""
+
+    nodata: Annotated[
+        Optional[Union[str, int, float]],
+        Query(
+            title="Nodata value",
+            description="Overwrite internal Nodata value",
+        ),
+    ] = None
+    reproject_method: Annotated[
+        Optional[WarpResampling],
+        Query(
+            alias="reproject",
+            description="WarpKernel resampling algorithm (only used when doing re-projection). Defaults to `nearest`.",
+        ),
+    ] = None
+
+    def __post_init__(self):
+        """Post Init."""
+        if self.nodata is not None:
+            self.nodata = numpy.nan if self.nodata == "nan" else float(self.nodata)
+```
+
+</details>
+
+
+#### DatasetParams
+
+Same as `titiler.core.dependencies.PartFeatureParams` but with `resampling` option
+
+| Name      | Type      | Required | Default
+| ------    | ----------|----------|--------------
+| **max_size** | Query (int) | No | None
+| **height** | Query (int) | No | None
+| **width** | Query (int) | No | None
+| **resampling** | Query (str) | No | 'nearest'
+
+
+<details>
+
+```python
+@dataclass
+class PartFeatureParams(DefaultDependency):
+    """Common parameters for bbox and feature."""
+
+    max_size: Annotated[Optional[int], "Maximum image size to read onto."] = None
+    height: Annotated[Optional[int], "Force output image height."] = None
+    width: Annotated[Optional[int], "Force output image width."] = None
+    resampling_method: Annotated[
+        Optional[RIOResampling],
+        Query(
+            alias="resampling",
+            description="RasterIO resampling algorithm. Defaults to `nearest`.",
+        ),
+    ] = None
+
+    def __post_init__(self):
+        """Post Init."""
+        if self.width and self.height:
+            self.max_size = None
+
+```
+
+</details>
diff --git a/docs/src/advanced/endpoints_factories.md b/docs/src/advanced/endpoints_factories.md
index 354eaf34b..aae919746 100644
--- a/docs/src/advanced/endpoints_factories.md
+++ b/docs/src/advanced/endpoints_factories.md
@@ -343,7 +343,7 @@ class: `titiler.xarray.factory.TilerFactory`
 - **reader**: Dataset Reader **required**.
 - **path_dependency**: Dependency to use to define the dataset url. Defaults to `titiler.core.dependencies.DatasetPathParams`.
 - **reader_dependency**: Dependency to control options passed to the reader instance init. Defaults to `titiler.xarray.dependencies.XarrayParams`
-- **layer_dependency**: Dependency to define band indexes or expression. Defaults to `titiler.core.dependencies.DefaultDependency`.
+- **layer_dependency**: Dependency to define band indexes or expression. Defaults to `titiler.core.dependencies.BidxParams`.
 - **dataset_dependency**: Dependency to overwrite `nodata` value and change the `Warp` resamplings. Defaults to `titiler.xarray.dependencies.DatasetParams`.
 - **tile_dependency**: Dependency for tile creation options. Defaults to `titiler.core.dependencies.DefaultDependency`.
 - **stats_dependency**: Dependency to define options for *rio-tiler*'s statistics method used in `/statistics` endpoints. Defaults to `titiler.core.dependencies.StatisticsParams`.
diff --git a/docs/src/endpoints/cog.md b/docs/src/endpoints/cog.md
index 701327fc9..cc6253bcf 100644
--- a/docs/src/endpoints/cog.md
+++ b/docs/src/endpoints/cog.md
@@ -40,7 +40,7 @@ The `/cog` routes are based on `titiler.core.factory.TilerFactory` but with `cog
     - **x** (int): TMS tile's column.
     - **y** (int): TMS tile's row.
     - **scale** (int): Tile size scale, default is set to 1 (256x256). **Optional**
-    - **format** (str): Output [image format](../output_format.md), default is set to None and will be either JPEG or PNG depending on masked value. **Optional**
+    - **format** (str): Output [image format](../user_guide/output_format.md), default is set to None and will be either JPEG or PNG depending on masked value. **Optional**
 
 - QueryParams:
     - **url** (str): Cloud Optimized GeoTIFF URL. **Required**
@@ -72,7 +72,7 @@ Example:
 `:endpoint:/cog/preview[.{format}]`
 
 - PathParams:
-    - **format** (str): Output [image format](../output_format.md), default is set to None and will be either JPEG or PNG depending on masked value. **Optional**
+    - **format** (str): Output [image format](../user_guide/output_format.md), default is set to None and will be either JPEG or PNG depending on masked value. **Optional**
 
 - QueryParams:
     - **url** (str): Cloud Optimized GeoTIFF URL. **Required**
@@ -110,7 +110,7 @@ Example:
 
 - PathParams:
     - **minx,miny,maxx,maxy** (str): Comma (',') delimited bounding box in WGS84.
-    - **format** (str): Output [image format](../output_format.md).
+    - **format** (str): Output [image format](../user_guide/output_format.md).
     - **height** (int): Force output image height.
     - **width** (int): Force output image width.
 
@@ -150,7 +150,7 @@ Example:
 - PathParams:
     - **height** (int): Force output image height. **Optional**
     - **width** (int): Force output image width. **Optional**
-    - **format** (str): Output [image format](../output_format.md), default is set to None and will be either JPEG or PNG depending on masked value. **Optional**
+    - **format** (str): Output [image format](../user_guide/output_format.md), default is set to None and will be either JPEG or PNG depending on masked value. **Optional**
 
 - QueryParams:
     - **url** (str): Cloud Optimized GeoTIFF URL. **Required**
@@ -213,7 +213,7 @@ Example:
 
 - QueryParams:
     - **url** (str): Cloud Optimized GeoTIFF URL. **Required**
-    - **tile_format** (str): Output [image format](../output_format.md), default is set to None and will be either JPEG or PNG depending on masked value.
+    - **tile_format** (str): Output [image format](../user_guide/output_format.md), default is set to None and will be either JPEG or PNG depending on masked value.
     - **tile_scale** (int): Tile size scale, default is set to 1 (256x256).
     - **minzoom** (int): Overwrite default minzoom.
     - **maxzoom** (int): Overwrite default maxzoom.
@@ -249,7 +249,7 @@ Example:
 
 - QueryParams:
     - **url** (str): Cloud Optimized GeoTIFF URL. **Required**
-    - **tile_format** (str): Output [image format](../output_format.md), default is set to None and will be either JPEG or PNG depending on masked value.
+    - **tile_format** (str): Output [image format](../user_guide/output_format.md), default is set to None and will be either JPEG or PNG depending on masked value.
     - **tile_scale** (int): Tile size scale, default is set to 1 (256x256).
     - **minzoom** (int): Overwrite default minzoom.
     - **maxzoom** (int): Overwrite default maxzoom.
diff --git a/docs/src/endpoints/stac.md b/docs/src/endpoints/stac.md
index 9e710d1d0..140c3605f 100644
--- a/docs/src/endpoints/stac.md
+++ b/docs/src/endpoints/stac.md
@@ -40,7 +40,7 @@ The `/stac` routes are based on `titiler.core.factory.MultiBaseTilerFactory` but
     - **x** (int): TMS tile's column.
     - **y** (int): TMS tile's row.
     - **scale** (int): Tile size scale, default is set to 1 (256x256). **Optional**
-    - **format** (str): Output [image format](../output_format.md), default is set to None and will be either JPEG or PNG depending on masked value. **Optional**
+    - **format** (str): Output [image format](../user_guide/output_format.md), default is set to None and will be either JPEG or PNG depending on masked value. **Optional**
 
 - QueryParams:
     - **url** (str): STAC Item URL. **Required**
@@ -77,7 +77,7 @@ Example:
 `:endpoint:/stac/preview[.{format}]`
 
 - PathParams:
-    - **format**: Output [image format](../output_format.md), default is set to None and will be either JPEG or PNG depending on masked value. **Optional**
+    - **format**: Output [image format](../user_guide/output_format.md), default is set to None and will be either JPEG or PNG depending on masked value. **Optional**
 
 - QueryParams:
     - **url** (str): STAC Item URL. **Required**
@@ -122,7 +122,7 @@ Example:
     - **minx,miny,maxx,maxy** (str): Comma (',') delimited bounding box in WGS84.
     - **height** (int): Force output image height. **Optional**
     - **width** (int): Force output image width. **Optional**
-    - **format** (str): Output [image format](../output_format.md), default is set to None and will be either JPEG or PNG depending on masked value. **Optional**
+    - **format** (str): Output [image format](../user_guide/output_format.md), default is set to None and will be either JPEG or PNG depending on masked value. **Optional**
 
 - QueryParams:
     - **url** (str): STAC Item URL. **Required**
@@ -163,7 +163,7 @@ Example:
 - PathParams:
     - **height** (int): Force output image height. **Optional**
     - **width** (int): Force output image width. **Optional**
-    - **format** (str): Output [image format](../output_format.md), default is set to None and will be either JPEG or PNG depending on masked value. **Optional**
+    - **format** (str): Output [image format](../user_guide/output_format.md), default is set to None and will be either JPEG or PNG depending on masked value. **Optional**
 
 - QueryParams:
     - **url** (str): STAC Item URL. **Required**
@@ -235,7 +235,7 @@ Example:
     - **expression** (str): rio-tiler's math expression with asset names (e.g `Asset1_b1/Asset2_b1`).
     - **asset_as_band** (bool): tell rio-tiler that each asset is a 1 band dataset, so expression `Asset1/Asset2` can be passed.
     - **asset_bidx** (array[str]): Per asset band math expression (e.g `Asset1|1,2,3`).
-    - **tile_format** (str): Output [image format](../output_format.md), default is set to None and will be either JPEG or PNG depending on masked value.
+    - **tile_format** (str): Output [image format](../user_guide/output_format.md), default is set to None and will be either JPEG or PNG depending on masked value.
     - **tile_scale** (int): Tile size scale, default is set to 1 (256x256).
     - **minzoom** (int): Overwrite default minzoom.
     - **maxzoom** (int): Overwrite default maxzoom.
@@ -275,7 +275,7 @@ Example:
     - **expression** (str): rio-tiler's math expression with asset names (e.g `Asset1_b1/Asset2_b1`).
     - **asset_as_band** (bool): tell rio-tiler that each asset is a 1 band dataset, so expression `Asset1/Asset2` can be passed.
     - **asset_bidx** (array[str]): Per asset band math expression (e.g `Asset1|1,2,3`).
-    - **tile_format** (str): Output [image format](../output_format.md), default is set to None and will be either JPEG or PNG depending on masked value.
+    - **tile_format** (str): Output [image format](../user_guide/output_format.md), default is set to None and will be either JPEG or PNG depending on masked value.
     - **tile_scale** (int): Tile size scale, default is set to 1 (256x256).
     - **minzoom** (int): Overwrite default minzoom.
     - **maxzoom** (int): Overwrite default maxzoom.
diff --git a/docs/src/user_guide/algorithms.md b/docs/src/user_guide/algorithms.md
index 9f1c5f7d1..e5c5c180c 100644
--- a/docs/src/user_guide/algorithms.md
+++ b/docs/src/user_guide/algorithms.md
@@ -9,7 +9,7 @@ We added a set of custom algorithms:
 - `hillshade`: Create hillshade from elevation dataset (parameters: azimuth (45), angle_altitude(45))
 - `contours`: Create contours lines (raster) from elevation dataset (parameters: increment (35), thickness (1))
 - `slope`: Create degrees of slope from elevation dataset
-- `terrarium`: [Mapzen's format]((https://github.com/tilezen/joerd/blob/master/docs/formats.md#terrarium)) to encode elevation value in RGB values  `elevation = (red * 256 + green + blue / 256) - 32768`
+- `terrarium`: [Mapzen's format](https://github.com/tilezen/joerd/blob/master/docs/formats.md#terrarium) to encode elevation value in RGB values  `elevation = (red * 256 + green + blue / 256) - 32768`
 - `terrainrgb`: [Mapbox](https://docs.mapbox.com/data/tilesets/guides/access-elevation-data/)/[Maptiler](https://docs.maptiler.com/guides/map-tilling-hosting/data-hosting/rgb-terrain-by-maptiler/)'s format to encode elevation value in RGB values `elevation = -10000 + ((red * 256 * 256 + green * 256 + blue) * 0.1)`
 - `normalizedIndex`: Normalized Difference Index (e.g NDVI)
 - `cast`: Cast data to integer
diff --git a/docs/src/user_guide/output_format.md b/docs/src/user_guide/output_format.md
index 8d32ad577..2055ff931 100644
--- a/docs/src/user_guide/output_format.md
+++ b/docs/src/user_guide/output_format.md
@@ -47,7 +47,7 @@ print(data.shape)
 data, mask = data[0:-1], data[-1]
 ```
 
-Notebook: [Working_with_NumpyTile](examples/notebooks/Working_with_NumpyTile.ipynb)
+Notebook: [Working_with_NumpyTile](../examples/notebooks/Working_with_NumpyTile.ipynb)
 
 ## JSONResponse
 
diff --git a/docs/src/user_guide/rendering.md b/docs/src/user_guide/rendering.md
index fa131ff4d..d3db4bd9f 100644
--- a/docs/src/user_guide/rendering.md
+++ b/docs/src/user_guide/rendering.md
@@ -61,7 +61,7 @@ Titiler supports colormaps that are both discrete (where pixels will be one of t
 
 For more information, please check out [rio-tiler's docs](https://cogeotiff.github.io/rio-tiler/colormap/).
 
-It is also possible to add a [colormap dependency](../../examples/code/tiler_with_custom_colormap) to automatically apply
+It is also possible to add a [colormap dependency](../examples/code/tiler_with_custom_colormap) to automatically apply
 a default colormap.
 
 ## Color Formula
@@ -130,5 +130,5 @@ giving a possible range of 0 to 255 or 0 to 65,536, so Titiler will use these ra
 For certain datasets (e.g. DEMs) this default behaviour can make the image seem washed out (or even entirely one color),
 so if you see this happen look into rescaling your images to something that makes sense for your data.
 
-It is also possible to add a [rescaling dependency](../../api/titiler/core/dependencies/#rescalingparams) to automatically apply
+It is also possible to add a [rescaling dependency](../api/titiler/core/dependencies/#rescalingparams) to automatically apply
 a default rescale.
diff --git a/docs/src/user_guide/tile_matrix_sets.md b/docs/src/user_guide/tile_matrix_sets.md
index eea52d992..3488ff54e 100644
--- a/docs/src/user_guide/tile_matrix_sets.md
+++ b/docs/src/user_guide/tile_matrix_sets.md
@@ -26,7 +26,7 @@ $ curl http://127.0.0.1:8000/tileMatrixSets | jq '.tileMatrixSets[] | .id'
 "WebMercatorQuad"
 ```
 
-You can easily add more TileMatrixSet support, see [custom tms](advanced/customization.md#custom-tms).
+You can easily add more TileMatrixSet support, see [custom tms](../advanced/customization.md#custom-tms).
 
 
-Notebook: [Working_with_nonWebMercatorTMS](examples/notebooks/Working_with_nonWebMercatorTMS.ipynb)
+Notebook: [Working_with_nonWebMercatorTMS](../examples/notebooks/Working_with_nonWebMercatorTMS.ipynb)
diff --git a/src/titiler/core/README.md b/src/titiler/core/README.md
index 79598062d..c74712f10 100644
--- a/src/titiler/core/README.md
+++ b/src/titiler/core/README.md
@@ -33,8 +33,6 @@ cog = TilerFactory()
 app.include_router(cog.router, tags=["Cloud Optimized GeoTIFF"])
 ```
 
-See [titiler.application](../application) for a full example.
-
 ## Package structure
 
 ```
diff --git a/src/titiler/extensions/README.md b/src/titiler/extensions/README.md
index 3451fae87..c39f75a9d 100644
--- a/src/titiler/extensions/README.md
+++ b/src/titiler/extensions/README.md
@@ -58,9 +58,6 @@ tiler = TilerFactory(
 app.include_router(tiler.router, prefix="/cog")
 ```
 
-See [titiler.application](../application) for a full example.
-
-
 ## Create your own
 
 ```python
diff --git a/src/titiler/xarray/notebooks/xarray_dataset_cache.ipynb b/src/titiler/xarray/notebooks/xarray_dataset_cache.ipynb
index e515e12c8..a7692741d 100644
--- a/src/titiler/xarray/notebooks/xarray_dataset_cache.ipynb
+++ b/src/titiler/xarray/notebooks/xarray_dataset_cache.ipynb
@@ -9,7 +9,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 2,
+   "execution_count": 1,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -43,8 +43,8 @@
     "    decode_times: bool = attr.ib(default=False)\n",
     "\n",
     "    # xarray.DataArray options\n",
-    "    datetime: Optional[str] = attr.ib(default=None)\n",
-    "    drop_dim: Optional[str] = attr.ib(default=None)\n",
+    "    sel: Optional[List[str]] = attr.ib(default=None)\n",
+    "    method: Optional[str] = attr.ib(default=None)\n",
     "\n",
     "    tms: TileMatrixSet = attr.ib(default=WEB_MERCATOR_TMS)\n",
     "\n",
@@ -78,8 +78,8 @@
     "        self.input = get_variable(\n",
     "            self.ds,\n",
     "            self.variable,\n",
-    "            datetime=self.datetime,\n",
-    "            drop_dim=self.drop_dim,\n",
+    "            sel=self.sel,\n",
+    "            method=self.method,\n",
     "        )\n",
     "        super().__attrs_post_init__()"
    ]
@@ -93,7 +93,7 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Adding dataset in Cache: ../tests/fixtures/dataset_2d.nc_group:None_time:False\n",
+      "Found dataset in Cache ../tests/fixtures/dataset_2d.nc_group:None_time:False\n",
       "<xarray.Dataset> Size: 16MB\n",
       "Dimensions:  (x: 2000, y: 1000)\n",
       "Coordinates:\n",
@@ -106,7 +106,7 @@
     {
      "data": {
       "text/plain": [
-       "<matplotlib.image.AxesImage at 0x15e4d40d0>"
+       "<matplotlib.image.AxesImage at 0x16b1fc7d0>"
       ]
      },
      "execution_count": 3,
@@ -115,7 +115,7 @@
     },
     {
      "data": {
-      "image/png": "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bHH5/X6de+65ksR1XWdB/fSM+ukZ9XN21FHPeqqfeFtap/F7XAAAqxBcAACrWBtcgUBAK1eu5KLlr0H99Iz66Rn1c3bUUc8Gsn6snJwBAHCXtS0uAICbCC4AgFUILgCAVQguAIBVrAyup59+Wueff77OOeccFRUV6e233051kVLiZz/7mXw+X8wyefLk6PqTJ0+qsrJSo0eP1siRI1VRUXHGj3h6zc6dO3XdddcpPz9fPp9PL730Usx6Y4wefvhh5eXladiwYSopKdHHH38cs83Ro0e1ePFiZWRkKCsrS7fffruOHz+exL0YOGern1tvvfWMz1RZWVnMNl6tn9raWs2aNUujRo1STk6O5s+fr4aGhphtevOdampq0rx58zR8+HDl5OTo3nvvVWdnZzJ3ZcD0po6uvPLKMz5Dd9xxR8w2/a0j64LrL3/5i6qrq7Vy5Uq99957mjFjhkpLS2N+mNIlF110kZqbm6PL66+/Hl1311136a9//as2bNigHTt26NNPP9XChQtTWNqBd+LECc2YMUNPP/10t+tXr16tJ598UmvWrNGuXbs0YsQIlZaW6uTJk9FtFi9erA8++EBbtmzRpk2btHPnTi1btixZuzCgzlY/klRWVhbzmXr++edj1nu1fnbs2KHKykq99dZb2rJlizo6OjR37lydOHEius3ZvlNdXV2aN2+eTp06pTfffFPPPvus1q1bp4cffjgVu5RwvakjSVq6dGnMZ2j16tXRdQmpI2OZSy+91FRWVkYfd3V1mfz8fFNbW5vCUqXGypUrzYwZM7pd19raaoYOHWo2bNgQfe7DDz80kkxdXV2SSphakszGjRujjyORiAkGg+ZXv/pV9LnW1lYTCATM888/b4wxZt++fUaSeeedd6LbvPLKK8bn85n//Oc/SSt7Mny1fowxZsmSJeb666//2te4VD+HDh0yksyOHTuMMb37Tv397383fr/fhEKh6DbPPPOMycjIMO3t7cndgST4ah0ZY8z3vvc985Of/ORrX5OIOrKqxXXq1CnV19erpKQk+pzf71dJSYnq6upSWLLU+fjjj5Wfn68JEyZo8eLFampqkiTV19ero6Mjpq4mT56scePGOVtXBw4cUCgUiqmTzMxMFRUVReukrq5OWVlZuuSSS6LblJSUyO/3a9euXUkvcyps375dOTk5uuCCC7R8+XIdOXIkus6l+mlra5MkZWdnS+rdd6qurk7Tpk1Tbm5udJvS0lKFw2F98MEHSSx9cny1jk577rnnNGbMGE2dOlU1NTX6/PPPo+sSUUdW3WT3s88+U1dXV8wOS1Jubq4++uijFJUqdYqKirRu3TpdcMEFam5u1qpVq3TFFVdo7969CoVCSk9PV1ZWVsxrcnNzFQqFUlPgFDu93919fk6vC4VCysnJiVk/ZMgQZWdnO1FvZWVlWrhwoQoLC7V//3498MADKi8vV11dndLS0pypn0gkojvvvFOXX365pk6dKkm9+k6FQqFuP1+n13lJd3UkSTfddJPGjx+v/Px87dmzR/fff78aGhr04osvSkpMHVkVXIhVXl4e/ff06dNVVFSk8ePH64UXXtCwYcNSWDLYatGiRdF/T5s2TdOnT9fEiRO1fft2zZkzJ4UlS67Kykrt3bs3ZswYsb6ujr483jlt2jTl5eVpzpw52r9/vyZOnJiQv21VV+GYMWOUlpZ2xiyelpYWBYPBFJVq8MjKytK3vvUtNTY2KhgM6tSpU2ptbY3ZxuW6Or3fPX1+gsHgGRN9Ojs7dfToUSfrbcKECRozZowaGxsluVE/VVVV2rRpk1577TWdd9550ed7850KBoPdfr5Or/OKr6uj7hQVFUlSzGeov3VkVXClp6dr5syZ2rp1a/S5SCSirVu3qri4OIUlGxyOHz+u/fv3Ky8vTzNnztTQoUNj6qqhoUFNTU3O1lVhYaGCwWBMnYTDYe3atStaJ8XFxWptbVV9fX10m23btikSiUS/gC755JNPdOTIEeXl5Unydv0YY1RVVaWNGzdq27ZtKiwsjFnfm+9UcXGx/vnPf8aE+5YtW5SRkaEpU6YkZ0cG0NnqqDu7d++WpJjPUL/rqI+TSVLmz3/+swkEAmbdunVm3759ZtmyZSYrKytmhoor7r77brN9+3Zz4MAB88Ybb5iSkhIzZswYc+jQIWOMMXfccYcZN26c2bZtm3n33XdNcXGxKS4uTnGpB9axY8fM+++/b95//30jyfz6178277//vvn3v/9tjDHml7/8pcnKyjIvv/yy2bNnj7n++utNYWGh+eKLL6LvUVZWZr797W+bXbt2mddff91MmjTJ3HjjjanapYTqqX6OHTtm7rnnHlNXV2cOHDhgXn31VfOd73zHTJo0yZw8eTL6Hl6tn+XLl5vMzEyzfft209zcHF0+//zz6DZn+051dnaaqVOnmrlz55rdu3ebzZs3m7Fjx5qamppU7FLCna2OGhsbzSOPPGLeffddc+DAAfPyyy+bCRMmmNmzZ0ffIxF1ZF1wGWPMU089ZcaNG2fS09PNpZdeat56661UFyklbrjhBpOXl2fS09PNueeea2644QbT2NgYXf/FF1+YH//4x+Yb3/iGGT58uFmwYIFpbm5OYYkH3muvvWYknbEsWbLEGPPfKfEPPfSQyc3NNYFAwMyZM8c0NDTEvMeRI0fMjTfeaEaOHGkyMjLMbbfdZo4dO5aCvUm8nurn888/N3PnzjVjx441Q4cONePHjzdLly4946TQq/XTXb1IMmvXro1u05vv1L/+9S9TXl5uhg0bZsaMGWPuvvtu09HRkeS9GRhnq6OmpiYze/Zsk52dbQKBgPnmN79p7r33XtPW1hbzPv2tI37WBABgFavGuAAAILgAAFYhuAAAViG4AABWIbgAAFYhuAAAViG4AABWIbgAAFYhuAAAViG4AABWIbgAAFYhuAAAVvn/DbXKOsc2f2sAAAAASUVORK5CYII=",
+      "image/png": "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",
       "text/plain": [
        "<Figure size 640x480 with 1 Axes>"
       ]
@@ -159,7 +159,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.9.19"
+   "version": "3.12.3"
   }
  },
  "nbformat": 4,
diff --git a/src/titiler/xarray/notebooks/xarray_reader.ipynb b/src/titiler/xarray/notebooks/xarray_reader.ipynb
new file mode 100644
index 000000000..33da74dd3
--- /dev/null
+++ b/src/titiler/xarray/notebooks/xarray_reader.ipynb
@@ -0,0 +1,324 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Using titiler.xarray Reader"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from titiler.xarray.io import Reader\n",
+    "\n",
+    "import matplotlib.pyplot as plt"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\n",
+      "    \"bounds\": [\n",
+      "        -170.085,\n",
+      "        -80.08,\n",
+      "        169.914999999975,\n",
+      "        79.91999999999659\n",
+      "    ],\n",
+      "    \"crs\": \"http://www.opengis.net/def/crs/EPSG/0/4326\",\n",
+      "    \"band_metadata\": [\n",
+      "        [\n",
+      "            \"b1\",\n",
+      "            {}\n",
+      "        ]\n",
+      "    ],\n",
+      "    \"band_descriptions\": [\n",
+      "        [\n",
+      "            \"b1\",\n",
+      "            \"dataset\"\n",
+      "        ]\n",
+      "    ],\n",
+      "    \"dtype\": \"float64\",\n",
+      "    \"nodata_type\": \"Nodata\",\n",
+      "    \"colorinterp\": null,\n",
+      "    \"scales\": null,\n",
+      "    \"offsets\": null,\n",
+      "    \"colormap\": null,\n",
+      "    \"name\": \"dataset\",\n",
+      "    \"count\": 1,\n",
+      "    \"width\": 2000,\n",
+      "    \"height\": 1000,\n",
+      "    \"dimensions\": [\n",
+      "        \"y\",\n",
+      "        \"x\"\n",
+      "    ],\n",
+      "    \"attrs\": {\n",
+      "        \"valid_min\": 1.0,\n",
+      "        \"valid_max\": 1000.0,\n",
+      "        \"fill_value\": 0\n",
+      "    }\n",
+      "}\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "<matplotlib.image.AxesImage at 0x11df61ca0>"
+      ]
+     },
+     "execution_count": 10,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "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",
+      "text/plain": [
+       "<Figure size 640x480 with 1 Axes>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "# With a simple 2 Dataset\n",
+    "with Reader(\"../tests/fixtures/dataset_2d.nc\", \"dataset\") as src:\n",
+    "    print(src.info().model_dump_json(indent=4))\n",
+    "\n",
+    "    tile = src.tms.tile(src.bounds[0], src.bounds[1], src.minzoom)\n",
+    "    img = src.tile(*tile)\n",
+    "\n",
+    "plt.imshow(img.data_as_image())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{\n",
+      "    \"bounds\": [\n",
+      "        -170.085,\n",
+      "        -80.08,\n",
+      "        169.914999999975,\n",
+      "        79.91999999999659\n",
+      "    ],\n",
+      "    \"crs\": \"http://www.opengis.net/def/crs/EPSG/0/4326\",\n",
+      "    \"band_metadata\": [\n",
+      "        [\n",
+      "            \"b1\",\n",
+      "            {}\n",
+      "        ],\n",
+      "        [\n",
+      "            \"b2\",\n",
+      "            {}\n",
+      "        ]\n",
+      "    ],\n",
+      "    \"band_descriptions\": [\n",
+      "        [\n",
+      "            \"b1\",\n",
+      "            \"2022-01-01T00:00:00.000000000\"\n",
+      "        ],\n",
+      "        [\n",
+      "            \"b2\",\n",
+      "            \"2023-01-01T00:00:00.000000000\"\n",
+      "        ]\n",
+      "    ],\n",
+      "    \"dtype\": \"float64\",\n",
+      "    \"nodata_type\": \"Nodata\",\n",
+      "    \"colorinterp\": null,\n",
+      "    \"scales\": null,\n",
+      "    \"offsets\": null,\n",
+      "    \"colormap\": null,\n",
+      "    \"name\": \"dataset\",\n",
+      "    \"count\": 2,\n",
+      "    \"width\": 2000,\n",
+      "    \"height\": 1000,\n",
+      "    \"dimensions\": [\n",
+      "        \"time\",\n",
+      "        \"y\",\n",
+      "        \"x\"\n",
+      "    ],\n",
+      "    \"attrs\": {\n",
+      "        \"valid_min\": 1.0,\n",
+      "        \"valid_max\": 1000.0,\n",
+      "        \"fill_value\": 0\n",
+      "    }\n",
+      "}\n",
+      "There are 2 Time Values (represented as Bands)\n",
+      "[('b1', '2022-01-01T00:00:00.000000000'), ('b2', '2023-01-01T00:00:00.000000000')]\n"
+     ]
+    }
+   ],
+   "source": [
+    "# With a 3D Dataset (Time, X, Y)\n",
+    "with Reader(\"../tests/fixtures/dataset_3d.nc\", \"dataset\") as src:\n",
+    "    info = src.info()\n",
+    "\n",
+    "    print(info.model_dump_json(indent=4))\n",
+    "    print(\"There are 2 Time Values (represented as Bands)\")\n",
+    "    print(info.band_descriptions)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<matplotlib.image.AxesImage at 0x138e27a70>"
+      ]
+     },
+     "execution_count": 17,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "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",
+      "text/plain": [
+       "<Figure size 640x480 with 1 Axes>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "# View the first time value\n",
+    "with Reader(\"../tests/fixtures/dataset_3d.nc\", \"dataset\") as src:\n",
+    "    tile = src.tms.tile(src.bounds[0], src.bounds[1], src.minzoom)\n",
+    "    img = src.tile(*tile, indexes=1)\n",
+    "\n",
+    "plt.imshow(img.data_as_image())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<matplotlib.image.AxesImage at 0x13ebc25d0>"
+      ]
+     },
+     "execution_count": 18,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "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",
+      "text/plain": [
+       "<Figure size 640x480 with 1 Axes>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "# View the second time value\n",
+    "with Reader(\"../tests/fixtures/dataset_3d.nc\", \"dataset\") as src:\n",
+    "    tile = src.tms.tile(src.bounds[0], src.bounds[1], src.minzoom)\n",
+    "    img = src.tile(*tile, indexes=2)\n",
+    "\n",
+    "plt.imshow(img.data_as_image())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[('b1', '2023-01-01T00:00:00.000000000')]\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "<matplotlib.image.AxesImage at 0x11f958410>"
+      ]
+     },
+     "execution_count": 20,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "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",
+      "text/plain": [
+       "<Figure size 640x480 with 1 Axes>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "# Select time with Xarray Sel method\n",
+    "with Reader(\n",
+    "    \"../tests/fixtures/dataset_3d.nc\",\n",
+    "    \"dataset\",\n",
+    "    sel=[\"time=2023-01-01\"],\n",
+    "    method=\"nearest\",\n",
+    ") as src:\n",
+    "    print(src.info().band_descriptions)\n",
+    "    tile = src.tms.tile(src.bounds[0], src.bounds[1], src.minzoom)\n",
+    "    img = src.tile(*tile)\n",
+    "\n",
+    "plt.imshow(img.data_as_image())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "py39",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.12.3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/src/titiler/xarray/pyproject.toml b/src/titiler/xarray/pyproject.toml
index 334e620b4..406c8b493 100644
--- a/src/titiler/xarray/pyproject.toml
+++ b/src/titiler/xarray/pyproject.toml
@@ -31,7 +31,7 @@ classifiers = [
 dynamic = ["version"]
 dependencies = [
     "titiler.core==0.21.1",
-    "rio-tiler>=7.2,<8.0",
+    "rio-tiler>=7.6.1,<8.0",
     "xarray",
     "rioxarray",
 ]
diff --git a/src/titiler/xarray/tests/test_dependencies.py b/src/titiler/xarray/tests/test_dependencies.py
index 8d53916f9..1453860c9 100644
--- a/src/titiler/xarray/tests/test_dependencies.py
+++ b/src/titiler/xarray/tests/test_dependencies.py
@@ -46,23 +46,31 @@ def tiles(
         params = response.json()
         assert params == {"variable": "yo"}
 
-        response = client.get("/tiles/1/2/3", params={"drop_dim": "yo=yo"})
+        response = client.get("/tiles/1/2/3", params={"sel": "yo=yo"})
         params = response.json()
-        assert params == {"drop_dim": ["yo=yo"]}
+        assert params == {"sel": ["yo=yo"]}
 
-        response = client.get("/tiles/1/2/3", params={"drop_dim": "yo=1.0"})
+        response = client.get("/tiles/1/2/3", params={"sel": "yo=1.0"})
         params = response.json()
-        assert params == {"drop_dim": ["yo=1.0"]}
+        assert params == {"sel": ["yo=1.0"]}
 
-        response = client.get("/tiles/1/2/3", params={"drop_dim": ["yo=yo", "ye=ye"]})
+        response = client.get("/tiles/1/2/3", params={"sel": ["yo=yo", "ye=ye"]})
         params = response.json()
-        assert params == {"drop_dim": ["yo=yo", "ye=ye"]}
+        assert params == {"sel": ["yo=yo", "ye=ye"]}
 
-        response = client.get("/tiles/1/2/3", params={"drop_dim": "yo"})
+        response = client.get("/tiles/1/2/3?sel=yo=yo&sel=ye=ye")
+        params = response.json()
+        assert params == {"sel": ["yo=yo", "ye=ye"]}
+
+        response = client.get("/tiles/1/2/3", params={"sel": "yo"})
         assert response.status_code == 422
 
-        response = client.get("/tiles/1/2/3", params={"drop_dim": "=yo"})
+        response = client.get("/tiles/1/2/3", params={"sel": "=yo"})
         assert response.status_code == 422
 
-        response = client.get("/tiles/1/2/3", params={"drop_dim": "yo="})
+        response = client.get("/tiles/1/2/3", params={"sel": "yo="})
         assert response.status_code == 422
+
+        response = client.get("/tiles/1/2/3", params={"sel_method": "nearest"})
+        params = response.json()
+        assert params == {"method": "nearest"}
diff --git a/src/titiler/xarray/tests/test_factory.py b/src/titiler/xarray/tests/test_factory.py
index 84c0d0f86..17c731599 100644
--- a/src/titiler/xarray/tests/test_factory.py
+++ b/src/titiler/xarray/tests/test_factory.py
@@ -135,22 +135,55 @@ def test_info_da_options(app):
     """Test /info endpoints with Dataarray options."""
     resp = app.get(
         "/md/info",
-        params={"url": dataset_4d_nc, "variable": "dataset", "drop_dims": "z=0"},
+        params={"url": dataset_4d_nc, "variable": "dataset", "sel": "time=2023-01-01"},
     )
     assert resp.status_code == 200
     assert resp.headers["content-type"] == "application/json"
+    body = resp.json()
+    assert body["band_descriptions"] == [["b1", "0"]]
+
+    resp = app.get(
+        "/md/info",
+        params={"url": dataset_4d_nc, "variable": "dataset", "sel": "z=0"},
+    )
+    assert resp.status_code == 200
+    assert resp.headers["content-type"] == "application/json"
+    body = resp.json()
+    assert body["band_descriptions"] == [
+        ["b1", "2022-01-01T00:00:00.000000000"],
+        ["b2", "2023-01-01T00:00:00.000000000"],
+    ]
+
+    resp = app.get(
+        "/md/info",
+        params={
+            "url": dataset_4d_nc,
+            "variable": "dataset",
+            "sel": "z=1",
+            "sel_method": "nearest",
+        },
+    )
+    assert resp.status_code == 200
+    assert resp.headers["content-type"] == "application/json"
+    body = resp.json()
+    assert body["band_descriptions"] == [
+        ["b1", "2022-01-01T00:00:00.000000000"],
+        ["b2", "2023-01-01T00:00:00.000000000"],
+    ]
 
     resp = app.get(
         "/md/info",
         params={
             "url": dataset_3d_nc,
             "variable": "dataset",
-            "datetime": "2023-01-01",
+            "sel": "time=2023-01-01",
             "decode_times": True,
         },
     )
     assert resp.status_code == 200
     assert resp.headers["content-type"] == "application/json"
+    body = resp.json()
+    assert body["band_descriptions"] == [["b1", "2023-01-01T00:00:00.000000000"]]
 
 
 @pytest.mark.parametrize(
@@ -165,21 +198,21 @@ def test_tiles(filename, app):
 
     resp = app.get(
         "/md/tiles/WebMercatorQuad/0/0/0",
-        params={"url": filename, "variable": "dataset", "rescale": "0,500"},
+        params={"url": filename, "variable": "dataset", "rescale": "0,500", "bidx": 1},
     )
     assert resp.status_code == 200
     assert resp.headers["content-type"] == "image/png"
 
     resp = app.get(
         "/md/tiles/WebMercatorQuad/0/0/0.jpeg",
-        params={"url": filename, "variable": "dataset", "rescale": "0,500"},
+        params={"url": filename, "variable": "dataset", "rescale": "0,500", "bidx": 1},
     )
     assert resp.status_code == 200
     assert resp.headers["content-type"] == "image/jpeg"
 
     resp = app.get(
         "/md/WebMercatorQuad/tilejson.json",
-        params={"url": filename, "variable": "dataset", "rescale": "0,500"},
+        params={"url": filename, "variable": "dataset", "rescale": "0,500", "bidx": 1},
     )
     assert resp.status_code == 200
     assert resp.headers["content-type"] == "application/json"
@@ -284,7 +317,7 @@ def test_part(filename, app):
 
     resp = app.post(
         "/md/feature",
-        params={"url": filename, "variable": "dataset", "rescale": "0,500"},
+        params={"url": filename, "variable": "dataset", "rescale": "0,500", "bidx": 1},
         json=feat,
     )
     assert resp.status_code == 200
@@ -292,7 +325,7 @@ def test_part(filename, app):
 
     resp = app.post(
         "/md/feature.png",
-        params={"url": filename, "variable": "dataset", "rescale": "0,500"},
+        params={"url": filename, "variable": "dataset", "rescale": "0,500", "bidx": 1},
         json=feat,
     )
     assert resp.status_code == 200
@@ -300,7 +333,7 @@ def test_part(filename, app):
 
     resp = app.post(
         "/md/feature/100x100.png",
-        params={"url": filename, "variable": "dataset", "rescale": "0,500"},
+        params={"url": filename, "variable": "dataset", "rescale": "0,500", "bidx": 1},
         json=feat,
     )
     assert resp.status_code == 200
@@ -308,14 +341,14 @@ def test_part(filename, app):
 
     resp = app.get(
         "/md/bbox/-100,-25,40,60.jpeg",
-        params={"url": filename, "variable": "dataset", "rescale": "0,500"},
+        params={"url": filename, "variable": "dataset", "rescale": "0,500", "bidx": 1},
     )
     assert resp.status_code == 200
     assert resp.headers["content-type"] == "image/jpeg"
 
     resp = app.get(
         "/md/bbox/-100,-25,40,60/100x100.png",
-        params={"url": filename, "variable": "dataset", "rescale": "0,500"},
+        params={"url": filename, "variable": "dataset", "rescale": "0,500", "bidx": 1},
     )
     assert resp.status_code == 200
     assert resp.headers["content-type"] == "image/png"
diff --git a/src/titiler/xarray/tests/test_io_tools.py b/src/titiler/xarray/tests/test_io_tools.py
index 0b32e06d2..017fab195 100644
--- a/src/titiler/xarray/tests/test_io_tools.py
+++ b/src/titiler/xarray/tests/test_io_tools.py
@@ -31,17 +31,49 @@ def test_get_variable():
     ds = data.to_dataset(name="dataset")
     da = get_variable(ds, "dataset")
     assert da.rio.crs
+    assert da.dims == ("time", "y", "x")
+    assert da["time"].shape == (2,)
+
+    da = get_variable(ds, "dataset", sel=["time=2022-01-01"])
+    assert da.rio.crs
     assert da.dims == ("y", "x")
-    # Default to the first Time value
     assert da["time"] == numpy.datetime64("2022-01-01")
 
-    da = get_variable(ds, "dataset", datetime="2023-01-01T01:00:00.000Z")
+    da = get_variable(ds, "dataset", sel=["time=2023-01-01T00:00:00"])
+    assert da.rio.crs
+    assert da.dims == ("y", "x")
+    assert da["time"] == numpy.datetime64("2023-01-01")
+
+    # no time for 2022-12-01T00:00:00
+    with pytest.raises(KeyError):
+        get_variable(ds, "dataset", sel=["time=2022-12-01", "time=2023-01-01"])
+
+    da = get_variable(
+        ds,
+        "dataset",
+        sel=["time=2022-12-01", "time=2023-01-01"],
+        method="nearest",
+    )
+    assert da.rio.crs
+    assert da.dims == ("time", "y", "x")
+    assert da["time"].shape == (2,)
+    assert da["time"][0] == numpy.datetime64("2023-01-01")
+    assert da["time"][1] == numpy.datetime64("2023-01-01")
+
+    da = get_variable(ds, "dataset", sel=["time=2022-01-01", "time=2023-01-01"])
+    assert da.rio.crs
+    assert da.dims == ("time", "y", "x")
+    assert da["time"].shape == (2,)
+    assert da["time"][0] == numpy.datetime64("2022-01-01")
+    assert da["time"][1] == numpy.datetime64("2023-01-01")
+
+    da = get_variable(ds, "dataset", sel=["time=1st of January 2023"])
     assert da.rio.crs
     assert da.dims == ("y", "x")
     assert da["time"] == numpy.datetime64("2023-01-01")
 
     # Select the Nearest Time
-    da = get_variable(ds, "dataset", datetime="2024-01-01T01:00:00.000Z")
+    da = get_variable(ds, "dataset", sel=["time=2024-01-01T01:00:00"], method="nearest")
     assert da.rio.crs
     assert da.dims == ("y", "x")
     assert da["time"] == numpy.datetime64("2023-01-01")
@@ -51,7 +83,7 @@ def test_get_variable():
     ds = data.to_dataset(name="dataset")
     da = get_variable(ds, "dataset")
     assert da.rio.crs
-    assert da.dims == ("y", "x")
+    assert da.dims == ("time", "y", "x")
 
     # 4D dataset
     arr = numpy.arange(0, 33 * 35 * 2).reshape(2, 1, 33, 35)
@@ -66,9 +98,15 @@ def test_get_variable():
         },
     )
     ds = data.to_dataset(name="dataset")
-    da = get_variable(ds, "dataset")
+
+    # We need to reduce the dim
+    with pytest.raises(AssertionError):
+        get_variable(ds, "dataset")
+
+    # Reduce on Z
+    da = get_variable(ds, "dataset", sel=["z=0"])
     assert da.rio.crs
-    assert da.dims == ("z", "y", "x")
+    assert da.dims == ("time", "y", "x")
 
     # 5D dataset
     arr = numpy.arange(0, 33 * 35 * 2).reshape(2, 1, 1, 33, 35)
@@ -87,11 +125,14 @@ def test_get_variable():
     with pytest.raises(AssertionError):
         get_variable(ds, "dataset")
 
-    da = get_variable(ds, "dataset", drop_dim=["universe=somewhere"])
+    with pytest.raises(AssertionError):
+        da = get_variable(ds, "dataset", sel=["universe=somewhere"])
+
+    da = get_variable(ds, "dataset", sel=["universe=somewhere", "time=2022-01-01"])
     assert da.rio.crs
     assert da.dims == ("z", "y", "x")
 
-    # 5D dataset - drop time dim
+    # 5D dataset
     arr = numpy.arange(0, 33 * 35 * 2).reshape(2, 1, 1, 33, 35)
     data = xarray.DataArray(
         arr,
@@ -106,7 +147,7 @@ def test_get_variable():
     )
 
     da = get_variable(
-        ds, "dataset", drop_dim=["universe=somewhere", "time=2022-01-01T00:00:00"]
+        ds, "dataset", sel=["universe=somewhere", "time=2022-01-01T00:00:00"]
     )
     assert da.rio.crs
     assert da.dims == ("z", "y", "x")
diff --git a/src/titiler/xarray/titiler/xarray/dependencies.py b/src/titiler/xarray/titiler/xarray/dependencies.py
index 4f223b264..8f3769fc0 100644
--- a/src/titiler/xarray/titiler/xarray/dependencies.py
+++ b/src/titiler/xarray/titiler/xarray/dependencies.py
@@ -1,7 +1,7 @@
 """titiler.xarray dependencies."""
 
 from dataclasses import dataclass
-from typing import List, Optional, Union
+from typing import List, Literal, Optional, Union
 
 import numpy
 from fastapi import Query
@@ -31,27 +31,29 @@ class XarrayIOParams(DefaultDependency):
         ),
     ] = None
 
-    # cache_client
 
-
-DropDimStr = Annotated[str, StringConstraints(pattern=r"^[^=]+=[^=]+$")]
+SelDimStr = Annotated[str, StringConstraints(pattern=r"^[^=]+=[^=]+$")]
 
 
 @dataclass
 class XarrayDsParams(DefaultDependency):
     """Xarray Dataset Options."""
 
-    variable: Annotated[str, Query(description="Xarray Variable name")]
+    variable: Annotated[str, Query(description="Xarray Variable name.")]
 
-    drop_dim: Annotated[
-        Optional[List[DropDimStr]],
+    sel: Annotated[
+        Optional[List[SelDimStr]],
         Query(
-            description="Dimensions to drop in form of `{dimension}={value}`",
+            description="Xarray Indexing using dimension names `{dimension}={value}`.",
         ),
     ] = None
 
-    datetime: Annotated[
-        Optional[str], Query(description="Slice of time to read (if available)")
+    method: Annotated[
+        Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]],
+        Query(
+            alias="sel_method",
+            description="Xarray indexing method to use for inexact matches.",
+        ),
     ] = None
 
 
@@ -71,17 +73,23 @@ class CompatXarrayParams(XarrayIOParams):
     it would fail without the variable query-parameter set.
     """
 
-    variable: Annotated[Optional[str], Query(description="Xarray Variable name")] = None
+    variable: Annotated[Optional[str], Query(description="Xarray Variable name.")] = (
+        None
+    )
 
-    drop_dim: Annotated[
-        Optional[List[DropDimStr]],
+    sel: Annotated[
+        Optional[List[SelDimStr]],
         Query(
-            description="Dimensions to drop in form of `{dimension}={value}`",
+            description="Xarray Indexing using dimension names `{dimension}={value}`.",
         ),
     ] = None
 
-    datetime: Annotated[
-        Optional[str], Query(description="Slice of time to read (if available)")
+    method: Annotated[
+        Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]],
+        Query(
+            alias="sel_method",
+            description="Xarray indexing method to use for inexact matches.",
+        ),
     ] = None
 
 
diff --git a/src/titiler/xarray/titiler/xarray/factory.py b/src/titiler/xarray/titiler/xarray/factory.py
index 579091685..770a8b084 100644
--- a/src/titiler/xarray/titiler/xarray/factory.py
+++ b/src/titiler/xarray/titiler/xarray/factory.py
@@ -11,6 +11,7 @@
 from typing_extensions import Annotated
 
 from titiler.core.dependencies import (
+    BidxParams,
     CoordCRSParams,
     CRSParams,
     DatasetPathParams,
@@ -37,8 +38,8 @@ class TilerFactory(BaseTilerFactory):
 
     reader_dependency: Type[DefaultDependency] = XarrayParams
 
-    # Indexes/Expression Dependencies (Not layer dependencies for Xarray)
-    layer_dependency: Type[DefaultDependency] = DefaultDependency
+    # Indexes Dependencies
+    layer_dependency: Type[DefaultDependency] = BidxParams
 
     # Dataset Options (nodata, reproject)
     dataset_dependency: Type[DefaultDependency] = DatasetParams
diff --git a/src/titiler/xarray/titiler/xarray/io.py b/src/titiler/xarray/titiler/xarray/io.py
index 14d021b29..6aa592e86 100644
--- a/src/titiler/xarray/titiler/xarray/io.py
+++ b/src/titiler/xarray/titiler/xarray/io.py
@@ -1,10 +1,11 @@
 """titiler.xarray.io"""
 
-from typing import Any, Callable, Dict, List, Optional
+from typing import Any, Callable, Dict, List, Literal, Optional, Union
 from urllib.parse import urlparse
 
 import attr
 import numpy
+import pandas
 import xarray
 from morecantile import TileMatrixSet
 from rio_tiler.constants import WEB_MERCATOR_TMS
@@ -135,19 +136,32 @@ def _arrange_dims(da: xarray.DataArray) -> xarray.DataArray:
     return da
 
 
+def _cast_to_type(value, dtype: Any) -> Any:
+    if "timedelta" in str(dtype):
+        value = pandas.to_timedelta(value)
+
+    elif numpy.issubdtype(dtype, numpy.integer):
+        value = int(value)
+
+    elif numpy.issubdtype(dtype, numpy.floating):
+        value = float(value)
+
+    return value
+
+
 def get_variable(
     ds: xarray.Dataset,
     variable: str,
-    datetime: Optional[str] = None,
-    drop_dim: Optional[List[str]] = None,
+    sel: Optional[List[str]] = None,
+    method: Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]] = None,
 ) -> xarray.DataArray:
     """Get Xarray variable as DataArray.
 
     Args:
         ds (xarray.Dataset): Xarray Dataset.
         variable (str): Variable to extract from the Dataset.
-        datetime (str, optional): datetime to select from the DataArray.
-        drop_dim (list of str, optional): DataArray dimension to drop in form of `[{dimension}={value}],`.
+        sel (list of str, optional): List of Xarray Indexes.
+        method (str): Xarray indexing method.
 
     Returns:
         xarray.DataArray: 2D or 3D DataArray.
@@ -155,10 +169,20 @@ def get_variable(
     """
     da = ds[variable]
 
-    if drop_dim:
-        for dim in drop_dim:
-            dim_to_drop, dim_val = dim.split("=")
-            da = da.sel({dim_to_drop: dim_val}).drop_vars(dim_to_drop)
+    if sel:
+        _idx: Dict[str, List] = {}
+        for s in sel:
+            val: Union[str, slice]
+            dim, val = s.split("=")
+            val = _cast_to_type(val, da[dim].dtype)
+
+            if dim in _idx:
+                _idx[dim].append(val)
+            else:
+                _idx[dim] = [val]
+
+        sel_idx = {k: v[0] if len(v) < 2 else v for k, v in _idx.items()}
+        da = da.sel(sel_idx, method=method)
 
     da = _arrange_dims(da)
 
@@ -173,20 +197,6 @@ def get_variable(
         # Sort the dataset by the updated longitude coordinates
         da = da.sortby(da.x)
 
-    # TODO: Technically we don't have to select the first time, rio-tiler should handle 3D dataset
-    if "time" in da.dims:
-        if datetime:
-            # TODO: handle time interval
-            time_as_str = datetime.split("T")[0]
-            if da["time"].dtype == "O":
-                da["time"] = da["time"].astype("datetime64[ns]")
-
-            da = da.sel(
-                time=numpy.array(time_as_str, dtype=numpy.datetime64), method="nearest"
-            )
-        else:
-            da = da.isel(time=0)
-
     assert len(da.dims) in [2, 3], "titiler.xarray can only work with 2D or 3D dataset"
 
     return da
@@ -206,8 +216,10 @@ class Reader(XarrayReader):
     decode_times: bool = attr.ib(default=True)
 
     # xarray.DataArray options
-    datetime: Optional[str] = attr.ib(default=None)
-    drop_dim: Optional[str] = attr.ib(default=None)
+    sel: Optional[List[str]] = attr.ib(default=None)
+    method: Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]] = attr.ib(
+        default=None
+    )
 
     tms: TileMatrixSet = attr.ib(default=WEB_MERCATOR_TMS)
 
@@ -227,8 +239,8 @@ def __attrs_post_init__(self):
         self.input = get_variable(
             self.ds,
             self.variable,
-            datetime=self.datetime,
-            drop_dim=self.drop_dim,
+            sel=self.sel,
+            method=self.method,
         )
         super().__attrs_post_init__()
 


Reviews:
user: login: vincentsarago
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-22T20:51:47Z
user: login: vincentsarago
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-22T20:52:31Z
user: login: vincentsarago
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-22T20:53:51Z
user: login: j08lue
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-23T07:14:26Z
user: login: j08lue
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-23T07:24:05Z
user: login: j08lue
body: I made a few suggestions to make the `sel` parameter parsing more robust:

1. Splitting on comma and using as args for `slice` should only happen when there are two commas.
2. Preserve the original form of datetime strings (no dtype casting) to rely on Pandas magic.
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-04-23T07:31:06Z
user: login: vincentsarago
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-23T07:51:25Z
user: login: j08lue
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-23T08:04:06Z
user: login: vincentsarago
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-23T08:28:12Z
user: login: vincentsarago
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-23T08:34:36Z
user: login: j08lue
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-23T09:07:39Z
user: login: vincentsarago
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-23T12:11:26Z
user: login: j08lue
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-23T20:00:23Z
user: login: hrodmn
body: I really like bringing the `sel` interface to the titiler endpoints - it's easy to imagine how you could build a UI that combines the `/dataset/info` response with some user input to generate tile URLs.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T20:23:04Z
user: login: j08lue
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-23T20:40:55Z
user: login: vincentsarago
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-24T08:38:55Z
user: login: vincentsarago
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-24T08:40:36Z
user: login: j08lue
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-24T10:32:04Z
user: login: vincentsarago
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-24T10:47:51Z
user: login: vincentsarago
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-24T11:08:11Z
user: login: j08lue
body: Nice, this is a very powerful feature - and with the new naming and behavior it will be very familiar to Xarray users.

Should we rename the `method` parameter to indicate that it is specific to the `sel` operation, e.g. `sel_method`? 🤔 Just a thought.
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-24T12:18:49Z
user: login: abarciauskas-bgse
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T14:41:14Z
user: login: vincentsarago
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-24T14:42:19Z
user: login: github-actions[bot]
body: <!-- github-benchmark-action-comment(start): TiTiler performance Benchmarks Alert -->
# :warning: **Performance Alert** :warning:

Possible performance regression was detected for benchmark **'TiTiler performance Benchmarks'**.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold `1.30`.

| Benchmark suite | Current: 8fc2dda4bb80fed10e87bc150ae447c8b832c2d3 | Previous: 6aeb6d68071bf5b308feb42abdbeb18de54a4c58 | Ratio |
|-|-|-|-|
| `WebMercator longest_transaction` | `0.07` s | `0.05` s | `1.40` |

This comment was automatically generated by [workflow](https://github.com/developmentseed/titiler/actions?query=workflow%3Abenchmark) using [github-action-benchmark](https://github.com/marketplace/actions/continuous-benchmark).
<!-- github-benchmark-action-comment(end): TiTiler performance Benchmarks Alert -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T17:05:50Z

Review comments:
diff_hunk: @@ -173,20 +183,6 @@ def get_variable(
         # Sort the dataset by the updated longitude coordinates
         da = da.sortby(da.x)
 
-    # TODO: Technically we don't have to select the first time, rio-tiler should handle 3D dataset
-    if "time" in da.dims:
-        if datetime:
-            # TODO: handle time interval
-            time_as_str = datetime.split("T")[0]
-            if da["time"].dtype == "O":
-                da["time"] = da["time"].astype("datetime64[ns]")
-
-            da = da.sel(
-                time=numpy.array(time_as_str, dtype=numpy.datetime64), method="nearest"
-            )
-        else:
-            da = da.isel(time=0)
path: src/titiler/xarray/titiler/xarray/io.py
user: login: vincentsarago
body: ⚠️ we do not select the first time dimension now 
created_at: 2025-04-22T20:51:47Z
author_association: MEMBER
diff_hunk: @@ -138,27 +138,37 @@ def _arrange_dims(da: xarray.DataArray) -> xarray.DataArray:
 def get_variable(
     ds: xarray.Dataset,
     variable: str,
-    datetime: Optional[str] = None,
-    drop_dim: Optional[List[str]] = None,
+    sel: Optional[List[str]] = None,
+    method: Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]] = None,
 ) -> xarray.DataArray:
     """Get Xarray variable as DataArray.
 
     Args:
         ds (xarray.Dataset): Xarray Dataset.
         variable (str): Variable to extract from the Dataset.
-        datetime (str, optional): datetime to select from the DataArray.
-        drop_dim (list of str, optional): DataArray dimension to drop in form of `[{dimension}={value}],`.
+        sel (list of str, optional): List of Xarray Indexes.
+        method (str): Xarray indexing method.
 
     Returns:
         xarray.DataArray: 2D or 3D DataArray.
 
     """
     da = ds[variable]
 
-    if drop_dim:
-        for dim in drop_dim:
-            dim_to_drop, dim_val = dim.split("=")
-            da = da.sel({dim_to_drop: dim_val}).drop_vars(dim_to_drop)
+    if sel:
+        sel_idx = []
+        for s in sel:
+            val: Union[str, slice]
+            dim, val = s.split("=")
+            dt = da[dim].dtype
+            if "," in val:
+                val = slice(*[numpy.array(v).astype(dt) for v in val.split(",")])
+            else:
+                val = numpy.array(val).astype(dt)
path: src/titiler/xarray/titiler/xarray/io.py
user: login: vincentsarago
body: we need to `cast` the value to the array datatype (e.g `z="0"` -> `z=0`)
created_at: 2025-04-22T20:52:31Z
author_association: MEMBER
diff_hunk: @@ -138,27 +138,37 @@ def _arrange_dims(da: xarray.DataArray) -> xarray.DataArray:
 def get_variable(
     ds: xarray.Dataset,
     variable: str,
-    datetime: Optional[str] = None,
-    drop_dim: Optional[List[str]] = None,
+    sel: Optional[List[str]] = None,
+    method: Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]] = None,
 ) -> xarray.DataArray:
     """Get Xarray variable as DataArray.
 
     Args:
         ds (xarray.Dataset): Xarray Dataset.
         variable (str): Variable to extract from the Dataset.
-        datetime (str, optional): datetime to select from the DataArray.
-        drop_dim (list of str, optional): DataArray dimension to drop in form of `[{dimension}={value}],`.
+        sel (list of str, optional): List of Xarray Indexes.
+        method (str): Xarray indexing method.
 
     Returns:
         xarray.DataArray: 2D or 3D DataArray.
 
     """
     da = ds[variable]
 
-    if drop_dim:
-        for dim in drop_dim:
-            dim_to_drop, dim_val = dim.split("=")
-            da = da.sel({dim_to_drop: dim_val}).drop_vars(dim_to_drop)
+    if sel:
+        sel_idx = []
+        for s in sel:
+            val: Union[str, slice]
+            dim, val = s.split("=")
+            dt = da[dim].dtype
+            if "," in val:
+                val = slice(*[numpy.array(v).astype(dt) for v in val.split(",")])
path: src/titiler/xarray/titiler/xarray/io.py
user: login: vincentsarago
body: I took a chance here, would a value have `,`? 🤷 

basically this is to support things like `time=date1,date2` -> da.sel(time=slice(date1, date2))`
created_at: 2025-04-22T20:53:51Z
author_association: MEMBER
diff_hunk: @@ -138,27 +138,37 @@ def _arrange_dims(da: xarray.DataArray) -> xarray.DataArray:
 def get_variable(
     ds: xarray.Dataset,
     variable: str,
-    datetime: Optional[str] = None,
-    drop_dim: Optional[List[str]] = None,
+    sel: Optional[List[str]] = None,
+    method: Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]] = None,
 ) -> xarray.DataArray:
     """Get Xarray variable as DataArray.
 
     Args:
         ds (xarray.Dataset): Xarray Dataset.
         variable (str): Variable to extract from the Dataset.
-        datetime (str, optional): datetime to select from the DataArray.
-        drop_dim (list of str, optional): DataArray dimension to drop in form of `[{dimension}={value}],`.
+        sel (list of str, optional): List of Xarray Indexes.
+        method (str): Xarray indexing method.
 
     Returns:
         xarray.DataArray: 2D or 3D DataArray.
 
     """
     da = ds[variable]
 
-    if drop_dim:
-        for dim in drop_dim:
-            dim_to_drop, dim_val = dim.split("=")
-            da = da.sel({dim_to_drop: dim_val}).drop_vars(dim_to_drop)
+    if sel:
+        sel_idx = []
+        for s in sel:
+            val: Union[str, slice]
+            dim, val = s.split("=")
+            dt = da[dim].dtype
+            if "," in val:
+                val = slice(*[numpy.array(v).astype(dt) for v in val.split(",")])
path: src/titiler/xarray/titiler/xarray/io.py
user: login: j08lue
body: You could branch on the dimension dtype being string and in that case not do the slice. 🤷 

Otherwise, I cannot think of a case where a value would contain comma. So perhaps just leave as-is until someone hits this issue.
created_at: 2025-04-23T07:14:26Z
author_association: MEMBER
diff_hunk: @@ -138,27 +138,37 @@ def _arrange_dims(da: xarray.DataArray) -> xarray.DataArray:
 def get_variable(
     ds: xarray.Dataset,
     variable: str,
-    datetime: Optional[str] = None,
-    drop_dim: Optional[List[str]] = None,
+    sel: Optional[List[str]] = None,
+    method: Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]] = None,
 ) -> xarray.DataArray:
     """Get Xarray variable as DataArray.
 
     Args:
         ds (xarray.Dataset): Xarray Dataset.
         variable (str): Variable to extract from the Dataset.
-        datetime (str, optional): datetime to select from the DataArray.
-        drop_dim (list of str, optional): DataArray dimension to drop in form of `[{dimension}={value}],`.
+        sel (list of str, optional): List of Xarray Indexes.
+        method (str): Xarray indexing method.
 
     Returns:
         xarray.DataArray: 2D or 3D DataArray.
 
     """
     da = ds[variable]
 
-    if drop_dim:
-        for dim in drop_dim:
-            dim_to_drop, dim_val = dim.split("=")
-            da = da.sel({dim_to_drop: dim_val}).drop_vars(dim_to_drop)
+    if sel:
+        sel_idx = []
+        for s in sel:
+            val: Union[str, slice]
+            dim, val = s.split("=")
+            dt = da[dim].dtype
+            if "," in val:
+                val = slice(*[numpy.array(v).astype(dt) for v in val.split(",")])
+            else:
+                val = numpy.array(val).astype(dt)
path: src/titiler/xarray/titiler/xarray/io.py
user: login: j08lue
body: Does this work well for datetime dtype?

For datetime dimension dtype, you could also not cast the indices (do the comma-split to slices, though) and leave the casting to Pandas, preserving the nice magic is has: https://github.com/developmentseed/titiler/issues/1112#issuecomment-2761260478
created_at: 2025-04-23T07:24:05Z
author_association: MEMBER
diff_hunk: @@ -106,7 +126,7 @@ def test_get_variable():
     )
 
     da = get_variable(
-        ds, "dataset", drop_dim=["universe=somewhere", "time=2022-01-01T00:00:00"]
+        ds, "dataset", sel=["universe=somewhere", "time=2022-01-01T00:00:00"]
path: src/titiler/xarray/tests/test_io_tools.py
user: login: j08lue
body: Suggestion: Add a test where you select `time` with some fuzzy time string like `1st of January 2022`.

This would fail due to the comma-slicing, though: `January 1st, 2022`
created_at: 2025-04-23T07:26:33Z
author_association: MEMBER
diff_hunk: @@ -138,27 +138,37 @@ def _arrange_dims(da: xarray.DataArray) -> xarray.DataArray:
 def get_variable(
     ds: xarray.Dataset,
     variable: str,
-    datetime: Optional[str] = None,
-    drop_dim: Optional[List[str]] = None,
+    sel: Optional[List[str]] = None,
+    method: Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]] = None,
 ) -> xarray.DataArray:
     """Get Xarray variable as DataArray.
 
     Args:
         ds (xarray.Dataset): Xarray Dataset.
         variable (str): Variable to extract from the Dataset.
-        datetime (str, optional): datetime to select from the DataArray.
-        drop_dim (list of str, optional): DataArray dimension to drop in form of `[{dimension}={value}],`.
+        sel (list of str, optional): List of Xarray Indexes.
+        method (str): Xarray indexing method.
 
     Returns:
         xarray.DataArray: 2D or 3D DataArray.
 
     """
     da = ds[variable]
 
-    if drop_dim:
-        for dim in drop_dim:
-            dim_to_drop, dim_val = dim.split("=")
-            da = da.sel({dim_to_drop: dim_val}).drop_vars(dim_to_drop)
+    if sel:
+        sel_idx = []
+        for s in sel:
+            val: Union[str, slice]
+            dim, val = s.split("=")
+            dt = da[dim].dtype
+            if "," in val:
+                val = slice(*[numpy.array(v).astype(dt) for v in val.split(",")])
path: src/titiler/xarray/titiler/xarray/io.py
user: login: j08lue
body: Although, there is the case where you do `time=January 1st, 2022`.

Maybe you could check whether there are exactly 2 commas in the string and only then use it as args to `slice`?
created_at: 2025-04-23T07:28:37Z
author_association: MEMBER
diff_hunk: @@ -138,27 +138,37 @@ def _arrange_dims(da: xarray.DataArray) -> xarray.DataArray:
 def get_variable(
     ds: xarray.Dataset,
     variable: str,
-    datetime: Optional[str] = None,
-    drop_dim: Optional[List[str]] = None,
+    sel: Optional[List[str]] = None,
+    method: Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]] = None,
 ) -> xarray.DataArray:
     """Get Xarray variable as DataArray.
 
     Args:
         ds (xarray.Dataset): Xarray Dataset.
         variable (str): Variable to extract from the Dataset.
-        datetime (str, optional): datetime to select from the DataArray.
-        drop_dim (list of str, optional): DataArray dimension to drop in form of `[{dimension}={value}],`.
+        sel (list of str, optional): List of Xarray Indexes.
+        method (str): Xarray indexing method.
 
     Returns:
         xarray.DataArray: 2D or 3D DataArray.
 
     """
     da = ds[variable]
 
-    if drop_dim:
-        for dim in drop_dim:
-            dim_to_drop, dim_val = dim.split("=")
-            da = da.sel({dim_to_drop: dim_val}).drop_vars(dim_to_drop)
+    if sel:
+        sel_idx = []
+        for s in sel:
+            val: Union[str, slice]
+            dim, val = s.split("=")
+            dt = da[dim].dtype
+            if "," in val:
+                val = slice(*[numpy.array(v).astype(dt) for v in val.split(",")])
path: src/titiler/xarray/titiler/xarray/io.py
user: login: vincentsarago
body: 😓 I guess we need to come up with something else. 
created_at: 2025-04-23T07:51:25Z
author_association: MEMBER
diff_hunk: @@ -138,27 +138,37 @@ def _arrange_dims(da: xarray.DataArray) -> xarray.DataArray:
 def get_variable(
     ds: xarray.Dataset,
     variable: str,
-    datetime: Optional[str] = None,
-    drop_dim: Optional[List[str]] = None,
+    sel: Optional[List[str]] = None,
+    method: Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]] = None,
 ) -> xarray.DataArray:
     """Get Xarray variable as DataArray.
 
     Args:
         ds (xarray.Dataset): Xarray Dataset.
         variable (str): Variable to extract from the Dataset.
-        datetime (str, optional): datetime to select from the DataArray.
-        drop_dim (list of str, optional): DataArray dimension to drop in form of `[{dimension}={value}],`.
+        sel (list of str, optional): List of Xarray Indexes.
+        method (str): Xarray indexing method.
 
     Returns:
         xarray.DataArray: 2D or 3D DataArray.
 
     """
     da = ds[variable]
 
-    if drop_dim:
-        for dim in drop_dim:
-            dim_to_drop, dim_val = dim.split("=")
-            da = da.sel({dim_to_drop: dim_val}).drop_vars(dim_to_drop)
+    if sel:
+        sel_idx = []
+        for s in sel:
+            val: Union[str, slice]
+            dim, val = s.split("=")
+            dt = da[dim].dtype
+            if "," in val:
+                val = slice(*[numpy.array(v).astype(dt) for v in val.split(",")])
path: src/titiler/xarray/titiler/xarray/io.py
user: login: j08lue
body: Nah, I think it's fair to expect that people do not use the most [obscure](https://xkcd.com/1179/) ways of specifying datetime.

So I'd stick to the splitting on comma - just raise good errors when it fails.
created_at: 2025-04-23T08:04:06Z
author_association: MEMBER
diff_hunk: @@ -138,27 +138,37 @@ def _arrange_dims(da: xarray.DataArray) -> xarray.DataArray:
 def get_variable(
     ds: xarray.Dataset,
     variable: str,
-    datetime: Optional[str] = None,
-    drop_dim: Optional[List[str]] = None,
+    sel: Optional[List[str]] = None,
+    method: Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]] = None,
 ) -> xarray.DataArray:
     """Get Xarray variable as DataArray.
 
     Args:
         ds (xarray.Dataset): Xarray Dataset.
         variable (str): Variable to extract from the Dataset.
-        datetime (str, optional): datetime to select from the DataArray.
-        drop_dim (list of str, optional): DataArray dimension to drop in form of `[{dimension}={value}],`.
+        sel (list of str, optional): List of Xarray Indexes.
+        method (str): Xarray indexing method.
 
     Returns:
         xarray.DataArray: 2D or 3D DataArray.
 
     """
     da = ds[variable]
 
-    if drop_dim:
-        for dim in drop_dim:
-            dim_to_drop, dim_val = dim.split("=")
-            da = da.sel({dim_to_drop: dim_val}).drop_vars(dim_to_drop)
+    if sel:
+        sel_idx = []
+        for s in sel:
+            val: Union[str, slice]
+            dim, val = s.split("=")
+            dt = da[dim].dtype
+            if "," in val:
+                val = slice(*[numpy.array(v).astype(dt) for v in val.split(",")])
path: src/titiler/xarray/titiler/xarray/io.py
user: login: vincentsarago
body: we could also use `slice` is user pass twice the same dim `time=date1,time=date2` -> `time=slice(date1, date2)` 🤷‍♂️ 
created_at: 2025-04-23T08:28:12Z
author_association: MEMBER
diff_hunk: @@ -138,27 +138,37 @@ def _arrange_dims(da: xarray.DataArray) -> xarray.DataArray:
 def get_variable(
     ds: xarray.Dataset,
     variable: str,
-    datetime: Optional[str] = None,
-    drop_dim: Optional[List[str]] = None,
+    sel: Optional[List[str]] = None,
+    method: Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]] = None,
 ) -> xarray.DataArray:
     """Get Xarray variable as DataArray.
 
     Args:
         ds (xarray.Dataset): Xarray Dataset.
         variable (str): Variable to extract from the Dataset.
-        datetime (str, optional): datetime to select from the DataArray.
-        drop_dim (list of str, optional): DataArray dimension to drop in form of `[{dimension}={value}],`.
+        sel (list of str, optional): List of Xarray Indexes.
+        method (str): Xarray indexing method.
 
     Returns:
         xarray.DataArray: 2D or 3D DataArray.
 
     """
     da = ds[variable]
 
-    if drop_dim:
-        for dim in drop_dim:
-            dim_to_drop, dim_val = dim.split("=")
-            da = da.sel({dim_to_drop: dim_val}).drop_vars(dim_to_drop)
+    if sel:
+        sel_idx = []
+        for s in sel:
+            val: Union[str, slice]
+            dim, val = s.split("=")
+            dt = da[dim].dtype
+            if "," in val:
+                val = slice(*[numpy.array(v).astype(dt) for v in val.split(",")])
+            else:
+                val = numpy.array(val).astype(dt)
path: src/titiler/xarray/titiler/xarray/io.py
user: login: vincentsarago
body: 🤦 we need to do like xpublish https://github.com/xpublish-community/xpublish-wms/blob/15aaa48ead7468f80d4794456b674a28bbc7dbe0/xpublish_wms/wms/get_map.py#L251-L269
created_at: 2025-04-23T08:34:36Z
author_association: MEMBER
diff_hunk: @@ -138,27 +138,37 @@ def _arrange_dims(da: xarray.DataArray) -> xarray.DataArray:
 def get_variable(
     ds: xarray.Dataset,
     variable: str,
-    datetime: Optional[str] = None,
-    drop_dim: Optional[List[str]] = None,
+    sel: Optional[List[str]] = None,
+    method: Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]] = None,
 ) -> xarray.DataArray:
     """Get Xarray variable as DataArray.
 
     Args:
         ds (xarray.Dataset): Xarray Dataset.
         variable (str): Variable to extract from the Dataset.
-        datetime (str, optional): datetime to select from the DataArray.
-        drop_dim (list of str, optional): DataArray dimension to drop in form of `[{dimension}={value}],`.
+        sel (list of str, optional): List of Xarray Indexes.
+        method (str): Xarray indexing method.
 
     Returns:
         xarray.DataArray: 2D or 3D DataArray.
 
     """
     da = ds[variable]
 
-    if drop_dim:
-        for dim in drop_dim:
-            dim_to_drop, dim_val = dim.split("=")
-            da = da.sel({dim_to_drop: dim_val}).drop_vars(dim_to_drop)
+    if sel:
+        sel_idx = []
+        for s in sel:
+            val: Union[str, slice]
+            dim, val = s.split("=")
+            dt = da[dim].dtype
+            if "," in val:
+                val = slice(*[numpy.array(v).astype(dt) for v in val.split(",")])
path: src/titiler/xarray/titiler/xarray/io.py
user: login: j08lue
body: Wait, why do we do slices at all? Apart from maybe the spatial dimensions, you always need to reduce the dimensions to 1, i.e. select a single index, no?

Passing the same dim twice would, to me, mean `sel(time=[date1, date2])` - but same thing here re reducing dimensionality.

Or are you planning to treat multiple 2D fields as "bands"?
created_at: 2025-04-23T09:07:39Z
author_association: MEMBER
diff_hunk: @@ -135,30 +136,53 @@ def _arrange_dims(da: xarray.DataArray) -> xarray.DataArray:
     return da
 
 
+def _cast_to_type(value, dtype: Any) -> Any:
+    if "timedelta" in str(dtype):
+        value = pandas.to_timedelta(value)
+
+    elif numpy.issubdtype(dtype, numpy.integer):
+        value = int(value)
+
+    elif numpy.issubdtype(dtype, numpy.floating):
+        value = float(value)
+
+    return value
+
+
 def get_variable(
     ds: xarray.Dataset,
     variable: str,
-    datetime: Optional[str] = None,
-    drop_dim: Optional[List[str]] = None,
+    sel: Optional[List[str]] = None,
+    method: Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]] = None,
 ) -> xarray.DataArray:
     """Get Xarray variable as DataArray.
 
     Args:
         ds (xarray.Dataset): Xarray Dataset.
         variable (str): Variable to extract from the Dataset.
-        datetime (str, optional): datetime to select from the DataArray.
-        drop_dim (list of str, optional): DataArray dimension to drop in form of `[{dimension}={value}],`.
+        sel (list of str, optional): List of Xarray Indexes.
+        method (str): Xarray indexing method.
 
     Returns:
         xarray.DataArray: 2D or 3D DataArray.
 
     """
     da = ds[variable]
 
-    if drop_dim:
-        for dim in drop_dim:
-            dim_to_drop, dim_val = dim.split("=")
-            da = da.sel({dim_to_drop: dim_val}).drop_vars(dim_to_drop)
+    if sel:
+        _idx: Dict[str, List] = {}
+        for s in sel:
+            val: Union[str, slice]
+            dim, val = s.split("=")
+            val = _cast_to_type(val, da[dim].dtype)
+
+            if dim in _idx:
+                _idx[dim].append(val)
+            else:
+                _idx[dim] = [val]
+
+        sel_idx = {k: v[0] if len(v) < 2 else slice(*v) for k, v in _idx.items()}
path: src/titiler/xarray/titiler/xarray/io.py
user: login: vincentsarago
body: if a `dim` is provided multiple times we transform values to `slice` 
created_at: 2025-04-23T12:11:26Z
author_association: MEMBER
diff_hunk: @@ -135,30 +136,53 @@ def _arrange_dims(da: xarray.DataArray) -> xarray.DataArray:
     return da
 
 
+def _cast_to_type(value, dtype: Any) -> Any:
+    if "timedelta" in str(dtype):
+        value = pandas.to_timedelta(value)
+
+    elif numpy.issubdtype(dtype, numpy.integer):
+        value = int(value)
+
+    elif numpy.issubdtype(dtype, numpy.floating):
+        value = float(value)
+
+    return value
+
+
 def get_variable(
     ds: xarray.Dataset,
     variable: str,
-    datetime: Optional[str] = None,
-    drop_dim: Optional[List[str]] = None,
+    sel: Optional[List[str]] = None,
+    method: Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]] = None,
 ) -> xarray.DataArray:
     """Get Xarray variable as DataArray.
 
     Args:
         ds (xarray.Dataset): Xarray Dataset.
         variable (str): Variable to extract from the Dataset.
-        datetime (str, optional): datetime to select from the DataArray.
-        drop_dim (list of str, optional): DataArray dimension to drop in form of `[{dimension}={value}],`.
+        sel (list of str, optional): List of Xarray Indexes.
+        method (str): Xarray indexing method.
 
     Returns:
         xarray.DataArray: 2D or 3D DataArray.
 
     """
     da = ds[variable]
 
-    if drop_dim:
-        for dim in drop_dim:
-            dim_to_drop, dim_val = dim.split("=")
-            da = da.sel({dim_to_drop: dim_val}).drop_vars(dim_to_drop)
+    if sel:
+        _idx: Dict[str, List] = {}
+        for s in sel:
+            val: Union[str, slice]
+            dim, val = s.split("=")
+            val = _cast_to_type(val, da[dim].dtype)
+
+            if dim in _idx:
+                _idx[dim].append(val)
+            else:
+                _idx[dim] = [val]
+
+        sel_idx = {k: v[0] if len(v) < 2 else slice(*v) for k, v in _idx.items()}
path: src/titiler/xarray/titiler/xarray/io.py
user: login: j08lue
body: Sounds like a good API design choice, but should we actually be supporting slicing? https://github.com/developmentseed/titiler/pull/1134#discussion_r2055602147
created_at: 2025-04-23T20:00:22Z
author_association: MEMBER
diff_hunk: @@ -165,21 +165,21 @@ def test_tiles(filename, app):
 
     resp = app.get(
         "/md/tiles/WebMercatorQuad/0/0/0",
-        params={"url": filename, "variable": "dataset", "rescale": "0,500"},
+        params={"url": filename, "variable": "dataset", "rescale": "0,500", "bidx": 1},
path: src/titiler/xarray/tests/test_factory.py
user: login: hrodmn
body: why do you need to add `bidx=1` now? Is it because the reader will return a 3D array now with the new `sel` interface (instead of 2D with `drop_dim`)?
created_at: 2025-04-23T20:17:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -71,17 +74,22 @@ class CompatXarrayParams(XarrayIOParams):
     it would fail without the variable query-parameter set.
     """
 
-    variable: Annotated[Optional[str], Query(description="Xarray Variable name")] = None
+    variable: Annotated[Optional[str], Query(description="Xarray Variable name.")] = (
+        None
+    )
 
-    drop_dim: Annotated[
-        Optional[List[DropDimStr]],
+    sel: Annotated[
path: src/titiler/xarray/titiler/xarray/dependencies.py
user: login: hrodmn
body: this is so cool!
created_at: 2025-04-23T20:17:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -165,21 +165,21 @@ def test_tiles(filename, app):
 
     resp = app.get(
         "/md/tiles/WebMercatorQuad/0/0/0",
-        params={"url": filename, "variable": "dataset", "rescale": "0,500"},
+        params={"url": filename, "variable": "dataset", "rescale": "0,500", "bidx": 1},
path: src/titiler/xarray/tests/test_factory.py
user: login: j08lue
body: Same question as I asked, basically: https://github.com/developmentseed/titiler/pull/1134#discussion_r2055602147
created_at: 2025-04-23T20:40:55Z
author_association: MEMBER
diff_hunk: @@ -138,27 +138,37 @@ def _arrange_dims(da: xarray.DataArray) -> xarray.DataArray:
 def get_variable(
     ds: xarray.Dataset,
     variable: str,
-    datetime: Optional[str] = None,
-    drop_dim: Optional[List[str]] = None,
+    sel: Optional[List[str]] = None,
+    method: Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]] = None,
 ) -> xarray.DataArray:
     """Get Xarray variable as DataArray.
 
     Args:
         ds (xarray.Dataset): Xarray Dataset.
         variable (str): Variable to extract from the Dataset.
-        datetime (str, optional): datetime to select from the DataArray.
-        drop_dim (list of str, optional): DataArray dimension to drop in form of `[{dimension}={value}],`.
+        sel (list of str, optional): List of Xarray Indexes.
+        method (str): Xarray indexing method.
 
     Returns:
         xarray.DataArray: 2D or 3D DataArray.
 
     """
     da = ds[variable]
 
-    if drop_dim:
-        for dim in drop_dim:
-            dim_to_drop, dim_val = dim.split("=")
-            da = da.sel({dim_to_drop: dim_val}).drop_vars(dim_to_drop)
+    if sel:
+        sel_idx = []
+        for s in sel:
+            val: Union[str, slice]
+            dim, val = s.split("=")
+            dt = da[dim].dtype
+            if "," in val:
+                val = slice(*[numpy.array(v).astype(dt) for v in val.split(",")])
path: src/titiler/xarray/titiler/xarray/io.py
user: login: vincentsarago
body: > Or are you planning to treat multiple 2D fields as "bands"?

Yes we do support 3D data now, meaning you could have multiple Z (time or dim) represented as bands 
created_at: 2025-04-24T08:38:55Z
author_association: MEMBER
diff_hunk: @@ -165,21 +165,21 @@ def test_tiles(filename, app):
 
     resp = app.get(
         "/md/tiles/WebMercatorQuad/0/0/0",
-        params={"url": filename, "variable": "dataset", "rescale": "0,500"},
+        params={"url": filename, "variable": "dataset", "rescale": "0,500", "bidx": 1},
path: src/titiler/xarray/tests/test_factory.py
user: login: vincentsarago
body: > why do you need to add bidx=1 now? Is it because the reader will return a 3D array now with the new sel interface (instead of 2D with drop_dim)?

Exactly, also before we were always selecting the first time value. Now we can have 3D arrays 
created_at: 2025-04-24T08:40:36Z
author_association: MEMBER
diff_hunk: @@ -135,30 +136,53 @@ def _arrange_dims(da: xarray.DataArray) -> xarray.DataArray:
     return da
 
 
+def _cast_to_type(value, dtype: Any) -> Any:
+    if "timedelta" in str(dtype):
+        value = pandas.to_timedelta(value)
+
+    elif numpy.issubdtype(dtype, numpy.integer):
+        value = int(value)
+
+    elif numpy.issubdtype(dtype, numpy.floating):
+        value = float(value)
+
+    return value
+
+
 def get_variable(
     ds: xarray.Dataset,
     variable: str,
-    datetime: Optional[str] = None,
-    drop_dim: Optional[List[str]] = None,
+    sel: Optional[List[str]] = None,
+    method: Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]] = None,
 ) -> xarray.DataArray:
     """Get Xarray variable as DataArray.
 
     Args:
         ds (xarray.Dataset): Xarray Dataset.
         variable (str): Variable to extract from the Dataset.
-        datetime (str, optional): datetime to select from the DataArray.
-        drop_dim (list of str, optional): DataArray dimension to drop in form of `[{dimension}={value}],`.
+        sel (list of str, optional): List of Xarray Indexes.
+        method (str): Xarray indexing method.
 
     Returns:
         xarray.DataArray: 2D or 3D DataArray.
 
     """
     da = ds[variable]
 
-    if drop_dim:
-        for dim in drop_dim:
-            dim_to_drop, dim_val = dim.split("=")
-            da = da.sel({dim_to_drop: dim_val}).drop_vars(dim_to_drop)
+    if sel:
+        _idx: Dict[str, List] = {}
+        for s in sel:
+            val: Union[str, slice]
+            dim, val = s.split("=")
+            val = _cast_to_type(val, da[dim].dtype)
+
+            if dim in _idx:
+                _idx[dim].append(val)
+            else:
+                _idx[dim] = [val]
+
+        sel_idx = {k: v[0] if len(v) < 2 else slice(*v) for k, v in _idx.items()}
path: src/titiler/xarray/titiler/xarray/io.py
user: login: j08lue
body: Hmm, coming back to this, I think I would as an API user really expect multiple `sel` URL parameters to select those exact levels, instead of constructing a slice.

I think you should drop the `slice` support altogether. Here is why:

1. Unpredictable "bands" - If you want to get multiple bands (e.g. for band math), you want to know exactly what indexes they correspond to. Slicing can give a lot of surprises - fewer or more indexes included in the slice than you expected, maybe there was a level missing that you thought was there, etc.
2. Slicing without reducing is not really useful - I cannot think of a use case from my NetCDF / data cube work where I would do slices but then not reduce the data over that dimension (e.g. averaging a time slice).
3. TiTiler ultimately needs 2D - the user always needs to reduce the data to a 2D field, if not through singular indexing, than through "band" math (aka expressions), I guess. There are few workflows where slicing would be part of a predictable process of getting to a 2D field.

Do you have strong reasons for supporting slicing, @vincentsarago?
created_at: 2025-04-24T10:32:04Z
author_association: MEMBER
diff_hunk: @@ -135,30 +136,53 @@ def _arrange_dims(da: xarray.DataArray) -> xarray.DataArray:
     return da
 
 
+def _cast_to_type(value, dtype: Any) -> Any:
+    if "timedelta" in str(dtype):
+        value = pandas.to_timedelta(value)
+
+    elif numpy.issubdtype(dtype, numpy.integer):
+        value = int(value)
+
+    elif numpy.issubdtype(dtype, numpy.floating):
+        value = float(value)
+
+    return value
+
+
 def get_variable(
     ds: xarray.Dataset,
     variable: str,
-    datetime: Optional[str] = None,
-    drop_dim: Optional[List[str]] = None,
+    sel: Optional[List[str]] = None,
+    method: Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]] = None,
 ) -> xarray.DataArray:
     """Get Xarray variable as DataArray.
 
     Args:
         ds (xarray.Dataset): Xarray Dataset.
         variable (str): Variable to extract from the Dataset.
-        datetime (str, optional): datetime to select from the DataArray.
-        drop_dim (list of str, optional): DataArray dimension to drop in form of `[{dimension}={value}],`.
+        sel (list of str, optional): List of Xarray Indexes.
+        method (str): Xarray indexing method.
 
     Returns:
         xarray.DataArray: 2D or 3D DataArray.
 
     """
     da = ds[variable]
 
-    if drop_dim:
-        for dim in drop_dim:
-            dim_to_drop, dim_val = dim.split("=")
-            da = da.sel({dim_to_drop: dim_val}).drop_vars(dim_to_drop)
+    if sel:
+        _idx: Dict[str, List] = {}
+        for s in sel:
+            val: Union[str, slice]
+            dim, val = s.split("=")
+            val = _cast_to_type(val, da[dim].dtype)
+
+            if dim in _idx:
+                _idx[dim].append(val)
+            else:
+                _idx[dim] = [val]
+
+        sel_idx = {k: v[0] if len(v) < 2 else slice(*v) for k, v in _idx.items()}
path: src/titiler/xarray/titiler/xarray/io.py
user: login: vincentsarago
body: > Unpredictable "bands" - If you want to get multiple bands (e.g. for band math), you want to know exactly what indexes they correspond to. Slicing can give a lot of surprises - fewer or more indexes included in the slice than you expected, maybe there was a level missing that you thought was there, etc

FYI we do not support band math, only band selection. 

> you want to know exactly what indexes they correspond to

If you hit the `/info` endpoint first you would know the band indexes 

> Slicing without reducing is not really useful - I cannot think of a use case from my NetCDF / data cube work where I would do slices but then not reduce the data over that dimension (e.g. averaging a time slice).

My idea was that sometime you don't know exactly which value you want and `slicing` might be better than `nearest` selection. We could also think about user doing `slice` selection and then reducing using algorithm (mean/sum....) 

> TiTiler ultimately needs 2D - the user always needs to reduce the data to a 2D field, if not through singular indexing, than through "band" math (aka expressions), I guess. There are few workflows where slicing would be part of a predictable process of getting to a 2D field.

Not really you want 3D data where you can do band combination or apply algorithm 

created_at: 2025-04-24T10:47:51Z
author_association: MEMBER
diff_hunk: @@ -135,30 +136,53 @@ def _arrange_dims(da: xarray.DataArray) -> xarray.DataArray:
     return da
 
 
+def _cast_to_type(value, dtype: Any) -> Any:
+    if "timedelta" in str(dtype):
+        value = pandas.to_timedelta(value)
+
+    elif numpy.issubdtype(dtype, numpy.integer):
+        value = int(value)
+
+    elif numpy.issubdtype(dtype, numpy.floating):
+        value = float(value)
+
+    return value
+
+
 def get_variable(
     ds: xarray.Dataset,
     variable: str,
-    datetime: Optional[str] = None,
-    drop_dim: Optional[List[str]] = None,
+    sel: Optional[List[str]] = None,
+    method: Optional[Literal["nearest", "pad", "ffill", "backfill", "bfill"]] = None,
 ) -> xarray.DataArray:
     """Get Xarray variable as DataArray.
 
     Args:
         ds (xarray.Dataset): Xarray Dataset.
         variable (str): Variable to extract from the Dataset.
-        datetime (str, optional): datetime to select from the DataArray.
-        drop_dim (list of str, optional): DataArray dimension to drop in form of `[{dimension}={value}],`.
+        sel (list of str, optional): List of Xarray Indexes.
+        method (str): Xarray indexing method.
 
     Returns:
         xarray.DataArray: 2D or 3D DataArray.
 
     """
     da = ds[variable]
 
-    if drop_dim:
-        for dim in drop_dim:
-            dim_to_drop, dim_val = dim.split("=")
-            da = da.sel({dim_to_drop: dim_val}).drop_vars(dim_to_drop)
+    if sel:
+        _idx: Dict[str, List] = {}
+        for s in sel:
+            val: Union[str, slice]
+            dim, val = s.split("=")
+            val = _cast_to_type(val, da[dim].dtype)
+
+            if dim in _idx:
+                _idx[dim].append(val)
+            else:
+                _idx[dim] = [val]
+
+        sel_idx = {k: v[0] if len(v) < 2 else slice(*v) for k, v in _idx.items()}
path: src/titiler/xarray/titiler/xarray/io.py
user: login: vincentsarago
body: Summary of our discussion on meet. 

- We should drop `slice` 
- user might want to select multiple values e.g `date1` and `date3` without selecting `date2` (`time=date1&time=date3`)

created_at: 2025-04-24T11:08:11Z
author_association: MEMBER
diff_hunk: @@ -135,22 +135,39 @@ def test_info_da_options(app):
     """Test /info endpoints with Dataarray options."""
     resp = app.get(
         "/md/info",
-        params={"url": dataset_4d_nc, "variable": "dataset", "drop_dims": "z=0"},
+        params={"url": dataset_4d_nc, "variable": "dataset", "sel": "time=2023-01-01"},
     )
     assert resp.status_code == 200
     assert resp.headers["content-type"] == "application/json"
+    body = resp.json()
+    print(body)
path: src/titiler/xarray/tests/test_factory.py
user: login: abarciauskas-bgse
body: nit: probably don't intend to keep the print statement here?
created_at: 2025-04-24T14:41:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -135,22 +135,39 @@ def test_info_da_options(app):
     """Test /info endpoints with Dataarray options."""
     resp = app.get(
         "/md/info",
-        params={"url": dataset_4d_nc, "variable": "dataset", "drop_dims": "z=0"},
+        params={"url": dataset_4d_nc, "variable": "dataset", "sel": "time=2023-01-01"},
     )
     assert resp.status_code == 200
     assert resp.headers["content-type"] == "application/json"
+    body = resp.json()
+    print(body)
path: src/titiler/xarray/tests/test_factory.py
user: login: vincentsarago
body: 😓 🙏 
created_at: 2025-04-24T14:42:19Z
author_association: MEMBER

PR comments:
user: login: maxrjones
created_at: 2025-04-24T12:30:40Z
body: Amazing improvement! What if someone wants to use different methods along different dimensions? E.g., I could imagine wanting nearest in space but exact in time. IMO it would make more sense to include method in the param for sel and split on ‘method=‘
author_association: MEMBER
user: login: vincentsarago
created_at: 2025-04-24T12:35:06Z
body: @maxrjones 

> Amazing improvement! What if someone wants to use different methods along different dimensions? E.g., I could imagine wanting nearest in space but exact in time. IMO it would make more sense to include method in the param for sel and split on ‘method=‘

Interesting, for now we are not chaining the `sel` operations but using `dict` to pass everything to one operation so the method would be the same for all the `dim` 

I'm a bit worry about over complexity of `method per dim` 🤔 



author_association: MEMBER
user: login: maxrjones
created_at: 2025-04-24T15:39:41Z
body: > @maxrjones
> 
> > Amazing improvement! What if someone wants to use different methods along different dimensions? E.g., I could imagine wanting nearest in space but exact in time. IMO it would make more sense to include method in the param for sel and split on ‘method=‘
> 
> Interesting, for now we are not chaining the `sel` operations but using `dict` to pass everything to one operation so the method would be the same for all the `dim`
> 
> I'm a bit worry about over complexity of `method per dim` 🤔

that makes sense. I didn't test this your PR out thoroughly but generally really like the approach of using `sel`.
author_association: MEMBER
user: login: vincentsarago
created_at: 2025-04-24T16:43:38Z
body: @maxrjones I had more though about `chaining` sel and I don't think it will be possible . 

I think I'm going to merge this PR as is right now but we could re-visit the logic in `titiler-multidim`.  `titiler.xarray` will provide a simple default behaviour and sub-libraries can explore more complex ways to access the data which we then can bring back here after user feedback. 
author_association: MEMBER