A side-project by Jake Coppinger.

A visualisation of realtime Sydney bus congestion. Each line on the graph (a Marey chart) represents a bus completing its route (percentage) over time. Click on a line to highlight the position of that particular bus on the map. When the angle of the line is shallow, there is bus congestion. When the lines are bunched together, there is bus bunching.

Less bus congestion results in faster trip times, which in turn reduces labour costs, decreases bus headways (or reduces need for new buses) and improves passenger throughput.

If I have time I'm interested in:


Headshot of Jake Coppinger

I'm currently working as a software engineer at Atlassian. I built this in my spare time as I'm fascinated by transit design & urban planning.

Have any questions? Got an interesting transit design or urban planning related role? Reach out to me at [email protected]

See more of my side projects & hobbies at

Behind the scenes

The web app is built with vanilla JS (TypeScript), p5.js for the graph, and Mapbox GL JS for the map (which uses OpenStreetMap data).

Data is sourced from Transport for NSW via OpenData. Realtime data is ingested every few seconds via an service running on AWS EC2 to store Protocol Buffer files on AWS S3. I'm storing a lot of data (since before COVID-19 hit).

When requested via an API, a service on AWS Lambda retrives these Protocol Buffer files and computes the trip progress and occupancy of every bus in a specified time window.

I adjustably quantise the number of Protocol Buffers requested (and thus the number of results) via looking up available timestamps.

Trip progress is calculated by comparing positions against bus route shapes. These route shapes have been precomputed from GTFS database dumps (via Sqlite) and stored on AWS S3 as JSON.