Crop Calendars datasets - Rwema25/AE-project GitHub Wiki

1. AgMIP-GGCMI Crop Calendar

This crop calendar is a foundational input for global crop modeling, enabling harmonized and reproducible assessments of climate change impacts on agriculture.

Overview

Attribute Description
Short Description The AgMIP-GGCMI Crop Calendar is a global dataset providing multi-year average planting (sowing) and maturity (harvest) dates for 18 major crops, distinguishing between rainfed and irrigated systems, at 0.5° spatial resolution. It is a composite product merging various observational data sources and is designed to support harmonized crop modeling and climate impact assessments.
Provider/Source AgMIP (Agricultural Model Intercomparison and Improvement Project) and GGCMI (Global Gridded Crop Model Intercomparison), led by institutions including NASA GISS, Potsdam Institute for Climate Impact Research, University of Minnesota, and University of Goettingen.
Homepage/Link Zenodo Dataset
License/Terms of Use Open for research and non-commercial use; cite original sources as appropriate.
Spatial Coverage Global, 0.5° x 0.5° land grid cells.
Temporal Coverage Multi-year average (static growing periods; no interannual variability).
Spatial Resolution 0.5° x 0.5° latitude/longitude.
Temporal Resolution One growing season per crop per grid cell (with exceptions for wheat and rice).
Key Variables Planting day of year (DOY), maturity (harvest) day of year (DOY) for 18 crops, with separate values for rainfed and irrigated systems.
18 crops covered The 18 crops covered in the AgMIP-GGCMI Crop Calendar are: 1. Maize, 2. Wheat (including winter and spring wheat), 3. Rice (including two main growing seasons), 4. Soybean, 5. Barley, 6. Millet, 7. Rapeseed, 8. Rye, 9. Sorghum, 10. Sugar beet, 11. Sugar cane, 12. Cotton, 13. Cassava, 14. Groundnut, 15. Field pea, 16. Sunflower, 17. Dry bean, 18. Potato.

Data Access and Format

Attribute Description
Access Methods Download from Zenodo; source code and tools available on GitHub.
Data Formats NetCDF (.nc), CSV, and R data objects.
Data Organization Organized by crop, grid cell, and management system (rainfed/irrigated); one growing season per crop/cell, except for wheat and rice (multiple seasons).
Potential Challenges Static averages only; no crop rotations or interannual variability; gap-filling and spatial extrapolation in areas lacking observations.

Technical Details

Attribute Description
File Naming Conventions Typically includes crop name, management system, and phase (e.g., maize_rainfed_phase3.nc).
Variable Names & Units Planting_day (DOY), Maturity_day (DOY); units are day of year (1–365/366).
Coordinate Systems Latitude and longitude in WGS 84 datum; grid cell centers.
Data Processing Composite of multiple observational sources; spatial extrapolation and gap-filling for uncultivated or missing areas; only a single season per crop/cell except for wheat and rice.
Handling Missing Data Gap-filled using best available sources; uncultivated areas extrapolated.

API Information

API Availability Description
Direct API No direct API.
Programmatic Access Data and scripts available for download and batch processing via Zenodo and GitHub; R scripts provided for simulation and adaptation of crop calendars.

Relevance for Agroecological Research

Application/Strength/Limitation Description
Potential Applications
- Calibration of crop model phenology (e.g., heat unit/PHU requirements)
- Harmonization of growing periods for multi-model crop simulations and climate impact studies
- Assessment of climate change impacts on crop timing and yields at regional to global scales
- Scenario development for adaptation strategies by simulating changes in planting/harvest dates
Strengths
- Consistent, global, crop-specific growing periods for 18 major crops
- Distinguishes between rainfed and irrigated systems
- Supports harmonized, reproducible crop modeling and climate impact research
Limitations
- Provides static (multi-year average) growing periods only; no annual variability or crop rotations
- Extrapolated data in areas with sparse observations; users should check data quality for their region of interest

Further Resources

Resource Type Description/Link
User Guides/Documentation Zenodo Dataset Documentation; GitHub Repository for Scripts.
Primary Publication Jägermeyr et al. (2021), "Climate impacts on global agriculture emerge earlier in new generation of climate and crop," Nature Food, DOI.
Additional Studies Minoli et al. (2022), "Global crop yields can be lifted by timely adaptation of growing periods to climate change," Nature Communications, DOI.
Community/Support Contact dataset authors via Zenodo or institutional affiliations listed in the dataset record.

2. Jägermeyr Crop Calendar

This crop calendar dataset provides globally gridded, multi-crop planting and maturity dates, serving as a key input for harmonized global crop modeling and climate impact assessments.

Overview

Attribute Description
Short Description The Jägermeyr Crop Calendar is a global dataset offering multi-year average planting (sowing) and maturity (harvest) dates for 18 major crops, distinguishing rainfed and irrigated systems at 0.5° spatial resolution. It is a composite product merging multiple observational sources, with gap-filling and spatial extrapolation to cover cultivated and uncultivated areas. Designed primarily for global gridded crop model intercomparison and climate impact studies.
Provider/Source Developed by Jonas Jägermeyr and collaborators, hosted by AgMIP-GGCMI (Agricultural Model Intercomparison and Improvement Project - Global Gridded Crop Model Intercomparison) with contributions from institutions including the Potsdam Institute for Climate Impact Research and NASA GISS.
Homepage/Link Zenodo Dataset
License/Terms of Use Open for research and non-commercial use; users should cite original publications appropriately.
Spatial Coverage Global land areas at 0.5° x 0.5° grid cells.
Temporal Coverage Multi-year average (static growing periods; no interannual variability).
Spatial Resolution 0.5° latitude/longitude grid cells.
Temporal Resolution One growing season per crop per grid cell, except for wheat (winter and spring) and rice (two main seasons).
Key Variables Planting day of year (DOY), maturity (harvest) day of year (DOY), separated by rainfed and irrigated management.
Crops Covered 18 crops: maize, wheat (winter and spring), rice (two seasons), soybean, barley, millet, rapeseed, rye, sorghum, sugar beet, sugar cane, cotton, cassava, groundnut, field pea, sunflower, dry bean, potato.

Data Access and Format

Attribute Description
Access Methods Download via Zenodo; source code and modeling scripts available on GitHub.
Data Formats NetCDF (.nc), CSV, and R data objects.
Data Organization Data organized by crop, grid cell, and management system (rainfed/irrigated); includes one growing season per crop per cell except for wheat and rice with multiple seasons.
Potential Challenges Static averages only, no representation of crop rotations or year-to-year variability; spatial extrapolation and gap-filling applied in regions lacking observations.

