feat(osm-equity): interactive MapLibre choropleth heat map#24
Conversation
BuildEquityReport now emits a self-contained MapLibre GL "heat map" of per-tract OSM attribute completeness (green=well-mapped, red=under-mapped), in the facetwork-maps gallery house style: inline GeoJSON, CARTO Voyager raster basemap, click popups (income / completeness / POI diversity / footprint completeness / data-desert flag), a legend, a findings banner (Spearman rho, Moran's I, temporal trend), and red outlines on data-desert tracts. Prominently labelled SYNTHETIC DEMONSTRATION DATA. map_path now points at this interactive map (equity_map.html); the raw choropleth GeoJSON is still written alongside. Test asserts the map is a MapLibre document. ruff clean; 13 tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request replaces the static GeoJSON choropleth output with an interactive MapLibre GL heat map HTML report. Feedback focuses on improving robustness and cross-platform compatibility: specifically, handling potential MultiPolygon geometries when calculating map bounds to avoid unpacking errors, explicitly specifying UTF-8 encoding when writing the HTML map, and using a context manager with explicit encoding when reading files in tests to prevent resource leaks.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| xs, ys = [], [] | ||
| for f in feats: | ||
| for ring in f["geometry"]["coordinates"]: | ||
| for x, y in ring: | ||
| xs.append(x) | ||
| ys.append(y) |
There was a problem hiding this comment.
The current coordinate extraction logic assumes all geometries are single Polygons. If any tract geometry is a MultiPolygon (which is common for real-world census tracts), f["geometry"]["coordinates"] will have an extra level of nesting, causing for x, y in ring: to raise a ValueError: too many values to unpack.
Since shapely.geometry.shape is already imported, we can compute the bounding box robustly for any geometry type (including Polygon and MultiPolygon) by using the .bounds property of the shapely shape.
xs, ys = [], []
for f in feats:
geom = f.get("geometry")
if geom:
try:
sh = shape(geom)
if not sh.is_empty:
minx, miny, maxx, maxy = sh.bounds
xs.extend([minx, maxx])
ys.extend([miny, maxy])
except Exception:
pass|
|
||
| # the interactive heat map (this is the returned map_path) | ||
| map_path = out_dir() / "equity_map.html" | ||
| map_path.write_text(render_maplibre_map(feats, title, stats_res, deserts)) |
There was a problem hiding this comment.
When writing text files in Python, it is a best practice to explicitly specify encoding="utf-8". Otherwise, Python will fall back to the platform's default encoding (e.g., cp1252 on Windows), which can lead to UnicodeEncodeError if the HTML content contains non-ASCII characters.
| map_path.write_text(render_maplibre_map(feats, title, stats_res, deserts)) | |
| map_path.write_text(render_maplibre_map(feats, title, stats_res, deserts), encoding="utf-8") |
| assert len(records) >= 9 | ||
| assert os.path.exists(report["report_html"]) | ||
| assert os.path.exists(report["map_path"]) | ||
| assert "maplibre" in open(report["map_path"]).read().lower() # interactive heat map |
There was a problem hiding this comment.
Using open().read() without a with statement leaves the file handle open until garbage collection runs, which can cause resource leaks or file locking issues (especially on Windows). Additionally, specifying encoding="utf-8" ensures the test runs consistently across different platforms.
| assert "maplibre" in open(report["map_path"]).read().lower() # interactive heat map | |
| with open(report["map_path"], encoding="utf-8") as f: | |
| assert "maplibre" in f.read().lower() # interactive heat map |
Adds a self-contained MapLibre GL heat map to the osm-equity example's Phase-5 reporting, in the facetwork-maps gallery house style (inline GeoJSON, CARTO Voyager basemap, popups, legend, findings banner, data-desert outlines). Prominently labelled SYNTHETIC DEMONSTRATION DATA.
map_pathnow returns this interactive map. 13 tests pass; ruff clean.🤖 Generated with Claude Code