q06·intermediate

Is my reservoir / lake / river running low compared to historical normals?

hydrologywater-resourcesdrought Datasets: 6 15–45 min
Find the data for your area

Draw a rectangle to pick your area of interest, then see what NASA data covers it (live, here in your browser) or download a ready-to-run notebook with your AOI pre-filled. The notebook runs in any Python environment — it needs a free Earthdata Login to fetch the data.

Current AOI: -114.7, 36 → -114, 36.4 (Lake Mead, NV/AZ)
On this page

Is my reservoir / lake / river running low compared to historical normals?

What you can answer

  • Water-surface elevation time series (SWOT for rivers ≥100 m / lakes ≥250×250 m; ICESat-2 for smaller bodies)
  • Surface-area time series (HLS NDWI on cloud-free dates)
  • Total water-storage anomaly at regional scale 300+ km (GRACE-FO mascons)
  • Inflow precipitation context (GPM IMERG climatology vs current year)
  • Comparison to multi-year normal to flag drought conditions

What you can NOT answer with these alone

  • Underground storage (groundwater fluctuations need GRACE-FO + soil moisture + a land-surface model)
  • Daily-to-hourly water level during fast-changing events (storm surge, dam-release) — satellite revisit is too slow; use ground gauges or hydraulic models
  • Direct water quality (sediment, algae, salinity) without optical/hyperspectral overlays

Code template

import earthaccess
import requests

earthaccess.login(strategy="netrc")

# Lake Mead, Nevada-Arizona — drought poster child
aoi = (-114.7, 36.0, -114.0, 36.4)
window = ("2024-01-01", "2025-12-31")

# 1. SWOT lake heights via Hydrocron (much easier than raw L2)
lake_id = "7250000000"  # Hydrocron's Lake Mead ID (look up in their catalog)
hydrocron_url = (
    f"https://soto.podaac.earthdatacloud.nasa.gov/hydrocron/v1/timeseries"
    f"?feature=PriorLake&feature_id={lake_id}&start_time={window[0]}T00:00:00Z"
    f"&end_time={window[1]}T23:59:59Z&output=geojson&fields=wse,area_total,time_str"
)
swot_data = requests.get(hydrocron_url).json()

# 2. HLS for surface-area cross-check
hls = earthaccess.search_data(short_name="HLSL30", bounding_box=aoi,
                               temporal=window, cloud_cover=20)
# Compute NDWI = (Green - NIR) / (Green + NIR); threshold > 0 → water mask
# Sum water-mask pixels × 30² m² → surface area per scene

# 3. GRACE-FO mascon for regional total water storage anomaly
grace = earthaccess.search_data(short_name="GRACEFO_L3_JPL_RL06.X_M",
                                bounding_box=aoi, temporal=("2002-04-01", window[1]))
# Extract liquid water equivalent (LWE) anomaly time series

# 4. GPM IMERG for precipitation accumulation
imerg = earthaccess.search_data(short_name="GPM_3IMERGDF", bounding_box=aoi,
                                temporal=window)
# Compute monthly + annual rainfall sum

# 5. Plot: water-surface elevation, area, regional TWS, precipitation — same x-axis

Expected output

  • Multi-panel time-series: lake surface elevation (SWOT) · surface area (HLS) · regional TWS (GRACE) · monthly precipitation (IMERG)
  • Anomaly bar chart: current year vs 30-year normal for each variable
  • Map: current vs typical extent overlay

Caveats

  • SWOT 21-day revisit + 20 km nadir gap — your reservoir may be missed on a given pass
  • NDWI cloud sensitivity — cloudy scenes destroy area estimates
  • GRACE-FO at 300 km resolution can’t isolate one reservoir; it captures regional pattern
  • HLS L30/S30 calibration consistency is good but not perfect across sensor changes (Landsat 7 era vs 8/9 era)
  • Use Hydrocron, not raw L2 HR pixel-cloud for first analyses — Hydrocron pre-aggregates to feature

Cross-DAAC composition

PO.DAAC (SWOT, GRACE-FO) + LP DAAC (HLS) + GES DISC (IMERG) — three DAACs, single auth, see r01.

Sources

How a scientist answers this
Parameters
Water-surface elevation (WSE, meters) and surface area from SWOT L2 HR RiverSP (rivers ≥100 m wide, ~21-day cadence) and LakeSP (lakes ≥250×250 m), with ICESat-2 ATL13 for smaller bodies; surface-water extent from HLS L30/S30 via NDWI on cloud-free dates; GRACE-FO mascons for regional total-water-storage context and GPM IMERG for inflow precipitation. The 'normal' is a multi-year mean/percentile for the same calendar period.
Method
Build a WSE (and area) time series for the feature, then express the current value as an anomaly / percentile relative to the historical distribution for that season (standardized z-score against the available record); cross-reference with IMERG precipitation climatology to attribute low levels to deficient inflow, and use GRACE-FO to confirm a broader regional storage decline. Note the satellite record is short, so percentiles are over a limited baseline.
Validation
Cross-check SWOT/ICESat-2 elevations against in-situ gauges (e.g., USGS/Dahiti) where available; verify NDWI area against an independent optical scene and flag cloud gaps; state the (short) baseline period explicitly since anomalies depend on it.
In plain EnglishTrack the lake or river's height and surface area over time and compare the current level to what's typical for this time of year, then check whether rainfall has been short. A few low readings during a dry season point to drought rather than a one-off dip.

Make it yours → Set the feature ID or AOI, the date window, and the baseline period in the notebook to study your own water body.

Run the core method · no login

The thresholding a measurement into classes at the heart of this question — runnable on synthetic data, right here. The full earthaccess code template further down does it on real NASA data (needs an Earthdata login).

editable · runs in your browser

Datasets used