Skip to main content

Mapping UK Data: A Journalist’s Guide

Choropleth maps, postcodes, UK statistical geographies, and the free tools UK newsrooms use to map public data.

Last reviewed: Next review due:

Why maps matter in data journalism

Maps give readers an immediate sense of geographic variation that tables cannot convey. “Which parts of the country have the highest knife crime rates?” is a question your reader can answer at a glance from a choropleth map, but not from a 300-row table. Maps also help journalists spot patterns — two boroughs on either side of a boundary that have dramatically different outcomes can be a story in themselves.

For most UK newsrooms, Datawrapper is the starting point for maps. It supports UK local authority, parliamentary constituency, and electoral ward boundaries without any GIS knowledge.

UK statistical geographies explained

GeographyApprox. count (E&W)Used for
Output Area (OA)188,000Finest census geography — too granular for most stories
LSOA33,000Deprivation indices, crime rates, health data
MSOA7,000Census data, GP patient data, population estimates
Local Authority (LA)317Most government reporting — council-level statistics
Parliamentary Constituency650Electoral data, MP-level issues
Region9NHS regions, police regions, broad economic data
Nation4England, Scotland, Wales, Northern Ireland

Geocoding UK postcodes with Python

import pandas as pd

# Download ONS Postcode Directory from geoportal.statistics.gov.uk
# Then merge with your dataset:
postcodes = pd.read_csv('ONSPD_latest.csv',
    usecols=['pcds', 'lat', 'long', 'lsoa11', 'ladnm'])

# Rename for clarity
postcodes.columns = ['postcode', 'lat', 'lon', 'lsoa', 'local_authority']

# Clean postcode format in both datasets (remove spaces, uppercase)
df['postcode_clean'] = df['postcode'].str.replace(' ', '').str.upper()
postcodes['postcode_clean'] = postcodes['postcode'].str.replace(' ', '').str.upper()

# Merge
geo_df = df.merge(postcodes[['postcode_clean','lat','lon','lsoa','local_authority']],
                  on='postcode_clean', how='left')

# Export for Datawrapper point map
geo_df[['name', 'lat', 'lon', 'value']].to_csv('map_data.csv', index=False)

When a map is the right choice

  • 1The story is fundamentally about geographic variation — where is the problem worst/best?
  • 2Your reader has a local interest — which local authority, ward, or constituency affects them?
  • 3The pattern reveals something about infrastructure, deprivation, or resource allocation that is best seen spatially.
  • 4You are tracking something moving over time — e.g. the spread of a disease or housing prices by area.

Red flags

  • Mapping absolute counts rather than rates — large rural areas look worse just because they are bigger.
  • Using a colour scale that makes small differences look dramatic — check your colour breakpoints.
  • Mixing geographies — e.g. some data at LSOA level and some at LA level in the same map.
  • Postcodes that geocode to the wrong location because of format inconsistencies in your data.
  • Sharing a Datawrapper map before checking it renders correctly at mobile screen size.

Mapping checklist

  • I am mapping a rate or proportion, not an absolute count (unless population differences are not relevant).
  • My geographic codes match the boundary file I am using (e.g. 2021 LA codes vs 2011 LA codes).
  • I have checked a sample of geocoded postcodes against a known address.
  • My colour scale is accessible to colour-blind readers.
  • I have added a source line, a legend, and a clear headline.
  • I have checked the map on a mobile screen.

Tools for mapping

Datawrapper is the quickest route to a publishable choropleth map. For boundary files and postcode data, the ONS Open Geography Portal is the authoritative source.

Common mistakes

  • Using boundary files from a different year than the data — ONS geographies change at each census.
  • Not accounting for the Modifiable Areal Unit Problem — patterns change depending on which geographic scale you use.
  • Mapping data that has been suppressed or rounded at fine geographies for statistical disclosure reasons.
  • Using Mercator projection which distorts northern areas — Datawrapper uses appropriate UK projections by default.

Related guides

Primary sources

Frequently asked questions

What are LSOA, MSOA, and LA in UK data?
These are UK statistical geographies — hierarchical spatial units used by ONS for publishing data. LSOA (Lower Layer Super Output Area) contains roughly 400–1,200 households; England and Wales have about 33,000. MSOA (Middle Layer Super Output Area) contains roughly 2,000–6,000 households. LA (Local Authority) is the council level. Above that are regions (e.g. North West) and then nations. Data published at LSOA level is the finest-grained routinely published ONS data.
How do I geocode UK postcodes for a map?
The ONS Postcode Directory (available from geoportal.statistics.gov.uk) maps every postcode to its LSOA, MSOA, local authority, and coordinates (easting/northing and latitude/longitude). For small batches: postcodes.io provides a free API. For bulk geocoding in Python: merge your dataset with the ONS Postcode Directory on the postcode column.
What is a choropleth map and when should I use one?
A choropleth map shades geographic areas by a data value — darker shading for higher values, lighter for lower, for example. They are excellent for showing geographic variation in rates and proportions: unemployment rate by local authority, crime rate by police force area, average house price by parliamentary constituency. They are misleading when areas have very different populations — large rural areas dominate visually even when they contain few people. Always label your map clearly and explain what the shading represents.