qin6·intermediate

Is my region shifting from one crop a year to two or three?

biosphereagriculturelandfood-security Datasets: 4 15–30 min

When a field is planted, it turns green as the crop grows, then browns off at harvest. That's one full "green wave" per crop. Satellites measure greenness from orbit as a number called NDVI. Count how many green waves a place goes through in a year and you know whether it grows one crop, two, or three. When that count climbs over the years, farmers and economists call it intensification.

Is my region shifting from one crop a year to two or three?

When a field is planted, it turns green as the crop grows, then browns off at harvest. That’s one full “green wave” per crop. Satellites measure greenness from orbit as a number called NDVI. Count how many green waves a place goes through in a year and you know whether it grows one crop, two, or three. When that count climbs over the years, farmers and economists call it intensification.

Which data to use, and how

Use this dataset: MODIS MOD13Q1 (short name MOD13Q1), a greenness (NDVI/EVI) snapshot taken every 16 days at 250 m going back to 2000. The long record and ready-made greenness numbers make it the easiest place to start. If your fields are small and crowded together, swap in the sharper HLS (HLSS30 / HLSL30) at 30 m later, but start coarse.

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 years you care about.
  2. Get the green wave. For each pixel, line up its NDVI readings through the year into a time series, and smooth out the jitter from clouds and noise.
  3. Count the waves per year. Each green-up-then-brown-off bump above a greenness cutoff counts as roughly one crop. One bump is single-cropping, two is double, three is triple.
  4. Watch the count over time. Track cycles-per-year across the record and map where it’s rising. Up means adding crop seasons (intensifying); flat means no change.

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

  • How many crops per year your region grows: single, double, or triple cropping, from counted NDVI cycles.
  • Whether intensity is rising over time, by finding where cycles-per-year are climbing across the record.
  • A map of intensification showing which sub-regions added a growing season.
  • The crop calendar: when each green-up and harvest happens through the year.
  • Coarse vs fine: the MODIS 250 m trend compared with sharper HLS 30 m for fragmented fields.

What it can’t tell you

  • Which crop is actually grown. NDVI cycles count seasons, not species. Wheat, rice, and sugarcane all just look like “green.” To name the crop, pair this with crop-type maps or ground truth.
  • Exact field boundaries (at MODIS scale). A 250 m pixel is bigger than many smallholder plots, so it blends several fields together. For sharp boundaries drop to HLS/Sentinel-2 at 30 m.
  • Whether the water came from irrigation or rain. A second green wave suggests irrigation or leftover soil moisture, but it doesn’t prove the source. You need extra water/irrigation data for that.
  • Yield or total production. Counting crops tells you how often a field is farmed (intensity), not how much it produced. For output, combine with yield models and census data.

Gotchas to watch for

  • One pixel can cover several fields (mixed pixels). At 250 m, a single MODIS pixel may blend fields on different planting calendars, smearing the green waves together or double-counting them, so your crop count comes out blurry. For fragmented smallholder landscapes, drop to HLS at 30 m.
  • Forests and grass green up too. Natural vegetation turns green and brown on its own schedule, producing NDVI cycles that aren’t crops and inflating your count. Mask to cropland with a land-cover map before you start counting.
  • Clouds punch holes in the record. During the monsoon (the kharif growing season) heavy cloud hides the ground and thins the data, and a real green wave can vanish into the gap. Smooth and gap-fill the series, and lean on the built-in quality flag (pixel-reliability QA) that marks dodgy readings.
  • The cutoffs are knobs, not laws. The greenness threshold and the minimum bump size (prominence) you use to call something “a crop” depend on the crop and region, so numbers borrowed from elsewhere will mis-count. Calibrate them against a local crop calendar rather than trusting one fixed value.
  • Check the result against the census. Before claiming a region really shifted from one crop to two, cross-check your trend with the agricultural census / district crop statistics. If they disagree, trust the ground data and re-examine the code.

The real-data code

The Run it cell above runs this method on synthetic data with no login. Below is the whole recipe against the real archive: search MOD13Q1, open the NDVI grids, count green-wave cycles per pixel per year, trend cycles-per-year over the record, and plot it. It needs a free Earthdata Login.

import earthaccess, numpy as np, xarray as xr
from scipy.signal import savgol_filter, find_peaks
import matplotlib.pyplot as plt

earthaccess.login(strategy="netrc")

aoi = (74, 29.5, 77, 32)     # your region as (W, S, E, N) — here, Punjab
years = range(2010, 2025)

# Greenness / amplitude rules — tune and verify against a local crop calendar.
ndvi_threshold = 0.4    # a peak must exceed this to count as a crop cycle
min_prominence = 0.15   # min NDVI rise/fall so noise isn't counted as a crop

def cycles_per_year(ndvi_1d):
    """Count crop cycles in one year's (time-ordered) NDVI series."""
    s = savgol_filter(ndvi_1d, window_length=5, polyorder=2)
    peaks, _ = find_peaks(s, height=ndvi_threshold, prominence=min_prominence)
    return len(peaks)

# 1. Search MOD13Q1 (16-day NDVI, 250 m) across the whole year range, then open
#    each granule's NDVI grid (scale 1e-4) and screen with pixel-reliability QA.
def ndvi_stack(y):
    grans = earthaccess.search_data(
        short_name="MOD13Q1", bounding_box=aoi,
        temporal=(f"{y}-01-01", f"{y}-12-31"))
    frames = []
    for fh in earthaccess.open(grans):
        ds = xr.open_dataset(fh, engine="rasterio")  # HDF-EOS subdatasets
        ndvi = ds["_250m_16_days_NDVI"].squeeze() * 1e-4
        qa = ds["_250m_16_days_pixel_reliability"].squeeze()
        frames.append(ndvi.where(qa == 0))           # 0 = good data
    return xr.concat(frames, dim="time").sortby("time")

