feat(viz): point-in-polygon choropleth from user GeoJSON + richer hover + theme-aware geo maps#4088
Merged
Merged
Conversation
…ndalone) Bin each row's lat/lon directly into a user-supplied GeoJSON's polygons and use the matched feature id as the location — exact, works at any admin level, and needs no geocoding or GeoNames lookup. Even-odd ray casting handles holes and MultiPolygon. Points outside every region snap to the nearest feature by default; --no-snap drops them. Either way a stderr coverage note reports how many points missed every polygon (pip_assign distinguishes Inside/Snapped/ Outside so snapped points are visible, not silently absorbed). Wired into `viz smart` as the "Regions" panel when --geojson is supplied, and into standalone `viz choropleth`. Zero new Cargo.lock crates (hand-rolled on geojson 0.24, default-features off). Gallery: seismic dashboard now leads with a Japan-prefecture choropleth (examples/viz/japan_prefectures.geojson). Why PIP and not a code/name join: GeoNames admin1 `code` is alphabetical (JP.01=Aichi), not ISO 3166-2 (JP46=Kagoshima), and no dump carries ISO 3166-2, so the only sub-national key is the locale-fragile UTF-8 name. PIP on lat/lon sidesteps the join entirely. Closes part of #302. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rank) Choropleth hover previously showed only a cryptic feature id and a bare number. Each region now shows a human-readable name + id (Kagoshima (JP46)), the value labeled with its measure (count: 65), the share of total (15.6% of total, for count/sum aggregations only), and the rank (rank 1 of 47). The whole label is pre-rendered in Rust and attached via hover_text_array + HoverInfo::Text (the proven ScatterGeo pattern), so it sidesteps plotly hovertemplate token-binding and handles the Rust-computed pct/rank uniformly. Region names come from the new --feature-name-key flag, or are auto-detected from common name properties (properties.name, etc.). PipFeature now retains an HTML-escaped name; the resolvers realign names to aggregate's output order and return the hover array, which PanelKind::Choropleth carries to the smart render arm. Applies to all paths (point-in-polygon, literal --locations, geocoded) and both the geo Choropleth and MapLibre ChoroplethMap (--map) basemaps. Browser-verified the rendered tooltip; regenerated the gallery so the showcase dashboards reflect the new hover. 6 new unit + 4 new integration tests. Part of #302. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rors Address roborev job #3243 (two Medium findings on the PIP choropleth commit): 1. build_choropleth_plot selected point-in-polygon mode whenever --geojson + --lat/--lon were present, silently ignoring an also-supplied --locations column. lat/lon binning and a pre-keyed --locations column are two different ways to identify regions; supplying both without --geocode now errors as ambiguous instead of quietly dropping --locations. 2. build_smart_pip_choropleth_panel used `.ok()?`, swallowing GeoJSON load/parse errors and an unmatched --feature-id-key so `viz smart --geojson` succeeded with no Regions panel and no diagnostic. It now returns CliResult<Option<Panel>> and propagates those errors via `?`; Ok(None) is reserved for valid input that yields fewer than 2 regions. Added 2 integration tests (ambiguous pip+locations; smart bad --feature-id-key). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…leths Address roborev job #3244 (Medium): the enriched hover's human-readable region names were only wired through the point-in-polygon paths. A literal --locations choropleth backed by a custom --geojson (the geojson-id and --map paths) never resolved feature names, so --feature-name-key and auto-detected properties.name were silently ignored and hover fell back to the bare id — despite the docs and CHANGELOG saying names apply there. choropleth_literal_locations now, when --geojson is present, loads/builds the features with feature_id_key + feature_name_key, aligns names to the aggregated locations, and passes them into choropleth_hover_text. The name-alignment logic (previously duplicated in the PIP resolver and the smart PIP panel) is extracted into a shared aligned_region_names() helper. Added a literal+geojson hover-names integration test; regenerated the gallery so figure 28 (--map western_states) shows state names (Colorado (CO), ...). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nels) The geo-subplot charts always rendered light-gray land (and light-blue ocean for scatter-geo) regardless of --theme, so a dark theme showed light land on a dark page. Now the geo land/ocean fills follow the theme: - A shared geo_palette(theme) returns light (qsv's built-in look, unchanged) or dark land/water, applied at all five LayoutGeo sites (choropleth standalone + smart render arm, geo subcommand, smart scatter-geo grid + inline panels). - Choropleth (no oceancolor by default) paints a dark ocean under a dark theme, since the geo.bgcolor "sea" fallback isn't settable via the pinned plotly fork's typed LayoutGeo builder. - The viz smart light/dark toggle now relayouts geo landcolor/oceancolor/ lakecolor too (previously only geo.bgcolor), so switching modes live recolors the map's land and sea, not just its background. Light/default renders are visually unchanged (land stays the lightgray hex, choropleths keep their white sea). Added viz_choropleth_geo_theme_aware test; browser-verified dark standalone choropleth + smart toggle both directions. Regenerated the gallery and all smart dashboards (incl. the three --dictionary infer LLM dashboards, refreshed via a local LM Studio endpoint). Part of #302. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follows up the theme-aware-geo change now that the plotly fork exposes `geo.bgcolor` on the typed `LayoutGeo` builder (dathere/plotly feat/choropleth-maps @ c933b51). bgcolor is the canonical plotly.js attribute for the geo subplot background — the toggle JS already relayouted it — so this replaces the prior workaround: - geo_palette now returns (land, water, background); all five LayoutGeo sites set .bgcolor(geo_bg) directly. - The two choropleth sites drop the dark-only showocean/oceancolor branch: a choropleth paints no ocean, so geo.bgcolor IS the sea. Light/dark is now symmetric (white vs #111111), and the background also covers the area outside the projection — fixing the white corners a global/oval dark map showed under the oceancolor-only workaround. - Scatter-geo sites keep their light-blue ocean and now also set bgcolor. Bumps the plotly pin in Cargo.lock (branch unchanged in Cargo.toml). Updated viz_choropleth_geo_theme_aware to assert geo bgcolor; browser-verified a global dark choropleth (uniformly dark, no white corners). Regenerated the gallery and the geo smart dashboards (incl. the --dictionary infer world choropleth). Part of #302. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Up to standards ✅🟢 Issues
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Builds on #4087. Six commits, all part of #302.
What's new
Point-in-polygon choropleth from a user GeoJSON (
viz choropleth+viz smart). Each row's--lat/--lonis binned directly into the GeoJSON region whose polygon contains it (even-odd ray casting; handles holes & MultiPolygon), and the matched feature id becomes the location — exact, works at any admin level, no geocoding/GeoNames needed. Points outside every region snap to the nearest feature by default (--no-snapdrops them); either way a stderr coverage note reports how many missed every polygon. Wired intoviz smartas the "Regions" panel when--geojsonis supplied. Zero new Cargo.lock crates (hand-rolled ongeojson 0.24, default-features off).Why PIP and not a code/name join: GeoNames admin1
codeis alphabetical (JP.01=Aichi), not ISO 3166-2 (JP46=Kagoshima), and no dump carries ISO 3166-2 — so the only sub-national key is the locale-fragile UTF-8 name. PIP on lat/lon sidesteps the join entirely.Richer choropleth hover. Instead of a bare feature id + value, each region shows a human-readable name + id (
Kagoshima (JP46)), the labeled value (count: 65), the share of total (15.6% of total, count/sum aggs only), and the rank (rank 1 of 47). Names come from a new--feature-name-keyflag or are auto-detected from common name properties. Applies to all paths (PIP, literal--locations, geocoded) and both the geo and MapLibre (--map) basemaps.Input disambiguation + error propagation. Supplying
--lat/--lon + --geojson(PIP) and--locations(pre-keyed) without--geocodenow errors instead of silently ignoring one.viz smart --geojsonnow propagates GeoJSON load/parse/--feature-id-keyerrors instead of silently dropping the panel.Theme-aware geo maps.
geo-subplot charts (choropleth,geo,viz smartmap/region panels) previously always rendered light-gray land regardless of--theme. They now follow the theme — dark land + darkgeo.bgcolorunder a dark theme so the whole map (sea + area outside the projection) matches the page. Theviz smartlight/dark toggle also recolors the geo land/sea live.Cross-repo dependency
Cargo.lock) to dathere/plotly@c933b51onfeat/choropleth-maps, which addsgeo.bgcolorto the typedLayoutGeobuilder (the canonical plotly.js attribute, mirroring the existing land/ocean color fields).Cargo.tomlis unchanged (pin is by branch). CI fetches the fork commit automatically.Tests & artifacts
--dictionary inferLLM dashboards refreshed via a local LM Studio endpoint).docs/help/viz.mdregenerated for the new--feature-name-key/--no-snapflags.🤖 Generated with Claude Code