q08·beginner

How much rainfall has my region had this year compared to the 30-year normal?

hydrologyprecipitationclimate-anomaly Datasets: 4 5–15 min

Rainfall is the depth of water that fell from the sky, measured in millimetres. Satellites estimate it from orbit by watching clouds and storms, so you can add up how much rain your region got this year even with no weather stations on the ground. The trick is comparing that total to what's normal: the average for the same months across many past years. "60% of normal" means a dry year, "140%" a wet one.

How much rainfall has my region had this year vs the 30-year normal?

Rainfall is the depth of water that fell from the sky, measured in millimetres. Satellites estimate it from orbit by watching clouds and storms, so you can add up how much rain your region got this year even with no weather stations on the ground. The trick is comparing that total to what’s normal: the average for the same months across many past years. “60% of normal” means a dry year, “140%” a wet one.

Which data to use, and how

Use this dataset: GPM IMERG (monthly) (short name GPM_3IMERGM), which gives one rainfall total per month per ~10 km pixel, covering 2000 → today, almost everywhere on Earth. Monthly totals are the easiest place to start. For finer detail, like day-by-day rainfall for the current year, switch to the daily version, GPM IMERG (daily) (GPM_3IMERGDF).

Then do four steps. The runnable code further down does all of this; this is just the idea.

  1. Pick your region (a small latitude/longitude box around it) and the months you care about.
  2. Add up this year’s rain. Sum the rainfall inside your box over those months, giving one total (the “current year” number).
  3. Work out the normal. Do the same sum for every past year (back to 2000) and average them. That average is your baseline, the “normal” you compare against. Always use the same months in both, or the comparison is meaningless.
  4. Compare them. Express this year as a percent of normal. Above 100% = wetter than usual, below 100% = drier. Make a map so you can see which sub-areas are driest or wettest.

That’s the whole method. Below, “How a scientist answers this” names the exact tools, and the Run it cell does it live on synthetic data so you can see each step work.

What you can find out

  • This year’s total rainfall for any region you draw.
  • How this year compares to the normal: the percent-of-normal, using the 2000–2024 IMERG baseline.
  • A dry-or-wet score: the anomaly index expressed as % of normal, which flags drought or flooding years.
  • Where it’s driest or wettest. The map shows the pattern across sub-regions, not just one number for the whole area.
  • Season by season. Split monsoon from non-monsoon, or wet season from dry, instead of lumping the whole year together.

What it can’t tell you

  • A true 30-year normal. The satellite record (IMERG) only starts in 2000, so you have ~25 years, not 30. For a proper 30-year baseline you need an older or longer product: the earlier satellite era (TRMM, 1997–2015, tropics only) or a model reconstruction (MERRA-2, from 1980).
  • Snowfall as water. Snow depth converted to its water content needs ground stations or dedicated snow data (SnowEx); the rainfall product alone won’t give it.
  • Single-hour extreme storms outside the half-hourly grid. For sub-hourly bursts you need the half-hourly IMERG version, not the daily or monthly totals.

Gotchas to watch for

  • The most accurate data arrives late. The best, fully-corrected version (IMERG “Final”) shows up about 3.5 months after the fact. If you need rainfall for right now, use the quicker versions (“Late” at ~12-hour delay, or “Early” at ~4-hour delay) and accept they’re a bit less accurate.
  • Use the current version, not the old one. Version V07 is current; V06 is retired. If you cached any data from before 2023, re-download it so you’re not mixing versions.
  • Mountains read low. In steep terrain (the Himalayas, the Western Ghats) the satellite systematically under-counts rain compared to ground gauges (an effect called orographic underestimation, where rain on mountainsides is missed). Cross-check against gauges if your region is mountainous.
  • Always state your baseline. “140% of normal” is meaningless unless you say which years defined “normal.” A fixed window (e.g. 2000–2020) keeps different years comparable, so write it down every time.

The real-data code

The Run it cell above runs the method on synthetic data with no login. Below is the whole recipe against the real archive: search, open, accumulate this year, build the baseline normal, compute percent-of-normal and a standardized anomaly, and map it. It needs a free Earthdata Login.

import earthaccess, numpy as np, xarray as xr
import matplotlib.pyplot as plt

earthaccess.login(strategy="netrc")

# AOI: Maharashtra agricultural belt — a small (West, South, East, North) box.
aoi = (74, 18, 78, 21)
this_year = 2025
base_years = range(2000, 2021)   # fixed baseline ("normal") window — state it!

# Open all monthly IMERG granules for a year, clip to the AOI, and return
# precipitation (mm/day per pixel) as one xarray DataArray (time, lat, lon).
def imerg_year(y):
    grans = earthaccess.search_data(
        short_name="GPM_3IMERGM", bounding_box=aoi,
        temporal=(f"{y}-01-01", f"{y}-12-31"))
    ds = xr.open_mfdataset(earthaccess.open(grans), combine="by_coords")
    pr = ds["precipitation"].sel(
        lon=slice(aoi[0], aoi[2]), lat=slice(aoi[1], aoi[3]))
    return pr.load()

# 1. This year's rain: months are mm/day, so scale each by its day-count and
#    sum over time -> annual total (mm) per pixel.
cur = imerg_year(this_year)
days = cur["time"].dt.days_in_month
cur_total = (cur * days).sum("time")

# 2. The normal: do the same per baseline year, then average across years.
yearly = []
for y in base_years:
    py = imerg_year(y)
    yearly.append((py * py["time"].dt.days_in_month).sum("time"))
stack = xr.concat(yearly, dim="year")
clim_mean = stack.mean("year")
clim_std = stack.std("year")

# 3. Percent-of-normal + standardized anomaly (z-score, the SPI-style drought number).
pct = cur_total / clim_mean * 100.0
z = (cur_total - clim_mean) / clim_std

# Area-mean the AOI (latitude weighting is negligible at this small box) for the headline.
w = np.cos(np.deg2rad(cur_total["lat"]))
pct_area = float(pct.weighted(w).mean(("lat", "lon")))
z_area = float(z.weighted(w).mean(("lat", "lon")))
label = "wetter" if pct_area > 100 else "drier"
print(f"{this_year}: {pct_area:.0f}% of the {base_years.start}-{base_years.stop-1} "
      f"normal ({label} than usual), standardized anomaly z={z_area:+.2f}")

# 4. Map the percent-of-normal field: red = dry, white ~ normal, blue = wet.
pct.plot(cmap="BrBG", vmin=40, vmax=160, cbar_kwargs={"label": "% of normal"})
plt.title(f"{this_year} rainfall vs {base_years.start}-{base_years.stop-1} normal")
plt.tight_layout(); plt.show()

# Before you trust it: cross-check IMERG against CHIRPS or a rain gauge — satellite
# precip under-counts in steep terrain (the Western Ghats here; see the gotchas).

Expected output: a map of this year’s rainfall (mm) per pixel; a percent-of-normal map (red below 80%, green 80–120%, blue above 120%); a running total of this year’s rain against the normal range; and monsoon-season bars (this year’s June–Sept total vs the multi-year June–Sept mean).

Where the data comes from

Everything here is GPM IMERG, which lives in a single NASA archive (GES DISC) behind one free login (Earthdata Login). One sign-in covers both the daily and monthly versions.

Sources

How a scientist answers this
Parameters
Total precipitation from GPM IMERG (2000–present, ~10 km, near-global) or CHIRPS (gauge-blended, strong over land). The 'normal' is the WMO 1991–2020 climatology for the same calendar period; the answer is this year's total as a percent of normal, plus a standardized anomaly (z-score / SPI) for drought framing.
Method
Area-weight and accumulate precipitation over your region for the period of interest, build the 1991–2020 climatology for that same period, then express the current total as percent-of-normal and as a standardized anomaly. A fixed baseline keeps different years comparable.
Validation
Cross-check IMERG against CHIRPS or rain gauges (satellite precipitation is biased, especially for extremes), and always state the baseline — percent-of-normal is meaningless without it.
In plain EnglishAdd up the rain your region got, compare it to what it normally gets over 30 years for the same months, and report it as a percentage: 60% of normal is a dry year, 140% a wet one.

Make it yours → Choose your region, the months, and the baseline; the notebook computes percent-of-normal and the drought index. Switch between IMERG and CHIRPS depending on whether you need global/recent or land-focused/long-record.

🧪 Virtual Mock Lab stand-in data · runs in your browser · no login

A safe place to practise the method on GPM_3IMERGM. The code is the real earthaccess workflow, but we feed it stand-in data shaped like the real product — so you can run it, change the numbers, and break it without an account. When you want the real data, use the recipe under “The real-data code” above, or download the notebook below.

editable · runs in your browser

Datasets used

Computed · real data Worked examples, computed end-to-end on real satellite data — not yet scientist-verified · expand ▾
Real trends, computed on Google Earth Engine (area-weighted Theil–Sen + Mann–Kendall).

We ran the analysis on real data for Indian regions and report exactly what came back — including the honest nulls and refusals. Each card shows the slope, significance, and (for rainfall) a gauge cross-check.

Has annual rainfall in the Marathwada region declined from 1990 to 2020?
rainfall Marathwada 1990–2020
-1.183 mm/year (trend) no significant trend
95% CI [-8.646, 7.167] Mann–Kendall p = 0.6341

The data doesn't support a rainfall change here — an earned null, not a missing answer.

⚠ Ground-truth: gauges disagree IMD gauges ↓ · ERA5 ↑ · CHIRPS ↑ sources DISAGREE on direction — treat the trend as unresolved. IMD = India Meteorological Dept. gauge grid (the ground-truth); * = significant.
computed · ERA5/GEE · not yet scientist-verified
Has rainfall over the Western Ghats crest meaningfully changed from 1991 to 2020?
rainfall Western Ghats crest 1991–2020
-0.245 mm/year (trend) no significant trend
95% CI [-16.379, 16.596] Mann–Kendall p = 1

The data doesn't support a rainfall change here — an earned null, not a missing answer.

✓ Ground-truth: gauges agree IMD gauges ↑ · ERA5 ↑ · CHIRPS ↑ all sources agree on direction. IMD = India Meteorological Dept. gauge grid (the ground-truth); * = significant.
computed · ERA5/GEE · not yet scientist-verified
Rainfall trend over Punjab, 1990-2020?
rainfall Punjab 1990–2020
-5.799 mm/year (trend) no significant trend
95% CI [-12.603, 1.898] Mann–Kendall p = 0.1739

The data doesn't support a rainfall change here — an earned null, not a missing answer.

⚠ Ground-truth: gauges disagree IMD gauges ↓ · ERA5 ↓ · CHIRPS ↑* sources DISAGREE on direction — treat the trend as unresolved. IMD = India Meteorological Dept. gauge grid (the ground-truth); * = significant.
computed · ERA5/GEE · not yet scientist-verified
Rainfall trend over Kerala, 1990-2020?
rainfall Kerala 1990–2020
+6.541 mm/year (trend) no significant trend
95% CI [-4.858, 15.146] Mann–Kendall p = 0.1438

The data doesn't support a rainfall change here — an earned null, not a missing answer.

✓ Ground-truth: gauges agree IMD gauges ↑ · ERA5 ↑ · CHIRPS ↑* all sources agree on direction. IMD = India Meteorological Dept. gauge grid (the ground-truth); * = significant.
computed · ERA5/GEE · not yet scientist-verified
What was the mean annual rainfall over the Krishna basin, 2000-2020?
rainfall Krishna basin 2000–2020
1129.3mm/year
computed · ERA5/GEE · not yet scientist-verified
Has monsoon-season (JJAS) rainfall over central India changed from 1990 to 2020?
rainfall Central India 1990–2020
+1.23 mm/year (trend) no significant trend
95% CI [-9.445, 13.019] Mann–Kendall p = 0.6341

The data doesn't support a rainfall change here — an earned null, not a missing answer.

✓ Ground-truth: gauges agree IMD gauges ↑ · ERA5 ↑ · CHIRPS ↑ all sources agree on direction. IMD = India Meteorological Dept. gauge grid (the ground-truth); * = significant.
computed · ERA5/GEE · not yet scientist-verified
Has annual rainfall over Tamil Nadu changed from 1990 to 2020?
rainfall Tamil Nadu 1990–2020
+4.088 mm/year (trend) no significant trend
95% CI [-5.939, 12.906] Mann–Kendall p = 0.3412

The data doesn't support a rainfall change here — an earned null, not a missing answer.

✓ Ground-truth: gauges agree IMD gauges ↑ · ERA5 ↑ · CHIRPS ↑* all sources agree on direction. IMD = India Meteorological Dept. gauge grid (the ground-truth); * = significant.
computed · ERA5/GEE · not yet scientist-verified
Has annual rainfall over Karnataka changed from 1990 to 2020?
rainfall Karnataka 1990–2020
+1.402 mm/year (trend) no significant trend
95% CI [-4.89, 9.295] Mann–Kendall p = 0.6341

The data doesn't support a rainfall change here — an earned null, not a missing answer.

✓ Ground-truth: gauges agree IMD gauges ↑ · ERA5 ↑ · CHIRPS ↑ all sources agree on direction. IMD = India Meteorological Dept. gauge grid (the ground-truth); * = significant.
computed · ERA5/GEE · not yet scientist-verified
Has annual rainfall over Gujarat changed from 1990 to 2020?
rainfall Gujarat 1990–2020
+8.447 mm/year (trend) no significant trend
95% CI [-4.367, 17.172] Mann–Kendall p = 0.1347

The data doesn't support a rainfall change here — an earned null, not a missing answer.