Technical Details

Attribute Description
File Naming Conventions Filenames typically include crop name, management system, and growth phase (e.g., maize_rainfed_phase3.nc).
Variable Names & Units Planting_day (DOY), Maturity_day (DOY); units are day of year (1–365/366).
Coordinate Systems Latitude and longitude in WGS 84 datum, grid cell centers.
Data Processing Composite product derived by merging multiple observational sources, with gap-filling and spatial extrapolation for uncultivated or data-sparse areas.
Handling Missing Data Missing data gap-filled using best available sources; uncultivated areas extrapolated based on neighboring data.

API Information

API Availability Description
Direct API No direct API available.
Programmatic Access Data and scripts can be downloaded for batch processing from Zenodo and GitHub. R scripts support simulation and adaptation of crop calendars.

Relevance for Agroecological Research

Application/Strength/Limitation Description
Potential Applications - Calibration of crop model phenology (e.g., heat unit requirements)
- Harmonization of growing periods for multi-model crop simulations and climate impact assessments
- Evaluation of climate change impacts on crop timing and yields at regional to global scales
- Development of adaptation scenarios via simulation of altered planting and harvest dates
Strengths - Globally consistent, crop-specific growing periods for 18 major crops
- Differentiates rainfed and irrigated systems
- Supports reproducible, harmonized global crop modeling and climate impact research
Limitations - Static multi-year averages only; no interannual variability or crop rotations
- Spatial extrapolation in data-poor regions may reduce local accuracy; users should verify data quality for their area of interest

Further Resources

Resource Type Description/Link
User Guides/Documentation Zenodo Dataset Documentation; GitHub Repository for Scripts
Primary Publication Jägermeyr et al. (2021), "Climate impacts on global agriculture emerge earlier in new generation of climate and crop," Nature Food, DOI
Additional Studies Minoli et al. (2022), "Global crop yields can be lifted by timely adaptation of growing periods to climate change," Nature Communications, DOI
Community/Support Contact dataset authors via Zenodo or institutional affiliations listed in the dataset record

3. MIRCA-OS (Monthly Irrigated and Rainfed Cropped Area, Open Source)

The MIRCA-OS dataset is a valuable resource for agroecological research, providing detailed spatial and temporal crop area information essential for modeling and monitoring agricultural systems globally.

Overview

Attribute Description
Short Description MIRCA-OS is a global, open-source dataset providing monthly irrigated and rainfed cropped area maps for 23 crop classes at 5-arcminute (~10 km) spatial resolution for the years 2000, 2005, 2010, and 2015. It combines subnational crop-specific harvested area statistics with global gridded land cover and crop calendar data to produce monthly growing area grids and annual harvested area maps.
Provider/Source Developed by an international team led by researchers associated with AgMIP and global land use modeling groups.
Homepage/Link MIRCA-OS Dataset Description (Nature Scientific Data)
License/Terms of Use Open for research and non-commercial use; citation of original dataset recommended.
Spatial Coverage Global (180°W to 180°E longitude, 90°S to 90°N latitude).
Temporal Coverage Years 2000, 2005, 2010, and 2015.
Spatial Resolution 5 arcminutes (approx. 10 km x 10 km); also annual maps at 0.5° resolution.
Temporal Resolution Monthly growing area grids representing crop growth stages from planting to maturity.
Key Variables Monthly growing area (ha) for irrigated and rainfed systems, annual harvested area (ha), crop calendars (planting and maturity months).
23 crops covered The 23 major crops covered in the MIRCA-OS dataset, with distinctions for irrigated and rainfed systems, are: 1. Barley, 2. Cassava (Tapioca), 3. Cocoa, 4. Coffee, 5. Cotton, 6. Fodder (Alfalfa; grasses and legumes; clover; hay; haylage), 7. Groundnuts (Peanuts), 8. Maize (Corn, including grain, silage, sweet corn, popcorn), 9. Millet (Pearl millet; finger millet; small millet), 10. Oil palm, 11. Potatoes, 12. Pulses (Chickpeas; pigeon peas; cowpeas; peas, beans; lentils; other pulses), 13. Rapeseed (Canola; mustard), 14. Rice (Paddy), 15. Rye, 16. Sugar beet, 17. Sugar cane, 18. Sorghum (grain and silage), 19. Soybeans, 20. Sunflower, 21. Wheat (spring soft wheat; winter soft wheat; durum), 22. Other perennials (e.g., almonds, apples, bananas, citrus fruits, grapes, olives, etc.), 23. Other annuals (various crops not listed above)

Data Access and Format

Attribute Description
Access Methods Download via HydroShare, GitHub (code), and journal supplementary materials.
Data Formats GeoTIFF and NetCDF for spatial data; CSV for crop calendars.
Data Organization Organized by crop, year, irrigation system (irrigated/rainfed), and month; includes monthly growing area grids, maximum monthly growing area maps, and annual harvested area maps.
Potential Challenges Large file sizes; requires GIS or scientific programming tools to process (e.g., Python with xarray, R, QGIS).

Technical Details

Attribute Description
File Naming Conventions Format includes crop name, sub-crop number (for multiple cropping), year, irrigation system, and version (e.g., MIRCA-OS_Rice1_2015_ir_v0.1.nc).
Variable Names & Units Growing area or harvested area in hectares (ha). Monthly layers numbered 1–12 represent January to December.
Coordinate Systems Longitude/latitude in WGS84 datum.
Data Processing Combines subnational harvested area statistics with global land cover and crop calendars; downscaled to 5-arcminute grids using area weighting and cropping calendars; gap-filling and mosaicking applied.
Handling Missing Data Areas with no crop presence assigned zero; gap-filling based on regional statistics and land cover.

API Information

API Availability Description
Direct API No dedicated API available.
Programmatic Access Data and processing scripts available on GitHub; datasets downloadable for use in GIS and programming environments.

Relevance for Agroecological Research

Application/Strength/Limitation Description
Potential Applications:
- Mapping spatial and temporal distribution of crop areas for yield modeling and food security assessments
- Differentiating irrigated and rainfed cropping systems in climate impact and water resource studies
- Supporting crop phenology and cropping intensity analyses
- Input for crop models requiring spatially explicit cropped area and calendar information
Strengths:
- High spatial (5 arcminutes) and temporal (monthly) resolution
- Covers 23 major crops with irrigated and rainfed distinctions
- Combines statistical and remote sensing data for improved accuracy
Limitations:
- Temporal coverage limited to four years (2000, 2005, 2010, 2015)
- Static within each year, no interannual variability
- Requires technical skills to process large spatial datasets

