SBS Map Utilities (sbs_map.py)
Classifies Soil Burn Severity (SBS) rasters into canonical WEPP burn classes, whether the source raster uses numeric breaks or a color table.
See also:
../../AGENTS.mdfor NoDb controller conventions and test expectations.
Overview
wepppy/nodb/mods/baer/sbs_map.py is the canonical SBS raster normalization module used by BAER and disturbed-land workflows. It accepts source rasters with or without color tables, validates map readiness, and produces stable class outputs used by WEPP pipelines and map clients.
The module supports two ingestion paths:
- Numeric-class rasters (4-class or BARC-like
0..255ranges) using breakpoint classification. - Palette rasters using GDAL color-table lookup mapped to SBS severities (
unburned,low,mod,high).
The output contract is stable across both paths:
- Runtime classification can use
130..133(130=unburned,131=low,132=moderate,133=high). export_4class_mapwrites canonical output classes0..3(plus255for NoData/unknown).- Unknown color-table indices map to
255in the color-table classification path. export_4class_map(..., export_palette="shifted")is the default.export_4class_map(..., export_palette="legacy")remains available for transition workflows.
Preparing SBS Map for wepp.cloud
Use this section when preparing an SBS file for upload to wepp.cloud, especially if you are not a GIS specialist.
Minimum checklist before upload
- Use a single-band raster (GeoTIFF is the safest choice).
- Store integer values only (no decimal pixel values).
- Keep total unique values at
<= 256. - Ensure the file has a valid spatial reference (projection metadata). If uncertain, reproject to a local UTM CRS.
- Use one of these data styles:
- Integer classes without a color table (for example
0,1,2,3or BARC-style0..255), or - A color-table raster whose colors match known SBS severity colors.
- Integer classes without a color table (for example
Practical workflow (QGIS/ArcGIS style)
- Open your SBS raster and confirm it is a thematic class map (not a continuous float surface).
- Reproject to your local UTM zone if needed. Use nearest-neighbor resampling.
- Convert/export as an integer raster (
Byteor another integer type) and preserve NoData where possible. - Save as GeoTIFF and keep the layer as one band.
- If you use a color table, make sure at least one burn class color (
low,mod, orhigh) is a recognized SBS color. - Upload to wepp.cloud; if validation fails, use the message table below.
Common validation messages and fixes
| Message from upload validation | What it means | Quick fix |
|---|---|---|
Map contains an invalid projection. Try reprojecting to UTM. |
CRS metadata is missing or invalid. | Reproject to a valid projected CRS (typically UTM), then export again. |
Map has non-integer classes |
Pixel values contain decimals/floats. | Reclassify or round to integer class values and export as integer raster. |
Map has more than 256 classes |
Too many unique pixel values were detected. | Reclassify to a smaller set of thematic classes (for example 4-class or BARC-style). |
Map has no valid color table |
A color table exists, but recognized SBS colors were not found. | Fix/remap the palette to known SBS colors, or remove the color table and use numeric classes. |
API
| Symbol | Purpose |
|---|---|
sbs_map_sanity_check(fname) |
Fast validity gate for uploads and batch ingestion. |
get_sbs_color_table(fn, color_to_severity_map=None) |
Reads GDAL color table and resolves severity index buckets. |
classify(v, breaks, nodata_vals=None, offset=0) |
Numeric breakpoint classification path. |
ct_classify(v, ct, offset=0, nodata_vals=None) |
Color-table index classification path. |
SoilBurnSeverityMap |
Main wrapper with class maps, counts, and export helpers. |
Installation / Setup
sbs_map.py relies on GDAL in two ways:
- Python bindings (
from osgeo import gdal) - CLI tools used by export helpers (
gdalwarp,gdaldem,gdal_translate)
Optional acceleration:
- Rust helpers from
wepppyo3.sbs_mapare used when available. - Python logic is the fallback and remains the behavior baseline.
Color Table And Palette Contracts
Source of truth: if code and docs diverge, update both in the same change.
Lookup map locations:
wepppy/nodb/mods/baer/data/sbs_color_map.json(primary)_DEFAULT_COLOR_TO_SEVERITYinwepppy/nodb/mods/baer/sbs_map.py(fallback)
Ingest Color Recognition (color-table path)
The lookup accepts multiple aliases per class. Representative examples:
| Severity | Recognized RGB examples |
|---|---|
unburned |
0,100,0, 0,115,74, 0,158,115, 0,0,0 |
low |
127,255,212, 77,230,0, 86,180,233, 0,255,255 |
mod |
255,255,0, 255,232,32, 240,228,66 |
high |
255,0,0, 204,121,167 |
Validation rule used by sbs_map_sanity_check:
- A color table is considered valid when at least one of
low,mod, orhighis recognized.
4-Class Export Palettes
export_4class_map writes classes 0..3 and applies one of these palettes:
| Severity | Export class | shifted (default) |
legacy |
|---|---|---|---|
| Unburned | 0 |
0,158,115 (#009E73) |
0,100,0 (#006400) |
| Low | 1 |
86,180,233 (#56B4E9) |
127,255,212 (#7FFFD4) |
| Moderate | 2 |
240,228,66 (#F0E442) |
255,255,0 (#FFFF00) |
| High | 3 |
204,121,167 (#CC79A7) |
255,0,0 (#FF0000) |
| NoData | 255 |
255,255,255,0 |
255,255,255,0 |
Quick Start / Examples
from wepppy.nodb.mods.baer.sbs_map import SoilBurnSeverityMap, sbs_map_sanity_check
status, message = sbs_map_sanity_check("/path/to/sbs.tif")
if status != 0:
raise RuntimeError(message)
sbs = SoilBurnSeverityMap("/path/to/sbs.tif")
# Raw value -> canonical class code strings ("130".."133", or "255")
pixel_map = sbs.class_pixel_map
# Human-facing grouped counts
counts = sbs.burn_class_counts
# Export normalized 4-class GeoTIFF (0..3 + 255 nodata)
sbs.export_4class_map("/tmp/sbs_4class.tif")
Override lookup map (for controlled ingest experiments):
custom_map = {
(0, 158, 115): "unburned",
(86, 180, 233): "low",
(240, 228, 66): "mod",
(204, 121, 167): "high",
}
sbs = SoilBurnSeverityMap("/path/to/sbs.tif", color_map=custom_map)
Key Concepts / Domain Model
| Concept | Description |
|---|---|
| Runtime class codes | 130..133 when classification uses an SBS offset (130=unburned, 133=high). |
| Export class codes | 0..3 in export_4class_map; this is the canonical 4-class raster output. |
| Unknown class handling | Unknown color-table entries map to 255 (NoData sentinel). |
ignore_ct=True |
Forces breakpoint classification even when a color table exists. |
is256 |
Indicates inferred BARC-like style (0..255) in non-color-table workflows. |
Accessibility Guidance: Color-Shifted SBS Maps
Use this checklist when implementing or reviewing Color Shift behavior for universal design:
- Keep severity semantics stable. Color Shift changes display color only, not class meaning.
- Keep text labels explicit (
Unburned,Low,Moderate,High) in legends and tooltips. - Keep one-to-one class mapping across raster colors, legend chips, and tooltips.
- Keep unknown colors explicit (
255) rather than silently coercing values. - Ensure color is not the only cue; pair color with labels, order, or numeric codes.
Developer Notes
- Rust acceleration is used when available (
wepppyo3.sbs_map); Python fallback remains authoritative. _SBS_COLOR_MAP_PATHis passed into Rust helpers so Python and Rust share the same lookup contract.export_4class_mapfails fast withValueErrorfor unsupportedexport_palettevalues.- When updating color lookup behavior:
- Update
sbs_map.pyfallback defaults. - Update
data/sbs_color_map.json. - Update SBS tests that mirror lookup dictionaries.
- Update
Targeted tests:
wctl run-pytest tests/nodb/mods/baer/test_sbs_map_extended.py tests/nodb/mods/baer/test_sbs_map_classify_validation.py tests/sbs_map/test_sbs_map.py
Operational Notes
sbs_map_sanity_checkvalidates projection, integer classes, class count, and color-table recognizability; it does not clip/crop rasters to a run extent.- BAER/Disturbed run workflows perform grid alignment later (for example,
gdalwarpto project/run extent in BAER).
Further Reading
wepppy/nodb/mods/baer/README.mdwepppy/nodb/mods/baer/sbs_map.pywepppy/nodb/mods/baer/sbs_map.pyiwepppy/nodb/mods/baer/data/sbs_color_map.jsondocs/ui-docs/control-ui-styling/sbs_controls_behavior.md