Geoskill: Phenology Metrics

Extracts SOS, EOS, LOS, peak value/date, amplitude, and integral phenology metrics from NDVI/EVI time series using threshold, derivative, or logistic methods.

ruiduobao

@ruiduobao

What This Skill Does

Command-line tool that extracts vegetation phenology metrics (SOS, EOS, LOS, peak, amplitude, integral) from NDVI/EVI time series using threshold, derivative, or double logistic fitting methods. Accepts CSV or multi-band GeoTIFF input and outputs results as CSV or JSON.

Replaces manual curve-fitting and spreadsheet-based phenology analysis by automating metric extraction from vegetation index time series with multiple validated methods.

When to Use It

  • Compute start and end of growing season from satellite NDVI time series
  • Estimate vegetation peak productivity and date from field sensor data
  • Calculate length of season and total seasonal productivity for crop monitoring
  • Compare phenology extraction methods (threshold vs. derivative vs. logistic) on the same dataset
  • Fit a double logistic curve to noisy vegetation index data for research-grade analysis
  • Batch-process multiple pixel time series from a GeoTIFF stack for landscape-scale phenology mapping

Install

$ openclaw skills install @ruiduobao/phenology-metrics

Phenology Metrics

Extract vegetation phenology metrics from NDVI/EVI time series. Supports threshold, derivative, and double logistic fitting methods.

Features

  • Key metrics: SOS, EOS, LOS, Peak value, Peak date, Amplitude, Integral
  • Threshold method: 10%/50% of amplitude ratio
  • Derivative method: Inflection points of fitted curve
  • Logistic fitting: Double logistic function for smooth phenology
  • Input formats: CSV (date, value) or multi-band GeoTIFF stack
  • Output formats: CSV and JSON

Phenology Metrics

MetricDescription
SOSStart of Season (green-up)
EOSEnd of Season (senescence)
LOSLength of Season (EOS - SOS)
PeakMaximum NDVI/EVI value
Peak DateDate of peak value
AmplitudePeak - baseline
IntegralArea under curve (season productivity)

Usage

Extract from CSV time series

python scripts\phenology-metrics.py extract \
  --input ndvi_series.csv \
  --date-col date --value-col ndvi \
  --method threshold --threshold-ratio 0.5 \
  --output phenology.json

Fit double logistic curve

python scripts\phenology-metrics.py fit \
  --input ndvi_series.csv \
  --date-col date --value-col ndvi \
  --output fitted.json --plot-data plot.csv

Generate plot data

python scripts\phenology-metrics.py plot-data \
  --input ndvi_series.csv --date-col date --value-col ndvi \
  --output curve.csv

Installation

pip install numpy>=1.21.0 scipy>=1.7.0 pandas>=1.3.0
# Or: pip install -r scripts/requirements.txt

Parameters

  • --input: Input CSV file (date, value columns)
  • --date-col: Date column name (default: date)
  • --value-col: Value column name (default: ndvi)
  • --method: Extraction method (threshold, derivative, logistic)
  • --threshold-ratio: Threshold ratio for SOS/EOS (default: 0.5)
  • --output: Output file path (CSV or JSON)
  • --plot-data: Output fitted curve data for plotting
  • --json: Output as JSON

Output

  • Phenology metrics: CSV/JSON with all computed metrics
  • Fitted curve: CSV with date, original, fitted values
  • Statistics: Goodness of fit (R²)

Dependencies

numpy>=1.21.0
scipy>=1.7.0
pandas>=1.3.0

GeoTIFF Stack Usage

Use a multi-band GeoTIFF stack (one band per time step) as input:

python scripts\phenology-metrics.py extract \
  --input ndvi_stack.tif \
  --input-format geotiff \
  --date-file dates.txt \
  --method logistic \
  --output phenology.json
  • --input-format geotiff: Specifies GeoTIFF stack input
  • --date-file: Text file with one date per line (YYYY-MM-DD), one per band
  • --band-epoch: Reference date for band numbering (default: band 1 = first date)

Date Format Specification

Supported date formats:

FormatExampleNotes
ISO date2023-06-15Recommended (YYYY-MM-DD)
US date06/15/2023MM/DD/YYYY
DOY166Day of year (1-366)
Year-DOY2023-166Combined format

Specify with --date-format parameter.

Method Selection Guidance

MethodBest ForPros / Cons
thresholdQuick estimation, sparse dataSimple but less precise
derivativePrecise timing, smooth dataSensitive to noise
logisticSmooth curves, research-gradeBest fit but needs clean data

Recommendation: Use threshold for exploratory analysis; logistic for publication-quality results.

Missing Data Handling

Time series gaps are common (clouds, sensor issues). The tool handles them via:

  • Interpolation: Linear interpolation for gaps ≤30 days (configurable via --max-gap)
  • Gap filling: Savitzky-Golay smoothing for noisy data
  • Flagging: Outputs data quality flag in results
python scripts\phenology-metrics.py extract \
  --input ndvi_series.csv --method logistic \
  --max-gap 30 --sg-window 7 \
  --output phenology.json

Multi-Year Data Handling

For multi-year time series:

  • Per-year extraction: Use --year-range 2020-2023 to loop over each year
  • Specify year: Use --year 2022 for single-year analysis
  • Phenology metrics: Computed separately per year, output as multi-row CSV/JSON
python scripts\phenology-metrics.py extract \
  --input ndvi_series.csv --method logistic \
  --year-range 2020-2023 \
  --output phenology_multiyear.csv

Batch Processing for Multiple Pixels

Process multiple pixels from a GeoTIFF stack:

python scripts\phenology-metrics.py batch \
  --input ndvi_stack.tif \
  --input-format geotiff \
  --method logistic \
  --output-dir ./phenology_results/ \
  --max-workers 4

Outputs one JSON per pixel (row, col) in the output directory.

Visualization

  • Time series: Plot NDVI/EVI points with fitted curve overlay
  • Key dates: Vertical lines for SOS, EOS, Peak Date
  • Multi-year: Facet plot showing each year's phenology curve
import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_csv('fitted.csv')
plt.plot(df['date'], df['original'], 'o', label='Original')
plt.plot(df['date'], df['fitted'], '-', label='Fitted')
plt.axvline(x=sos_date, color='green', label='SOS')
plt.axvline(x=eos_date, color='red', label='EOS')
plt.legend()
plt.show()

Citation