# 2. Count cycles per pixel per year -> a (year, y, x) intensity cube.
intensity = []
for y in years:
    cube = ndvi_stack(y).interpolate_na("time").bfill("time").ffill("time")
    n = xr.apply_ufunc(cycles_per_year, cube, input_core_dims=[["time"]],
                       vectorize=True, dask="allowed")
    intensity.append(n)
intensity = xr.concat(intensity, dim=xr.DataArray(list(years), dims="year"))

# 3. Trend: regress cycles-per-year vs year per pixel; positive slope = shifting
#    toward double/triple cropping. Region mean gives the headline verdict.
yr = np.array(list(years), float)
mean_int = intensity.mean(dim=("y", "x"))
slope = np.polyfit(yr, mean_int.values, 1)[0]
verdict = "intensifying" if slope > 0.02 else "stable"
print(f"Punjab cropping intensity: {mean_int.values[0]:.2f} -> "
      f"{mean_int.values[-1]:.2f} crops/yr, slope {slope:+.3f}/yr ({verdict})")

# 4. Plot the regional cropping-intensity trend.
plt.plot(yr, mean_int.values, "o-")
plt.ylabel("mean crops / year"); plt.xlabel("year")
plt.title("Cropping intensity trend"); plt.tight_layout(); plt.show()

# Before you trust it: mask to cropland (forest/grass green up too) and cross-check
# the trend against the district agricultural census (see the gotchas above).

Where the data comes from

The whole core workflow comes from NASA through one free login (Earthdata Login). The MODIS greenness (MOD13) and the sharper HLS data both live at the LP DAAC archive, so there’s a single sign-in to manage. The only extra piece is an optional cropland mask (a national land-cover map) to screen out forest and grass, which may come from a separate source.

Sources

How a scientist answers this
Parameters
Vegetation-index time series (MODIS MOD13 NDVI/EVI, 16-day, 250 m, 2000–present; or HLS/Sentinel-2 at 30 m for smaller fields). Each NDVI green-up → peak → senescence cycle within a year corresponds roughly to one crop, so the number of cycles per year is the cropping intensity (single / double / triple), and its change over years is the trend you want.
Method
Build the per-pixel NDVI/EVI time series, smooth out noise and cloud gaps (e.g. Savitzky–Golay or a temporal composite), then count the green-up/senescence cycles per crop-year that exceed a greenness threshold and a minimum amplitude — one peak ≈ one crop. Track the cycle count year over year and map where intensity is rising (1→2→3 crops). Use a relative amplitude/persistence rule rather than one fixed NDVI value so it travels across regions and sensors.
Validation
At MODIS 250 m a pixel often mixes several smallholder fields, blurring or double-counting cycles — drop to HLS/Sentinel-2 30 m for fragmented landscapes. Separate crops from natural vegetation (forest/grassland also green up) using cropland masks, distinguish irrigated double-cropping from rain-fed single seasons, and cross-check the intensity trend against the agricultural census / district crop statistics before claiming a shift.
In plain EnglishEach time a field turns green and then browns off, that's roughly one crop. Counting those green waves per year tells you whether a place grows one, two, or three crops — and watching that count climb over the years shows intensification.

Make it yours → Pick your region and year range, set the greenness threshold and smoothing, and the notebook counts crop cycles per year and maps the change. Switch from MODIS 250 m to HLS 30 m when fields are small.

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

A safe place to practise the method on MOD13Q1. 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 growing-season greenness (NDVI) over Punjab changed since 2003?
greenness (NDVI) Punjab 2003–2022
+0.003 NDVI (trend) significant trend
95% CI [0.002, 0.004] Mann–Kendall p = 0.0001
computed · ERA5/GEE · not yet scientist-verified
Has growing-season greenness (NDVI) over the Indo-Gangetic Plain changed since 2003?
greenness (NDVI) Indo-Gangetic Plain 2003–2022
+0.003 NDVI (trend) significant trend
95% CI [0.001, 0.003] Mann–Kendall p = 0
computed · ERA5/GEE · not yet scientist-verified
Has growing-season greenness (NDVI) over Marathwada changed since 2003?
greenness (NDVI) Marathwada 2003–2022
+0.003 NDVI (trend) significant trend
95% CI [0.001, 0.005] Mann–Kendall p = 0.0032
computed · ERA5/GEE · not yet scientist-verified
Has growing-season greenness (NDVI) over Gujarat changed since 2003?
greenness (NDVI) Gujarat 2003–2022
+0.003 NDVI (trend) significant trend
95% CI [0.002, 0.004] Mann–Kendall p = 0.0001
computed · ERA5/GEE · not yet scientist-verified
Has growing-season greenness (NDVI) over Madhya Pradesh changed since 2003?
greenness (NDVI) Madhya Pradesh 2003–2022
+0.003 NDVI (trend) significant trend
95% CI [0.002, 0.005] Mann–Kendall p = 0.0001
computed · ERA5/GEE · not yet scientist-verified
Has growing-season greenness (NDVI) over Tamil Nadu changed since 2003?
greenness (NDVI) Tamil Nadu 2003–2022
+0.002 NDVI (trend) significant trend
95% CI [0, 0.004] Mann–Kendall p = 0.0252
computed · ERA5/GEE · not yet scientist-verified

See all verified answers →