Spring Thaw: Snowmelt & Flood Vulnerability Assessor
Spring Thaw: Snowmelt & Flood Vulnerability Assessor
Steamboat Springs, Colorado
A spatial analysis project that identifies residential properties at highest risk of flooding during spring snowmelt by integrating FEMA flood zones, historical (April 12, 2024) snow water equivalent (SWE) data, and building footprints.
Live Interactive Map: View the web map here: https://dander1989.github.io/Spring-Thaw-Flood-Assessor/risk_map.html
Problem Statement
Spring flooding isn’t just about proximity to a river; rapid snowmelt is the primary catalyst. By enriching standard flood zone and building footprint data with historical snowpack levels, emergency managers can transition from generic “flood warnings” to pinpointing exactly which neighborhoods face the highest immediate risk from localized snowmelt.
This project demonstrates how open geospatial data and spatial analysis can support actionable emergency preparedness decisions.
Project Outcome
525 buildings in Steamboat Springs’ flood zones have been ranked by snowmelt flood vulnerability, enabling:
- Emergency managers to prioritize evacuation and preparation efforts
- City planners to identify high-risk neighborhoods for infrastructure investment
- Residents to understand their exposure to spring flood risk
Risk Distribution:
- Very High Risk: 217 buildings (41%)
- High Risk: 222 buildings (42%)
- Medium Risk: 57 buildings (11%)
- Low Risk: 29 buildings (6%)
Data Sources
| Source | Type | Resolution | Coverage | Notes |
|---|---|---|---|---|
| NOAA SNODAS | Raster (SWE) | 1 km | Continental US | April 12, 2024 snapshot |
| OpenStreetMap | Vector (buildings) | Feature-level | Global | 5,794 buildings in study area |
| FEMA NFHL | Vector (flood zones) | Polygon | United States | Routt County, CO (2005 vintage) |
Methodology
1. Study Area Definition
Steamboat Springs city boundary fetched from OpenStreetMap using osmnx.geocode_to_gdf(). A 0.35 km buffer was applied to capture complete raster grid cells at the boundary edge (prevents clipping artifacts).
2. Snowpack Data Processing
- Downloaded SNODAS binary data (April 12, 2024) from NOAA NSIDC
- Extracted tar archive and identified SWE file (code 1034)
- Converted binary to GeoTIFF using GDAL with proper geotransform
- Clipped to buffered boundary using Rasterio
- Applied scale factor (÷ 1000) to convert stored integers to meters
- Replaced negative values with 0 (model artifacts in high-elevation areas)
3. Vector Data Preparation
- Fetched OSM building footprints (all types, 5,794 total)
- Downloaded FEMA flood hazard zones for Routt County
- Filtered to high-risk zones (A, AE, AO designations per FEMA standards)
- Reprojected all datasets to EPSG:26913 (UTM Zone 13N, meters) for accurate distance calculations
- Reprojected back to EPSG:4326 for export and web visualization
4. Raster-to-Vector Grid Conversion
Converted clipped SNODAS raster to regular vector grid (168 cells, 1 km × 1 km each) with SWE values attached. Used nested loops with geotransform calculations to generate grid cell polygons:
min_x = minx + (col * pixel_width)
max_x = min_x + pixel_width
max_y = maxy + (row * pixel_height)
min_y = max_y + pixel_height
polygon = Polygon([(min_x, max_y), (max_x, max_y), (max_x, min_y), (min_x, min_y)])
5. Spatial Analysis (DuckDB)
All spatial operations performed using DuckDB with the spatial extension:
Building-Flood Zone Intersection:
SELECT DISTINCT buildings.id, buildings.geom
FROM buildings
JOIN flood_zones ON ST_Intersects(buildings.geom, flood_zones.geom)
Result: 525 buildings (9% of total)
SWE Value Assignment:
SELECT buildings.id, AVG(grid.swe) as avg_swe
FROM buildings
JOIN grid ON ST_Intersects(buildings.geom, grid.geom)
GROUP BY buildings.id
Averaged SWE values for buildings intersecting multiple grid cells.
6. Vulnerability Scoring
Normalization:
- SWE normalized to 0-100 scale:
(swe - 0) / 32.512 * 100 - Distance to river normalized to 0-100 scale:
(max_distance - actual_distance) / (max_distance - min_distance) * 100
Final Score:
- Distance weight: 50%
- SWE weight: 50%
- Formula:
(normalized_distance * 0.5) + (normalized_swe * 0.5)
Risk Categories (based on final score):
- 0-25: Low Risk
- 25-50: Medium Risk
- 50-75: High Risk
- 75-100: Very High Risk
Key Findings
-
Geographic Concentration: 477 of 525 buildings (91%) are within 1 km of the Yampa River, indicating the primary flood driver is proximity to the main channel.
-
Snowpack Variation: SWE ranges from 0-32.5 meters across the study area. High-elevation areas show extreme values (up to 32.767m capped value), consistent with SNODAS model documentation.
-
Risk Stratification: The 50/50 weighting of distance and SWE produces meaningful differentiation: buildings far from the river score lower even with moderate snowpack, while buildings adjacent to the river score highest.
-
Data Quality: Approximately 25% of clipped raster cells had negative or zero SWE values due to model limitations in high-elevation zones. These were set to 0 (conservative estimate).
Deliverables
Maps & Data (in data/output/)
- 01_risk_by_building(1-4).png - Buildings colored by risk category with flood zones overlay throughout Steamboat Springs, CO.
- 02_SNODAS_Grid.png - SNODAS grid cells showing snowpack distribution and building risks
- 03_snodas_clipped.png - Snowpack data alone (context for SWE variation)
- 04_steamboat_all_buildings.png - Full building inventory in study area
- 05_flood_zones.png - FEMA flood hazard areas
- bldgs_vulnerability.csv - Ranked buildings (sorted by vulnerability score descending)
- Images that aren’t mentioned are supplemental and showing my overall process.
Data (in /data/processed/)
Main data here, but kept other processed data
bldgs_vulnerability_final.geojson- 525 buildings with vulnerability scores and risk categoriessnodas_grid.geojson- 168 grid cells with SWE valuesa_fld_zones_area.geojson- High-risk flood zone polygons
Interactive Web Map
risk_map.html- Standalone Leafmap-based web map (hosted on GitHub Pages)- See Live Map link above
Data Quality & Assumptions
SNODAS Raster
- Scale Factor: Values stored as 16-bit signed integers multiplied by 1000; divided by 1000 to recover meters
- Capped Values: Buildings in extreme snowpack areas (≥32.767m) retain capped value (not masked as nodata) to preserve high-risk signal
- Negative Values: Approximately 25% of clipped cells had negative values (model artifacts in high-elevation zones); replaced with 0
- Resolution: 1 km grid may obscure local microclimates and terrain-induced snow variation
Building Footprints (OSM)
- Coverage: 5,794 buildings mapped; mix of residential, commercial, and industrial
- Not filtered by type due to variable data quality (some areas have “residential” tags, others only “building”)
- Mapping Currency: OSM data current as of project date; real-world changes may not be reflected
FEMA Flood Zones
- Vintage: 2005 (most recent available for Routt County); does not reflect recent climate or development changes
- Designations: Filtered to A, AE, AO (1% annual chance flood zones per FEMA standards)
- Limitations: Based on historical hydrology; spring snowmelt patterns may differ from model assumptions
Distance to River
- Calibration: Maximum distance set to 1,000m based on data inspection (477 of 525 buildings within 1 km)
- Weighting: 50/50 split with SWE reflects judgment that proximity and snowpack are equally important
- Validation: Visual inspection in QGIS confirmed buildings far from river score lower
Limitations
- Single-Date Snapshot: Analysis represents conditions on April 12, 2024; doesn’t capture seasonal variation or multi-year trends
- Model Artifacts: SNODAS documentation acknowledges insufficient snow removal mechanisms in high-elevation areas, causing unbounded accumulation in some grid cells
- FEMA Data Age: 2005 flood zone boundaries may not reflect current river hydraulics or development patterns
- River Complexity: Yampa River represented as centerline only; actual flood extent depends on discharge, channel capacity, and local topography
- No Real-Time Updates: Snapshot analysis; would require scheduled data downloads for operational use
- Simplified Scoring: Vulnerability based on two factors (SWE and distance); doesn’t account for building elevation, structure type, or preparedness
How to Reproduce
Prerequisites
conda create -n flood-vuln python=3.10
conda activate flood-vuln
pip install geopandas rasterio gdal osmnx shapely duckdb folium leafmap pandas numpy
Run Analysis
# 1. Clone repository
git clone https://github.com/[your-username]/steamboat-springs-flood-vulnerability.git
cd steamboat-springs-flood-vulnerability
# 2. Use environment.yaml to obtain libraries
# 2. Download raw data (FEMA must be manual)
# - Visit: https://hazards.fema.gov/nhl/
# - Search: Routt County, CO
# - Download flood hazard layer (shapefile)
# - Save to: data/raw/
# 3. Run notebooks in order
jupyter spring_thaw.ipynb
# 4. View outputs
ls data/processed/
View Interactive Map
Open risk_map.html in a browser, or visit the Live Map.
Future Enhancements
Phase 2: Refined Modeling
- River Network Integration: Include tributary streams (not just main channel) for distance calculations
- Temperature Forecast: Integrate Open-Meteo 7-day forecast to predict melt timing
- Building Attributes: Add structure age, elevation, basement presence to refine risk score
Phase 3: Automation & Deployment
- Scheduled Updates: Daily SNODAS downloads with automated scoring refresh
- Web Service: Flask/FastAPI backend with REST API for queries
- Alert System: Push notifications to emergency managers when vulnerability thresholds crossed
Phase 4: Expansion
- Multi-Town Analysis: Replicate for Vail, Fort Collins, other Colorado flood-prone areas
- Historical Validation: Compare 2024 predictions to actual 2023 flood events
- User Dashboard: Streamlit or Dash interface for planners to run “what-if” scenarios
Phase 5: Integration
- Live Stream Gauges: Incorporate USGS real-time discharge data
- Evacuation Routes: Overlay with road network and emergency routes
- Damage Assessments: Post-flood analysis to validate model accuracy
Technical Stack
| Component | Tool | Version |
|---|---|---|
| Language | Python | 3.10+ |
| Geospatial | GeoPandas, Rasterio, GDAL, Shapely | Latest |
| Database | DuckDB (spatial extension) | 0.10+ |
| Web Mapping | Leafmap, Folium | Latest |
| Visualization | QGIS, Matplotlib | Latest |
| Version Control | Git/GitHub | — |
Learning Outcomes
This project demonstrates:
- Raster Processing: Download, convert, clip, and sample geospatial raster data (SNODAS)
- Vector Operations: Spatial joins, intersections, and aggregation (GeoPandas, DuckDB)
- Spatial SQL: Writing efficient queries with
ST_Intersects(),ST_Distance(), aggregation - CRS Management: Handling coordinate systems, reprojection, and validating geometric accuracy
- Data Quality: Identifying and handling model artifacts, outliers, and missing data
- Geospatial Workflow: End-to-end analysis from raw data to publication-ready maps and exports
- Portfolio Development: Documenting methodology, limitations, and future work for stakeholder communication
Lessons Learned
- Data Inspection Matters: Visual verification in QGIS caught an inflated max-distance value that would have skewed results
- CRS Consistency: Reprojection issues were debugged only after checking geometry validity and explicitly setting spatial references
- Iterative Refinement: River proximity integration seemed simple initially; complexity revealed the value of starting simple and adding features incrementally
- Documentation First: Decisions (buffer size, scaling factors, weighting) must be explained in code comments for reproducibility
Acknowledgments
- Data Providers: NOAA (SNODAS), OpenStreetMap, FEMA
- Open-Source Tools: GeoPandas, Rasterio, DuckDB, Leafmap
- Inspiration: Emergency management need for actionable flood risk data
License
This project is licensed under the MIT License. See LICENSE file for details.
Contact
Author: David J. Anderson
Project Date: March 2026
Questions? Open an issue on GitHub or reach out via [LinkedIn/personal site]
References
- NOAA SNODAS Documentation: https://nsidc.org/data/G02158/
- FEMA NFHL: https://hazards.fema.gov/nhl/
- OpenStreetMap: https://www.openstreetmap.org/
- DuckDB Spatial: https://duckdb.org/docs/extensions/spatial
- Geospatial Analysis in Python: https://geopandas.org/
Last Updated: March 17, 2026