HydroSeason
HydroSeason is an open-source Python package for hydrological-year detection and seasonal/aseasonal analysis from monthly satellite-derived surface-water extent.
HydroSeason turns a monthly surface-water record into a hydrological year report — from a satellite-derived water-mask time series (such as Digital Earth Australia Water Observations), it works out when a catchment floods and dries, where each hydrological year begins and ends, and whether the pattern is even seasonal at all.
[!NOTE] HydroSeason analyzes surface-water extent percentages. It does not estimate river discharge, channel depth, total water volume, or groundwater storage.
What you get
One function call gives you one self-contained HTML report, an interactive
water-extent timeline with each hydrological year, its wet and dry phases,
and the flood events and low spells found in the record. Plus four CSVs
carrying the same numbers for your own analysis: _monthly, _hydro_years,
_wet_event, and _low_spells.
Open a real one (no install needed):
- Fitzroy River (WA) — a strongly seasonal monsoonal catchment
- Lachlan River (NSW) — an aseasonal one, characterized by flood events and dry spells instead of forced hydrological years
- Fitzroy River, with rainfall context — the same water analysis, with rainfall added purely as annotation
Installation
pip install hydroseason # Core: CSV detection & reports (pandas, numpy)
pip install "hydroseason[raster]" # + xarray, rioxarray, rasterio, geopandas, dask, zarr
pip install "hydroseason[stac]" # + pystac-client, odc-stac (DEA STAC acquisition)
pip install "hydroseason[all]" # Complete raster + STAC dependencies
Quickstart
from hydroseason import run_hydroseason
result = run_hydroseason(
"monthly_extent.csv",
output_dir="output/report",
aoi_name="My AOI",
)
print(f"Regime: {result.analysis.regime.regime}")
print(f"Route: {result.analysis.route}")
print(f"HTML: {result.artifacts.html}")
run_hydroseason is the one function most people need — see
the four ways to run it below for rasters,
DEA fetching, and optional rainfall context.
Many AOIs: one vector row, one report
For independent DEA/STAC analyses from a multi-row vector layer, use
run_hydroseason_many. One input row produces one analysis and one report;
each result is isolated under its resolved identifier. This differs from
run_hydroseason, which treats a multi-row AOI as one combined analysis over
its union footprint. A one-row MultiPolygon is still one AOI.
from hydroseason import run_hydroseason_many
batch = run_hydroseason_many(
"catchments.gpkg",
output_dir="results",
cache_dir="cache",
start_date="2000-01-01",
end_date="2025-12-01",
id_col="catchment_id",
workers="auto",
)
for outcome in batch.outcomes:
if outcome.succeeded:
print(outcome.id, outcome.result.artifacts.html)
else:
print(outcome.id, outcome.error_type, outcome.error_message)
batch.raise_for_failures()
workers="auto" uses a default concurrency cap of 2 and admits work only
within 80% of currently available RAM. See the Usage Guide for memory and scheduling details.
For runs long enough to outlive a notebook session, use the CLI — same
orchestrator, its own process, resumable via --cache-dir:
hydroseason run --aoi data/fitzroy_kimberley_aoi.geojson --aoi-name "Fitzroy River (WA)" \
--start-date 2005-01-01 --end-date 2025-12-01 \
--output-dir output/fitzroy --cache-dir cache/fitzroy
hydroseason doctor reports whether an environment has the optional
dependencies a given path needs. Full recipes:
CLI Recipes.
How it works
- You give it monthly water-extent data — a CSV you already have, a raster/NetCDF/Zarr cube, or nothing at all (it fetches Digital Earth Australia satellite data for you).
- It checks whether the catchment has a reliable annual cycle — a signal-to-noise ratio (SNR): how strong and repeatable the yearly wet/dry swing is compared to noise.
- It picks the matching analysis automatically — a strong, repeatable cycle gets per-year hydrological boundaries; an irregular or dryland catchment gets discrete flood-event and dry-spell characterization instead, rather than forcing a yearly pattern that isn't really there.
- Optional rainfall adds context, never changes the answer — rainfall can be fetched or supplied alongside the water data, but it only annotates the report; it can never alter the regime, route, boundaries, phases, events, or spells that were already decided from water alone.
- It writes one self-contained HTML report and four CSVs — open the HTML anywhere, no server needed; the CSVs are ready for your own analysis.
CSV, raster, or DEA fetch → run_hydroseason → seasonal or aseasonal route → HTML report + 4 CSVs
The four ways to run it
| You have... | Pass it as water_source |
Extra required |
|---|---|---|
A monthly extent CSV or pandas.DataFrame |
the CSV path or the DataFrame | none (core install) |
A NetCDF/Zarr file, or an xarray object |
the file path, or the Dataset/DataArray |
hydroseason[raster] |
| Nothing yet — fetch it from DEA | None, plus aoi=, start_date=, end_date= |
hydroseason[stac] |
| Any of the above, plus rainfall context | add fetch_rainfall=True or rainfall_csv_path= |
hydroseason[raster] for SILO fetch |
Runnable examples for each: Usage Guide — The four ways to run it, or the notebooks — start with 01_quickstart.ipynb. Acquisition internals (the fixed historical water mask, planning footprints, cache integrity, composite bundles) are documented in Advanced: DEA acquisition internals.
Case Studies
Three fully reproducible offline case studies using 2005–2025 DEA 30 m whole-catchment extent data across five Australian catchments (Daly, Fitzroy, Gilbert, Lachlan, Moonie):
- Main Catchment Workflow — Route-aware analysis across five catchments: three seasonal/marginal monsoonal basins, two aseasonal dryland basins.
- Resolution and Acquisition Evidence — Why 30 m resolution is the release standard: 60/90/300 m coarsening fails pre-declared fidelity gates for low-SNR catchments.
- Rainfall Context — Proves rainfall is strictly additive: every water-only column stays byte-identical with rainfall attached.
Scientific Limitations
-
Timing evidence: Fewer than 30 usable annual timings (not 30 months) can make bootstrap intervals wide; fewer than five usable annual timings is insufficient for regime assessment.
-
Circular timing: A low mean resultant length can mean diffuse timing or two cancelling preferred seasons; inspect the accompanying Kuiper uniformity result and trough evidence.
-
Extent is not Volume or Discharge: Surface area percentage (
extent_pct) dilutes narrow river channels and misses sub-canopy water. -
Cloud Gaps: High cloud/shadow invalid coverage (
invalid_pct) distorts extent statistics if unflagged. -
Resolution: Coarsening spatial resolution distorts peak/trough timing and event boundaries. 30 m resolution remains authoritative.
Entry Points
| Symbol | Purpose |
|---|---|
run_hydroseason |
One-call orchestrator: resolve water input, analyze, optional rainfall, write report |
HydroSeasonRunResult |
Everything a run_hydroseason call produced (.analysis, .artifacts, .rainfall_status, ...) |
run_hydroseason_many |
DEA/STAC batch orchestrator: preserve each input vector row as one independent run |
HydroSeasonBatchResult |
Source-ordered successful and failed per-row outcomes; call .raise_for_failures() after inspection |
load_extent_csv |
Read a monthly extent CSV directly, for the lower-level building blocks |
analyze_catchment |
Assess regime, then run the analysis that regime supports (the routing authority) |
generate_catchment_report |
Write the self-contained HTML report plus the 4-CSV bundle |
load_wofs_monthly_extent |
Fetch DEA WOfS directly, without the full orchestrator |
Full API reference, grouped by task: Workflow, Loading Data, Analysis, Reporting.
Citation
If you use HydroSeason in your research, please cite the software release (see CITATION.cff):
@software{tayer_hydroseason,
author = {Tayer, Thiaggo C.},
title = {HydroSeason: Remote-sensing-first hydrological year and season detection},
year = {2026},
url = {https://github.com/tayerthiaggo/hydroseason},
doi = {10.5281/zenodo.21866898}
}
Full citation guidance, including the version-specific DOI policy, is in docs/citation.md.
License
MIT License — see LICENSE.
Release files for hydroseason 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| hydroseason-0.1.1.tar.gz | 676.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hydroseason-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.4 MB
Release files / hydroseason-0.1.1.tar.gz
| Download URL | hydroseason-0.1.1.tar.gz |
|---|---|
| Size | 676.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
98da39a74e406f8938db607e9adf975f3debfdf93902aa5a6d2fef36fd6b556a
|
|
BLAKE2b-256 checksum How to use checksums |
ea06964cc820bc78669c73ad9b259003662d2b65a401fc08dafa8fe6863cd236
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 20, 2026.
Transparency logRelease files / hydroseason-0.1.1-py3-none-any.whl
| Download URL | hydroseason-0.1.1-py3-none-any.whl |
|---|---|
| Size | 698.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
139bb34658aabdf1d7e3bccc403ca9f7b6a135665baae64cdfd7156079ce5c8e
|
|
BLAKE2b-256 checksum How to use checksums |
dab18d0af80724d333a1737c6f98993aac53054f6879dd9776659b4d85040135
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 20, 2026.
Transparency log