Showcase — Hurricane Harvey's record rainfall (NASA GPM, Earthdata)¶
When Hurricane Harvey stalled over southeast Texas in late August 2017 it produced the largest rainfall total of any tropical cyclone in US history — over 1.5 m (60 in) of rain, triggering catastrophic flooding in Houston. NASA's GPM IMERG merges a constellation of microwave and infrared satellites into a global half-hourly/daily precipitation grid. This notebook uses the earthlens Earthdata backend to pull the daily IMERG rainfall over Texas across the event and accumulate the storm total.
Uses NASA Earthdata; set
EARTHDATA_USERNAME/EARTHDATA_PASSWORD(a free Earthdata Login); the download skips gracefully without them. IMERG granules are global, so we crop to Texas after download.
What this notebook does¶
- Download daily GPM IMERG precipitation for 25–31 Aug 2017.
- Accumulate the daily rainfall into the storm total over Texas.
- Map the total and report the peak — among the highest tropical-cyclone rainfall totals ever recorded.
Setup¶
First the imports and a bit of noise-suppression. xarray does the cropping and
accumulation of the downloaded granules; earthlens provides the unified
EarthLens entry point.
import tempfile
import matplotlib.pyplot as plt
import numpy as np
import xarray as xr
from cleopatra.glyphs.gridded.array_glyph import ArrayGlyph
from cleopatra.styling.colorbar import ColorBar
from cleopatra.styling.params import DataStyle
from loguru import logger
from earthlens.base import AuthenticationError
from earthlens.core import EarthLens
logger.disable("earthlens")
logger.disable("pyramids")
1 · Download the daily IMERG granules¶
We build the request first — source, dataset, variable, the event date window,
and a bounding box over Texas. This is the daily IMERG Final Run v07, which
serves one global granule per day (we crop to Texas after download).
el = EarthLens(
data_source="earthdata",
dataset="GPM_3IMERGDF_07",
variables=["precipitation"],
start="2017-08-25",
end="2017-08-31",
aoi=[-99.0, 27.0, -93.0, 32.0],
path=tempfile.mkdtemp(),
)
Authentication and the download are kept as separate steps so each is easy to
read and re-run: authenticate() resolves the Earthdata login, then download()
fetches the daily granules. If credentials are missing the notebook skips the
download gracefully instead of erroring.
paths = None
try:
el.authenticate()
except AuthenticationError as exc: # noqa: BLE001
print("Earthdata download skipped (needs credentials):", exc)
else:
paths = el.download(progress_bar=False)
print(f"{len(paths)} daily IMERG granules")
2 · Accumulate the storm-total rainfall¶
Each granule carries precipitation in mm/day on a global 0.1° grid. We crop each day to a box over southeast Texas and sum the days into the storm total.
total = None
if paths:
for p in sorted(paths):
da = xr.open_dataset(p)["precipitation"].squeeze() # dims (lon, lat), mm/day
da = da.sel(lon=slice(-99, -93), lat=slice(27, 32)) # crop to SE Texas
total = da.copy() if total is None else total + da.values
total = total.transpose("lat", "lon")
print(
f"storm-total rainfall: peak {float(total.max()):.0f} mm "
f"({float(total.max()) / 25.4:.0f} in) over the cropped box"
)
3 · Map the storm total¶
The bullseye of >1 m sits over the Houston–Beaumont corridor, where Harvey's rainbands stalled for days.
if total is not None:
# cleopatra ArrayGlyph with the "total_precipitation" preset. IMERG rows may run
# south->north; imshow is north-up, so flip when the latitude axis ascends.
lat = np.asarray(total.lat)
arr = np.asarray(total.values)
if lat[0] < lat[-1]:
arr = arr[::-1]
glyph = ArrayGlyph(
arr,
extent=[
float(total.lon.min()),
float(total.lon.max()),
float(lat.min()),
float(lat.max()),
],
figsize=(9, 7),
title="Hurricane Harvey storm-total rainfall, 25\u201331 Aug 2017 (GPM IMERG)",
)
fig, ax = glyph.plot(
data_style=DataStyle(style="total_precipitation"),
colorbar=ColorBar(label="rainfall (mm)"),
)
ax.plot(-95.37, 29.76, "k*", ms=14)
ax.annotate("Houston", (-95.37, 29.76), fontsize=10, fontweight="bold")
ax.set_xlabel("longitude")
ax.set_ylabel("latitude")
plt.show()
else:
print("no granules \u2014 set EARTHDATA_USERNAME / EARTHDATA_PASSWORD and rerun")
Recap¶
The earthlens Earthdata backend fetches NASA's GPM IMERG granules; a few lines of xarray crop and accumulate them into the storm-total rainfall map that defined Harvey as the wettest US tropical cyclone on record.
Try it yourself¶
- Switch to the half-hourly product (
GPM_3IMERGHHL_07) for the rainfall-rate time series at a point. - Re-point at another storm (Florence 2018, Ida 2021) or a monsoon.
- See the Earthdata backend reference.