@software{phenology_metrics,
  author  = {ruiduobao},
  title   = {Phenology Metrics Extraction Tool},
  url     = {https://github.com/ruiduobao/phenology-metrics},
  version = {0.1.0},
  year    = {2024},
}

Troubleshooting

ErrorCauseSolution
ConnectionErrorNetwork issueCheck internet, retry
HTTP 429Rate limitWait 60s, retry
ValueErrorInvalid inputCheck parameter format
Empty outputNo valid dataCheck input data quality
ModuleNotFoundErrorMissing depRun pip install
Poor fit (low R²)Noisy dataTry logistic or increase --sg-window
Missing SOS/EOSWeak seasonalityLower threshold ratio or check data range

Data Source

Local processing of NDVI/EVI time series data.


Advanced Usage

Batch Pixel Processing

# Process a multi-band GeoTIFF stack (one pixel = one time series)
python scripts\phenology-metrics.py extract   --input ndvi_stack.csv --method logistic   --output phenology_results.csv

CI/CD Integration (GitHub Actions)

# .github/workflows/phenology-update.yml
name: Phenology Update
on:
  schedule:
    - cron: '0 0 1 3 *'  # Every March (growing season start)
jobs:
  extract:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      - run: pip install numpy scipy pandas
      - run: |
          python scripts\phenology-metrics.py extract \
            --input data/ndvi_2024.csv \
            --method logistic --output data/phenology_2024.csv

PostgreSQL Import

python scripts\phenology-metrics.py extract   --input ndvi_stack.csv --method logistic --output phenology.csv

psql -d gis_db -c "\COPY phenology(pixel_id, sos, eos, los, peak_date, amplitude) FROM 'phenology.csv' CSV HEADER"

Performance Tips

  • Use --method threshold for fastest results (least accurate)
  • --method logistic is recommended for most vegetation types
  • --sg-window 7 controls Savitzky-Golay smoothing window (larger = smoother)
  • --max-gap 30 fills gaps up to 30 days; increase for cloudy regions

中文说明

从 NDVI/EVI 时间序列数据中提取植被物候指标。支持阈值法、导数法和双 Logistic 拟合。

功能特性

  • 关键指标:SOS(生长季开始)、EOS(生长季结束)、LOS(生长季长度)、峰值、峰值日期、振幅、积分
  • 阈值法:振幅的 10%/50% 阈值
  • 导数法:拟合曲线的拐点
  • 双 Logistic 拟合:平滑物候曲线
  • 输入格式:CSV(日期, 值)或多波段 GeoTIFF
  • 输出格式:CSV 和 JSON

物候指标

指标说明
SOS生长季开始(返青)
EOS生长季结束(衰老)
LOS生长季长度(EOS - SOS)
Peak最大 NDVI/EVI 值
Peak Date峰值日期
Amplitude峰值 - 基线
Integral积分

使用示例

从 CSV 提取

python scripts\phenology-metrics.py extract \
  --input ndvi_series.csv \
  --date-col date --value-col ndvi \
  --method threshold --threshold-ratio 0.5 \
  --output phenology.json

双 Logistic 拟合

python scripts\phenology-metrics.py fit \
  --input ndvi_series.csv \
  --date-col date --value-col ndvi \
  --output fitted.json --plot-data plot.csv

生成绘图数据

python scripts\phenology-metrics.py plot-data \
  --input ndvi_series.csv --date-col date --value-col ndvi \
  --output curve.csv

安装

pip install numpy>=1.21.0 scipy>=1.7.0 pandas>=1.3.0
# 或: pip install -r scripts/requirements.txt

参数说明

  • --input: 输入 CSV 文件(日期, 值列)
  • --date-col: 日期列名(默认: date
  • --value-col: 值列名(默认: ndvi
  • --method: 提取方法(threshold, derivative, logistic
  • --threshold-ratio: SOS/EOS 阈值比率(默认: 0.5)
  • --output: 输出文件路径
  • --plot-data: 输出拟合曲线数据
  • --json: 以 JSON 输出

输出结果

  • 物候指标:CSV/JSON 格式的所有计算指标
  • 拟合曲线:CSV 含日期、原始值、拟合值
  • 统计信息:拟合优度(R²)

依赖库

numpy>=1.21.0
scipy>=1.7.0
pandas>=1.3.0

GeoTIFF 堆栈使用

使用多波段 GeoTIFF 堆栈(每个时间步一个波段)作为输入:

python scripts\phenology-metrics.py extract \
  --input ndvi_stack.tif \
  --input-format geotiff \
  --date-file dates.txt \
  --method logistic \
  --output phenology.json
  • --input-format geotiff:指定 GeoTIFF 堆栈输入
  • --date-file:每行一个日期的文本文件(YYYY-MM-DD),每个波段对应一个日期
  • --band-epoch:波段编号参考日期(默认:波段 1 = 第一个日期)

日期格式说明

支持的日期格式:

格式示例说明
ISO 日期2023-06-15推荐(YYYY-MM-DD)
美国格式06/15/2023MM/DD/YYYY
DOY166年积日(1-366)
年-DOY2023-166组合格式

使用 --date-format 参数指定。

方法选择指南

方法适用场景优缺点
threshold快速估算、稀疏数据简单但不够精确
derivative精确时间、平滑数据对噪声敏感
logistic平滑曲线、科研级拟合最佳但需要干净数据

建议:探索性分析用 threshold;发表级结果用 logistic

缺失数据处理

时间序列常有缺口(云、传感器问题)。工具通过以下方式处理:

  • 插值:≤30 天缺口使用线性插值(可通过 --max-gap 配置)
  • 缺口填充:Savitzky-Golay 平滑处理噪声数据
  • 标记:在结果中输出数据质量标志
python scripts\phenology-metrics.py extract \
  --input ndvi_series.csv --method logistic \
  --max-gap 30 --sg-window 7 \
  --output phenology.json

多年数据处理

对于多年时间序列:

  • 逐年提取:使用 --year-range 2020-2023 循环每年
  • 指定年份:使用 --year 2022 进行单年分析
  • 物候指标:每年单独计算,输出为多行 CSV/JSON
python scripts\phenology-metrics.py extract \
  --input ndvi_series.csv --method logistic \
  --year-range 2020-2023 \
  --output phenology_multiyear.csv

多像元批量处理

处理 GeoTIFF 堆栈中的多个像元:

python scripts\phenology-metrics.py batch \
  --input ndvi_stack.tif \
  --input-format geotiff \
  --method logistic \
  --output-dir ./phenology_results/ \
  --max-workers 4

输出每个像元(行, 列)一个 JSON 文件。

可视化

  • 时间序列:绘制 NDVI/EVI 点 + 拟合曲线叠加
  • 关键日期:SOS、EOS、峰值日期的垂直线
  • 多年对比:分面图展示每年物候曲线

引用格式

@software{phenology_metrics,
  author  = {ruiduobao},
  title   = {Phenology Metrics Extraction Tool},
  url     = {https://github.com/ruiduobao/phenology-metrics},
  version = {0.1.0},
  year    = {2024},
}

故障排除

错误原因解决方案
ConnectionError网络问题检查网络,重试
HTTP 429速率限制等待 60 秒后重试
ValueError无效输入检查参数格式
无输出无有效数据检查输入数据质量
ModuleNotFoundError缺少依赖运行 pip install
拟合差(低 R²)数据噪声大尝试 logistic 或增大 --sg-window
缺少 SOS/EOS季节性弱降低阈值比率或检查数据范围

数据来源

本地处理 NDVI/EVI 时间序列数据。

Top skills in this category