Further Resources

Resource Type Description/Link
User Guides/Documentation Nature Scientific Data Article describing dataset and methodology.
Code Repository MIRCA-OS GitHub Repository with data processing scripts.
Dataset Download HydroShare MIRCA-OS Dataset
Community/Support Contact dataset authors via GitHub or corresponding publication.

4. WorldCereal Project Crop Calendars

WorldCereal crop calendars are a foundational input for global crop mapping and monitoring, enabling harmonized and reproducible assessments of crop seasonality and supporting operational agricultural monitoring at scale.

Overview

Attribute Description
Short Description The WorldCereal Project Crop Calendars provide global, season-specific maps of the start (SOS) and end (EOS) of the growing seasons for key temporary crops, initially focusing on maize and wheat. These calendars are essential for global crop mapping and monitoring, supporting the generation of high-resolution, seasonally updated crop type and irrigation maps.
Provider/Source WorldCereal Consortium (funded by the European Space Agency, ESA)
Homepage/Link WorldCereal Project
Global crop calendars of maize and wheat (figshare)
License/Terms of Use Open and free for research and operational use under Creative Commons Attribution 4.0 License.
Spatial Coverage Global, with stratification into agro-ecological zones (AEZs).
Temporal Coverage Currently available for 2021 (Phase I); designed for seasonal and annual updates.
Spatial Resolution 0.5° x 0.5° latitude/longitude grid (approx. 50 km at equator); crop type maps at 10 m resolution.
Temporal Resolution Seasonally updated; provides start and end dates for each major growing season per crop.
Key Variables Start of Season (SOS), End of Season (EOS) for maize and wheat (winter and spring cereals); future versions will include additional crops (sunflower, rapeseed, millet, sorghum, barley, rye, soybean).

Data Access and Format

Attribute Description
Access Methods Download from figshare dataset page (includes gridded SOS/EOS maps and documentation); additional products and documentation available on the WorldCereal website.
Data Formats NetCDF, GeoTIFF, and CSV for spatial data; PDF and web documentation.
Data Organization Organized by crop, season (winter cereals, main maize, secondary maize), and grid cell; maps provided globally at 0.5° resolution.
Potential Challenges Currently focused on maize and wheat; spatial resolution of crop calendars is coarser (0.5°) than crop type maps (10 m); future versions will expand crop and temporal coverage.

Technical Details

Attribute Description
File Naming Conventions Files typically include crop, season, and variable (e.g., SOS_maize_main_2021.tif).
Variable Names & Units SOS (start of season), EOS (end of season); units are day-of-year (1–365/366).
Coordinate Systems Latitude/longitude (WGS84 datum) for gridded data; crop type maps use UTM or geographic coordinates.
Data Processing Crop calendars are generated by merging national/subnational calendars (GEOGLAM, USDA-FAS, FAO, ASAP) and training a spatially aware Random Forest model using ERA5 climate data to estimate SOS/EOS at each grid cell. This enables stratification into zones with similar growing seasons for crop mapping.
Handling Missing Data In areas lacking source data, crop calendars are simulated using climate and geographic predictors; quality flags and confidence layers are provided.

API Information

API Availability Description
Direct API No dedicated API for crop calendars.
Programmatic Access Data downloadable via figshare and WorldCereal website; can be integrated into GIS and remote sensing workflows using standard geospatial libraries.

Relevance for Agroecological Research

Application/Strength/Limitation Description
Potential Applications
- Crop-type mapping and monitoring at global and regional scales
- Crop condition monitoring, yield estimation, and forecasting
- Agroecological zoning and adaptation scenario development
- Supporting operational crop monitoring systems and early warning
- Input for crop models and remote sensing analysis
Strengths
- Combines multiple authoritative sources and machine learning for robust, spatially explicit crop calendars
- Season-specific, global coverage for maize and wheat, with future expansion to more crops
- Supports high-resolution (10 m) crop type and irrigation mapping
Limitations
- Currently limited to maize and wheat (expansion ongoing)
- Crop calendars at 0.5° resolution, which may be coarse for local studies
- Simulated data in regions with sparse observational input; users should review confidence layers

Further Resources

Resource Type Description/Link
User Guides/Documentation WorldCereal Final Report (PDF)
ESSD Data Descriptor Article
Dataset Download figshare: Global crop calendars of maize and wheat
Community/Support Contact via WorldCereal website or through project partners.

Rainfall-Based Seasonality Detection

Accurately detecting the onset and duration of rainy seasons is essential for effective agricultural planning, water resource management, and assessing climate impacts. Traditional calendar-based definitions of rainy seasons often fall short because they do not account for local variability or year-to-year fluctuations in rainfall patterns. This limitation highlights the need for objective, data-driven methods that leverage rainfall time series to characterize seasonality more precisely.

Key aspects to identify in rainfall time series include:

  • Onset of the rainy season: The point at which rainfall begins to increase consistently, signaling the start of the wet period.
  • Cessation of the rainy season: When rainfall declines or stops, marking the end of the wet season.
  • Length and intensity of rainy periods: The duration and magnitude of rainfall events that define the overall seasonality.

Possible Detection Approaches

Several methodological approaches exist to detect the onset, duration, and cessation of rainy seasons from rainfall time series data. The main approaches include:

Approach Description Relevant R Packages
Threshold-based methods Define rainfall thresholds (e.g., cumulative rainfall over a set number of days) to identify the start and end of rainy seasons. Simple and widely used in hydrological studies. hydroTSM (seasonality index), custom threshold scripts
Change point detection Use statistical techniques to detect significant shifts or changes in rainfall patterns, such as abrupt increases or decreases in rainfall intensity or frequency. changepoint, bfast
Time series decomposition Separate rainfall data into trend, seasonal, and residual components using methods like STL (Seasonal-Trend decomposition using Loess), enabling clearer identification of seasonal cycles and anomalies. stats (base R stl()), seas
Machine learning or signal processing methods Employ advanced algorithms to recognize complex patterns in rainfall data, including clustering, classification, or neural networks, to detect seasonality and rainfall events. These methods can capture nonlinearities and interactions beyond traditional statistics. prophet, TSclust, caret

Each approach offers distinct advantages and can be selected based on data availability, complexity, and study objectives. Threshold methods provide a straightforward implementation, while change point and decomposition methods offer more nuanced detection of seasonality. Machine learning approaches are promising for large datasets and complex climatic regions but require more computational resources and expertise.

