Lifemap is a thin layer over public data. The site is editorial; the data is somebody else’s. This page documents every transformation that happens between a UK postcode and a number on the screen, so any figure can be reproduced from first principles.
The pipeline produces uk_la_data.json: a flat object keyed by area slug. Each record carries life expectancy, healthy life expectancy, and five lifestyle indicators. The slug is the lowercased admin_district field that postcodes.io returns for any UK postcode, with a small set of known aliases, so a successful postcode lookup is always one direct dictionary read away.
Country aggregates (England, Wales, Scotland, NI, UK) live under _meta.country_totals — available for editorial reference, kept out of the per-area lookup.
OHID Fingertips occasionally retires an indicator ID and replaces it with a fresh one. We’ve had at least two confirmed deaths in this dataset’s lifetime: 93798 and 91414. The pipeline therefore resolves indicators by name search rather than hardcoded ID.
/api/indicator_search?search_text=… with the natural-language name./api/indicator_metadata/by_indicator_id?indicator_ids=… to confirm the description still matches the keywords we expect._meta.resolved_indicators so drift is auditable.This is the difference between a pipeline that silently produces blanks and one that fails loudly when the upstream changes shape.
For two-tier areas of England (Kent + Canterbury, West Sussex + Adur, Norfolk + Norwich, …), we fetch Fingertips lifestyle indicators at both upper-tier (area_type_id=502) and lower-tier (area_type_id=501) level. This way Canterbury’s record carries Canterbury’s own smoking, obesity, activity and 5-a-day figures, not Kent’s.
One indicator—higher-risk drinking, Fingertips 92778—does not publish at LTLA. For that field, English districts have null in the data file and the frontend surfaces the parent county’s value as a clearly labelled adjacency block, never as the district’s own number.
In the JSON, the district’s parent_utla_slug field points at the county. The frontend uses this pointer to render the parent’s HLE and drinking values in a separate, dashed-border block, not in the main stat tiles. The district row stays clean.
England’s lifestyle indicators come from OHID Fingertips. Scotland’s from Scottish Government surveys (SSCQ for smoking; SHeS council-area Shiny dashboard for the other four). Wales’s from the Welsh Health Survey 2014–15 via InfoBaseCymru. Northern Ireland publishes adult lifestyle prevalence at HSC Trust level (5 trusts) only, never at LGD2014 council level (11 districts), so the five lifestyle fields stay null for NI districts.
Per-country source URLs and the exact period each indicator covers are documented on /sources/ and machine-readable under uk_la_data.json._meta.lifestyle_sources.
England (Fingertips 93088) reports “Overweight including obesity” at BMI ≥ 25. Scotland (SHeS) and Wales (WHS) report obesity at BMI ≥ 30. The two definitions are not interchangeable, so cross-country obesity comparisons must be read with the threshold in mind. We disclose the mismatch on every page that surfaces obesity, and in _meta.lifestyle_sources.
For drinking and physical activity we have closer alignment after the Scotland refresh: Scotland uses the same >14 units/week and CMO 150 min/wk MVPA thresholds Fingertips uses. Wales is still on its pre-2016 daily-units and 5×30 min/wk definitions and is flagged as not directly comparable.
Postcodes.io returns admin_district for every UK postcode. ONS publishes data keyed by GSS area code (E06000023, S12000026, …). The pipeline normalises both to a slug (lowercase, accents stripped, “, City of” suffixes dropped, non-alphanumerics collapsed to single spaces) and joins on slug. A small alias list (data.js → LM_SLUG_ALIASES) handles the few cases where the two providers disagree on naming — e.g. Bristol, City of vs Bristol.
/current/….xlsx rotate filenames between releases. The pipeline scrapes the dataset landing page each run rather than hardcoding a path./api/all_data/csv/by_indicator_id) returns HTTP 500 and looks deprecated. We use the documented /api/all_data/csv/for_one_indicator instead.area_type_id=502 is the post-April-2023 UTLA type; =501 is post-April-2023 LTLA; older =102 and =101 are dead.FY1 1AA is terminated (withdrawn May 2010). Tests use FY1 2AA instead.The pipeline is a single Python script at build_dataset.py. To rebuild from scratch:
git clone https://github.com/visata/lifemap.git && cd lifemappython3 -m venv venv && source venv/bin/activate && pip install -r requirements.txtpython3 build_dataset.pyFirst run downloads roughly 5 MB of ONS XLSX files into cache/ and makes a handful of Fingertips API calls. Subsequent runs reuse the cache. Output is written to the project root as uk_la_data.json; you should get bit-for-bit-equivalent output to what this site serves, modulo upstream releases since our last build.