FIRMS — fire-season time-series¶
Count daily fire pixels and total daily FRP over a fire season for one region, then plot the activity curve. Shows the backend chunking a multi-week window into ≤10-day requests transparently.
Setup¶
The imports plus an output directory for the downloaded detections. FIRMS is a vector backend, so
download() writes the active-fire table to OUT_DIR and returns it for plotting.
import datetime as dt
import os
from pathlib import Path
from earthlens import EarthLens
OUT_DIR = Path('firms_output')
OUT_DIR.mkdir(exist_ok=True)
Credentials¶
FIRMS needs a free MAP_KEY (https://firms.modaps.eosdis.nasa.gov/api/map_key/). Set FIRMS_MAP_KEY
in your environment; the live cells below skip cleanly (nbval-lax-safe) when it is absent, so the
notebook never fails offline.
HAS_KEY = bool(os.environ.get('FIRMS_MAP_KEY'))
print('FIRMS_MAP_KEY set:', HAS_KEY)
Query a fire-season window¶
A several-week window is split into ≤10-day chunks internally and returned merged. Use a recent window so the NRT sensor has coverage — here the last 30 days.
TODAY = dt.date.today()
START = (TODAY - dt.timedelta(days=30)).strftime('%Y-%m-%d')
END = TODAY.strftime('%Y-%m-%d')
Download the detections¶
The request is built first, then download() is called on its own line so each step reads clearly.
The whole fetch is wrapped in a guard so the notebook skips gracefully when the key is missing or the
live query fails.
fires = None
if HAS_KEY:
try:
firms = EarthLens(
data_source='firms',
variables=['VIIRS_SNPP_NRT'],
start=START,
end=END,
aoi=[-124.0, 36.0, -118.0, 42.0], # Northern California / Pacific NW
path=str(OUT_DIR),
)
fires = firms.download(progress_bar=False)
print('detections:', len(fires))
except Exception as exc:
print('skipped live query:', exc)
Daily fire activity¶
Group the detections by acquisition date to get a daily fire-pixel count and the total daily FRP. These two series drive the activity plot.
daily = None
if fires is not None and len(fires):
daily = fires.assign(date=fires['acq_datetime'].dt.date).groupby('date')
counts = daily.size()
total_frp = daily['frp'].sum()
Plot the activity curve¶
Bars show the daily fire-pixel count (left axis) and the line shows total FRP in MW (right axis); the busiest day is annotated as the peak.
if daily is not None:
import matplotlib.pyplot as plt
fig, ax1 = plt.subplots(figsize=(9, 4))
ax1.bar(counts.index, counts.values, color='tab:orange', alpha=0.6)
ax1.set_ylabel('fire-pixel count', color='tab:orange')
ax1.set_xlabel('date')
ax2 = ax1.twinx()
ax2.plot(total_frp.index, total_frp.values, color='tab:red', marker='o')
ax2.set_ylabel('total FRP (MW)', color='tab:red')
ax1.set_title(f'Daily fire activity, {START} to {END}')
peak = counts.idxmax()
ax1.annotate(
f'peak: {peak}',
xy=(peak, counts.max()),
xytext=(0.6, 0.85),
textcoords='axes fraction',
arrowprops=dict(arrowstyle='->'),
)
fig.tight_layout()
plt.show()