Is deforestation happening in this area, and what are its effects?
Draw a rectangle, then check which collections cover it. Most NASA data is global, so a big box matches a lot.
73.5, 15 → 78.5, 20 (Maharashtra Western Ghats)A satellite can't see "a forest." It sees how green the ground is. Healthy leaves bounce back a lot of invisible near-infrared light and soak up red light, so you can turn each pixel into a single greenness score. When forest is cleared, that score drops and stays down. Watch the score over several years and you can spot where the trees went, then check whether those spots got hotter and drier than the forest left standing next door.
Is deforestation happening in this area, and what are its effects?
A satellite can’t see “a forest.” It sees how green the ground is. Healthy leaves bounce back a lot of invisible near-infrared light and soak up red light, so you can turn each pixel into a single greenness score. When forest is cleared, that score drops and stays down. Watch the score over several years and you can spot where the trees went, then check whether those spots got hotter and drier than the forest left standing next door.
Which data to use, and how
Use this dataset: HLS L30 (short name HLSL30), NASA’s “Harmonized
Landsat-Sentinel” surface reflectance. It gives you a ~30 m picture of the ground every few days from
2013 on, already cleaned up so the colors are comparable across dates. It’s the easiest place to start
because greenness is just simple arithmetic on two of its color bands.
Then do four steps (the runnable code further down does all of this; this is just the idea):
- Pick your area (a small latitude/longitude box around the forest you care about) and a before year and an after year.
- Turn each pixel into greenness by computing NDVI, a standard 0-to-1 greenness score:
(near-infrared − red) / (near-infrared + red). Dense forest scores high; bare or cleared ground scores low. - Compare before vs after. Average the greenness for the early period and for the recent period, then subtract. Pixels that dropped a lot are your candidate clearings.
- Sanity-check the loss. For the spots that lost greenness, also check whether they warmed up relative to nearby forest that stayed put. Hotter and less green is the fingerprint of real deforestation, not just a noisy year.
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
- Where forest cover dropped in your area over the last few years (the greenness time-series, or the ready-made annual loss map from Hansen Global Forest Change).
- How much biomass was lost, in tons of carbon, by averaging tree-height-and-mass measurements from GEDI L4A (a space laser that sampled forest height) inside the loss areas.
- Whether trees grew back: a greenness recovery curve after the clearing.
- Downstream effects you can begin to test. Did the cleared spots get hotter, lose moisture, or shift their rainfall-runoff? These are first checks, not proof.
What it can’t tell you
- Why the forest was lost. A drop in greenness looks the same whether it was logging, fire, disease, or a new town. Telling them apart needs extra maps (fire detections, land-use records).
- Tiny changes. HLS pixels are about 30 m across, so a few felled trees inside one pixel get averaged away. You can’t see change smaller than the pixel.
- A continuous biomass film. The GEDI L4A laser only sampled scattered footprints along its flight path, not every spot, so biomass loss is sampled, not wall-to-wall.
Gotchas to watch for
- Clouds hide the ground, especially in the wet season. The example filters to scenes with under 20% cloud, which is strict, and a monsoon region like the Western Ghats loses most of its June–September views that way. Some months can end up with almost no clear images at all. Compare the same dry-season months across years, and if you’re starved for data, loosen the cloud limit.
- The laser took a break. GEDI ran its main mission 2019–March 2023, then paused, then resumed in 2024 from the Space Station, which leaves a gap with no biomass samples. Lean on greenness (NDVI) for the timeline and bring in GEDI only where its dates overlap your window.
- “Loss” has a strict definition. Hansen Global Forest Change only flags a 30 m pixel as lost when it lost at least half its canopy. Gentle, gradual change (like small-farm agroforestry) may not register, so real thinning can slip past. The safest move is to cross-read the Hansen map against your own greenness drop rather than trusting either one alone.
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 HLS, open the bands, compute NDVI before vs after, find the greenness-drop pixels, then read GEDI laser biomass inside them and plot. It needs a free Earthdata Login.
import earthaccess, numpy as np, rasterio, h5py
import matplotlib.pyplot as plt
earthaccess.login(strategy="netrc")
aoi = (73.5, 15.0, 78.5, 20.0) # your forest as (W, S, E, N) — here, Maharashtra Western Ghats
before, after = 2018, 2024 # a before year and an after year (compare same dry-season months)
# 1. Search HLS L30 surface reflectance for a clear dry-season scene in each year.
def ndvi_scene(year):
grans = earthaccess.search_data(
short_name="HLSL30", bounding_box=aoi,
temporal=(f"{year}-01-01", f"{year}-03-31"), cloud_cover=20)
# HLS L30 GeoTIFFs: B05 = NIR, B04 = Red. Open the two bands with rasterio.
links = earthaccess.open(grans[:1]) # one clear scene is enough for a before/after
paths = [l.full_name for l in links] if hasattr(links[0], "full_name") else grans[:1]
b = {}
for g in grans[:1]:
for url in g.data_links():
if url.endswith("B05.tif"): b["nir"] = url
if url.endswith("B04.tif"): b["red"] = url
fs = earthaccess.get_fsspec_https_session()
with rasterio.open(b["red"]) as r: red = r.read(1).astype("f4") * 1e-4
with rasterio.open(b["nir"]) as r: nir = r.read(1).astype("f4") * 1e-4
red[red <= 0] = np.nan; nir[nir <= 0] = np.nan
return (nir - red) / (nir + red) # 2. NDVI = (NIR - Red) / (NIR + Red)
ndvi_before, ndvi_after = ndvi_scene(before), ndvi_scene(after)
# 3. Before vs after: pixels whose greenness dropped a lot are candidate clearings.
delta = ndvi_after - ndvi_before
lost = delta < -0.20 # >0.2 NDVI drop = likely cleared
pct = 100 * np.nansum(lost) / np.isfinite(delta).sum()
print(f"NDVI dropped >0.2 over {pct:.1f}% of the scene "
f"({before}->{after}); mean drop there = {np.nanmean(delta[lost]):.2f}")
# 4. Read GEDI L4A laser biomass and average it where forest was lost (tons C/ha cleared).
gedi = earthaccess.search_data(
short_name="GEDI_L4A_AGB_Density_V2_1_2056", bounding_box=aoi,
temporal=(f"{before}-01-01", f"{before}-12-31"))
agbd = []
for fh in earthaccess.open(gedi[:3]): # HDF5: one group per laser beam
with h5py.File(fh, "r") as f:
for beam in [k for k in f.keys() if k.startswith("BEAM")]:
a = f[f"{beam}/agbd"][:]; q = f[f"{beam}/l4_quality_flag"][:]
agbd.append(a[(q == 1) & (a > 0)])
agbd = np.concatenate(agbd) if agbd else np.array([np.nan])
print(f"GEDI footprint biomass in area: median {np.nanmedian(agbd):.0f} Mg/ha "
f"-- the carbon density at risk where greenness fell")
# 5. Plot: the before/after greenness drop, and the biomass-at-risk distribution.
fig, ax = plt.subplots(1, 2, figsize=(10, 4))
im = ax[0].imshow(delta, cmap="RdYlGn", vmin=-0.5, vmax=0.5)
ax[0].set_title(f"NDVI change {before}->{after}"); fig.colorbar(im, ax=ax[0])
ax[1].hist(agbd, bins=40); ax[1].set_xlabel("GEDI biomass (Mg/ha)")
ax[1].set_title("Carbon density at risk"); plt.tight_layout(); plt.show()
# Before you trust it: cross-read the NDVI drop against the Hansen Global Forest Change
# loss map (a 30 m pixel only counts as "lost" at >=50% canopy removal -- see the gotchas).
Where the data comes from
Everything here comes from NASA through one free login (Earthdata Login), even though the pieces
live in different archives. HLS and MODIS come from the LP DAAC, and the GEDI laser biomass comes from
the ORNL DAAC. Same login, slightly different file formats: HLS reads like ordinary image tiles,
while GEDI ships as HDF5 (a scientific data container) that takes a little more code to open. The
ready-made Hansen forest-loss map is a popular outside add-on (from the University of Maryland) that
people commonly join in. See recipes/r01-three-daac-composition.mdx for the general pattern.
Sources + further reading
- GEDI L4A user guide: https://daac.ornl.gov/cgi-bin/dsviewer.pl?ds_id=2056
- HLS user guide: https://lpdaac.usgs.gov/products/hlsl30v002/
- Hansen Global Forest Change: https://earthenginepartners.appspot.com/science-2013-global-forest
Make it yours → Draw your own area and download the notebook, then change the forest-loss years, the before/after windows, and how far away the control pixels are drawn. The verified worked examples are on /verify.
A safe place to practise the method on HLSL30. 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.
Datasets used
Computed · real data Worked examples, computed end-to-end on real satellite data — not yet scientist-verified · expand ▾
Not the answer for your own area — that you run yourself above. Two forests show the deforestation fingerprint (Amazon, Sumatra); three Indian forests come out a genuine null — the method discriminates, it doesn't just confirm. A change must clear an empirical noise floor to count; a null is reported as a null. Computed on Google Earth Engine.
Rondônia, Brazil
The trustworthy local signals agree with the deforestation signature: land surface temperature warmer; greenness ndvi less green. Regional/coarse variables (rainfall, wind, humidity) are directional hints at best; soil moisture is model-based and reported without a consistency verdict. Weight the strong tier; treat the rest as context.
Observational analog (a natural experiment over comparable places) — evidence, not a prediction for any one spot. Each bar shows the change versus the natural jitter between undisturbed control pixels; it must clear the ┊ tick to count as a real signal.
Provenance & full trace — reproducible
Every number came from this exact query on Google Earth Engine. Same query → same number.
DEFORESTATION ANALOG — combined report region [-63.5, -11.0, -60.0, -8.5] | forest lost 2005-2008 | before 2001-2004 -> after 2015-2020 Before-After-Control-Impact (BACI): change at deforested sites MINUS the same change at kept-forest controls. Observational evidence, NOT a causal prediction. [STRONG (local, trustworthy)] land_surface_temperature BACI +0.956 degC (warmer) [def 10500px / ctrl 63223px] greenness_ndvi BACI -0.046 NDVI (less green) [def 10500px / ctrl 63223px] [WEAK (regional process, coarse grid — directional hint)] rainfall BACI -7.8 mm/year (no clear change) [def 512px / ctrl 1893px] [WEAKEST (coarse + regional — read the control-pixel count)] wind BACI -0.01 m/s (no clear change) [def 25px / ctrl 62px] <- NOT in the expected direction (investigate) humidity BACI +0.1 % RH (no clear change) [def 25px / ctrl 62px] <- NOT in the expected direction (investigate) [AMBIGUOUS (model-based, no expected direction — reported, not judged)] soil_moisture BACI -0.001 m3/m3 (no clear change) [def 165px / ctrl 423px] VERDICT The trustworthy local signals agree with the deforestation signature: land surface temperature warmer; greenness ndvi less green. Regional/coarse variables (rainfall, wind, humidity) are directional hints at best; soil moisture is model-based and reported without a consistency verdict. Weight the strong tier; treat the rest as context.
Riau, Sumatra
The trustworthy local signals agree with the deforestation signature: land surface temperature warmer; greenness ndvi less green. Regional/coarse variables (rainfall, wind, humidity) are directional hints at best; soil moisture is model-based and reported without a consistency verdict. Weight the strong tier; treat the rest as context.
Observational analog (a natural experiment over comparable places) — evidence, not a prediction for any one spot. Each bar shows the change versus the natural jitter between undisturbed control pixels; it must clear the ┊ tick to count as a real signal.
Provenance & full trace — reproducible
Every number came from this exact query on Google Earth Engine. Same query → same number.
DEFORESTATION ANALOG — combined report region [101.0, 0.0, 103.5, 2.0] | forest lost 2005-2008 | before 2001-2004 -> after 2015-2020 Before-After-Control-Impact (BACI): change at deforested sites MINUS the same change at kept-forest controls. Observational evidence, NOT a causal prediction. [STRONG (local, trustworthy)] land_surface_temperature BACI +0.764 degC (warmer) [def 8135px / ctrl 11790px] greenness_ndvi BACI -0.021 NDVI (less green) [def 8135px / ctrl 11790px] [WEAK (regional process, coarse grid — directional hint)] rainfall BACI +15.7 mm/year (no clear change) [def 321px / ctrl 267px] <- NOT in the expected direction (investigate) [WEAKEST (coarse + regional — read the control-pixel count)] wind BACI +0.02 m/s (windier) [def 19px / ctrl 5px] humidity BACI -0.2 % RH (drier) [def 19px / ctrl 5px] [AMBIGUOUS (model-based, no expected direction — reported, not judged)] soil_moisture BACI -0.002 m3/m3 (drier soil) [def 89px / ctrl 50px] VERDICT The trustworthy local signals agree with the deforestation signature: land surface temperature warmer; greenness ndvi less green. Regional/coarse variables (rainfall, wind, humidity) are directional hints at best; soil moisture is model-based and reported without a consistency verdict. Weight the strong tier; treat the rest as context.
Central India (Maharashtra)
No clear local change: every strong-tier variable came back below the noise floor (LST/NDVI ~ flat between deforested and control sites here). The deforestation signal in this box is weak or absent — possibly little real loss, slow recovery, or the window is too short. Do not over-read the coarse/regional hints; the trustworthy signal is null.
Observational analog (a natural experiment over comparable places) — evidence, not a prediction for any one spot. Each bar shows the change versus the natural jitter between undisturbed control pixels; it must clear the ┊ tick to count as a real signal.
Provenance & full trace — reproducible
Every number came from this exact query on Google Earth Engine. Same query → same number.
DEFORESTATION ANALOG — combined report region [79.5, 19.0, 83.0, 22.0] | forest lost 2005-2008 | before 2001-2004 -> after 2015-2020 Before-After-Control-Impact (BACI): change at deforested sites MINUS the same change at kept-forest controls. Observational evidence, NOT a causal prediction. [STRONG (local, trustworthy)] land_surface_temperature BACI +0.046 degC (no clear change) [def 1843px / ctrl 21713px] greenness_ndvi BACI -0.003 NDVI (no clear change) [def 1843px / ctrl 21713px] [WEAK (regional process, coarse grid — directional hint)] rainfall BACI -11.2 mm/year (no clear change) [def 93px / ctrl 666px] [WEAKEST (coarse + regional — read the control-pixel count)] wind BACI +0.05 m/s (windier) [def 2px / ctrl 19px] <- too few pixels; do not trust humidity BACI -0 % RH (no clear change) [def 2px / ctrl 19px] <- too few pixels; do not trust [AMBIGUOUS (model-based, no expected direction — reported, not judged)] soil_moisture BACI +0.001 m3/m3 (no clear change) [def 26px / ctrl 160px] VERDICT No clear local change: every strong-tier variable came back below the noise floor (LST/NDVI ~ flat between deforested and control sites here). The deforestation signal in this box is weak or absent — possibly little real loss, slow recovery, or the window is too short. Do not over-read the coarse/regional hints; the trustworthy signal is null.
Western Ghats (Karnataka)
No clear local change: every strong-tier variable came back below the noise floor (LST/NDVI ~ flat between deforested and control sites here). The deforestation signal in this box is weak or absent — possibly little real loss, slow recovery, or the window is too short. Do not over-read the coarse/regional hints; the trustworthy signal is null.
Observational analog (a natural experiment over comparable places) — evidence, not a prediction for any one spot. Each bar shows the change versus the natural jitter between undisturbed control pixels; it must clear the ┊ tick to count as a real signal.
Provenance & full trace — reproducible
Every number came from this exact query on Google Earth Engine. Same query → same number.
DEFORESTATION ANALOG — combined report region [74.3, 13.0, 75.6, 15.2] | forest lost 2005-2008 | before 2001-2004 -> after 2015-2020 Before-After-Control-Impact (BACI): change at deforested sites MINUS the same change at kept-forest controls. Observational evidence, NOT a causal prediction. [STRONG (local, trustworthy)] land_surface_temperature BACI +0.031 degC (no clear change) [def 1149px / ctrl 12668px] greenness_ndvi BACI +0.001 NDVI (no clear change) [def 1149px / ctrl 12668px] <- NOT in the expected direction (investigate) [WEAK (regional process, coarse grid — directional hint)] rainfall BACI +9.3 mm/year (no clear change) [def 48px / ctrl 431px] <- NOT in the expected direction (investigate) [WEAKEST (coarse + regional — read the control-pixel count)] wind BACI -0.01 m/s (no clear change) [def 2px / ctrl 15px] <- NOT in the expected direction (investigate) humidity BACI -0.1 % RH (no clear change) [def 2px / ctrl 15px] <- too few pixels; do not trust [AMBIGUOUS (model-based, no expected direction — reported, not judged)] soil_moisture BACI +0 m3/m3 (no clear change) [def 14px / ctrl 109px] VERDICT No clear local change: every strong-tier variable came back below the noise floor (LST/NDVI ~ flat between deforested and control sites here). The deforestation signal in this box is weak or absent — possibly little real loss, slow recovery, or the window is too short. Do not over-read the coarse/regional hints; the trustworthy signal is null.
Northeast India (Assam–Meghalaya)
No clear local change: every strong-tier variable came back below the noise floor (LST/NDVI ~ flat between deforested and control sites here). The deforestation signal in this box is weak or absent — possibly little real loss, slow recovery, or the window is too short. Do not over-read the coarse/regional hints; the trustworthy signal is null.
Observational analog (a natural experiment over comparable places) — evidence, not a prediction for any one spot. Each bar shows the change versus the natural jitter between undisturbed control pixels; it must clear the ┊ tick to count as a real signal.
Provenance & full trace — reproducible
Every number came from this exact query on Google Earth Engine. Same query → same number.
DEFORESTATION ANALOG — combined report region [91.0, 25.0, 94.0, 26.6] | forest lost 2005-2008 | before 2001-2004 -> after 2015-2020 Before-After-Control-Impact (BACI): change at deforested sites MINUS the same change at kept-forest controls. Observational evidence, NOT a causal prediction. [STRONG (local, trustworthy)] land_surface_temperature BACI +0.099 degC (no clear change) [def 3445px / ctrl 24430px] greenness_ndvi BACI -0.005 NDVI (no clear change) [def 3445px / ctrl 24430px] [WEAK (regional process, coarse grid — directional hint)] rainfall BACI +12.3 mm/year (no clear change) [def 100px / ctrl 690px] <- NOT in the expected direction (investigate) [WEAKEST (coarse + regional — read the control-pixel count)] wind BACI +0 m/s (no clear change) [def 2px / ctrl 20px] <- too few pixels; do not trust humidity BACI +0.1 % RH (no clear change) [def 2px / ctrl 20px] <- NOT in the expected direction (investigate) [AMBIGUOUS (model-based, no expected direction — reported, not judged)] soil_moisture BACI -0 m3/m3 (no clear change) [def 29px / ctrl 161px] VERDICT No clear local change: every strong-tier variable came back below the noise floor (LST/NDVI ~ flat between deforested and control sites here). The deforestation signal in this box is weak or absent — possibly little real loss, slow recovery, or the window is too short. Do not over-read the coarse/regional hints; the trustworthy signal is null.