From be45093c10b7b77b3966fc42ffc0b4cf11950f33 Mon Sep 17 00:00:00 2001 From: rlemke Date: Mon, 13 Jul 2026 19:28:53 -0700 Subject: [PATCH] feat(osm-equity): selectable heat-map metric (+ grey N/A shading) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit render_maplibre_map gains metric/metric_label params (default attr_completeness), so a map can colour units by any per-unit metric — e.g. footprint_completeness to show the OSM-vs-authoritative building gap. Negative sentinels (N/A, e.g. no footprint reference) now render grey via a MapLibre `case` rather than as the worst colour. Default behaviour unchanged. Used to render a full-detail tiled Tucson map (real OSM 282k buildings vs 252k Microsoft footprints): 21/167 2-sq-mi tiles fall below 50% OSM building completeness — intra-city under-mapping the national aggregate hides. Co-Authored-By: Claude Opus 4.8 --- .../handlers/shared/equity_utils.py | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/examples/osm-equity/handlers/shared/equity_utils.py b/examples/osm-equity/handlers/shared/equity_utils.py index 65d67db9..757d3374 100644 --- a/examples/osm-equity/handlers/shared/equity_utils.py +++ b/examples/osm-equity/handlers/shared/equity_utils.py @@ -708,12 +708,20 @@ def data_deserts(records: list[dict]) -> list[str]: def render_maplibre_map( - feats: list[dict], title: str, stats_res: dict, deserts: list[str], synthetic: bool = True + feats: list[dict], + title: str, + stats_res: dict, + deserts: list[str], + synthetic: bool = True, + metric: str = "attr_completeness", + metric_label: str = "Attribute completeness", ) -> str: - """Self-contained MapLibre GL choropleth ("heat map") of tract OSM - attribute completeness, styled to match the facetwork-maps gallery: - inline GeoJSON, CARTO Voyager raster basemap, click popups, a legend, - and a findings banner. Data-desert tracts get a red outline.""" + """Self-contained MapLibre GL choropleth ("heat map") of a per-unit OSM + metric (default attribute completeness), styled to match the facetwork-maps + gallery: inline GeoJSON, CARTO Voyager raster basemap, click popups, a + legend, and a findings banner. Data-desert units get a red outline. + Negative metric values (N/A sentinels, e.g. no footprint reference) render + grey rather than as the worst colour.""" fc = json.dumps({"type": "FeatureCollection", "features": feats}) # total bounds via shapely (handles Polygon + MultiPolygon uniformly) xmin = ymin = float("inf") @@ -764,7 +772,7 @@ def render_maplibre_map(
-
Attribute completeness
+
{metric_label}
0.00.51.0
@@ -783,8 +791,9 @@ def render_maplibre_map( map.on('load',()=>{{ map.addSource('tracts',{{type:'geojson',data}}); map.addLayer({{id:'fill',type:'fill',source:'tracts',paint:{{ - 'fill-color':['interpolate',['linear'],['get','attr_completeness'], - 0.0,'#d73027',0.25,'#fc8d59',0.5,'#fee08b',0.75,'#91cf60',1.0,'#1a9850'], + 'fill-color':['case',['<',['to-number',['get','{metric}']],0],'#999999', + ['interpolate',['linear'],['to-number',['get','{metric}']], + 0.0,'#d73027',0.25,'#fc8d59',0.5,'#fee08b',0.75,'#91cf60',1.0,'#1a9850']], 'fill-opacity':0.72}}}}); map.addLayer({{id:'outline',type:'line',source:'tracts',paint:{{ 'line-color':'#333','line-width':0.4}}}});