aihydro-data 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aihydro_data-0.2.0/LICENSE +19 -0
- aihydro_data-0.2.0/PKG-INFO +566 -0
- aihydro_data-0.2.0/README.md +481 -0
- aihydro_data-0.2.0/aihydro_data/__init__.py +150 -0
- aihydro_data-0.2.0/aihydro_data/_pipeline.py +843 -0
- aihydro_data-0.2.0/aihydro_data/_version.py +2 -0
- aihydro_data-0.2.0/aihydro_data/cache/__init__.py +321 -0
- aihydro_data-0.2.0/aihydro_data/cache/manifest.py +162 -0
- aihydro_data-0.2.0/aihydro_data/cli.py +74 -0
- aihydro_data-0.2.0/aihydro_data/contracts.py +250 -0
- aihydro_data-0.2.0/aihydro_data/exceptions.py +89 -0
- aihydro_data-0.2.0/aihydro_data/geometry/__init__.py +161 -0
- aihydro_data-0.2.0/aihydro_data/geometry/batch.py +92 -0
- aihydro_data-0.2.0/aihydro_data/geometry/measures.py +58 -0
- aihydro_data-0.2.0/aihydro_data/help_topics/__init__.py +20 -0
- aihydro_data-0.2.0/aihydro_data/help_topics/auth.md +72 -0
- aihydro_data-0.2.0/aihydro_data/help_topics/batch.md +64 -0
- aihydro_data-0.2.0/aihydro_data/help_topics/caching.md +57 -0
- aihydro_data-0.2.0/aihydro_data/help_topics/deprecations.md +45 -0
- aihydro_data-0.2.0/aihydro_data/help_topics/errors.md +51 -0
- aihydro_data-0.2.0/aihydro_data/help_topics/fallback.md +57 -0
- aihydro_data-0.2.0/aihydro_data/help_topics/first_fetch.md +50 -0
- aihydro_data-0.2.0/aihydro_data/help_topics/products.md +94 -0
- aihydro_data-0.2.0/aihydro_data/mcp/__init__.py +815 -0
- aihydro_data-0.2.0/aihydro_data/products/__init__.py +92 -0
- aihydro_data-0.2.0/aihydro_data/products/dem.py +248 -0
- aihydro_data-0.2.0/aihydro_data/products/et.py +305 -0
- aihydro_data-0.2.0/aihydro_data/products/landcover.py +222 -0
- aihydro_data-0.2.0/aihydro_data/products/optical.py +313 -0
- aihydro_data-0.2.0/aihydro_data/products/precipitation.py +331 -0
- aihydro_data-0.2.0/aihydro_data/products/soil.py +124 -0
- aihydro_data-0.2.0/aihydro_data/products/soil_moisture.py +73 -0
- aihydro_data-0.2.0/aihydro_data/products/streamflow.py +256 -0
- aihydro_data-0.2.0/aihydro_data/products/temperature.py +332 -0
- aihydro_data-0.2.0/aihydro_data/products/vegetation.py +155 -0
- aihydro_data-0.2.0/aihydro_data/routing/__init__.py +75 -0
- aihydro_data-0.2.0/aihydro_data/routing/detect.py +57 -0
- aihydro_data-0.2.0/aihydro_data/routing/policy.py +149 -0
- aihydro_data-0.2.0/aihydro_data/routing/regions.py +90 -0
- aihydro_data-0.2.0/aihydro_data/sampling/__init__.py +29 -0
- aihydro_data-0.2.0/aihydro_data/sampling/catchment.py +321 -0
- aihydro_data-0.2.0/aihydro_data/sampling/chunked.py +200 -0
- aihydro_data-0.2.0/aihydro_data/skills/__init__.py +15 -0
- aihydro_data-0.2.0/aihydro_data/sources/__init__.py +11 -0
- aihydro_data-0.2.0/aihydro_data/sources/_common.py +55 -0
- aihydro_data-0.2.0/aihydro_data/sources/_gee_vendored/__init__.py +23 -0
- aihydro_data-0.2.0/aihydro_data/sources/_gee_vendored/auth.py +365 -0
- aihydro_data-0.2.0/aihydro_data/sources/_gee_vendored/cli.py +115 -0
- aihydro_data-0.2.0/aihydro_data/sources/_gee_vendored/contracts.py +259 -0
- aihydro_data-0.2.0/aihydro_data/sources/_gee_vendored/map_layers.py +158 -0
- aihydro_data-0.2.0/aihydro_data/sources/_gee_vendored/presets.py +138 -0
- aihydro_data-0.2.0/aihydro_data/sources/_gee_vendored/timeseries.py +143 -0
- aihydro_data-0.2.0/aihydro_data/sources/_retry.py +145 -0
- aihydro_data-0.2.0/aihydro_data/sources/base.py +102 -0
- aihydro_data-0.2.0/aihydro_data/sources/cds_glofas.py +448 -0
- aihydro_data-0.2.0/aihydro_data/sources/direct_api.py +546 -0
- aihydro_data-0.2.0/aihydro_data/sources/gee/__init__.py +398 -0
- aihydro_data-0.2.0/aihydro_data/sources/gee/_composite.py +327 -0
- aihydro_data-0.2.0/aihydro_data/sources/gee/_download.py +315 -0
- aihydro_data-0.2.0/aihydro_data/sources/geoglows_retro.py +312 -0
- aihydro_data-0.2.0/aihydro_data/sources/hyriver.py +402 -0
- aihydro_data-0.2.0/aihydro_data/sources/openmeteo_flood.py +201 -0
- aihydro_data-0.2.0/aihydro_data/sources/stac.py +383 -0
- aihydro_data-0.2.0/aihydro_data/transforms/__init__.py +53 -0
- aihydro_data-0.2.0/aihydro_data/transforms/cloud_mask.py +191 -0
- aihydro_data-0.2.0/aihydro_data/transforms/indices.py +524 -0
- aihydro_data-0.2.0/aihydro_data/viz/__init__.py +108 -0
- aihydro_data-0.2.0/aihydro_data/viz/_common.py +91 -0
- aihydro_data-0.2.0/aihydro_data/viz/_compare.py +200 -0
- aihydro_data-0.2.0/aihydro_data/viz/auto.py +198 -0
- aihydro_data-0.2.0/aihydro_data/viz/hydrology.py +327 -0
- aihydro_data-0.2.0/aihydro_data/viz/spatial.py +159 -0
- aihydro_data-0.2.0/aihydro_data.egg-info/PKG-INFO +566 -0
- aihydro_data-0.2.0/aihydro_data.egg-info/SOURCES.txt +98 -0
- aihydro_data-0.2.0/aihydro_data.egg-info/dependency_links.txt +1 -0
- aihydro_data-0.2.0/aihydro_data.egg-info/entry_points.txt +8 -0
- aihydro_data-0.2.0/aihydro_data.egg-info/requires.txt +72 -0
- aihydro_data-0.2.0/aihydro_data.egg-info/top_level.txt +1 -0
- aihydro_data-0.2.0/pyproject.toml +226 -0
- aihydro_data-0.2.0/setup.cfg +4 -0
- aihydro_data-0.2.0/tests/test_auto_batch.py +129 -0
- aihydro_data-0.2.0/tests/test_cache_and_batch.py +365 -0
- aihydro_data-0.2.0/tests/test_indices.py +408 -0
- aihydro_data-0.2.0/tests/test_layering.py +73 -0
- aihydro_data-0.2.0/tests/test_live_backends.py +284 -0
- aihydro_data-0.2.0/tests/test_live_sweep.py +228 -0
- aihydro_data-0.2.0/tests/test_mcp_tools.py +385 -0
- aihydro_data-0.2.0/tests/test_open_meteo.py +281 -0
- aihydro_data-0.2.0/tests/test_optical_products.py +242 -0
- aihydro_data-0.2.0/tests/test_phase1_fixes.py +323 -0
- aihydro_data-0.2.0/tests/test_phase2_integrity.py +193 -0
- aihydro_data-0.2.0/tests/test_phase3_products.py +253 -0
- aihydro_data-0.2.0/tests/test_phase3_routing_cache.py +168 -0
- aihydro_data-0.2.0/tests/test_phase4_products.py +225 -0
- aihydro_data-0.2.0/tests/test_phase_d_robustness.py +142 -0
- aihydro_data-0.2.0/tests/test_routing.py +246 -0
- aihydro_data-0.2.0/tests/test_sampling.py +357 -0
- aihydro_data-0.2.0/tests/test_scaffold.py +191 -0
- aihydro_data-0.2.0/tests/test_stac.py +125 -0
- aihydro_data-0.2.0/tests/test_viz.py +266 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
Copyright 2026 Mohammad Galib (mgalib@purdue.edu) and AI-Hydro contributors.
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
See the License for the specific language governing permissions and
|
|
17
|
+
limitations under the License.
|
|
18
|
+
|
|
19
|
+
For the full Apache-2.0 text, see https://www.apache.org/licenses/LICENSE-2.0.txt
|
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aihydro-data
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Global hydrology dataverse — multi-source, region-aware data fetch (GEE + STAC + HyRiver) for AI agents and humans
|
|
5
|
+
Author-email: Mohammad Galib <mgalib@purdue.edu>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/AI-Hydro/aihydro-data
|
|
8
|
+
Project-URL: Documentation, https://github.com/AI-Hydro/AI-Hydro/wiki
|
|
9
|
+
Project-URL: Repository, https://github.com/AI-Hydro/aihydro-data
|
|
10
|
+
Project-URL: Issues, https://github.com/AI-Hydro/aihydro-data/issues
|
|
11
|
+
Keywords: hydrology,geospatial,earth-engine,STAC,global,data-fetch,MCP,agentic,CAMELS
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Hydrology
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: aihydro-core<0.2,>=0.1.0
|
|
25
|
+
Requires-Dist: numpy>=1.24.0
|
|
26
|
+
Requires-Dist: pandas>=2.0.0
|
|
27
|
+
Requires-Dist: pydantic>=2.0.0
|
|
28
|
+
Requires-Dist: requests>=2.31.0
|
|
29
|
+
Requires-Dist: python-dateutil>=2.8.2
|
|
30
|
+
Requires-Dist: shapely>=2.0.0
|
|
31
|
+
Requires-Dist: geopandas>=0.13.0
|
|
32
|
+
Requires-Dist: pyproj>=3.6.0
|
|
33
|
+
Provides-Extra: gee
|
|
34
|
+
Requires-Dist: earthengine-api>=0.1.390; extra == "gee"
|
|
35
|
+
Provides-Extra: stac
|
|
36
|
+
Requires-Dist: pystac-client>=0.7.0; extra == "stac"
|
|
37
|
+
Requires-Dist: stackstac>=0.5.0; extra == "stac"
|
|
38
|
+
Requires-Dist: planetary-computer>=1.0.0; extra == "stac"
|
|
39
|
+
Requires-Dist: rioxarray>=0.15.0; extra == "stac"
|
|
40
|
+
Requires-Dist: rasterio>=1.3.0; extra == "stac"
|
|
41
|
+
Requires-Dist: xarray>=2023.0.0; extra == "stac"
|
|
42
|
+
Provides-Extra: hyriver
|
|
43
|
+
Requires-Dist: pynhd>=0.16.0; extra == "hyriver"
|
|
44
|
+
Requires-Dist: pygeohydro>=0.16.0; extra == "hyriver"
|
|
45
|
+
Requires-Dist: pygridmet>=0.15.0; extra == "hyriver"
|
|
46
|
+
Requires-Dist: py3dep>=0.15.0; extra == "hyriver"
|
|
47
|
+
Requires-Dist: hydrofunctions>=0.2.0; extra == "hyriver"
|
|
48
|
+
Requires-Dist: rioxarray>=0.15.0; extra == "hyriver"
|
|
49
|
+
Requires-Dist: xarray>=2023.0.0; extra == "hyriver"
|
|
50
|
+
Provides-Extra: direct
|
|
51
|
+
Requires-Dist: hydrofunctions>=0.2.0; extra == "direct"
|
|
52
|
+
Provides-Extra: opendap
|
|
53
|
+
Requires-Dist: xarray>=2023.0.0; extra == "opendap"
|
|
54
|
+
Requires-Dist: netCDF4>=1.6.0; extra == "opendap"
|
|
55
|
+
Provides-Extra: glofas
|
|
56
|
+
Requires-Dist: cdsapi>=0.7.0; extra == "glofas"
|
|
57
|
+
Requires-Dist: xarray>=2023.0.0; extra == "glofas"
|
|
58
|
+
Requires-Dist: netCDF4>=1.6.0; extra == "glofas"
|
|
59
|
+
Requires-Dist: pyproj>=3.4.0; extra == "glofas"
|
|
60
|
+
Requires-Dist: shapely>=2.0.0; extra == "glofas"
|
|
61
|
+
Provides-Extra: geoglows
|
|
62
|
+
Requires-Dist: geoglows>=2.2; extra == "geoglows"
|
|
63
|
+
Requires-Dist: s3fs>=2023.0.0; extra == "geoglows"
|
|
64
|
+
Requires-Dist: zarr>=2.14.0; extra == "geoglows"
|
|
65
|
+
Requires-Dist: pyproj>=3.4.0; extra == "geoglows"
|
|
66
|
+
Requires-Dist: shapely>=2.0.0; extra == "geoglows"
|
|
67
|
+
Provides-Extra: cache
|
|
68
|
+
Requires-Dist: diskcache>=5.6.0; extra == "cache"
|
|
69
|
+
Provides-Extra: mcp
|
|
70
|
+
Requires-Dist: fastmcp>=2.0.0; extra == "mcp"
|
|
71
|
+
Provides-Extra: viz
|
|
72
|
+
Requires-Dist: matplotlib>=3.7.0; extra == "viz"
|
|
73
|
+
Requires-Dist: folium>=0.15.0; extra == "viz"
|
|
74
|
+
Provides-Extra: all
|
|
75
|
+
Requires-Dist: aihydro-data[cache,direct,gee,geoglows,glofas,hyriver,mcp,opendap,stac,viz]; extra == "all"
|
|
76
|
+
Provides-Extra: dev
|
|
77
|
+
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
78
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
79
|
+
Requires-Dist: pytest-mock>=3.12.0; extra == "dev"
|
|
80
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
81
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
82
|
+
Requires-Dist: build>=1.0.0; extra == "dev"
|
|
83
|
+
Requires-Dist: twine>=4.0.0; extra == "dev"
|
|
84
|
+
Dynamic: license-file
|
|
85
|
+
|
|
86
|
+
# aihydro-data
|
|
87
|
+
|
|
88
|
+
**Global hydrology dataverse — fetch any variable, anywhere, from the best available source.**
|
|
89
|
+
|
|
90
|
+
`aihydro-data` is a variable-centric, multi-source, region-aware Python library that unifies Google Earth Engine (GEE), HyRiver, and direct HTTP APIs behind a single `fetch()` call. It is the data backbone of the AI-Hydro toolchain.
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from aihydro_data import fetch
|
|
94
|
+
|
|
95
|
+
# Auto mode — router picks the best product for the geometry's region
|
|
96
|
+
result = fetch(
|
|
97
|
+
variable="precipitation",
|
|
98
|
+
geometry=watershed_gdf, # GeoDataFrame, GeoJSON, shapely, (lat, lon), or bbox
|
|
99
|
+
start="2010-01-01",
|
|
100
|
+
end="2020-12-31",
|
|
101
|
+
)
|
|
102
|
+
print(result.product) # "CHIRPS" (auto-selected)
|
|
103
|
+
print(result.source) # "gee"
|
|
104
|
+
print(result.citation) # full bibliographic reference
|
|
105
|
+
result.data # pd.DataFrame or xr.DataArray
|
|
106
|
+
result.next_steps # agent-facing hints: what to do with this data
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
[](https://pypi.org/project/aihydro-data/)
|
|
110
|
+
[](https://pypi.org/project/aihydro-data/)
|
|
111
|
+
[](LICENSE)
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Table of Contents
|
|
116
|
+
|
|
117
|
+
- [Why](#why)
|
|
118
|
+
- [Install](#install)
|
|
119
|
+
- [Quick Start](#quick-start)
|
|
120
|
+
- [Products (32 total)](#products)
|
|
121
|
+
- [Routing System](#routing-system)
|
|
122
|
+
- [Auth Setup](#auth-setup)
|
|
123
|
+
- [MCP Tools](#mcp-tools)
|
|
124
|
+
- [Architecture](#architecture)
|
|
125
|
+
- [Contributing](#contributing)
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Why
|
|
130
|
+
|
|
131
|
+
Before `aihydro-data`, fetching hydrology data meant hard-coding a single CONUS-only source per variable (GridMET for precip, NWIS for streamflow, POLARIS for soil). Anything outside CONUS meant writing a new fetcher from scratch.
|
|
132
|
+
|
|
133
|
+
`aihydro-data` turns this into a single declarative routing problem: **one call, every region, every variable, documented fallbacks**.
|
|
134
|
+
|
|
135
|
+
| Variable | CONUS (primary) | Global (primary) | Fallback chain |
|
|
136
|
+
|---|---|---|---|
|
|
137
|
+
| Precipitation | GridMET | CHIRPS (GEE) | IMERG, ERA5-Land, CHIRPS-IRI* |
|
|
138
|
+
| Tmax / Tmin | GridMET, Daymet | ERA5-Land | — |
|
|
139
|
+
| ET (actual) | MOD16 | MOD16 | TerraClimate, ERA5-Land |
|
|
140
|
+
| ET (potential) | GridMET | ERA5-Land | MOD16 |
|
|
141
|
+
| Soil moisture | SMAP | SMAP | — |
|
|
142
|
+
| Land cover | NLCD | ESA WorldCover | Dynamic World |
|
|
143
|
+
| Soil properties | POLARIS | SoilGrids | — |
|
|
144
|
+
| DEM | 3DEP (10 m) | Copernicus GLO-30 | SRTM, MERIT-DEM |
|
|
145
|
+
| Streamflow | USGS NWIS | — | — |
|
|
146
|
+
| NDVI | MODIS (250 m) | MODIS (250 m) | Sentinel-2 (10 m) |
|
|
147
|
+
| LAI | MODIS | MODIS | — |
|
|
148
|
+
|
|
149
|
+
\* `CHIRPS_IRI` — auth-free OPeNDAP fallback, no GEE account required.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Install
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Full install (all backends)
|
|
157
|
+
pip install aihydro-data[all]
|
|
158
|
+
|
|
159
|
+
# Per-backend
|
|
160
|
+
pip install aihydro-data[gee] # Google Earth Engine (20 products)
|
|
161
|
+
pip install aihydro-data[hyriver] # CONUS via HyRiver (10 products)
|
|
162
|
+
pip install aihydro-data[stac] # STAC catalogues (Planetary Computer)
|
|
163
|
+
pip install aihydro-data[opendap] # IRI OPeNDAP (CHIRPS auth-free fallback)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
> **Python**: 3.10+ | **GEE auth**: required for 20 GEE products (see [Auth Setup](#auth-setup))
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Quick Start
|
|
171
|
+
|
|
172
|
+
### 1. Auto mode — global watershed
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
from aihydro_data import fetch
|
|
176
|
+
import geopandas as gpd
|
|
177
|
+
|
|
178
|
+
# Any geometry: GeoDataFrame, shapely Point/Polygon, (lat, lon) tuple, or bbox
|
|
179
|
+
gdf = gpd.read_file("ganges_basin.geojson")
|
|
180
|
+
|
|
181
|
+
result = fetch("precipitation", gdf, "2015-01-01", "2015-12-31")
|
|
182
|
+
print(result.product) # "CHIRPS" (auto-selected for South Asia)
|
|
183
|
+
print(result.data)
|
|
184
|
+
# date precipitation
|
|
185
|
+
# 0 2015-01-01 1.23
|
|
186
|
+
# 1 2015-01-02 0.00
|
|
187
|
+
# ...
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 2. Auto mode — CONUS watershed
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
from aihydro_data import fetch
|
|
194
|
+
from shapely.geometry import Point
|
|
195
|
+
|
|
196
|
+
# Kansas City — routes to GridMET (no GEE auth needed)
|
|
197
|
+
result = fetch("precipitation", Point(-94.5, 39.1), "2020-01-01", "2020-12-31")
|
|
198
|
+
print(result.product) # "GRIDMET_PRECIP"
|
|
199
|
+
print(result.source) # "hyriver"
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### 3. Manual mode — pin a specific product
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
result = fetch(
|
|
206
|
+
"et",
|
|
207
|
+
gdf,
|
|
208
|
+
"2010-01-01", "2020-12-31",
|
|
209
|
+
mode="manual",
|
|
210
|
+
product="MOD16_ET",
|
|
211
|
+
)
|
|
212
|
+
print(result.units) # "mm/month"
|
|
213
|
+
print(result.citation) # Running et al. 2019 ...
|
|
214
|
+
print(result.bibtex) # @dataset{...}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### 4. Plot the result (v0.1.2+)
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
result = fetch("streamflow", "03245500", "2010-01-01", "2020-12-31")
|
|
221
|
+
|
|
222
|
+
# Auto-dispatched plot — picks line/bar/imshow based on data shape
|
|
223
|
+
result.plot(logy=True)
|
|
224
|
+
|
|
225
|
+
# Interactive folium map preview
|
|
226
|
+
result.map()
|
|
227
|
+
|
|
228
|
+
# Multi-source comparison in one call
|
|
229
|
+
from aihydro_data.viz import compare
|
|
230
|
+
fig = compare(
|
|
231
|
+
["GRIDMET_PRECIP", "CHIRPS", "ERA5L_PRECIP"],
|
|
232
|
+
watershed_gdf, "2015-01-01", "2020-12-31",
|
|
233
|
+
plots=["timeseries", "climatology", "scatter", "double_mass"],
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
# Research-grade hydrology plots
|
|
237
|
+
from aihydro_data.viz import flow_duration_curve, climatology, budyko
|
|
238
|
+
flow_duration_curve(streamflow_result)
|
|
239
|
+
budyko(precip_result, pet_result, et_result, label="My catchment")
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Install with `pip install aihydro-data[viz]` (matplotlib + folium).
|
|
243
|
+
|
|
244
|
+
### 5. Discover available products
|
|
245
|
+
|
|
246
|
+
```python
|
|
247
|
+
from aihydro_data import list_products, get_product
|
|
248
|
+
|
|
249
|
+
# List all precipitation products
|
|
250
|
+
for p in list_products(variable="precipitation"):
|
|
251
|
+
print(f"{p.id:20s} {p.coverage} {p.resolution_m}m {p.source}")
|
|
252
|
+
|
|
253
|
+
# Inspect one product's full spec
|
|
254
|
+
spec = get_product("CHIRPS")
|
|
255
|
+
print(spec.common_pitfalls)
|
|
256
|
+
print(spec.examples)
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### 6. Validate before fetching
|
|
260
|
+
|
|
261
|
+
```python
|
|
262
|
+
from aihydro_data.mcp import data_validate_request
|
|
263
|
+
|
|
264
|
+
check = data_validate_request(
|
|
265
|
+
variable="et",
|
|
266
|
+
geometry={"type": "Point", "coordinates": [-94.5, 39.1]},
|
|
267
|
+
start="1990-01-01",
|
|
268
|
+
end="2000-12-31",
|
|
269
|
+
)
|
|
270
|
+
# {"ok": False, "issues": [{"code": "DATE_OUT_OF_RANGE",
|
|
271
|
+
# "product": "MOD16_ET", "message": "MOD16 starts 2000-01-01."}], ...}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Products
|
|
277
|
+
|
|
278
|
+
32 products across 13 variables, live-tested against real backends (v0.2.0).
|
|
279
|
+
|
|
280
|
+
### Precipitation (6 products)
|
|
281
|
+
|
|
282
|
+
| ID | Source | Coverage | Resolution | Timestep | Notes |
|
|
283
|
+
|---|---|---|---|---|---|
|
|
284
|
+
| `CHIRPS` | GEE | Global | 5 km | Daily | Primary global; GEE auth required |
|
|
285
|
+
| `IMERG_PRECIP` | GEE | Global | 11 km | Daily | NASA GPM V07; GEE auth required |
|
|
286
|
+
| `ERA5L_PRECIP` | GEE | Global | 11 km | Daily | Reanalysis; 1950–present |
|
|
287
|
+
| `GRIDMET_PRECIP` | HyRiver | CONUS | 4 km | Daily | Primary CONUS; no auth |
|
|
288
|
+
| `DAYMET_PRECIP` | HyRiver | N. America | 1 km | Daily | High-res; no auth |
|
|
289
|
+
| `CHIRPS_IRI` | Direct API | Global | 5 km | Daily | **Auth-free fallback** via IRI OPeNDAP |
|
|
290
|
+
|
|
291
|
+
### Temperature (7 products)
|
|
292
|
+
|
|
293
|
+
| ID | Source | Coverage | Resolution | Timestep |
|
|
294
|
+
|---|---|---|---|---|
|
|
295
|
+
| `ERA5L_TMAX` | GEE | Global | 11 km | Daily |
|
|
296
|
+
| `ERA5L_TMIN` | GEE | Global | 11 km | Daily |
|
|
297
|
+
| `ERA5L_TMEAN` | GEE | Global | 11 km | Daily |
|
|
298
|
+
| `GRIDMET_TMAX` | HyRiver | CONUS | 4 km | Daily |
|
|
299
|
+
| `GRIDMET_TMIN` | HyRiver | CONUS | 4 km | Daily |
|
|
300
|
+
| `DAYMET_TMAX` | HyRiver | N. America | 1 km | Daily |
|
|
301
|
+
| `DAYMET_TMIN` | HyRiver | N. America | 1 km | Daily |
|
|
302
|
+
|
|
303
|
+
### Evapotranspiration (5 products)
|
|
304
|
+
|
|
305
|
+
| ID | Variable | Source | Coverage | Resolution | Timestep |
|
|
306
|
+
|---|---|---|---|---|---|
|
|
307
|
+
| `MOD16_ET` | ET (actual) | GEE | Global | 500 m | 8-day → monthly |
|
|
308
|
+
| `TERRACLIMATE_AET` | ET (actual) | GEE | Global | 4.6 km | Monthly |
|
|
309
|
+
| `MOD16_PET` | PET | GEE | Global | 500 m | 8-day → monthly |
|
|
310
|
+
| `ERA5L_PET` | PET | GEE | Global | 11 km | Daily |
|
|
311
|
+
| `GRIDMET_PET` | PET | HyRiver | CONUS | 4 km | Daily |
|
|
312
|
+
|
|
313
|
+
### DEM (4 products)
|
|
314
|
+
|
|
315
|
+
| ID | Source | Coverage | Resolution | Notes |
|
|
316
|
+
|---|---|---|---|---|
|
|
317
|
+
| `GLO30` | GEE | Global | 30 m | Copernicus; primary global DEM |
|
|
318
|
+
| `SRTM` | GEE | 60°S–60°N | 30 m | NASA SRTM v3 |
|
|
319
|
+
| `MERIT_DEM` | GEE | Global | 90 m | Hydrologically conditioned |
|
|
320
|
+
| `DEM3DEP_10M` | HyRiver | CONUS | 10 m | USGS 3DEP; highest resolution |
|
|
321
|
+
|
|
322
|
+
### Soil Moisture (1 product)
|
|
323
|
+
|
|
324
|
+
| ID | Source | Coverage | Resolution | Timestep |
|
|
325
|
+
|---|---|---|---|---|
|
|
326
|
+
| `SMAP_SM` | GEE | Global | 9 km | Daily (2015–present) |
|
|
327
|
+
|
|
328
|
+
### Land Cover (3 products)
|
|
329
|
+
|
|
330
|
+
| ID | Source | Coverage | Notes |
|
|
331
|
+
|---|---|---|---|
|
|
332
|
+
| `NLCD` | HyRiver | CONUS | NLCD 2021; 30 m |
|
|
333
|
+
| `ESA_WORLDCOVER` | GEE | Global | 10 m; 2020 & 2021 |
|
|
334
|
+
| `DYNAMIC_WORLD` | GEE | Global | 10 m; Sentinel-2 derived |
|
|
335
|
+
|
|
336
|
+
### Soil Properties (2 products)
|
|
337
|
+
|
|
338
|
+
| ID | Source | Coverage | Notes |
|
|
339
|
+
|---|---|---|---|
|
|
340
|
+
| `POLARIS` | HyRiver | CONUS | 30 m; 9 properties |
|
|
341
|
+
| `SOILGRIDS` | GEE | Global | 250 m; ISRIC |
|
|
342
|
+
|
|
343
|
+
### Vegetation (3 products)
|
|
344
|
+
|
|
345
|
+
| ID | Variable | Source | Coverage | Resolution | Timestep |
|
|
346
|
+
|---|---|---|---|---|---|
|
|
347
|
+
| `MODIS_NDVI` | NDVI | GEE | Global | 250 m | 16-day composite |
|
|
348
|
+
| `SENTINEL2_NDVI` | NDVI | GEE | Global | 10 m | ~5 day revisit |
|
|
349
|
+
| `MODIS_LAI` | LAI | GEE | Global | 500 m | 8-day composite |
|
|
350
|
+
|
|
351
|
+
### Streamflow (1 product)
|
|
352
|
+
|
|
353
|
+
| ID | Source | Coverage | Notes |
|
|
354
|
+
|---|---|---|---|
|
|
355
|
+
| `NWIS_STREAMFLOW` | Direct API | CONUS | USGS daily values; pass gauge ID as geometry |
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## Routing System
|
|
360
|
+
|
|
361
|
+
The router is a **declarative policy table** in `routing/policy.py` — no if/else chains, no source-specific logic. Adding a new product means adding one row.
|
|
362
|
+
|
|
363
|
+
```
|
|
364
|
+
fetch(variable, geometry, start, end)
|
|
365
|
+
│
|
|
366
|
+
▼
|
|
367
|
+
detect_region(geometry) ← CONUS? S_ASIA? EUROPE? global?
|
|
368
|
+
│
|
|
369
|
+
▼
|
|
370
|
+
PRODUCT_POLICY[(variable, region)] ← ordered list [primary, fallback1, fallback2, ...]
|
|
371
|
+
│
|
|
372
|
+
▼
|
|
373
|
+
resolve_product(spec) ← ProductSpec with backend_config
|
|
374
|
+
│
|
|
375
|
+
▼
|
|
376
|
+
Backend.fetch_timeseries() ← gee / hyriver / direct_api
|
|
377
|
+
│
|
|
378
|
+
▼
|
|
379
|
+
FetchResult(data, product, source, citation, units, next_steps)
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**Region detection** uses bounding-box math: if the geometry's centroid is inside the CONUS rectangle (−125° to −66°W, 24° to 50°N), the region is `"CONUS"`. Otherwise a Pfafstetter level-2 table resolves to `"S_ASIA"`, `"EUROPE"`, `"AFRICA"`, etc. Unknown regions fall to `"global"`.
|
|
383
|
+
|
|
384
|
+
**Fallback chain**: if the primary product raises `SourceUnavailable` or times out, the pipeline walks down the policy list automatically.
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## Auth Setup
|
|
389
|
+
|
|
390
|
+
### Google Earth Engine (20 products)
|
|
391
|
+
|
|
392
|
+
```bash
|
|
393
|
+
# 1. Install
|
|
394
|
+
pip install aihydro-data[gee]
|
|
395
|
+
|
|
396
|
+
# 2. Authenticate (one time — writes ~/.config/earthengine/credentials)
|
|
397
|
+
python -c "import ee; ee.Authenticate()"
|
|
398
|
+
|
|
399
|
+
# 3. Verify
|
|
400
|
+
python -c "from aihydro_data.mcp import data_doctor; print(data_doctor())"
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
> GEE requires a [Google account registered for Earth Engine](https://earthengine.google.com/signup/). Academic / research use is free.
|
|
404
|
+
|
|
405
|
+
### HyRiver (10 products)
|
|
406
|
+
|
|
407
|
+
No auth required. Just install:
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
pip install aihydro-data[hyriver]
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### CHIRPS IRI / NWIS (2 products)
|
|
414
|
+
|
|
415
|
+
No auth required:
|
|
416
|
+
|
|
417
|
+
```bash
|
|
418
|
+
pip install aihydro-data[opendap] # CHIRPS_IRI — needs xarray + netCDF4
|
|
419
|
+
# NWIS_STREAMFLOW works with [hyriver] — no extra auth
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
---
|
|
423
|
+
|
|
424
|
+
## MCP Tools
|
|
425
|
+
|
|
426
|
+
`aihydro-data` ships 9 MCP tools that expose the full API to AI agents (Claude, etc.) via the AI-Hydro MCP server:
|
|
427
|
+
|
|
428
|
+
| Tool | Description |
|
|
429
|
+
|---|---|
|
|
430
|
+
| `data_fetch` | Fetch a variable for a geometry and date range |
|
|
431
|
+
| `data_batch_fetch` | Fetch multiple geometries in one call |
|
|
432
|
+
| `data_list_products` | Discover products by variable / region / source |
|
|
433
|
+
| `data_describe_product` | Full spec for one product (citation, pitfalls, examples) |
|
|
434
|
+
| `data_validate_request` | Dry-run validation before fetching (size estimate, date checks) |
|
|
435
|
+
| `data_get_cache_status` | Inspect the disk cache |
|
|
436
|
+
| `data_invalidate_cache` | Clear cached entries |
|
|
437
|
+
| `data_doctor` | Environment check: auth, backends, cache, missing extras |
|
|
438
|
+
| `data_help` | Built-in onboarding guide (topics: auth, first_fetch, caching, …) |
|
|
439
|
+
|
|
440
|
+
The tools are auto-registered when `aihydro-data[mcp]` is installed, via the `aihydro.tools` entry-point group.
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## Architecture
|
|
445
|
+
|
|
446
|
+
```
|
|
447
|
+
aihydro_data/
|
|
448
|
+
├── __init__.py ← Public API: fetch(), list_products(), get_product()
|
|
449
|
+
├── fetch.py ← Unified entry point
|
|
450
|
+
├── _pipeline.py ← Routing → product resolution → backend dispatch → cache
|
|
451
|
+
├── contracts.py ← ProductSpec, FetchRequest, FetchResult (Pydantic)
|
|
452
|
+
├── exceptions.py ← Typed exceptions with agent-friendly .to_dict()
|
|
453
|
+
│
|
|
454
|
+
├── products/ ← Declarative variable registry (one file per variable)
|
|
455
|
+
│ ├── precipitation.py 6 products
|
|
456
|
+
│ ├── temperature.py 7 products
|
|
457
|
+
│ ├── et.py 5 products
|
|
458
|
+
│ ├── dem.py 4 products
|
|
459
|
+
│ ├── soil_moisture.py 1 product
|
|
460
|
+
│ ├── landcover.py 3 products
|
|
461
|
+
│ ├── soil.py 2 products
|
|
462
|
+
│ ├── vegetation.py 3 products
|
|
463
|
+
│ └── streamflow.py 1 product
|
|
464
|
+
│
|
|
465
|
+
├── sources/ ← Backend adapters (lazy imports — safe without extras)
|
|
466
|
+
│ ├── base.py SourceBackend ABC
|
|
467
|
+
│ ├── gee.py GEE backend (20 products)
|
|
468
|
+
│ ├── hyriver.py HyRiver backend (10 products)
|
|
469
|
+
│ ├── direct_api.py NWIS + CHIRPS IRI OPeNDAP (2 products)
|
|
470
|
+
│ ├── stac.py STAC/Planetary Computer (future)
|
|
471
|
+
│ └── _gee_vendored/ GEE auth + timeseries helpers (vendored from aihydro-tools)
|
|
472
|
+
│
|
|
473
|
+
├── routing/
|
|
474
|
+
│ ├── regions.py CONUS bbox, Pfafstetter region table
|
|
475
|
+
│ ├── detect.py detect_region(geometry) → str
|
|
476
|
+
│ └── policy.py PRODUCT_POLICY: (variable, region) → [product_ids]
|
|
477
|
+
│
|
|
478
|
+
├── geometry/
|
|
479
|
+
│ └── __init__.py coerce_geometry() — normalises all input types
|
|
480
|
+
│
|
|
481
|
+
├── cache/
|
|
482
|
+
│ └── __init__.py Disk cache at ~/.aihydro/cache/data/
|
|
483
|
+
│
|
|
484
|
+
├── mcp/
|
|
485
|
+
│ └── __init__.py 9 MCP tools (data_fetch, data_doctor, …)
|
|
486
|
+
│
|
|
487
|
+
└── help_topics/ Bundled markdown help (version-pinned to install)
|
|
488
|
+
├── first_fetch.md
|
|
489
|
+
├── auth.md
|
|
490
|
+
├── caching.md
|
|
491
|
+
└── ...
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### Three orthogonal axes
|
|
495
|
+
|
|
496
|
+
| Axis | What it is | Where it lives |
|
|
497
|
+
|---|---|---|
|
|
498
|
+
| **Variable** | *what* — precipitation, tmax, et, ndvi, dem, … | `products/<variable>.py` |
|
|
499
|
+
| **Source/Product** | *where from* — GridMET, CHIRPS, ERA5-Land, MOD16, … | `ProductSpec.backend_config` |
|
|
500
|
+
| **Region** | *where to* — CONUS, S_ASIA, EUROPE, global, … | `routing/policy.py` |
|
|
501
|
+
|
|
502
|
+
A user asks for "precipitation over this watershed" — the router resolves all three axes automatically, or the user pins any/all of them manually.
|
|
503
|
+
|
|
504
|
+
### Agent-friendly design
|
|
505
|
+
|
|
506
|
+
Every failure returns a structured envelope:
|
|
507
|
+
|
|
508
|
+
```python
|
|
509
|
+
{
|
|
510
|
+
"error": True,
|
|
511
|
+
"code": "GEE_AUTH_MISSING",
|
|
512
|
+
"message": "Google Earth Engine credentials not found.",
|
|
513
|
+
"recovery": "Run `python -c \"import ee; ee.Authenticate()\"`",
|
|
514
|
+
"next_tools": ["data_doctor", "data_help"],
|
|
515
|
+
"docs_anchor": "auth#gee"
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
Every success carries `citation`, `bibtex`, `units`, `license`, and `next_steps` so agents can chain downstream tools without re-planning.
|
|
520
|
+
|
|
521
|
+
---
|
|
522
|
+
|
|
523
|
+
## Contributing
|
|
524
|
+
|
|
525
|
+
### Adding a new product
|
|
526
|
+
|
|
527
|
+
1. Add a `ProductSpec` to the relevant `products/<variable>.py` (or create a new file).
|
|
528
|
+
2. Add a row to `routing/policy.py`.
|
|
529
|
+
3. If it's a new backend, add a `Backend` subclass to `sources/`.
|
|
530
|
+
4. Run `pytest -m "not live"` — no live credentials needed for the offline suite.
|
|
531
|
+
|
|
532
|
+
### Running tests
|
|
533
|
+
|
|
534
|
+
```bash
|
|
535
|
+
# Offline suite (no network, no auth — ~7 seconds)
|
|
536
|
+
pytest -m "not live"
|
|
537
|
+
|
|
538
|
+
# Live sweep — tests all 32 products against real backends (~13 minutes)
|
|
539
|
+
# Requires GEE auth + internet
|
|
540
|
+
pytest tests/test_live_sweep.py -v
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
---
|
|
544
|
+
|
|
545
|
+
## Status
|
|
546
|
+
|
|
547
|
+
**v0.1.5** — Pre-PyPI development. 34 products live-tested; visualization layer (auto-plot, hydrology plots, multi-source compare, folium map preview); STAC backend with auth-free DEM + landcover; cookbook notebook with 10 recipes; multi-OS CI. Versioning stays on `0.1.x` until the first public PyPI release.
|
|
548
|
+
|
|
549
|
+
See **[ROADMAP.md](ROADMAP.md)** for what's planned next, and **[examples/cookbook.ipynb](examples/cookbook.ipynb)** for 10 working recipes.
|
|
550
|
+
|
|
551
|
+
| Phase | Status | Description |
|
|
552
|
+
|---|---|---|
|
|
553
|
+
| 1: Scaffold | ✅ | Package structure, contracts, registry |
|
|
554
|
+
| 2: Precipitation vertical | ✅ | 6 products, routing, fallback chain |
|
|
555
|
+
| 3: CONUS migration | ✅ | Streamflow, temperature, landcover, soil |
|
|
556
|
+
| 4: Global gap-filling | ✅ | ET, DEM, soil moisture, vegetation |
|
|
557
|
+
| 5: Cache + provenance | ✅ | Disk cache, manifest, license tracking |
|
|
558
|
+
| 6: Batch fetching | ✅ | Multi-geometry parallel dispatch |
|
|
559
|
+
| 7: MCP tools | ✅ | 9 tools, help topics, doctor |
|
|
560
|
+
| 8: PyPI publish | 🔲 | v0.2.0 release |
|
|
561
|
+
|
|
562
|
+
---
|
|
563
|
+
|
|
564
|
+
## License
|
|
565
|
+
|
|
566
|
+
Apache-2.0. Data products carry their own licenses — always check `result.license` or `data_describe_product(id)`.
|