Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Fika · Maps that decide where infrastructure goes

A small case-study site, built in days, exploring the kind of work Fika's Digital team does: turning geospatial data and ML into maps that tell a non-technical decision-maker where infrastructure investment matters most. A landing page frames the problem, then three working map prototypes prove the value on a single click.

Live structure: / (case study) → /prioritizer · /map-goes-dark · /time-to-care

Case-study landing


The three prototypes

01 · The Prioritizer, the funding decision

Drag one slider, "how many bridges can you fund?", and watch candidate crossings get funded in priority order over a Zambian region. The first handful connect almost everyone cut off from health care; then the curve flattens. You discover Fika's 80/30 rule by dragging: ~31% of the bridges reach ~80% of the people, and cost-per-person climbs from ~$69 to ~$181 as you chase the long tail (the Pareto Trap). Built entirely on Fika's real model outputs (88 candidate bridges, 6,276 population hexes, travel-time-saved per site); the only added assumption is an illustrative flat cost per bridge.

The Prioritizer

02 · Where the Map Goes Dark, the problem, made visible

Drag a divider to compare the official map (OpenStreetMap) with Fika's WaterNet AI-detected waterways over a Zambian district. 80% of the waterways WaterNet finds here are missing from OpenStreetMap, the very rivers that isolate communities, invisible on the map governments plan from.

Where the Map Goes Dark

03 · Time to Care, the human scale

Tap a rural community in Chama District, Zambia and see how long it really takes to reach the nearest clinic or school on foot, then toggle how a single river crossing changes it. Luchenga Village goes from a 5h 41m walk to school down to 1h 34m with one bridge.

Time to Care

The three interlock: WaterNet (02) reveals the rivers that isolate people, the Prioritizer (01) decides which crossings to fund first, and Time to Care (03) shows what one of them means for a single village.

Why these choices

Decision Rationale
Svelte / SvelteKit Fika's main frontend. One unified app, three routes, shared design system.
MapLibre GL JS Open-source, token-free twin of Mapbox GL JS (which Fika uses). The public repo, live link and recordings all work with no access token.
Pre-computed, static data No live routing, no live ML inference. Python does the heavy work offline; the site is a fast, serverless static build.
Real open data OpenStreetMap geography + Fika's published WaterNet outputs (CC-BY-4.0). Nothing is invented.
Honest, illustrative models Travel times and coverage gaps are labelled illustrative. Clarity for a decision maker, not false precision.

How the numbers are made (offline, once)

data-prep/
  probe_districts.py        # picked Chama on OSM-coverage evidence
  fetch_osm.py              # real OSM communities/clinics/schools/rivers -> GeoJSON
  build_travel_times.py     # Time to Care: where would a crossing help most?
  finalize_web.py           # lean web bundle -> app/static/data  (~200 KB)
  waternet/
    prep_mapdark.py         # reads WaterNet COG over Chama, builds the reveal layer
                            #   + the headline: % of detected waterways absent from OSM
  prioritizer/
    build_prioritizer.py    # ranks Fika's real candidate bridges -> impact sequence JSON
  • The Prioritizer: consumes Fika's published model run for a Zambian region (t5-analysis on their public S3 bucket): 88 candidate bridges, 6,276 H3 population hexes, and per-hex travel-time-saved. A bridge "connects" a hex only when it actually reduces that hex's travel time to health care, so the greedy funding order and the cumulative curve are real, not modelled by us. Only the per-bridge cost is illustrative. Yields the 80/30 sequence the slider walks.
  • Time to Care model: major rivers (waterway=river) are barriers; streams are wadeable. For each community, find where a candidate crossing helps most - walk-straight-with-a-bridge vs. detour-to-the-nearest-existing-crossing, at 4.5 km/h with a 1.3× path-sinuosity factor. Every figure is reproducible from OSM geometry; none is hand-typed.
  • Map Goes Dark: reads only the Chama window from WaterNet's remote Cloud-Optimized GeoTIFF (no gigabyte download), thresholds confident waterways (>0.5), masks to the district, and rasterises OSM waterways to compute the share of the detected network with no OSM equivalent (80%).

Run it

cd app
npm install
npm run dev        # http://localhost:5173
npm run build      # production build (every route prerendered)

Deploy (Vercel)

The app lives in the app/ subdirectory and uses @sveltejs/adapter-vercel, so:

  1. Import the repo in Vercel.
  2. Set Root Directory to app (the only required setting; SvelteKit is then auto-detected).
  3. Deploy. Every route is prerendered, so it serves as a static, serverless site.

For any other static host (Netlify, GitHub Pages, S3), swap the adapter line in app/svelte.config.js for @sveltejs/adapter-static (adapter({ fallback: 'index.html' })) and serve app/build.

Regenerate data (optional, the shipped bundles are committed):

python3 -m venv data-prep/.venv && source data-prep/.venv/bin/activate
pip install shapely rasterio pyproj pillow matplotlib
python3 data-prep/probe_districts.py
python3 data-prep/fetch_osm.py
python3 data-prep/build_travel_times.py
python3 data-prep/finalize_web.py
python3 data-prep/waternet/prep_mapdark.py
# The Prioritizer (downloads Fika's t5-analysis outputs from their public bucket):
python3 data-prep/prioritizer/build_prioritizer.py

Deploying under a subpath (e.g. a GitHub Pages project site)? Set paths.base in app/svelte.config.js; all asset/data URLs already use SvelteKit's base.

Data & provenance

  • Geography, © OpenStreetMap contributors (ODbL).
  • WaterNet detected waterways, Fika / Better Planet Laboratory, CC-BY-4.0, via source.coop/fika/waternet (paper arXiv 2412.00050).
  • Bridge prioritisation, Fika's t5-analysis outputs (candidate bridges, population, travel-time-saved) from their public public-b2p-geodata S3 bucket.
  • Travel times & coverage gaps, illustrative, generated by the models above. In The Prioritizer, the prioritisation and impact are real; only per-bridge cost is illustrative.

Honest scope

A job-application prototype: small and finished over large and unfinished. Out of scope by design, live routing, multiple districts, accounts, real-time ML inference, cloud infrastructure. Candidate crossings and the coverage comparison are illustrative, not engineered conclusions.

Structure

app/
  src/routes/            /  ·  prioritizer  ·  map-goes-dark  ·  time-to-care
  src/lib/prioritizer/   PrioritizerMap, ImpactCurve
  src/lib/mapdark/       SwipeMap
  src/lib/timetocare/    Map, StoryCard, Intro, Legend
  src/lib/               shared: basemap, format, design tokens (app.css)
  static/prioritizer/    ranked bridges + cumulative impact sequence
  static/mapdark/        WaterNet reveal layer + OSM waterways + stats
  static/data/           Time to Care bundle
data-prep/               the offline Python pipeline

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages