NOVA Invasives
Detecting kudzu, phragmites, and other invasive species in Northern Virginia by exploiting their phenological signatures in Sentinel-2 time series — all processed on Google Earth Engine.
Study Area
5 Monitoring Sites
Click each marker to see the invasive species, GEE coordinate code, and detection signature. The dashed green box is the bounding box for the full study area.
Why It Works
How can a satellite see invasive plants?
The key is phenological asynchrony: invasive and native plants leaf out and senesce on different schedules, and that timing gap is clearly visible in satellite time series.
What is NDVI?
NDVI = (NIR − RED) / (NIR + RED)
Plant leaves absorb red light for photosynthesis and strongly reflect near-infrared. NDVI normalizes that ratio to [-1, +1] — higher values mean denser vegetation. Sentinel-2 uses B8 (NIR) and B4 (Red).
Detection Windows
Early Spring (Mar–Apr) · Late Autumn (Oct–Nov)
Invasive shrubs leaf out 2–3 weeks earlier and drop leaves 2–3 weeks later than native deciduous trees. During those windows, invasives show much higher NDVI than surrounding native vegetation — a detectable signal.

Simulation
Phenology Curve Comparison
Synthetic data confirming the core hypothesis: the orange (early spring) and brown (late autumn) bands mark the windows where invasive vs. native NDVI differs most.

Kudzu
Pueraria montana
Anomalously high summer NDVI (>0.8)
Year-roundAutumn Olive / Bush Honeysuckle
Elaeagnus / Lonicera
Leafs out 2-3 weeks earlier than natives
Mar–AprPhragmites
Phragmites australis
Persistently high NIR reflectance
Late summerEnglish Ivy
Hedera helix
High winter NDVI (evergreen)
Dec–FebReal Data
NDVI Time Series — 5 Sites (Sentinel-2 measurements)
Real data from Google Earth Engine: 360 monthly observations across 2019–2024. Switch to 'Monthly phenology' for multi-year averages, or 'Full time series' for raw monthly values. Toggle sites via the legend.
Source: COPERNICUS/S2_SR_HARMONIZED · 500 m buffer · monthly median composite · cloud cover < 30%
Classification
Automated Phenological Classification
A rule-based classifier (no training data needed) evaluates four seasonal NDVI features per site. Rules encode ecological priors: early leaf-out, late senescence, winter evergreen, summer explosion — any one exceeding the native baseline flags the site as invasive.
Dyke Marsh — Phragmites
Native vegetation- All metrics close to the native control
Spring
0.388
Summer
0.659
Autumn
0.504
Winter
0.316
Great Falls — Kudzu
Native vegetation- All metrics close to the native control
Spring
0.250
Summer
0.573
Autumn
0.415
Winter
0.199
Huntley Meadows — Phragmites
Deciduous invasive shrub (Autumn Olive / Honeysuckle-type)- Early-spring + +0.16 above control (early leaf-out)
- Late-autumn + +0.17 above control (delayed senescence)
Spring
0.525
Summer
0.847
Autumn
0.672
Winter
0.388
Native Forest (Control)
Native vegetation- All metrics close to the native control
Spring
0.363
Summer
0.559
Autumn
0.497
Winter
0.318
Scotts Run — Ivy
Native vegetation- All metrics close to the native control
Spring
0.458
Summer
0.625
Autumn
0.542
Winter
0.385


⚠️ Interpreting the Real-Data Results
Only Huntley Meadows was flagged as invasive in this run. Other known hotspots (kudzu at Great Falls, ivy at Scotts Run, phragmites at Dyke Marsh) were missed — likely because the 500 m buffer averages invasive patches with surrounding native vegetation. Next steps: (1) shrink the buffer to 100 m; (2) sample finer-grained locations; (3) add texture and SWIR bands.
Project Scripts
Analysis Pipeline
Four Python scripts form a complete analysis pipeline, one stage each.
Understand NDVI
01_explore_ndvi_concept.pyPlots the NDVI definition and simulated phenology curves for invasive vs. native plants.
Why this way: Before pulling real satellite data, make sure we know what we're measuring. No GEE account required.
Output: 01_ndvi_concept.png · 02_phenology_comparison.png · 03_study_area_map.html
Extract real NDVI via GEE
02_gee_ndvi_timeseries.pyConnects to Google Earth Engine and pulls monthly NDVI time series (2019–2024) for 5 sites from Sentinel-2.
Why this way: Sentinel-2 overpasses every 5 days — hundreds of scenes over 6 years. GEE parallelizes this in the cloud; nothing is downloaded locally.
Output: ndvi_timeseries_nova.csv · 04_gee_ndvi_timeseries.png
Download Landsat via STAC
03_download_landsat_stac.pyPulls raw Landsat 8/9 bands via the USGS STAC API and computes seasonal NDVI maps locally.
Why this way: STAC needs no GEE account — useful fallback. Landsat 30 m is suited for regional-scale analysis.
Output: data/*.tif · outputs/ndvi_*.png
Phenological classification
04_phenology_analysis.pyUses early-spring / late-autumn NDVI deltas as features in a rule-based classifier; exports JSON for the dashboard.
Why this way: This is the project goal: turn time-series signals into a yes/no invasive flag per location.
Output: phenology_features.csv · classification.json · 05/06_*.png
# 1. Load the Sentinel-2 dataset (lazy — nothing is downloaded yet)
collection = (
ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED")
.filterBounds(roi) # (1) keep only scenes over NOVA
.filterDate("2022-03-01", "2022-04-30") # (2) early-spring window
.filter(ee.Filter.lt("CLOUDY_PIXEL_PERCENTAGE", 30)) # (3) drop cloudy scenes
)
# 2. Compute NDVI on every image (runs in parallel on GEE servers)
def add_ndvi(image):
return image.addBands(
image.normalizedDifference(["B8", "B4"]).rename("NDVI")
)
# 3. Composite + extract a single value (this is where the actual call happens)
ndvi_median = collection.map(add_ndvi).select("NDVI").median()
stats = ndvi_median.reduceRegion(
reducer=ee.Reducer.mean(),
geometry=roi, # 500 m buffer
scale=10, # Sentinel-2 native resolution
).getInfo() # ← only this line triggers actual GEE computationTechnology
Sources: Copernicus Sentinel-2 · USGS Landsat · EDDMapS · iNaturalist
Study area: Northern Virginia (38.70°N–39.00°N, 77.00°W–77.55°W)