Over the past 15 years or so, railways have occupied my thoughts more than they probably should do. 

I don't work on the railways, I'm not a regular commuter, and I'm not a trainspotter, but I do enjoy railway infrastructure and architecture, and live within earshot of a railway line where I hear trains pass throughout the day.

A view looking down from a bridge of a single track railway line disappearing into the distance in a straight line.It's a stretch of single-track railway line in west Wales where, approximately every two hours, a westbound train heads past towards Tenby and on to Pembroke Dock with an eastbound train heading back around 40 minutes later.

After a while of living near the line, I've become accustomed to the familiar sounds of the wheels on rails getting louder, the tooting of the horn as it warns anyone who may be on the nearby footpaths, and then the sound of the engine as it rumbles through. And, because it's a single-track line, you subconsciously get to know the pattern and notice when trains aren't running to time - or not running at all. 

When I do use the trains, it's usually when I'm travelling to and from London for work. On my journeys back home, I have 9 minutes between when the train is scheduled to arrive at my nearest station and when the bus is scheduled to arrive at the station's bus stop. It's been more than once where I've been live-tracking the race between the train I'm on and the bus I'm hoping to catch with fingers tightly crossed that I make it.

Just for fun, a few years ago I built my own little train departure board showing live service information for my local station. Quite often I'd see delayed services and, seemingly, they had commonly appearing reasons: maintaining customer connections, a late train in front of this one, or signalling issues. That led me to think about delving deeper into the data to find out if those observations held up.

A character LCD display is attached with many, many wires to a Raspberry Pi Zero. It's showing an upcoming train service to Pembroke Dock, currently on time and due at 10:40. Two calling points are shown as Kilgetty and Saundersfoot, as well as a message stating that the train is formed of 2 coaches.
My plan for this is to find a suitable enclosure - I'm thinking a 1980s/90s radio alarm clock, the problem is finding one that can take the 5cm tall display module.

The Office of Rail and Road publish performance data for individual stations, but not - as far as I could see - the reasons why, so I decided to do it myself. And, even if they did publish it, where's the fun in not collating the data yourself?!

Using Claude Code, I (we?) whipped up a system that captures the last known service details as they're removed from the live National Rail Enquiries data feed, stores them in a database, and displays the results in a simple dashboard showing service histories and statistics. A scheduled task runs overnight to reconcile the stored data with that provided by Realtime Trains; very occasionally services can appear in the NRE data as both running and cancelled at the same time and I've found this reconciliation is the best method for getting the data as accurate as possible.

A screenshot of four stats: total services = 408, on time 205 (61.3%), average delay = 5m 25s, cancelled = 9 (2.2%). A heatmap shows daily blocks coloured red to green based on the proportion of on-time services.It's been more than four weeks of this running and the headline stat is that 63% of the 480 services ran on time (within 3 minutes of schedule). Unfortunately, I'll have to wait a few more weeks to be able to properly compare how these stats stack up against the official ORR numbers as my data recording started almost a week into the last reporting period; their numbers are 58.6% within 3 minutes (23 Aug - 19 Sept) vs my 61.3% (28 Aug - 19 Sept).

9 trains, 2.2%, during these four weeks were cancelled (which pretty much tallies with ORR's 2.0%) and, where trains were delayed, the average delay was 13½ minutes. The delay displayed in the screenshot here is the average delay across all services, not just the delayed ones.

Looking into the reasons for the delays, most didn't have a reason associated with them, they were just running late (36 services, 6½ minutes average delay). The top "proper" excuse was down to "the train departing late to maintain customer connections" (29 services, 11 minutes).

A bar chart showing the top 2 reasons for delays. "Delayed without reason" has a count of 36, "Delayed by the train departing late to maintain customer connections" has a count of 34.

This makes a lot of sense. There are two major service intersections out to the east of where I am: Carmarthen and Swansea. If a train coming down from, say, Manchester, is delayed, an onward connection out further west may hold on a little bit to ensure passengers aren't stuck waiting another 2 hours on the platform for the next train.

But remember I said that I live on a single-track stretch? If I'm on a train that has to hold at Carmarthen or Whitland before heading west, not only do I miss the bus but the eastbound service from Pembroke Dock has to wait at Tenby for my train to arrive before it can leave, causing knock-on delays and disruption later down the timetable. There are a couple of points where there's standing time at stations, again usually Carmarthen and Swansea as trains wait for others to arrive, which can help in balancing things back out... assuming the incoming services aren't also delayed.

It's complex.

Anyway, this is just the start of my data gathering. I'll keep this going for as long as I can and I'll come back to review when I have a bigger dataset.


PS: Just as I was getting ready to publish this, I was on a train back home from Cardiff. As we left Swansea we were told that, on reaching Carmarthen, we'd have to switch trains. Sure enough, our train arrived and about a minute later another one pulled in behind/in front of us (Carmarthen is an in/out reversing station) and all the onward-travelling passengers from both trains switched over. 

This did leave us in a bus vs train race which, thankfully, we won with a minute spare. And the recorded reason for the delay?

"This train has been delayed by the train departing late to maintain customer connections."

🐂💩


Post thumbnail photo: "Sheep on the line" by Jeremy Segrott via Flickr (cc-by/2.0).

No AI
used in this article.