Notes on packages

  • hydroTSM includes functions like si() to compute seasonality index from rainfall data.

  • changepoint and bfast are popular for detecting structural changes (breakpoints) in time series.

    • bfast decomposes time series into trend, seasonal, and remainder components and detects breaks in each.
    • changepoint provides various statistical methods to identify change points in mean or variance.
  • Base R’s stl() function (in the stats package) is widely used for seasonal-trend decomposition of time series.

  • seas is specialized for seasonal analysis in hydrology and ecology.

  • prophet (by Facebook) is a powerful tool for time series forecasting and seasonality detection, capable of handling multiple seasonalities and trend changes.

  • TSclust and caret support clustering and machine learning workflows on time series data, useful for more advanced pattern recognition and classification tasks.

Threshold-Based Methods

Threshold-based methods are among the simplest and most widely used approaches to detect the onset and cessation of rainy seasons. These methods define specific rainfall criteria, such as cumulative rainfall over a certain number of days or a minimum daily rainfall threshold, to objectively determine when the rainy season starts and ends.

As applied in previous literature:

Term Definition References
Onset Date (OD) The first period of five consecutive days accumulating at least 25 mm of rainfall, with the first day and at least two others having rainfall ≥ 1 mm, and no dry spell (rainfall < 1 mm) lasting 7 days or more in the following 30 days. Adelekan & Adegebo (2014); Mugo et al. (2016); Camberlin et al. (2009); Haleakala et al. (2018); Recha et al. (2012); Rwema et al. (2025)
Cessation Date (CD) The first day when the accumulated rainfall over ten consecutive days is less than half of the corresponding potential evapotranspiration (PET). Kijazi & Reason (2012) ; Sebaziga et al. (2024)
Season Length (SL) The number of days between the onset and cessation dates, calculated by subtracting OD from CD for each year. Gebremichael et al. (2014); Haleakala et al. (2018)

The modified Hargreaves formula for PET is given by: Here is a display math formula:

$$ \text{PET} = 0.00102 \times R_a \times \left(T_{\max} - T_{\min} - 0.0123 \times R\right)^{0.76} \times (T + 17) $$

where

  • $(R_a)$ is extraterrestrial radiation $(MJ m^{-2} day^{-1})$
  • $(T_{\max})$, $(T_{\min})$ are maximum and minimum air temperatures (°C)
  • $(R)$ is rainfall (mm)
  • $(T)$ is mean air temperature (°C)

We used tabulated Ra values from FAO56 Table 2.6

Onset Detection for a Single Year (1983): Code and Results

The following R code demonstrates how to detect the onset dates of the long and short rainy seasons for the year 1983 using our defined rainfall and dry spell criteria.

# --- Step 1: Load necessary libraries ---
library(readr)   # For reading CSV files
library(dplyr)   # For data manipulation
library(zoo)     # For rolling sums

# --- Step 2: Import your dataset ---
# Replace "climatedataset.csv" with your actual file path if needed
rain_data <- read_csv("climatedataset.csv")

# --- Step 3: Convert 'Date' column to Date class ---
# Assuming Date is in YYYYMMDD format like 19830101
rain_data$Date <- as.Date(as.character(rain_data$Date), format = "%Y%m%d")

# --- Step 4: Check data loaded correctly ---
head(rain_data)

# --- Step 5: Filter data for the year of interest (e.g., 1983) ---
year_of_interest <- 1983
rain_year <- rain_data %>% filter(format(Date, "%Y") == as.character(year_of_interest))

# --- Step 6: Define the precise onset detection function ---
detect_onset_precise <- function(rainfall, 
                                 onset_cum_threshold = 25, 
                                 onset_window = 5, 
                                 min_rainy_days = 3,  # including first day
                                 min_first_day_rain = 1,
                                 dry_threshold = 1,
                                 max_dry_spell_length = 6,  # less than 7 days allowed
                                 dry_spell_check_days = 30) {
  n <- length(rainfall)
  rolling_sum <- zoo::rollapply(rainfall, width = onset_window, FUN = sum, align = "left", fill = NA)
  
  for (i in 1:(n - onset_window - dry_spell_check_days + 1)) {
    # Check cumulative rainfall in 5-day window
    if (!is.na(rolling_sum[i]) && rolling_sum[i] >= onset_cum_threshold) {
      window_rain <- rainfall[i:(i + onset_window - 1)]
      
      # Check first day rainfall >= 1 mm
      if (window_rain[1] < min_first_day_rain) {
        next  # skip this window
      }
      
      # Check at least two other days (besides first) with rainfall >= 1 mm
      rainy_days_other <- sum(window_rain[-1] >= min_first_day_rain)
      if (rainy_days_other < (min_rainy_days - 1)) {
        next  # skip this window
      }
      
      # Check dry spell in the next 30 days after the 5-day window
      dry_period <- rainfall[(i + onset_window):(i + onset_window + dry_spell_check_days - 1)]
      
      # Find lengths of consecutive dry days (< 1 mm)
      rle_dry <- rle(dry_period < dry_threshold)
      
      # Check if any dry spell length >= 7 days
      if (any(rle_dry$values == TRUE & rle_dry$lengths >= 7)) {
        next  # reject this window due to long dry spell
      }
      
      # If all criteria met, return index of first day of onset
      return(i)
    }
  }
  return(NA)  # no onset detected
}

# --- Step 7: Define function to detect onset within a date range ---
detect_onset_period <- function(data, start_date, end_date) {
  period_data <- data %>% filter(Date >= start_date & Date <= end_date)
  onset_idx <- detect_onset_precise(period_data$Rainfall)
  if (!is.na(onset_idx)) {
    return(period_data$Date[onset_idx])
  } else {
    return(NA)
  }
}

# --- Step 8: Define rainy season periods for bimodal climate ---
long_rains_start <- as.Date(paste0(year_of_interest, "-03-01"))
long_rains_end <- as.Date(paste0(year_of_interest, "-06-30"))

short_rains_start <- as.Date(paste0(year_of_interest, "-09-01"))
short_rains_end <- as.Date(paste0(year_of_interest, "-12-31"))

# --- Step 9: Detect long rains onset ---
long_rains_onset <- detect_onset_period(rain_year, long_rains_start, long_rains_end)

# --- Step 10: Detect short rains onset ---
short_rains_onset <- detect_onset_period(rain_year, short_rains_start, short_rains_end)

