Ndvi2Gif: Multi-Seasonal Remote Sensing Index Composites
Richter's stained glass in Cologne Cathedral. Inspiration for this library.
Ndvi2Gif is a Python library for multi-temporal remote sensing analysis with Google Earth Engine. It provides seasonal compositing, 40+ vegetation and environmental indices, SAR preprocessing, time series analytics, land cover classification, and hydroperiod analysis — all server-side, without downloading raw data.
Built on top of Google Earth Engine and geemap. Adapted and extended through its use in the eLTER and SUMHAL projects.
📚 Documentation
https://digdgeo.github.io/Ndvi2Gif/
✨ What's New in v1.6.0
⚠️ Values change for some indices — please read before upgrading. A review of every index against its publication found that Sentinel-2 and MODIS bands were used as integers × 10000 instead of reflectance: band ratios such as NDVI were unaffected, but SAVI, EVI, LAI, AVI, WI2015, CRI and a few others came out wrong on those sensors (EVI 2–3 times too high). Sentinel-1 was processed and indexed in dB instead of linear power, and its terrain correction had no effect because the DEM lost its projection. Several formulas were also wrong (
aweinsh,wi2015,nmi,rfdi,dpsvi). All are fixed and tested; results computed with the affected indices should be recomputed. The CHANGELOG lists every index and how much it changes.
Multi-sensor classification — LandCoverClassifier([s2, s1]) combines indices from several sensors in one feature stack, e.g. indices={'S2': ['ndvi', 'ndmi'], 'S1': ['vv', 'vh']}. When resolutions differ you choose how to reconcile them (resample='coarser', 'finer' or a pixel size in meters). In the new Tawau Hills tutorial — natural forest versus oil palm under Borneo's clouds — Sentinel-2 + Sentinel-1 reach 0.76 overall accuracy against 0.73 and 0.58 for each sensor alone.
Reproducible classifications — export_model() saves the full configuration, every random-forest tree, the accuracy and the training samples with their coordinates, ready to refit the model in scikit-learn or R. Train/validation splits are now seeded and identical across feature stacks, so classifiers can be compared fairly.
An indices catalogue you can trust — the indices reference is rebuilt from the code: 111 variables, each with the formula as implemented and a verified reference. Each sensor now only accepts the indices it can actually compute.
Previously, in v1.5.0: raw reflectance bands as index= ('blue' … 'swir2', plus 'red_edge1-3' on S2) and key='count', the number of valid observations per pixel; v1.5.1 fixed band names shifting when a period had no images.
In v1.4.0: dispersion reducers — key='std', 'variance', 'range', 'cv' — and downloadable water masks from HydroperiodAnalyzer.
And in v1.3.0: SpatialPhenologyAnalyzer, GEE-native per-pixel phenology rasters (SOS/POS/EOS) with threshold, derivative and harmonic methods. See CHANGELOG for details.
Modules
| Module | Description |
|---|---|
NdviSeasonality |
Core engine: seasonal compositing, 40+ indices, 7 sensors, flexible ROI input |
HydroperiodAnalyzer |
Wetland flood duration analysis (days/year) with multi-year anomaly detection |
TimeSeriesAnalyzer |
Trend detection (Mann-Kendall, Sen's slope), phenology metrics, dashboards |
SpatialPhenologyAnalyzer |
Per-pixel phenology rasters (SOS/POS/EOS) via threshold, derivative or harmonic methods |
S1ARDProcessor |
Sentinel-1 SAR preprocessing: terrain correction, speckle filtering |
LandCoverClassifier |
Supervised (RF, SVM, CART) and unsupervised (K-means, LDA) classification, multi-sensor feature stacks, exportable models |
Installation
pip install ndvi2gif
conda install -c conda-forge ndvi2gif
Quick Start
import ee
from ndvi2gif import NdviSeasonality
ee.Authenticate()
ee.Initialize(project='your-project-id')
# Monthly NDVI composites from Sentinel-2 (2018–2024)
ndvi = NdviSeasonality(
roi=your_roi, sat='S2', periods=12,
start_year=2018, end_year=2024,
key='percentile', percentile=85, index='ndvi'
)
ndvi.get_gif(name='ndvi_evolution.gif')
Yes, it makes nice GIFs — but it's much more than that.
Crop pattern dance around Los Palacios y Villafranca (SW Spain)
What you can do with it
- Compute pixel-wise statistics over any region and time span — seasonal medians, percentiles, multi-year aggregations, or dispersion (std, variance, range, CV) to map variability instead of level
- Monitor 40+ indices across Sentinel-1/2/3, Landsat (4–9), MODIS, ERA5-Land, and CHIRPS
- Analyse wetland hydroperiod and multi-year flood anomalies with
HydroperiodAnalyzer - Detect trends and phenology (SOS, EOS, POS, Length of Season) with
TimeSeriesAnalyzer - Classify land cover with multi-temporal feature stacks and Random Forest, SVM, or K-means
- Preprocess Sentinel-1 SAR with terrain correction and speckle filtering
- Export to GeoTIFF, Google Drive, or Earth Engine Assets
- Use any ROI: shapefile, GeoJSON, drawn geometry, eLTER DEIMS ID, Sentinel-2 tile, or Landsat path/row
Supported Sensors
Sentinel-1 (SAR) · Sentinel-2 SR · Sentinel-3 OLCI · Landsat 4–9 SR · MODIS MOD09A1 · ERA5-Land · CHIRPS
Contributing
Bug reports and feature requests: GitHub Issues
Pull requests are welcome. See CONTRIBUTING.md for guidelines — it includes step-by-step instructions for adding new indices and datasets.
Citation
If you use Ndvi2Gif in your research, please cite the JOSS paper:
@article{GarciaDiaz2026,
author = {García Díaz, Diego},
title = {Ndvi2Gif: A Python Package for Multi-Seasonal Remote Sensing Analysis with Google Earth Engine},
journal = {Journal of Open Source Software},
year = {2026},
volume = {11},
number = {124},
pages = {10654},
publisher = {The Open Journal},
doi = {10.21105/joss.10654},
url = {https://doi.org/10.21105/joss.10654}
}
Acknowledgments
Special thanks to Qiusheng Wu for his invaluable work in developing and promoting open-source geospatial software, to the Google Earth Engine team, and to the broader open-source geospatial community.
License
MIT — see LICENSE.txt
Metadata
Release files for ndvi2gif 1.6.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ndvi2gif-1.6.1.tar.gz | 159.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ndvi2gif-1.6.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 285.3 kB
Release files / ndvi2gif-1.6.1.tar.gz
| Download URL | ndvi2gif-1.6.1.tar.gz |
|---|---|
| Size | 159.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d1af4f6e2ad07eae813538d517e958dc6497b5efcd5314e577ba3d8637bfab12
|
|
BLAKE2b-256 checksum How to use checksums |
8399b9f7904e821d4a36eaa835cf2eceeea07b465333f3e3ebd592f9c3dfb38a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|
Release files / ndvi2gif-1.6.1-py3-none-any.whl
| Download URL | ndvi2gif-1.6.1-py3-none-any.whl |
|---|---|
| Size | 125.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e59c11f99d59af05ccf41b5ef6a84655cb618443ec2ca8a1917f647ca3e53ab9
|
|
BLAKE2b-256 checksum How to use checksums |
742cc782194fe685d9f5b72ccd666ea60b534046e489d42fc4cd9fd8b4e13824
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|