stats19reports
Reproducible road safety reports for Great Britain from STATS19 data
Overview
stats19reports is an R package that automates the production of reproducible road safety reports for any area in Great Britain, built on top of the rOpenSci stats19 package. A full Local Authority report that would previously take days of manual data wrangling runs in a single command; individual sections can be updated and re-rendered without re-running the whole pipeline.
The package produces three types of report:
- Local Authority reports — comprehensive analysis for any GB Local Authority, matched by name against the ONS boundary files
- Parish council reports — the same framework scaled down to parish boundaries, with a longer default analysis period to compensate for small numbers
- National pavement reports — a GB-wide study of pedestrians struck on a footway or verge, with BBC-styled charts and treemaps of where fatalities happen
# install
remotes::install_github("ActiveAnalytics-nl/stats19reports")What the reports cover
Each Local Authority report works through the following sections, each independently cached so re-runs are fast:
| Section | What it covers |
|---|---|
| Rankings | LA’s position among all 206 GB authorities for fatal, KSI, serious and slight casualties — overall, cyclists and pedestrians |
| National maps | Choropleth grids of LA casualty rates across GB |
| Road network | Casualties matched to OpenStreetMap links; sortable table of top roads by collision count |
| Speed limits | Casualty and collision rates per km of road by speed limit category |
| Crash conditions | Bar charts by road surface, junction type, lighting, weather |
| LSOA / IMD | Population and casualty distribution by Lower Super Output Area and Index of Multiple Deprivation decile |
| MSOA | National casualty ranking for each MSOA in the LA; IMD scatter plots for the strongest deprivation-casualty correlations |
| Demographics | Casualties by age band and sex; KSI breakdown |
| Pavement collisions | Single-vehicle pavement collisions: waffle chart coloured by striking vehicle |
| Costs | DfT TAG / RAS4001 collision cost valuation by severity and road type |
Parish reports share the same engine but use parish boundaries from the national planning data platform and extend back to 2010 by default — necessary because small areas accumulate few collisions per year.
Usage
Iterating on one section
# after changing something in the MSOA analysis:
devtools::load_all()
build_la_report_data("Bristol", sections = "msoa", overwrite = TRUE)
render_la_report("Bristol")Parish council report
build_parish_report_data("Winsley")
render_parish_report("Winsley")National pavement report
build_pavement_report_data(base_year = 2021, upper_year = 2025)How the pipeline works
The pipeline is split into named sections that correspond to parts of the rendered report. Each section saves its outputs to outputs/<area>/data/sections/<name>.rds and is skipped on subsequent runs if that file already exists. Shared downloads — STATS19 data, LA boundaries and the IMD 2025 GeoPackage — are cached separately so they are fetched only once regardless of how many sections are (re-)run.
# see the section → report part mapping
report_sections()
#> rankings national interactive osm
#> "Introduction…" "Intro: maps…" "Where in LA?" "Road network…"
#> conditions lsoa msoa demographics
#> "Conditions…" "LSOA/IMD…" "MSOA…" "Demographics…"
#> pavements costs
#> "Pavements…" "Costs…"The design is deliberately compatible with the targets R package for projects that need full dependency tracking across multiple LAs — the internal sec_* functions map onto targets almost one-to-one.
Data sources
All data is downloaded programmatically at run time — no manual data preparation is required.
- STATS19 collision, casualty and vehicle data via the
stats19rOpenSci package - Local Authority and LSOA 2021 boundaries from ONS Open Geography Portal
- MSOA 2021 boundaries and House of Commons MSOA names lookup
- IMD 2025 LSOA-level Index of Multiple Deprivation
- LSOA population from ONS mid-year estimates
- OpenStreetMap driving network via
osmactive - DfT TAG / RAS4001 value of prevention costs (ODS download)
- Parish boundaries from planning.data.gov.uk (parish reports)
Technical approach
The package is built around a few design principles that make it practical to use in a production context:
Reproducibility — every output is derived from publicly available open data through documented, version-controlled code. The Quarto report template uses parameters rather than find-and-replace text substitution; all summary statistics and inline prose are generated by package functions rather than embedded in the template.
Incremental builds — slow sections (OSM network download, national choropleth maps, per-street maps) only run once. The OSM driving network is cached separately and shared between the road network and interactive map sections.
Separation of concerns — the report template is thin: it reads an RDS produced by the pipeline and calls helper functions. The prose helpers (la_summary_paragraph(), five_year_sentence(), change_phrase()) and table builders (tabulate_osm_roads(), tabulate_msoa_ranks() etc.) live in the package, so they can be tested and reused independently.
Open source — MIT licensed, available on GitHub. All dependencies are open source; the package avoids any proprietary data sources.
Installation and dependencies
remotes::install_github("activeanalytics-nl/stats19reports")Key dependencies installed automatically: stats19, sf, tmap (≥ 4.0), osmactive, ggplot2, gt, reactable, openair, readODS, waffle. The national pavement report additionally requires bbplot (remotes::install_github("bbc/bbplot")). The magick package (optional) enables the stitched multi-panel figures.
Full source: github.com/activeanalytics-nl/stats19reports