# --- Step 11: Print results ---
cat("Year:", year_of_interest, "\n")
cat("Long rains onset:", ifelse(is.na(long_rains_onset), "No onset detected", as.character(long_rains_onset)), "\n")
cat("Short rains onset:", ifelse(is.na(short_rains_onset), "No onset detected", as.character(short_rains_onset)), "\n")

## Inspect rainfall data for March–June 1983

library(ggplot2)

ggplot(rain_year %>% filter(Date >= long_rains_start & Date <= long_rains_end), aes(x = Date, y = Rainfall)) +
  geom_col(fill = "blue") +
  labs(title = "Rainfall March-June 1983", y = "Daily Rainfall (mm)")

#Inspect rainfall data for September-December 1983

library(ggplot2)

ggplot(rain_year %>% filter(Date >= short_rains_start & Date <= short_rains_end), aes(x = Date, y = Rainfall)) +
  geom_col(fill = "blue") +
  labs(title = "Rainfall September-December 1983", y = "Daily Rainfall (mm)")

#Inspect rainfall data for the whole year 1983

library(ggplot2)
library(dplyr)

# Assuming rain_year is your filtered data for the year 1983
# If not filtered yet, filter as:
# rain_year <- rain_data %>% filter(format(Date, "%Y") == "1983")

# Plot daily rainfall for the whole year
ggplot(rain_year, aes(x = Date, y = Rainfall)) +
  geom_col(fill = "blue") +
  labs(title = paste("Daily Rainfall for Year", unique(format(rain_year$Date, "%Y"))),
       x = "Date",
       y = "Rainfall (mm)") +
  theme_minimal() +
  scale_x_date(date_breaks = "1 month", date_labels = "%b") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

The output below shows the detected onset dates for the long and short rainy seasons in 1983 based on the applied criteria.

> cat("Year:", year_of_interest, "\n")
Year: 1983 
> cat("Long rains onset:", ifelse(is.na(long_rains_onset), "No onset detected", as.character(long_rains_onset)), "\n")
Long rains onset: No onset detected 
> cat("Short rains onset:", ifelse(is.na(short_rains_onset), "No onset detected", as.character(short_rains_onset)), "\n")
Short rains onset: 1983-10-07

Onset Detection for the dataset (1983-2021): Code and Results

Below is the complete R script to detect the onset dates of the long and short rainy seasons for each year from 1983 to 2021, using a precise rainfall and dry spell definition. The code processes the daily rainfall data, applies the onset detection criteria, and outputs a clean summary of onset dates for both seasons.

# --- Load libraries ---
library(readr)
library(dplyr)
library(zoo)

# --- Import your dataset ---
rain_data <- read_csv("climatedataset.csv")
rain_data$Date <- as.Date(as.character(rain_data$Date), format = "%Y%m%d")

# --- Define onset detection function as per your precise criteria ---
detect_onset_precise <- function(rainfall, 
                                 onset_cum_threshold = 25, 
                                 onset_window = 5, 
                                 min_rainy_days = 3,  # including first day
                                 min_first_day_rain = 1,
                                 dry_threshold = 1,
                                 max_dry_spell_length = 6,  # less than 7 days allowed
                                 dry_spell_check_days = 30) {
  n <- length(rainfall)
  rolling_sum <- zoo::rollapply(rainfall, width = onset_window, FUN = sum, align = "left", fill = NA)
  
  for (i in 1:(n - onset_window - dry_spell_check_days + 1)) {
    if (!is.na(rolling_sum[i]) && rolling_sum[i] >= onset_cum_threshold) {
      window_rain <- rainfall[i:(i + onset_window - 1)]
      if (window_rain[1] < min_first_day_rain) next
      rainy_days_other <- sum(window_rain[-1] >= min_first_day_rain)
      if (rainy_days_other < (min_rainy_days - 1)) next
      
      dry_period <- rainfall[(i + onset_window):(i + onset_window + dry_spell_check_days - 1)]
      rle_dry <- rle(dry_period < dry_threshold)
      if (any(rle_dry$values == TRUE & rle_dry$lengths >= 7)) next
      
      return(i)
    }
  }
  return(NA)
}

# --- Function to detect onset within a period for one year ---
detect_onset_period <- function(data, start_date, end_date) {
  period_data <- data %>% filter(Date >= start_date & Date <= end_date)
  onset_idx <- detect_onset_precise(period_data$Rainfall)
  if (!is.na(onset_idx)) {
    return(period_data$Date[onset_idx])
  } else {
    return(NA)
  }
}

# --- Years to analyze ---
years <- 1983:2021

# --- Initialize results dataframe ---
results <- data.frame(
  Year = integer(),
  LongRainsOnset = as.Date(character()),
  ShortRainsOnset = as.Date(character()),
  stringsAsFactors = FALSE
)

# --- Loop over years ---
for (yr in years) {
  rain_year <- rain_data %>% filter(format(Date, "%Y") == as.character(yr))
  
  long_rains_start <- as.Date(paste0(yr, "-03-01"))
  long_rains_end <- as.Date(paste0(yr, "-06-30"))
  short_rains_start <- as.Date(paste0(yr, "-09-01"))
  short_rains_end <- as.Date(paste0(yr, "-12-31"))
  
  long_onset <- detect_onset_period(rain_year, long_rains_start, long_rains_end)
  short_onset <- detect_onset_period(rain_year, short_rains_start, short_rains_end)
  
  results <- rbind(results, data.frame(
    Year = yr,
    LongRainsOnset = long_onset,
    ShortRainsOnset = short_onset
  ))
}

# --- View results ---
print(results)

# Optional: save results to CSV
# write.csv(results, "rainy_season_onsets_1983_2021.csv", row.names = FALSE)

The table below summarizes the detected onset dates for the long and short rainy seasons from 1983 to 2021 based on the applied rainfall and dry spell criteria.

print(results)
   Year LongRainsOnset ShortRainsOnset
