Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] add titiler.xarray module #1007

Closed
wants to merge 10 commits into from
Closed

Conversation

vincentsarago
Copy link
Member

@vincentsarago vincentsarago commented Oct 24, 2024

ref: developmentseed/titiler-xarray#68

depends on cogeotiff/rio-tiler#755

To Do

  • review .io.Reader
  • add Notebook for the new Reader
  • write factory
  • add tests
  • add docs
  • update CI to release titiler.xarray
  • add example of how to use the xarray.io.Reader in STAC based tiler

variable: str = attr.ib()

# xarray.Dataset options
opener: Callable[..., xarray.Dataset] = attr.ib(default=xarray_open_dataset)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By making the opener an option it eases the user to bring their own xarray_open_dataset callable which may add more protocol (e.g Azure, GCS ...)

reference: bool = attr.ib(default=False)
decode_times: bool = attr.ib(default=False)
consolidated: Optional[bool] = attr.ib(default=True)
cache_client: Optional[CacheClient] = attr.ib(default=None)
Copy link
Member Author

@vincentsarago vincentsarago Oct 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cache client is optional, basically users just need to provide an Object with get and set methods

da = da.rename({latitude_var_name: "y", longitude_var_name: "x"})

if "TIME" in da.dims:
da = da.rename({"TIME": "time"})
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was added for

from titiler.xarray.io import Reader

with Reader("s3://aodn-cloud-optimised/model_sea_level_anomaly_gridded_realtime.zarr/", "GSL") as src:
   print(src.info())

bounds=(-180.28109374046326, -60.1, 180.081081533432, 10.1) crs='http://www.opengis.net/def/crs/EPSG/0/4326' band_metadata=[] band_descriptions=[] dtype='float64' nodata_type='Nodata' colorinterp=None scales=None offsets=None colormap=None name='GSL' count=1 width=641 height=351 attrs={'description': 'GSLA + CAST2008 mean dynamic height ', 'long_name': 'gridded sea level', 'standard_name': 'sea_surface_height_above_geoid', 'units': 'm'}

vmin, vmax = da.attrs.get("valid_min"), da.attrs.get("valid_max")
if "valid_range" in da.attrs and not (vmin is not None and vmax is not None):
valid_range = da.attrs.get("valid_range")
da.attrs.update({"valid_min": valid_range[0], "valid_max": valid_range[1]})
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if valid_range is something we find usually

if "TIME" in da.dims:
da = da.rename({"TIME": "time"})

if _dims := [d for d in da.dims if d not in ["x", "y"]]:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to support dataset with more than 3 dimension (e.g more than time, x, y)

# 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
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

☝️ we might enable all the times values, and not select the first value by default

@vincentsarago
Copy link
Member Author

Screenshot 2024-10-29 at 6 47 50 PM

"query_string": urlencode(qs, doseq=True) if qs else None,
"bounds": bounds,
},
]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add layers to WMTS response

this will be use for STAC renders but maybe also for multiple variable support in XARRAY

right = Math.min(right, {{ tms.bbox.right }})
}
bottom = Math.max(bottom, {{ tms.bbox.bottom }})
top = Math.min(top, {{ tms.bbox.top }})
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I needed to do this because some NetCDF data have bounds that exceed the TMS bbox



@dataclass(init=False)
class CompatXarrayParams(DefaultDependency):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not directly used in titiler.xarray but could be in a Tiler that would want to support both GDAL/Xarray dataset



@define(kw_only=True)
class TilerFactory(BaseTilerFactory):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By sub-classing titiler.core.factory.TilerFactory we avoid re-writing code


# remove some attribute from init
img_preview_dependency: Type[DefaultDependency] = field(init=False)
add_preview: bool = field(init=False)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't want to have preview for now (I don't think any user would want this except if they control the dataset available)


return Response(content, media_type=media_type)

# custom /statistics endpoints (remove /statistics - GET)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

☝️ IMO having a full dataset /statistics in a bit dangerous (as for the /preview endpoints)

geojson: Annotated[
Union[FeatureCollection, Feature],
Body(description="GeoJSON Feature or FeatureCollection."),
],
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOTE: we should maybe extract this and make a dependency that user could customize to control the size of the GeoJSON

md.router,
prefix="/md",
tags=["Multi Dimensional"],
)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we might remove this in the final module

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants