Update, August 20, 2026. This note describes the first version of the dashboard. That version used 28 Utah reservoirs, the Reclamation RISE API alone, and a MapLibre GL JS comparison build. The project has since moved to the ArcGIS Maps SDK for JavaScript 5.1, and it now covers snow and drought as well. It also covers eleven western states instead of Utah, and it is called the Western Water Dashboard. The MapLibre build is retired, and its address now sends you to the current map. For the current application, read One place to see the water in the West.
Utah has spent years in drought, and the numbers that describe it — acre-feet of storage, percent of capacity — are hard to feel from a table. This dashboard put current storage for 28 Bureau of Reclamation-monitored Utah reservoirs on one map, each one drawn so that how depleted it is reads as a shape, not just a color. It was a personal project built with no framework and no build step, and it doubled as a deliberate side-by-side of a commercial mapping SDK against a fully open-source one.
Two ways to measure "low"
Every reservoir carries two drought metrics, both recomputed from the full record rather than read off a single reported number. Percent of period-of-record max compares today's storage against the highest storage that reservoir has reached since 2015 — a stand-in for physical capacity, not the real thing, but a consistent one across reservoirs of wildly different sizes. Seasonal percentile asks a different question: where does today's level rank against every other year's value within a seven-day window of the same calendar date? A reservoir can sit low against its all-time high yet still be normal for early August, and the two numbers together tell that apart.
Reading depletion as a shape
Each reservoir renders as two circles: a gray outline ring sized by that reservoir's period-of-record max, and a colored filled circle on top sized by current storage. The gap between ring and fill is a direct visual read of depletion. Both radii come from the same square-root-scaled size domain — needed to fit Lake Powell at millions of acre-feet and the smallest reservoirs at a few thousand into one legible spread — and the fill is sized as a share of its own ring, so the ring-to-fill ratio always means true percent depletion regardless of the reservoir's absolute size. Fill color follows the same three-tier ramp the popup spells out in words: red under 50%, orange 50–75%, green above 75%.
A pipeline that refreshed itself
The map was static; the data behind it was not. A Python script
(pandas, NumPy, and the RISE API) re-pulled each reservoir's full
daily storage series from 2015 to yesterday, recomputed both drought
metrics, and wrote a single reservoirs.json. A GitHub
Actions workflow ran it every morning at 6 a.m. Mountain, so
the dashboard stayed current with no server to maintain. RISE data
is provisional per Reclamation's own disclaimer, and the app
surfaced that caveat — in the title panel and in every popup
— rather than presenting the most recent days as settled.
Built twice: Esri vs. MapLibre
The first build used the ArcGIS Maps SDK for JavaScript, loaded
straight from Esri's CDN with plain script tags — no npm, no
webpack. Two FeatureLayers carried the symbology, driven
by Arcade valueExpressions, and the popup was a
declarative PopupTemplate that turned the raw percentage
into a plain-language status line and the acre-foot gap to the
historical peak.
The second build rebuilt that exact dashboard in MapLibre GL JS on CARTO's free Positron vector basemap — same data, same dual-circle symbology, same popup wording. The point was a fair comparison: both are WebGL vector renderers, so this replaced an earlier Leaflet attempt, which wasn't a like-for-like test (Leaflet paints raster tiles in the DOM). With both engines actually drawing vector data on the GPU, the results came out functionally identical — verified pixel-for-pixel against the same data, down to Flaming Gorge agreeing exactly on 2,669,060 acre-feet current against a 3,557,090 record max.
The real difference is tooling depth, not capability. Esri's
PopupTemplate and Arcade expressions are declarative
and productive once you know them; MapLibre's popups are plain HTML
you assemble yourself, and its data-driven styling uses native
interpolate/step/sqrt
expressions in place of Arcade. For this specific dashboard,
MapLibre's one-shared-source, two-layer model was arguably the
simpler thing to reason about, since both circle layers already read
from a single authoritative feature set. The open-source stack got
all the way to parity here; what you trade away is the higher-level
conveniences, not the rendering.
View the current Western Water Dashboard or the source on GitHub. The MapLibre GL comparison build is retired and is no longer published. Data: Bureau of Reclamation RISE.
