How have rainfall and temperature changed over my region in recent decades?
Draw a rectangle, then check which collections cover it. Most NASA data is global, so a big box matches a lot.
74, 18 → 80, 22 (Marathwada, Maharashtra)Rainfall is how much water fell on the ground over some period. Temperature is how warm the air was, measured a couple of metres above the surface. This question asks a plain thing. Over the last few decades, has your region been getting wetter or drier, hotter or cooler? And is that change real, or just normal year-to-year wobble?
How have rainfall and temperature changed over my region in recent decades?
Rainfall is how much water fell on the ground over some period. Temperature is how warm the air was, measured a couple of metres above the surface. This question asks a plain thing. Over the last few decades, has your region been getting wetter or drier, hotter or cooler? And is that change real, or just normal year-to-year wobble?
Which data to use, and how
Use this dataset: ERA5 reanalysis. A reanalysis is a best-guess weather record. Scientists take every observation they have (weather stations, balloons, satellites) and blend it with a physics model to produce one consistent gridded history of the whole planet, hour by hour, going back to 1980. ERA5 gives you both things you want here in one place: 2 m air temperature and total precipitation (rainfall). It’s the easiest start because you reach it through Google Earth Engine, with no files to download and no login juggling.
For rainfall specifically, you’ll later cross-check against a second, independent dataset, CHIRPS (rainfall built mostly from satellites plus rain gauges). If two datasets built in totally different ways agree, you trust the answer more.
Then do four steps (the runnable code further down does all of this — this is just the idea):
- Pick your region (a latitude/longitude box around it) and the years you care about (at least ~10).
- One number per year. Average the temperature (or add up the rainfall) inside your box for each year. That gives you a yearly time series.
- Fit a trend and test it. Draw the long-term line through those yearly points and check it’s bigger than the random year-to-year noise. Up = warming or wetter, down = cooling or drier, flat = no real change.
- Cross-check the rainfall. Repeat the rainfall trend with CHIRPS and see if it agrees with ERA5.
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
- Whether rainfall or temperature has changed over your region across recent decades. You get a robust long-term slope (a Theil–Sen slope, a way of fitting a line that ignores wild outliers) with a Mann–Kendall significance test (a check of whether the change is real and not luck) and a 95% confidence interval.
- A second opinion on rainfall. The precipitation trend computed two independent ways, ERA5 vs CHIRPS, so you can see whether they agree.
- The honest “nothing happened” answer. “No significant trend” is a real, useful result here, not a failure. Several of the demo regions land exactly there.
What it can’t tell you
- Whether humans caused it. Showing a region warmed is not the same as proving why. Saying “this is human-caused, not natural variability” needs a formal method called detection-and-attribution, far beyond a single trend line.
- Extreme days or short bursts. This is annual (or seasonal: JJAS for the monsoon, DJF for winter) trend analysis, not extreme-event statistics. It won’t tell you about the worst single storm or heatwave.
- Anything over too few years. A trend over less than ~10 years is untrustworthy. Too few points to fit a reliable slope. The tool here refuses spans that short on purpose.
Gotchas to watch for
- A reanalysis is a model, not raw truth. ERA5 is a physics model fed by observations, so over a data-sparse region it can drift from reality. That’s why you cross-check rainfall against CHIRPS: two methods, two error patterns. If they disagree sharply, trust neither blindly.
- You need enough years, or the slope is noise. Climate wobbles a lot from year to year. A “trend” over a short window is mostly that wobble, not a real signal. The minimum ~10-year span is the simplest fix, and the validator enforces it.
- Pick the right season. A whole-year average can hide a real change that lives in one season. A monsoon (June–September, JJAS) might shift while winter stays flat. If you care about the monsoon, run the trend on JJAS rainfall, not the annual total.
- “Flat” is a finding, not a bug. If your trend comes back not significant, that is a genuine result (an earned null). Don’t keep tweaking the box until you force a trend to appear. That’s fooling yourself.
The real-data code
The Run it cell above runs the method on synthetic data (no login). Below is the whole recipe against the real climate record through Google Earth Engine: pull ERA5, area-average per year, fit a robust trend, test it, cross-check the rainfall against CHIRPS, and plot it. It needs a free Earth Engine account.
import ee, numpy as np, pymannkendall as mk
import matplotlib.pyplot as plt
ee.Initialize()
aoi = ee.Geometry.Rectangle([74, 18, 80, 22]) # (W, S, E, N) — Marathwada, Maharashtra
years = list(range(1980, 2021)) # >= ~10 yr or the slope is just noise
# 1. One number per year, area-averaged over the box, straight off Earth Engine.
# ERA5 monthly: 2 m air temperature (K) + total precipitation (m), summed to mm/yr.
era5 = ee.ImageCollection("ECMWF/ERA5/MONTHLY")
def era5_year(y):
yr = era5.filterDate(f"{y}-01-01", f"{y}-12-31").filterBounds(aoi)
t = (yr.select("mean_2m_air_temperature").mean() # annual-mean temperature
.reduceRegion(ee.Reducer.mean(), aoi, 27830).get("mean_2m_air_temperature"))
p = (yr.select("total_precipitation").sum().multiply(1000) # m -> mm, summed over year
.reduceRegion(ee.Reducer.mean(), aoi, 27830).get("total_precipitation"))
return ee.Feature(None, {"t": t, "p": p})
rows = ee.FeatureCollection([era5_year(y) for y in years]).getInfo()["features"]
temp = np.array([r["properties"]["t"] for r in rows]) - 273.15 # K -> degC
rain = np.array([r["properties"]["p"] for r in rows])
# 2. Cross-check rainfall with CHIRPS (satellite + gauge), built a totally different way.
chirps = ee.ImageCollection("UCSB-CHG/CHIRPS/DAILY")
def chirps_year(y):
s = chirps.filterDate(f"{y}-01-01", f"{y}-12-31").filterBounds(aoi).sum()
return ee.Feature(None, {"p": s.reduceRegion(ee.Reducer.mean(), aoi, 5566).get("precipitation")})
crows = ee.FeatureCollection([chirps_year(y) for y in years]).getInfo()["features"]
rain_chirps = np.array([r["properties"]["p"] for r in crows])
# 3. Robust trend + significance for each series (Theil-Sen slope + Mann-Kendall test).
def trend(label, series, unit):
r = mk.original_test(series)
word = ("rising" if r.slope > 0 else "falling") if r.h else "flat"
print(f"{label}: {word} {r.slope:+.3f} {unit}/yr, p={r.p:.3f}",
"(significant)" if r.h else "(an earned null — not distinguishable from noise)")
return r
rt = trend("ERA5 temperature", temp, "degC")
rp = trend("ERA5 rainfall ", rain, "mm")
rc = trend("CHIRPS rainfall ", rain_chirps, "mm")
agree = (rp.slope > 0) == (rc.slope > 0)
print("Rainfall cross-check: ERA5 and CHIRPS",
"AGREE on direction" if agree else "DISAGREE — trust neither blindly")
# 4. Plot both series with their Theil-Sen lines.
x = np.array(years)
fig, ax = plt.subplots(2, 1, figsize=(8, 6), sharex=True)
ax[0].plot(x, temp, ".-"); ax[0].plot(x, rt.intercept + rt.slope * (x - x[0]), "k--")
ax[0].set_ylabel("2 m temp (degC)")
ax[1].plot(x, rain, ".-", label="ERA5"); ax[1].plot(x, rain_chirps, ".-", label="CHIRPS")
ax[1].plot(x, rc.intercept + rc.slope * (x - x[0]), "k--")
ax[1].set_ylabel("rainfall (mm/yr)"); ax[1].set_xlabel("year"); ax[1].legend()
plt.tight_layout(); plt.show()
# Trust it only if ERA5 and CHIRPS agree on rainfall direction — a reanalysis is a model,
# not raw truth, so two independent products disagreeing means trust neither (see gotchas).
Where the data comes from
Everything runs through Google Earth Engine, so there are no NASA files to download for this one. ERA5 (and the finer-resolution ERA5-Land) come from ECMWF, Europe’s weather centre. CHIRPS, the independent rainfall cross-check, comes from the UCSB Climate Hazards Center in the United States. Three different institutions, blended into one notebook, which is the whole point of the cross-check.
Verified answers
Real ERA5 trends, computed on Google Earth Engine and shown verbatim below. Most regional rainfall trends are statistically flat (an earned null), while Indo-Gangetic-Plain temperature shows significant warming. These are computed, not yet scientist-verified. Draw your own area of interest and download the notebook to reproduce the method for your region.
Make it yours → Draw your area of interest, choose annual or seasonal windows and the year range, and switch ERA5↔CHIRPS for the rainfall cross-check.
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.
Computed · real data Worked examples, computed end-to-end on real satellite data — not yet scientist-verified · expand ▾
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.
The data doesn't support a rainfall change here — an earned null, not a missing answer.
Prior: IMD/IPCC consensus: India land-surface warming ~0.6-0.7C/century, accelerating.
The data doesn't support a rainfall change here — an earned null, not a missing answer.
The data doesn't support a rainfall change here — an earned null, not a missing answer.
The data doesn't support a rainfall change here — an earned null, not a missing answer.
The data doesn't support a rainfall change here — an earned null, not a missing answer.
The data doesn't support a rainfall change here — an earned null, not a missing answer.
Prior: IMD/IPCC consensus: India land-surface warming.
The data doesn't support a rainfall change here — an earned null, not a missing answer.
Prior: IMD/IPCC consensus: India land-surface warming.
The data doesn't support a rainfall change here — an earned null, not a missing answer.
Prior: IMD/IPCC consensus: India land-surface warming.
The data doesn't support a rainfall change here — an earned null, not a missing answer.
Prior: IMD/IPCC consensus: India land-surface warming.
The data doesn't support a rainfall change here — an earned null, not a missing answer.
Prior: IMD/IPCC consensus: India land-surface warming.
The data doesn't support a rainfall change here — an earned null, not a missing answer.
Prior: IMD/IPCC consensus: India land-surface warming.
The data doesn't support a rainfall change here — an earned null, not a missing answer.
Prior: IMD/IPCC consensus: India land-surface warming.
Prior: IMD/IPCC consensus: India land-surface warming.
The data doesn't support a rainfall change here — an earned null, not a missing answer.
The data doesn't support a temperature change here — an earned null, not a missing answer.
Prior: IMD/IPCC consensus: India land-surface warming.
The data doesn't support a rainfall change here — an earned null, not a missing answer.
Prior: IMD/IPCC consensus: India land-surface warming.
The data doesn't support a land-surface temperature change here — an earned null, not a missing answer.
Prior: urban heat island + regional warming.
Prior: coastal city; warming likely but sea-moderated.
The data doesn't support a land-surface temperature change here — an earned null, not a missing answer.
Prior: rapid urban growth + heat island.
The data doesn't support a land-surface temperature change here — an earned null, not a missing answer.
Prior: coastal metro; warming likely but sea-moderated.
Prior: rapid urban growth + heat island.
Prior: dense delta metro; warming likely.
Prior: semi-arid city + heat island.
Prior: fast-growing city + heat island.
Prior: well-documented NW India groundwater depletion (Rodell et al. 2009).
Prior: NW India groundwater depletion.
Prior: Indian Ocean among the fastest-warming basins.
Prior: Indian Ocean rapid warming.
The data doesn't support a night-lights (VIIRS) change here — an earned null, not a missing answer.
Prior: urban growth + electrification.
Prior: urban growth.
The data doesn't support a night-lights (VIIRS) change here — an earned null, not a missing answer.
Prior: rapid tech-city growth.
The data doesn't support a night-lights (VIIRS) change here — an earned null, not a missing answer.
Prior: urban growth.
Prior: rural electrification across the plain.
…and what it refuses to answer
trend span < 10y — the validator refuses ill-posed questions rather than guessing. That discipline is the point.
unresolved region name — the validator refuses ill-posed questions rather than guessing. That discipline is the point.
answer temperature and precipitation separately — the validator refuses ill-posed questions rather than guessing. That discipline is the point.
the satellite NO2 record (TROPOMI, 2018+) is only ~6 years -- too short to honestly call a decadal trend. OMI reaches 2004 but is not in this GEE pipeline. Refuse rather than mislead. — the validator refuses ill-posed questions rather than guessing. That discipline is the point.