1  1983           <NA>      1983-10-07
2  1984           <NA>      1984-11-06
3  1985     1985-03-19            <NA>
4  1986     1986-04-10      1986-10-26
5  1987     1987-05-02      1987-10-16
6  1988     1988-03-15            <NA>
7  1989           <NA>            <NA>
8  1990     1990-03-04      1990-10-17
9  1991           <NA>            <NA>
10 1992           <NA>            <NA>
11 1993     1993-04-14      1993-11-01
12 1994           <NA>      1994-10-07
13 1995           <NA>      1995-10-30
14 1996     1996-03-06      1996-09-05
15 1997     1997-03-15      1997-10-21
16 1998     1998-03-03      1998-10-13
17 1999     1999-03-10      1999-11-02
18 2000           <NA>      2000-10-20
19 2001     2001-03-15      2001-09-18
20 2002     2002-03-03      2002-09-21
21 2003     2003-03-18      2003-10-12
22 2004     2004-03-05      2004-10-22
23 2005           <NA>            <NA>
24 2006     2006-03-07      2006-10-20
25 2007     2007-03-14      2007-10-03
26 2008           <NA>            <NA>
27 2009     2009-03-01      2009-10-05
28 2010           <NA>      2010-10-06
29 2011     2011-04-03            <NA>
30 2012     2012-04-19      2012-10-24
31 2013     2013-03-18      2013-11-20
32 2014           <NA>      2014-11-11
33 2015           <NA>            <NA>
34 2016           <NA>            <NA>
35 2017           <NA>      2017-11-10
36 2018     2018-03-01      2018-10-17
37 2019           <NA>      2019-09-27
38 2020     2020-03-01      2020-10-17
39 2021     2021-03-16      2021-09-15

Cessation Detection for a Single Year (1983): Code and Results

The following R code demonstrates how to detect the cessation dates of the long and short rainy seasons for the year 1983 using our defined criteria.

# --- Load necessary libraries ---
library(readr)
library(dplyr)
library(zoo)

# --- Import your dataset ---
# Replace "climatedataset.csv" with the correct path to your file
rain_data <- read_csv("climatedataset.csv")

# --- Convert 'Date' column to Date class ---
rain_data$Date <- as.Date(as.character(rain_data$Date), format = "%Y%m%d")

# --- Add Month column for Ra assignment ---
rain_data <- rain_data %>%
  mutate(Month = as.integer(format(Date, "%m")))

# --- Create Ra lookup table for Kigali (approximate FAO56 values at 0° latitude) ---
ra_lookup <- data.frame(
  Month = 1:12,
  Ra = c(36.2, 37.5, 37.9, 36.8, 34.8, 33.4, 33.9, 35.7, 37.2, 37.4, 36.3, 35.6)  # MJ m-2 day-1
)

# --- Join Ra values by Month ---
rain_data <- rain_data %>%
  left_join(ra_lookup, by = "Month")

# --- Calculate mean temperature and PET ---
rain_data <- rain_data %>%
  mutate(
    Tmean = (Tmax + Tmin) / 2,
    temp_diff = pmax(Tmax - Tmin - 0.0123 * Rainfall, 0),
    PET = 0.00102 * Ra * (temp_diff)^0.76 * (Tmean + 17)
  )

# --- Calculate rolling 10-day rainfall sum (including current day) ---
rain_data <- rain_data %>%
  arrange(Date) %>%
  mutate(
    Rainfall_10d = rollapply(Rainfall, width = 10, FUN = sum, align = "right", fill = NA, na.rm = TRUE)
  )

# --- Mark cessation candidate days where 10-day rainfall < 0.5 * PET ---
rain_data <- rain_data %>%
  mutate(
    CessationCandidate = ifelse(Rainfall_10d < 0.5 * PET, TRUE, FALSE)
  )

# --- Define cessation detection function for a given period ---
detect_cessation_period <- function(data, start_date, end_date) {
  period_data <- data %>% filter(Date >= start_date & Date <= end_date)
  cessation_days <- period_data %>% filter(CessationCandidate == TRUE)
  
  if (nrow(cessation_days) == 0) {
    return(NA)  # No cessation detected in this period
  }
  
  # Return earliest cessation candidate date (customize logic if needed)
  return(min(cessation_days$Date))
}

# --- Apply cessation detection for year 1983 ---

year_of_interest <- 1983

# Define bimodal rainy season periods for 1983
long_rains_start <- as.Date(paste0(year_of_interest, "-03-01"))
long_rains_end   <- as.Date(paste0(year_of_interest, "-06-30"))

short_rains_start <- as.Date(paste0(year_of_interest, "-09-01"))
short_rains_end   <- as.Date(paste0(year_of_interest, "-12-31"))

# Detect cessation dates
cessation_long <- detect_cessation_period(rain_data, long_rains_start, long_rains_end)
cessation_short <- detect_cessation_period(rain_data, short_rains_start, short_rains_end)

# Print results
cat("Year:", year_of_interest, "\n")
cat("Long rains cessation:", ifelse(is.na(cessation_long), "No cessation detected", as.character(cessation_long)), "\n")
cat("Short rains cessation:", ifelse(is.na(cessation_short), "No cessation detected", as.character(cessation_short)), "\n")

##for visualisation

library(ggplot2)

# Filter data for long rains period in 1983
long_rains_data <- rain_data %>%
  filter(Date >= long_rains_start & Date <= long_rains_end)

ggplot(long_rains_data, aes(x = Date)) +
  geom_col(aes(y = Rainfall), fill = "blue", alpha = 0.6) +
  geom_line(aes(y = PET), color = "red", size = 1) +
  geom_vline(xintercept = as.numeric(cessation_long), linetype = "dashed", color = "darkgreen") +
  labs(title = "Long Rains 1983: Rainfall, PET and Cessation",
       y = "Rainfall (mm) / PET (MJ m-2 day-1)") +
  theme_minimal()

library(ggplot2)

# Filter data for short rains period in 1983
short_rains_data <- rain_data %>%
  filter(Date >= short_rains_start & Date <= short_rains_end)

ggplot(short_rains_data, aes(x = Date)) +
  geom_col(aes(y = Rainfall), fill = "blue", alpha = 0.6) +
  geom_line(aes(y = PET), color = "red", size = 1) +
  geom_vline(xintercept = as.numeric(cessation_short), linetype = "dashed", color = "darkgreen") +
  labs(title = "Short Rains 1983: Rainfall, PET and Cessation",
       y = "Rainfall (mm) / PET (MJ m-2 day-1)",
       x = "Date") +
  theme_minimal()

library(ggplot2)
library(dplyr)

# Filter data for the year of interest, e.g., 1983
year_of_interest <- 1983
rain_year <- rain_data %>% filter(format(Date, "%Y") == as.character(year_of_interest))

# Plot daily Rainfall as bars and PET as a red line over the whole year
ggplot(rain_year, aes(x = Date)) +
  geom_col(aes(y = Rainfall), fill = "blue", alpha = 0.6) +
  geom_line(aes(y = PET), color = "red", size = 1) +
  labs(title = paste("Daily Rainfall and PET for Year", year_of_interest),
       y = "Rainfall (mm) / PET (MJ m⁻² day⁻¹)",
       x = "Date") +
  theme_minimal() +
  scale_x_date(date_breaks = "1 month", date_labels = "%b") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

