Every number on the dashboard, explained for a skeptical reader
Rainfall→food-price transmission is crop- and district-specific: tomato prices answer to Kolar and the Chittoor belt, onion prices to the Nashik belt. A national or state rainfall average mixes signal with irrelevance. MonsoonMandi's unit of analysis is a curated crop supply basin — an editorial construct (not an official administrative boundary) defined as the district cluster that feeds a set of reference wholesale markets.
Each basin is a named district cluster with 2–3 rainfall sample coordinates
(approximate district centroids, averaged). Definitions are versioned configuration
(config/basins.json, config/crops.json), not code — every change is visible in the
repository history. Current coverage: 9 basins across 5 crops (onion, tomato, potato, soyabean, tur/arhar).
Prices are queried per (commodity, district) from the official Agmarknet feed, so a basin's price evidence is whatever its districts' mandis actually reported that day. Reporting is uneven: the dashboard always shows how many mandis contributed and never extrapolates a national price from them.
ERA5 reanalysis via the Open-Meteo archive and forecast APIs. These are model-reanalysis values, not official IMD gauge figures — the two differ by a few percentage points. We label this basis everywhere. (IMD's own API requires a key with no documented public issuance path; if one is obtained, it can slot in as the primary source.) Recent days use the forecast API's actuals to cover the ~5-day reanalysis lag; the 7-day outlook is a forecast and is never presented as observation.
All basins track the SW monsoon (Jun 1–Sep 30). The southern tomato belts (Kolar, Chittoor–Annamayya) additionally track the NE monsoon (Oct 1–Dec 31), which delivers much of their rainfall — each with its own 1991–2020 climatology, per-year curves and analogs. A basin's active season is the window containing today, else its most recently completed window; every metric, analog and event is computed against the basin's own season. NE-season events carry distinct permanent URLs.
The baseline is a 30-year (1991–2020) climatology computed once per basin from the same ERA5 source and stored permanently — including every individual year's cumulative curve, which powers percentile ranks and analog seasons. It is not recomputed unless the methodology changes.
The Government of India's Agmarknet "Current Daily Price" resource on data.gov.in (modal/min/max wholesale price, ₹ per quintal). The upstream feed is a same-day snapshot with no history endpoint, so MonsoonMandi accumulates its own daily panel — collection started 2026-08-24, and series depth grows every day. Historical rows are never mutated by later runs.
Arrival quantities (tonnes reaching each mandi) would strengthen the causal chain (rainfall → arrivals → price), but no free, machine-readable, regularly updated arrivals source has been identified yet. Arrivals are therefore reported as missing — a first-class state — and the stress score renormalizes without them rather than pretending.
Basin rainfall = mean of the basin's sample points, daily. Crop price = median of modal prices across contributing mandis on the latest reported date, with dispersion (IQR as % of median) shown when at least 4 mandis report. The national strip is a plain average across live basins — labeled "basin-weighted", never presented as an all-India figure. Two price-context metrics use the multi-year backfill for the crop's primary district: a historical percentile (today's district median vs the same ±7-day calendar window in each of the last 10 seasons — nominal rupees, so the lookback is capped to limit inflation drift) and a 90-day baseline deviation (vs the trailing 90-day district median, inflation-immune). The 7-day rainfall outlook also carries an improving/stable/deteriorating label vs the climatological week — a forecast classification, never an observation.
Every source can be ok / partial / failed / missing / stale. A failed source
degrades to the last good data with a visible staleness banner; it never blanks the page and never
invents values. The data-status line in the footer reports each source's state for the current build.
A transparent weighted composite, per crop: rainfall severity (season deviation, full
score at −50%), rainfall persistence (share of the last 30 days below the daily normal), historical
extremeness (percentile of the season-to-date total among 1991–2020 seasons), price stress (week-over-week
median change, full score at +30%), forecast stress (7-day outlook vs the climatological next-7-days),
spatial extent (share of the crop's basins in deficit ≤ −10%), and arrivals (currently missing). Weights
live in config/weights.json; missing components are dropped and remaining weights renormalized;
every score exposes its component contributions and what was missing. Labels: 0–19 Minimal, 20–39 Low,
40–59 Moderate, 60–74 High, 75–89 Very High, 90–100 Extreme.
Each basin chart shows the driest and wettest seasons since 1991 as reference trajectories, and each basin's current season is ranked as a percentile among the 30 climatology years. Analogs are descriptive: "similar conditions occurred in year X" — never "this will happen again". Richer analog matching (trajectory similarity, subsequent price paths) requires multi-year price history, which is still accumulating.
Each crop carries an editorial lag window (e.g. tomato 7–21 days, onion 21–60 days) based on crop cycles and storage characteristics — labeled as estimates. Statistical lag estimation from our own panel begins only when enough seasons of joined data exist; we will not publish fitted lags from insufficient samples.
Before any narrative, the pipeline classifies whether the observed pattern is even consistent with a weather story: rainfall stress + rising prices (consistent), rainfall stress + falling prices (inconsistent — says so), price spikes on normal rainfall (unexplained by weather — says so), localized stress + steady prices (substitution possible). Statements are tagged observed / derived / likely / possible / insufficient-evidence, and the engine fails closed: missing evidence produces "insufficient evidence", never a stronger claim.
A curated substitution map lists each crop's alternate tracked basins and — honestly —
its untracked buffers (imports, cold storage, regions we don't model). The substitution assessment
classifies stress as localized (less-stressed regions may offset), multi-basin/systemic, or absent, always
"based on available evidence". The India Crop Supply Stress Index is a weighted average of
crop stress scores (weights in config, shown with every reading), published only when at least 4 crops have
scores. It is not a CPI forecast. Basin definitions carry editorial confidence ratings and their
methodology sources in config/basins.json.
Hindsight Mode reconstructs the dashboard for any monsoon week since 2009 using only data available on that date — rainfall through the day, prices observed on or before it. Two components are honestly irreconstructible (the 7-day forecast as issued that day, and arrivals, which never had a source), so replay stress scores renormalize over the rest and label what's missing. The track record then grades the signal mechanically: every weekly replay date is bucketed by its stress score, and the district price ~8 weeks later is tallied — hits and misses both published, buckets under 15 samples withheld. The observed gradient is real but modest; that is the honest shape of a rainfall signal on a many-cause price system, and it is presented as association, never prediction.
Rainfall is one driver among many (stocks, trade policy, fuel, festivals, procurement). MonsoonMandi describes whether observed patterns are consistent with weather-driven supply stress and shows the evidence; it does not claim causation, does not forecast prices, and is not advice.
Rainfall: Open-Meteo (CC-BY 4.0, attribution required). Prices: data.gov.in (GODL-India open license, attribution required). When reusing exports, cite both sources and MonsoonMandi as the compiler. Suggested citation text is available via the "Copy citation" button on each crop card.