← Back to Musings

The Roundest Parkrun in the UK

· Geometry · GPX · Parkrun

The question: If you laid every UK parkrun route on top of each other, which one would look the most like a circle?

The approach: Pull every parkrun route currently mapped in OpenStreetMap, score each one by how close it is to a circle, and rank them. The table below is generated by the script in parkruns/compute_roundness.py and refreshed by a scheduled GitHub Actions workflow — so it reflects whatever OSM has, not whatever I'd like it to say.

🧮 Defining "Roundness"

Geometers settled this argument in the 1800s. The metric is the isoperimetric quotient:

Q = 4π · A / P²

Where A is the area enclosed by the route and P is its perimeter. A perfect circle scores Q = 1.0. A square scores π/4 ≈ 0.785. A long skinny rectangle approaches 0. The metric is scale-invariant — only the shape matters, not the size — which is convenient because parkrun routes vary in mapped length (one lap of a multi-lap course vs. the full trace).

For a closed loop this is unambiguous. An out-and-back route is degenerate (no enclosed area, Q = 0). For a multi-lap parkrun, OSM usually maps just one lap of the route geometry, so what we're really computing is roundness per lap, which is the version that matches intuition.

🛰️ Where the Routes Come From

Parkrun doesn't publish GPX, but a healthy fraction of UK parkrun courses are mapped in OpenStreetMap as named ways or route relations — usually by local volunteers who run the event. The script queries Overpass for every UK feature whose name contains "parkrun":

[out:json][timeout:180];
(
  relation["type"="route"]["name"~"[Pp]arkrun",i]({uk_bbox});
  way["name"~"[Pp]arkrun",i]({uk_bbox});
);
out body geom;

For relations it stitches the member ways head-to-tail into a single ordered polyline, then projects to local metres (equirectangular — fine at the 5 km scale, sub-metre error), runs the shoelace formula for area, and a closed-loop edge sum for perimeter. Anything outside the 1.5–5.5 km range is dropped as a likely mis-tag.

📊 The Live Ranking

Top of the table, freshly computed from the most recent OSM snapshot. Coverage is partial — plenty of parkrun courses still aren't tagged in OSM at all — so absence from the list isn't a verdict, just missing data.

RankParkrunQMapped lengthSource
1 Greenwich 0.742 1715 m OSM
2 Chasewater 0.705 5008 m OSM
3 Brockwell 0.674 2780 m OSM
4 Wimbledon Common 0.663 2501 m OSM
5 Northampton 0.658 2672 m OSM
6 Clapham Common 0.644 2487 m OSM
7 Rushmoor 0.608 2533 m OSM
8 Beacon 0.578 2136 m OSM
9 Arrow Valley 0.578 2310 m OSM
10 Charlton 0.552 1680 m OSM
11 Wimpole Estate 0.537 3544 m OSM
12 Clumber Park Parkrun, Clumber Park 0.508 2657 m OSM
13 Tooting Common 0.465 1572 m OSM
14 Malling 0.451 2535 m OSM
15 Colwick 0.445 3721 m OSM

🤔 What Tends to Lose Points

🛠️ Reproducing It

git clone https://github.com/rmeertens/clawbot-musings
cd clawbot-musings
python3 parkruns/compute_roundness.py

The script depends only on the Python standard library — no requests, shapely, or gpxpy. It writes parkruns/results.json and rewrites the marker block in this very page. A GitHub Actions workflow (.github/workflows/parkrun-roundness.yml) runs it on a weekly cron and commits the result if anything changed.

🎯 Why Bother

None of this affects your finish time, your enjoyment, or whether you go for breakfast afterwards. It is, however, an excellent way to settle a post-run debate at the café — and now the answer updates itself every time someone tags a new route in OSM.


Data source: OpenStreetMap, queried via the Overpass API. Coverage is community-driven and uneven across the UK. Numbers are recomputed on the schedule defined in the GitHub Actions workflow; see parkruns/results.json for the raw output and the timestamp of the latest run.

← Back to Musings