The output below shows the detected cessation dates for the long and short rainy seasons in 1983 based on the applied criteria.

cat("Year:", year_of_interest, "\n")
Year: 1983 
> cat("Long rains cessation:", ifelse(is.na(cessation_long), "No cessation detected", as.character(cessation_long)), "\n")
Long rains cessation: 1983-03-12 
> cat("Short rains cessation:", ifelse(is.na(cessation_short), "No cessation detected", as.character(cessation_short)), "\n")
Short rains cessation: 1983-09-01 

Cessation Detection for the dataset (1983-2021): Code and Results

Below is the complete R script to detect the cessation dates of the long and short rainy seasons for each year from 1983 to 2021, using the provided definition.

# --- Load necessary libraries ---
library(readr)
library(dplyr)
library(zoo)
library(ggplot2)
library(tidyr)

# --- Step 1: Import your dataset ---
rain_data <- read_csv("climatedataset.csv")
rain_data$Date <- as.Date(as.character(rain_data$Date), format = "%Y%m%d")

# --- Step 2: Prepare data ---
rain_data <- rain_data %>%
  mutate(
    Year = as.integer(format(Date, "%Y")),
    Month = as.integer(format(Date, "%m"))
  )

# --- Step 3: Assign extraterrestrial radiation (Ra) for Kigali ---
ra_lookup <- data.frame(
  Month = 1:12,
  Ra = c(36.2, 37.5, 37.9, 36.8, 34.8, 33.4, 33.9, 35.7, 37.2, 37.4, 36.3, 35.6)  # MJ m-2 day-1
)

rain_data <- rain_data %>%
  left_join(ra_lookup, by = "Month")

# --- Step 4: Calculate PET ---
rain_data <- rain_data %>%
  mutate(
    Tmean = (Tmax + Tmin) / 2,
    temp_diff = pmax(Tmax - Tmin - 0.0123 * Rainfall, 0),
    PET = 0.00102 * Ra * (temp_diff)^0.76 * (Tmean + 17)
  )

# --- Step 5: Calculate rolling 10-day rainfall sum ---
rain_data <- rain_data %>%
  arrange(Date) %>%
  group_by(Year) %>%
  mutate(
    Rainfall_10d = rollapply(Rainfall, width = 10, FUN = sum, align = "right", fill = NA, na.rm = TRUE)
  ) %>%
  ungroup()

# --- Step 6: Mark cessation candidate days ---
rain_data <- rain_data %>%
  mutate(
    CessationCandidate = ifelse(Rainfall_10d < 0.5 * PET, TRUE, FALSE)
  )

# --- Step 7: Define cessation detection function ---
detect_cessation_period <- function(data, start_date, end_date) {
  period_data <- data %>% filter(Date >= start_date & Date <= end_date)
  cessation_days <- period_data %>% filter(CessationCandidate == TRUE)
  if (nrow(cessation_days) == 0) return(NA)
  return(min(cessation_days$Date))
}

# --- Step 8: Loop over years to detect cessation for bimodal seasons ---
years <- unique(rain_data$Year)
results <- data.frame(
  Year = integer(),
  LongRainsCessation = as.Date(character()),
  ShortRainsCessation = as.Date(character()),
  stringsAsFactors = FALSE
)

for (yr in years) {
  long_start <- as.Date(paste0(yr, "-03-01"))
  long_end <- as.Date(paste0(yr, "-06-30"))
  short_start <- as.Date(paste0(yr, "-09-01"))
  short_end <- as.Date(paste0(yr, "-12-31"))
  
  data_year <- rain_data %>% filter(Year == yr)
  
  long_cessation <- detect_cessation_period(data_year, long_start, long_end)
  short_cessation <- detect_cessation_period(data_year, short_start, short_end)
  
  results <- rbind(results, data.frame(
    Year = yr,
    LongRainsCessation = long_cessation,
    ShortRainsCessation = short_cessation
  ))
}

# --- Step 9: Print summary of cessation dates ---
print(results)

The table below summarizes the detected cessation dates for the long and short rainy seasons from 1983 to 2021 based on the definition we defined before.

 print(results)
   Year LongRainsCessation ShortRainsCessation
1  1983         1983-03-12          1983-09-01
2  1984         1984-03-27          1984-09-06
3  1985         1985-03-08          1985-09-01
4  1986         1986-03-26          1986-09-01
5  1987         1987-03-06          1987-09-01
6  1988         1988-05-31          1988-09-08
7  1989         1989-03-04          1989-09-11
8  1990         1990-05-04          1990-09-01
9  1991         1991-03-07          1991-09-01
10 1992         1992-03-04          1992-09-01
11 1993         1993-05-16          1993-09-01
12 1994         1994-04-08          1994-09-01
13 1995         1995-05-23          1995-09-01
14 1996         1996-05-08          1996-10-15
15 1997         1997-05-27          1997-09-10
16 1998         1998-05-25          1998-12-09
17 1999         1999-05-10          1999-09-22
18 2000         2000-05-23          2000-09-01
19 2001         2001-05-18          2001-09-01
20 2002         2002-05-26          2002-09-01
21 2003         2003-03-14          2003-09-05
22 2004         2004-05-13          2004-09-01
23 2005         2005-04-06          2005-09-01
24 2006         2006-05-28          2006-09-06
25 2007         2007-03-12          2007-09-01
26 2008         2008-05-02          2008-09-05
27 2009         2009-03-21          2009-09-01
28 2010         2010-03-16          2010-09-01
29 2011         2011-03-03          2011-09-08
30 2012         2012-03-14          2012-09-06
31 2013         2013-05-20          2013-09-01
32 2014         2014-03-08          2014-09-09
33 2015         2015-03-13          2015-09-01
34 2016         2016-03-10          2016-09-01
35 2017         2017-04-17          2017-09-01
36 2018         2018-06-14                <NA>
37 2019         2019-03-26          2019-09-12
38 2020         2020-05-26          2020-09-01
39 2021         2021-04-01          2021-09-11

Evaluation of Top Three Rain-Based Seasonal Detection Methods

Introduction

In evaluating rain-based seasonal detection methods, it is essential to consider criteria that reflect both scientific rigor and practical applicability. Key factors include the types of input variables required, the generalizability of the method across diverse climatic and soil conditions, and the extent to which the method has been adopted by major institutions and operational projects globally. It is important to balance methodological sophistication with feasibility, especially in data-limited contexts, while also ensuring that the approach aligns with real-world agricultural decision-making needs. This evaluation focuses on three representative methods that span this spectrum, from simple rainfall thresholds to integrated soil moisture models and advanced satellite vegetation indices, providing a comprehensive overview of their strengths, limitations, and institutional relevance.

