import os
import json
import requests
import folium
import branca.colormap as cm
# --- Load API key ---
# Option A: Running locally with .env / .Renviron file
try:
from dotenv import load_dotenv
load_dotenv("../.env")
load_dotenv("../.Renviron")
except ImportError:
pass
API_KEY = os.getenv("GJD_API_KEY", "")
# Option B: Running in Google Colab — uncomment and paste your key:
# API_KEY = "YOUR_API_KEY_HERE"
print("API key loaded:", "Yes" if API_KEY else "No")UC03: Spatial Deforestation in Caquetá & Putumayo (Municipalities)
Fetching municipal-level GeoJSON data from the GJD API and rendering interactive maps with Folium
Objective
In this use case we fetch deforestation data with municipality-level geometry for Caquetá and Putumayo (Colombia) from the GJD API. The API returns paginated GeoJSON, so we collect all pages. We render two interactive maps:
- Basic map — Display all 29 municipalities on a Leaflet map.
- Choropleth map — Color each municipality by its deforestation value and add a tooltip.
Prerequisites
pip install requests folium branca python-dotenvStep 1: Load Libraries and API Key
Step 2: Fetch Municipal GeoJSON from the API
We request deforestation data (topic_id 11) for all 29 municipalities of Caquetá (16) and Putumayo (13) for the year 2019, using IDEAM as source, with geojson=true to include polygon geometries.
Note: For GeoJSON requests, the API uses the parameter
topic_idinstead ofID_Topic. The API returns paginated results (10 features per page), so we loop through all pages.
BASE_URL = "https://api.greenjurisdictions.org/api/v1/dataPlaces/false/false/false"
MUNICIPALITIES = [
"CO-CAQ-18029", "CO-CAQ-18094", "CO-CAQ-18150", "CO-CAQ-18205",
"CO-CAQ-18247", "CO-CAQ-18256", "CO-CAQ-18001", "CO-CAQ-18460",
"CO-CAQ-18410", "CO-CAQ-18479", "CO-CAQ-18592", "CO-CAQ-18610",
"CO-CAQ-18753", "CO-CAQ-18756", "CO-CAQ-18785", "CO-CAQ-18860",
"CO-PUT-86219", "CO-PUT-86001", "CO-PUT-86320", "CO-PUT-86568",
"CO-PUT-86569", "CO-PUT-86571", "CO-PUT-86573", "CO-PUT-86755",
"CO-PUT-86757", "CO-PUT-86760", "CO-PUT-86749", "CO-PUT-86865",
"CO-PUT-86885",
]
params = {
"topic_id": 11,
"ID_Countries": '["CO"]',
"ID_Jurisdictions": '["CO-CAQ","CO-PUT"]',
"ID_Municipalities": json.dumps(MUNICIPALITIES),
"ID_years": '["2019"]',
"ID_sources": '[14]',
"ID_Classes": '[]',
"api": "true",
"lang": "en",
"type": "api",
"geojson": "true",
}
headers = {
"X-API-TOKEN": API_KEY,
"Accept": "application/json",
}
all_features = []
page = 1
while True:
params["page"] = page
response = requests.get(BASE_URL, params=params, headers=headers, timeout=120)
data = response.json()
pag = data["data"]["data"]
features = pag["data"]["features"]
all_features.extend(features)
print(f"Page {page}: {len(features)} features (total: {pag['total']})")
if page >= pag["last_page"]:
break
page += 1
print(f"\nTotal features collected: {len(all_features)}")Step 3: Build the GeoJSON FeatureCollection
We assemble all paginated features into a single GeoJSON FeatureCollection and add human-readable municipality names.
geojson = {"type": "FeatureCollection", "features": all_features}
for f in geojson["features"]:
props = f["properties"]
code = props["place_code"]
props["name"] = code
props["value"] = float(props["value"])
props["jurisdiction"] = "Caquetá" if code.startswith("CO-CAQ") else "Putumayo"
print(f"GeoJSON FeatureCollection with {len(geojson['features'])} municipalities")
for f in geojson["features"]:
p = f["properties"]
print(f" {p['name']}: {p['value']:,.2f} ha ({p['jurisdiction']})")Step 4: Basic Map
Display all 29 municipalities on a Leaflet map with a simple outline.
m1 = folium.Map(location=[0.5, -75.5], zoom_start=7, tiles="CartoDB positron")
folium.GeoJson(
geojson,
name="Municipalities",
style_function=lambda x: {
"color": "#2b7a78",
"weight": 2,
"fillOpacity": 0.15,
},
tooltip=folium.GeoJsonTooltip(
fields=["name", "jurisdiction"],
aliases=["Municipality", "Jurisdiction"],
),
).add_to(m1)
m1.fit_bounds(m1.get_bounds())
m1Step 5: Choropleth Map — Color by Deforestation
We create a color scale from light yellow to dark red based on deforestation values, and add a hover tooltip showing the municipality name, jurisdiction, and deforestation value.
values = [f["properties"]["value"] for f in geojson["features"]]
vmin, vmax = min(values), max(values)
colormap = cm.LinearColormap(
colors=["#fee5d9", "#fb6a4a", "#a50f15"],
vmin=vmin,
vmax=vmax,
caption="Deforestation (hectares) — 2019",
)
m2 = folium.Map(location=[0.5, -75.5], zoom_start=7, tiles="CartoDB positron")
folium.GeoJson(
geojson,
name="Deforestation",
style_function=lambda x: {
"fillColor": colormap(x["properties"]["value"]),
"color": "#333",
"weight": 1.5,
"fillOpacity": 0.7,
},
highlight_function=lambda x: {
"weight": 3,
"color": "#000",
"fillOpacity": 0.85,
},
tooltip=folium.GeoJsonTooltip(
fields=["name", "jurisdiction", "value"],
aliases=["Municipality", "Jurisdiction", "Deforestation (ha)"],
localize=True,
),
).add_to(m2)
colormap.add_to(m2)
m2.fit_bounds(m2.get_bounds())
m2Summary
In this use case we learned how to:
- Request municipal-level GeoJSON from the GJD API by adding
geojson=trueand specifyingID_Municipalities. - Handle paginated responses — the API returns 10 features per page; we loop through all pages.
- Display 29 municipalities on an interactive Folium/Leaflet map.
- Create a choropleth with a color scale, hover tooltips, and a legend.
Next Steps
- Extend to more jurisdictions across the Colombian or Brazilian Amazon.
- Add a temporal slider to compare deforestation across years.
- Overlay additional layers (e.g., protected areas, indigenous territories).