✓ Ground-truth: gauges agree IMD gauges ↑ · ERA5 ↑* · CHIRPS ↑* all sources agree on direction. IMD = India Meteorological Dept. gauge grid (the ground-truth); * = significant.
computed · ERA5/GEE · not yet scientist-verified
Has annual rainfall over Rajasthan changed from 1990 to 2020?
rainfall Rajasthan 1990–2020
+1.414 mm/year (trend) no significant trend
95% CI [-4.819, 7.13] Mann–Kendall p = 0.5184

The data doesn't support a rainfall change here — an earned null, not a missing answer.

✓ Ground-truth: gauges agree IMD gauges ↑ · ERA5 ↑ · CHIRPS ↑* all sources agree on direction. IMD = India Meteorological Dept. gauge grid (the ground-truth); * = significant.
computed · ERA5/GEE · not yet scientist-verified
Has annual rainfall over West Bengal changed from 1990 to 2020?
rainfall West Bengal 1990–2020
-6.59 mm/year (trend) no significant trend
95% CI [-16.478, 4.77] Mann–Kendall p = 0.1534

The data doesn't support a rainfall change here — an earned null, not a missing answer.

⚠ Ground-truth: gauges disagree IMD gauges ↓* · ERA5 ↓ · CHIRPS ↑ sources DISAGREE on direction — treat the trend as unresolved. IMD = India Meteorological Dept. gauge grid (the ground-truth); * = significant.
computed · ERA5/GEE · not yet scientist-verified
Has annual rainfall over Madhya Pradesh changed from 1990 to 2020?
rainfall Madhya Pradesh 1990–2020
+0.524 mm/year (trend) no significant trend
95% CI [-6.436, 11.043] Mann–Kendall p = 0.8918

The data doesn't support a rainfall change here — an earned null, not a missing answer.

⚠ Ground-truth: gauges disagree IMD gauges ↓ · ERA5 ↑ · CHIRPS ↑ sources DISAGREE on direction — treat the trend as unresolved. IMD = India Meteorological Dept. gauge grid (the ground-truth); * = significant.
computed · ERA5/GEE · not yet scientist-verified
Has annual rainfall over Odisha changed from 1990 to 2020?
rainfall Odisha 1990–2020
+3.624 mm/year (trend) no significant trend
95% CI [-15.228, 13.977] Mann–Kendall p = 0.5634

The data doesn't support a rainfall change here — an earned null, not a missing answer.

⚠ Ground-truth: gauges disagree IMD gauges ↓ · ERA5 ↑ · CHIRPS ↑ sources DISAGREE on direction — treat the trend as unresolved. IMD = India Meteorological Dept. gauge grid (the ground-truth); * = significant.
computed · ERA5/GEE · not yet scientist-verified
Has annual rainfall over Assam changed from 1990 to 2020?
rainfall Assam 1990–2020
-20.4 mm/year (trend) significant trend
95% CI [-36.556, -0.498] Mann–Kendall p = 0.0249
✓ Ground-truth: gauges agree IMD gauges ↓ · ERA5 ↓ · CHIRPS ↓ all sources agree on direction. IMD = India Meteorological Dept. gauge grid (the ground-truth); * = significant.
computed · ERA5/GEE · not yet scientist-verified
Has annual rainfall over the Delhi NCR changed from 1990 to 2020?
rainfall Delhi NCR 1990–2020
+0.094 mm/year (trend) no significant trend
95% CI [-7.46, 7.186] Mann–Kendall p = 1

The data doesn't support a rainfall change here — an earned null, not a missing answer.

⚠ Ground-truth: gauges disagree IMD gauges ↓* · ERA5 ↑ · CHIRPS ↑ sources DISAGREE on direction — treat the trend as unresolved. IMD = India Meteorological Dept. gauge grid (the ground-truth); * = significant.
computed · ERA5/GEE · not yet scientist-verified
Has annual rainfall over Mumbai & the Konkan coast changed from 1990 to 2020?
rainfall Mumbai & Konkan 1990–2020
+10.047 mm/year (trend) no significant trend
95% CI [-13.514, 28.655] Mann–Kendall p = 0.3412

The data doesn't support a rainfall change here — an earned null, not a missing answer.

✓ Ground-truth: gauges agree IMD gauges ↑ · ERA5 ↑ · CHIRPS ↑ all sources agree on direction. IMD = India Meteorological Dept. gauge grid (the ground-truth); * = significant.
computed · ERA5/GEE · not yet scientist-verified

…and what it refuses to answer

What is the rainfall trend over Maharashtra from 2018 to 2021?
rainfall Central India 2018–2021
⊘ Refused

trend span < 10y — the validator refuses ill-posed questions rather than guessing. That discipline is the point.

validator-enforced refusal

See all verified answers →