1. Rainfall Threshold Method (FAO Approach)

  • Input Variables: Daily rainfall only.
  • Generalizability:
    • Regional: Hard-coded parameters (e.g., "25mm in first dekad, 20mm in next two") limit global applicability.
    • Soil Blindness: Ignores soil properties (e.g., drainage in sandy vs. clay soils), reducing accuracy in heterogeneous regions.
  • Institutional Adoption:
    • High: FAO’s standard method for agrometeorological bulletins and seasonal maps.
    • Approach Type: Heuristic, rule-based method using fixed rainfall thresholds.
    • Strengths: Low technical barriers, ideal for resource-limited regions.
    • Weaknesses: Fails in climate-variable zones; no evaporation/temperature integration.
  • Documentation: FAO Handbook (2019).

2. Soil Moisture-Integrated Approach

  • Input Variables: Rainfall, soil type, temperature, evapotranspiration.
  • Generalizability:
    • Moderate-High: Accounts for soil water-holding capacity (e.g., sand vs. clay) and climate.
    • Adaptability: Adjustable parameters for regional calibration (e.g., using SoilGrids data).
  • Institutional Adoption:
    • Moderate: World Bank projects (e.g., East Africa climate-smart agriculture); not yet FAO-adopted.
    • Approach Type: Model-based, incorporating soil water balance and climate variables.
    • Strengths: Reflects actual planting conditions; superior to rainfall-only methods.
    • Weaknesses: Requires soil data and local calibration.
  • Documentation:

3. Vegetation Index-Driven Method (NDVI/MVDI)

  • Input Variables: Satellite vegetation indices (NDVI/PRI), rainfall, temperature.
  • Generalizability:
    • High: Tracks actual plant "green-up" via satellite; applicable globally.
    • Strength: Less noise from dry spells; captures phenology (e.g., growing season length).
  • Institutional Adoption:
    • Emerging: NASA/ESA projects (e.g., MODIS VI); limited operational use in agriculture.
    • Approach Type: Model-based using remote sensing to track vegetation phenology.
    • Strengths: Direct biomass monitoring; large-scale suitability.
    • Weaknesses: Cloud cover disrupts data; technical capacity required.
  • Documentation:

Comparative Summary

Method Input Variables Approach Type Generalizability Institutional Adoption Strengths Limitations
Rainfall Threshold Rainfall only Heuristic (rule-based) Regional; parameters often hard-coded for specific climates and soils High (FAO widely used) Simple, low data needs, easy to implement Limited transferability; ignores soil and temp
Soil Moisture-Integrated Rainfall + soil + climate Model-based Moderate-High; adaptable with soil and climate data Moderate (World Bank projects) More accurate; accounts for soil water retention Requires soil data and calibration; moderate complexity
Vegetation Index (MVDI) Satellite vegetation indices + climate Model-based High; applicable globally via remote sensing Emerging (NASA/ESA) Captures actual plant phenology; large-scale monitoring Cloud cover issues; technical and data intensive

Recommendations

  1. Tiered Implementation:

    • Resource-Limited: FAO rainfall threshold (simple, low-cost).
    • Data-Rich Regions: Soil moisture method (balanced accuracy/feasibility).
    • Advanced Monitoring: NDVI/MVDI for research/policy (e.g., climate adaptation).
  2. Validation Protocol:

    • Ground-truth methods using farmer-reported planting dates.

References

Investigation on NDVI Data Access

Normalized Difference Vegetation Index (NDVI) data is a valuable resource for monitoring vegetation health and phenology, widely used in agricultural and environmental applications. Accessing NDVI data for specific locations or regions can be done through several common sources and tools, including satellite products and cloud-based platforms.

Common NDVI Data Sources:

  • MODIS Satellite Products (NASA)
    MODIS provides global NDVI data at moderate spatial and temporal resolutions. It is freely available and widely used for vegetation monitoring.
    Documentation and access: MODIS Vegetation Indices (NASA)

  • Sentinel-2 (ESA)
    Sentinel-2 offers high-resolution multispectral imagery, including bands suitable for NDVI calculation. It is ideal for finer-scale vegetation analysis.
    Information: Sentinel-2 Overview (ESA)

  • Google Earth Engine (GEE) APIs
    GEE provides a powerful cloud computing platform with access to a vast archive of satellite imagery, including MODIS, Sentinel-2, Landsat, and others. It enables extraction of NDVI time series for points or regions via APIs.
    Tutorials and API docs:

Tools and Packages for NDVI Extraction:

  • MODISTools (R package)
    Facilitates downloading and processing MODIS NDVI data directly within R for user-defined locations.
    CRAN page: MODISTools

  • rgee (R interface to Google Earth Engine)
    Provides an R interface to the GEE platform, allowing users to run GEE scripts and extract NDVI data programmatically.
    GitHub repository and documentation: rgee

NDVI Datasets Available in Google Earth Engine

Google Earth Engine (GEE) provides access to several high-quality NDVI datasets derived from different satellite platforms, enabling global vegetation monitoring at various spatial and temporal resolutions.

Common NDVI Datasets in GEE

  • MODIS Vegetation Indices (MOD13 series)
    The MOD13 products provide 16-day and monthly NDVI composites at 250m to 1km resolution. These are widely used for global vegetation monitoring and are available as:

  • Landsat Series (e.g., Landsat 8 OLI)
    Landsat provides higher spatial resolution (30m) multispectral imagery, from which NDVI can be calculated on demand. Suitable for detailed local and regional analyses.
    Example GEE collection: LANDSAT/LC08/C02/T1_TOA
    More info: Landsat Collections in GEE

  • Sentinel-2 MSI
    Sentinel-2 offers 10-20m resolution multispectral data with frequent revisit times, ideal for fine-scale NDVI mapping.
    GEE collection: COPERNICUS/S2
    More info: Sentinel-2 Overview (ESA)

  • GIMMS NDVI (1982–2022)
    The GIMMS dataset provides a long-term NDVI record from AVHRR and MODIS sensors at 8km resolution, useful for climate and vegetation trend studies.
    GEE asset: "projects/sat-io/open-datasets/PKU-GIMMS-NDVI/AVHRR_MODIS_CONSOLIDATED"
    More info: GIMMS NDVI in GEE

⚠️ **GitHub.com Fallback** ⚠️