Fire event vase + climate merge (fire_plot)
FIRED daily fire perimeters and gridMET climate grids span the same era but rarely meet in a unified analysis space. FIRED tracks perimeter geometry day by day, while gridMET provides gridded meteorology over CONUS. CubeDynamics stitches these together so that fire progression, space–time geometry, and climate context can be explored in one object.
v.fire_plot packages this workflow. It chooses a FIRED event that fits gridMET temporal support, builds a space–time “vase” from the daily polygons, summarizes that vase as a triangulated hull, samples gridMET into the event window, and returns an interactive Plotly visualization plus metrics. The result is an event-centric cube you can visualize and quantify without writing glue code.
Concepts
Vase (space–time event volume)
Daily polygons are extruded through time to form a 3-D volume—a “vase.” Two knobs control how finely the perimeter is discretized:
n_ring_samples: number of radial samples along the boundary (and interior rings, if present).n_theta: angular resolution controlling mesh smoothness.
A well-sampled vase makes it possible to fill and merge gridded climate data into an event-defined space–time region, enabling event-centric statistics and visualization.
Hull (geometric summary)
The hull is a compact triangulated surface summarizing the vase. Key arrays include:
verts_km(N×3): vertices in kilometers (x, y, time/day).tris(M×3indices): triangle connectivity over the vertices.
Hull metrics (scale, duration, volume, surface) make it easy to summarize, compare, and render fire events.
Stream alignment (FIRED × gridMET)
gridMET has fixed temporal support. To ensure the fire window (plus buffer) sits inside that support, use GRIDMET_SUPPORT and pick_event_with_joint_support. They enforce that the chosen FIRED event can be paired with the requested climate buffer before running fire_plot.
Quickstart
Cube-first usage is recommended: load your climate cube (gridMET, PRISM, Sentinel-2 NDVI, etc.) however you prefer, then pipe it into v.fire_plot(fired_event=...).
from cubedynamics import verbs as v
from cubedynamics.fire_time_hull import (
load_fired_conus_ak,
GRIDMET_SUPPORT,
pick_event_with_joint_support,
)
# 1) FIRED daily (downloads & caches if enabled)
fired_daily = load_fired_conus_ak(which="daily", prefer="gpkg", download=True)
# 2) Choose an event that fits GRIDMET temporal support
event_id = pick_event_with_joint_support(
fired_daily,
climate_support=GRIDMET_SUPPORT,
time_buffer_days=14,
min_days=64,
)
# 3) Run fire_plot (returns hull + cube + summary + fig)
results = v.fire_plot(
fired_daily=fired_daily,
event_id=event_id,
climate_variable="vpd", # or "tmmx"
freq="D", # daily by default; avoid empty monthly windows
allow_synthetic=False, # fail loudly instead of using demo data
time_buffer_days=1,
n_ring_samples=200,
n_theta=296,
show_hist=False,
save_prefix=None,
)
# Optional: show interactive Plotly hull in notebook
results["fig_hull"].show(renderer="iframe")
hull = results["hull"]
summary = results["summary"]
cube = results["cube"]
print("Event:", results["event"].event_id)
print("Hull verts:", hull.verts_km.shape, "tris:", hull.tris.shape)
print("Cube:", getattr(cube, "da", None).shape if hasattr(cube, "da") else type(cube))
!!! tip "Daily by default"
fire_plot requests daily gridMET/PRISM data for event windows. Explicitly pass
freq="D" to emphasize daily sampling or a different frequency if needed.
What you get back
v.fire_plot returns a dictionary with:
event(FireEventDaily): cleaned FIRED daily perimeters, centroid, and time bounds.hull(TimeHull): triangulated vase geometry with metrics (scale_km,days,volume_km2_days,surface_km_day).cube(ClimateCube): gridMET DataArray clipped to the event window with any requested buffer.summary(HullClimateSummary): inside/outside pixel samples and per-day means for the event footprint.fig_hull(plotly.graph_objects.Figure): interactive Mesh3d hull colored by mean climate.color_limits(tuple[float, float]): min/max used for the Plotly colorbar.
If show_hist=True, a Matplotlib histogram is also drawn (for interactive QA) but is not returned in the dictionary.
Daily frequency (freq) for GRIDMET / PRISM
freq is forwarded to the GRIDMET/PRISM loaders and controls the cube's time index. For fire events, use daily sampling:
results = v.fire_plot(..., freq="D", ...)
- Default: when
freqis not supplied,fire_plotrequests daily GRIDMET/PRISM data (freq="D"). - Why daily? Fire events are short; daily timestamps prevent gaps and align with FIRED daily perimeters. The same setting applies if you target PRISM variables.
- Gotcha:
freq="MS"(month start) can yield zero timestamps for short windows (e.g., 2018-07-17 to 2018-07-25), producing an empty cube. Keepfreq="D"or widen the window when analyzing individual events.
Parameters and tuning
climate_variable: use"vpd"(vapor pressure deficit, kPa) to match the prototype or"tmmx"(daily max temperature). Other gridMET variables pass through unchanged.time_buffer_days: buffer applied insidefire_plotwhen fetching climate data around the event. This is separate from the selection buffer used inpick_event_with_joint_support—you can keep the selection buffer generous (e.g., 14 days) while using a smaller fetch buffer (e.g., 1 day) for plotting.n_ring_samples/n_theta: higher values yield smoother hulls at the cost of compute. Start with the defaults (200 / 296); for higher quality rendering, pushn_ring_samplestoward 300–400 andn_thetatoward 360–512.show_hist: enable when you want to visually compare inside vs. outside pixel distributions for QA.save_prefix: if set, Plotly static export attempts to write{save_prefix}.pngusing Kaleido; leaveNoneto skip file output.
Preview

!!! note
Image placeholder — after running locally, save a screenshot to docs/assets/workflows/fire_event_vase_hull.png.
Data provenance
Every cube returned by fire_plot carries provenance in cube.da.attrs:
source: one ofgridmet_streaming,gridmet_download,prism_streaming,prism_download, orsynthetic.is_synthetic:Trueonly when a synthetic fallback was generated.freq: temporal frequency actually used (daily by default for gridMET/PRISM).backend_error: present only when a fallback occurred (streaming → download or synthetic).
Inspect these fields after running the recipe to confirm that real data were fetched.
Common pitfalls
!!! warning
- Empty time axis: A short window with freq="MS" or freq="ME" can return zero timestamps. Use freq="D" for event-scale analyses.
- Synthetic fallback: By default allow_synthetic=False raises if the backend fails or returns empty/NaN data. Set allow_synthetic=True only for demos.
- Backend dependencies: If streaming is unavailable, install the required optional dependencies or point to cached downloads before retrying.
Troubleshooting
- FIRED download/cache issues: check the
load_fired_conus_akdocstring for cache layout and download guidance; ensure the target file exists or enabledownload=True. - No event found for selection: relax
min_daysor increasetime_buffer_daysinpick_event_with_joint_supportto widen the search window. - Plotly not rendering in notebooks: set an explicit renderer (e.g.,
results["fig_hull"].show(renderer="iframe")or"browser") and ensure Kaleido is installed only if exporting images.