Cycling from Cardiff to Prague
Preserving
This is just a quick post to commit to the cloud what will inevitably fade from memory..
Goal
In short: cycle from the front door of my house to the conference centre in Prague where RecSys 25 was being held. Last year for RecSys 24 I cycled 1,000km up through Sardinia (Cagliari - Olbia through the most gorgeous mountain passes) and then from the port of Rome (Civitavecchia) across Italy to Bari. That was a 7-day trip. Cardiff to Prague bumps up the distance by 50% to just over 1,500 km, but equally a big chunk of it would be on the Rhine River cyclepath so the elevation would be much easier to manage. I decided to try and do it in 10 days so an average of 150km per day, enabling exactly two weeks off work - one for travel and one for the conf itself.
How did it go?
In short, it ranged from the miserable to the sublime, with an average score of “amazing” (because all bike tours are remembered with rose-tinted glasses!).
If you want to get your geek on, I downloaded all of the .FIT files from my bike head unit (Wahoo Elemnt Bolt v2) and whipped up some Python code using fitparse, Pandas and folium to slice, dice and visualise the ride data. I’m not that impressed with the predictive machine learning algorithms that Strava use and it would be trivial to extend this code to calculate a nice Relative Effort metric using heart rate as a proxy for exertion (rolling window, total / avg / min / max).
Here’s the interactive version generated by the Python code - click on the stars to see day-by-day stats!
10-Day Ride Summary
| Day | Distance_km | Time_h | AvgSpeed_kmh | Calories | Elevation_m |
|---|---|---|---|---|---|
| 1 | 210.111 | 7.69583 | 27.3019 | 4016 | 1066 |
| 2 | 194.953 | 7.45611 | 26.1467 | 3634 | 1352 |
| 3 | 143.765 | 6.04333 | 23.7891 | 2459 | 213 |
| 4 | 158.403 | 6.99333 | 22.6505 | 2601 | 341 |
| 5 | 139.93 | 5.40889 | 25.8703 | 2612 | 288 |
| 6 | 123.276 | 5.17083 | 23.8406 | 2161 | 471 |
| 7 | 141.429 | 5.41639 | 26.1114 | 2599 | 475 |
| 8 | 106.121 | 4.25278 | 24.9533 | 2109 | 583 |
| 9 | 208.591 | 8.15278 | 25.5853 | 3974 | 1582 |
| 10 | 117.014 | 4.75222 | 24.6231 | 2104 | 881 |
Analysing the FIT files
[Might break this out into a separate post in the future]
It’s pretty simple code - fitparse, pandas and folium pretty much do all of the heavy lifting for us..
Here’s the complete Github repo
import pandas as pd
import numpy as np
import matplotlib.colors as mcolors
from fitparse import FitFile
# -----------------------------
# 1. Extract track data
# -----------------------------
def extract_fit_data(filepath):
fitfile = FitFile(filepath)
data = []
for record in fitfile.get_messages("record"):
row = {}
for d in record:
if d.name in ("position_lat", "position_long", "altitude", "timestamp"):
row[d.name] = d.value
if "position_lat" in row and "position_long" in row:
row["lat"] = row["position_lat"] * (180 / 2**31)
row["lon"] = row["position_long"] * (180 / 2**31)
data.append(row)
return pd.DataFrame(data)
# -----------------------------
# 2. Extract ride stats
# -----------------------------
def extract_stats(filepath):
fitfile = FitFile(filepath)
stats = {"file": filepath}
for msg in fitfile.get_messages("session"):
for d in msg:
if d.name in (
"total_distance",
"total_ascent",
"total_calories",
"total_timer_time",
):
stats[d.name] = d.value
return statsAnd the main driving function:
for i, ride in enumerate(rides):
stats = summary.iloc[i]
ride_ds = downsample(ride, max_points=500)
coords = list(zip(ride_ds.lat, ride_ds.lon))
n_segments = len(coords) - 1
if n_segments < 1:
continue
n_grad = min(50, n_segments)
seg_indices = np.linspace(0, n_segments - 1, n_grad, dtype=int)
seg_colors = gradient_colors(html_colors[i % 10], n_grad)
for j in range(len(seg_indices) - 1):
folium.PolyLine(
coords[seg_indices[j] : seg_indices[j + 1] + 1],
color=seg_colors[j],
weight=4,
opacity=0.9,
).add_to(m)Day 1: Cardiff - Thame (Oxford)
Right from the off the weather forecast looked disastrous. Monsoon bands of rain roaming at will across South Wales and gale force winds predicted on the Holland coast in two days time.. Got up at 7 am and spent 2 hours packing and faffing and looking out the window in angst. Then the rain stopped and at 09:15 I just went for it. Bone-dry all the way to the Severn bridge and over it too! But the ominous clouds eventually closed in and I got battered by rain just over the border in England - from Hill all the way to Berkeley and Ham.
Deep in the Gloucester countryside I turned down a narrow lane which clearly went through a farmyard and suddenly and without warning - there he was. An Irish wolfhound the size of a f**king shetland pony. He did a comical double-take at me a la a Wily E Coyote cartoon and then he and I were off to the races. This dog just could not believe his luck and I pedalled so hard that I earned a life-time 5 minute max power output later on as he loped beside me, trying to angle in for a big juicy bite of my calf. Bastard.. took a while for my heartrate to come down after that!
Stopped at the Waitrose in Stroud and spent 10 minutes listening to two teenagers discussing existential angst in the cafe instead of serving customers, gave up - got a sandwich deal and got back on the bike. Soaked through now and shivering so pedaled hard to warm up. Got hit again with hard rain at Witney but the hotel was close so just pushed on. 45 minute hot shower and a big fish supper got me back on track for Day 2..
Day 2: Thame (Oxford) - Port of Harwich
The weather forecast promised virtually zero rain today and that turned out to be total bullshit. Even though today was 211 km, the ferry didn’t go until 11 pm so I really only wanted to get there at dusk to avoid cycling in the dark. The heavens opened at Chelmsford and Colchester - Chelmsford having the added bonus of hail to get things going with a bang before moving onto the kind of big, fat, heavy raindrops that bounce off the tarmac. Cyclists are like eskimoes with snow - we recognise over 100 different types of rain!
I probably navigated too close to London - going through Barnet, Cockfosters and Enfield. I carefully negotiated drivers sitting in traffic who were slowly going insane. Got to Harwich just after 7 pm and celebrated with a double Big Mac meal before getting on the ferry. Two biggest days in the bag albeit with some rain attrition..
Day 3: Hook of Holland - Eindhoven
The ferry got in bang on time. There was some kind of classic car tour onboard so got slightly high breathing in raw petrol fumes on the car deck before dismebarking. Cycled straight into the customs red zone and some questioning looks from Dutch police. Told them I had nothing to declare and they told me politely to piss off then! Anxiously scanning the skies looking for the forecast gale-force winds but it was just a spicy cross-wind - bonus!
I’ve read about the Dutch cycling infrastructure but you really have to cycle it to believe it. Cycling exists as an entirely separate transport type to driving and drivers really respect cyclists. Heaven..
Day 4: Eindhoven - Cologne
Today was the day with forecast 60 mph wind gusts which would be unrideable. My hotel in Eindhoven turned out to be a safe haven for recovering addicts which they didn’t advertise very hard on booking.com I can tell you.. the only addict I saw in there was a young kid who put up a bit of a struggle when they took his phone off him. Prob no more addicted than 50% of the adult population of Western Europe..
The only thing marking the NL - DE border is a strange memorial to an airforce fight in 1939 - 1940 deep in the middle of the forest. Apart from that, the signage changed and that was that.
No-one ever talks about the weird chemical smell on the Rhine, but it is ever-present. It’s not deeply unpleasant but it’s not nice either, it’s just part of the scenery..
Day 5: Cologne - Babarach
TBC
Day 6: Babarach - Babenhausen
Day 6 Strava link Today was the day to start tacking east, having completed a lot of the south I needed to do. Left Babarach about 09:30 and 5 km the map is showing me a non-existent bridge over the Rhine. For a minute I thought about looking for a tunnel entrance (!) but then realised it was actually a ferry crossing over to Lorch on the east bank of the river. Frequency every 20 mins so not too bad.
By this stage, I’m pretty much done with the Rhine. It’s hard to take good photos / videos of it because it is just a flat, wide river. Thought I would get a spectacular photo of the Lorelei rock but it’s just a mud-brown outcrop?!
The centre-piece of today was getting up to Heddernheim north of Frankfurt am Main to a camping platz that I spent two summers living in as a student. They’ve just started turning it into a housing estate.. I looked in and could swear I recognised some of the old Mercs still in there from the summer of 1994!! That goal achieved, all that was left for me was to mosey on down to the Hotel Adler in Babenhausen for the night. Otherwise a pretty unremarkable day. Dinner was a massive doner kebap.
Day 7: Babenhausen - Creglingen
The host at Babenhausen is a bit of a character. “Oh ho - Englisch, Englisch! Manchester United, Liverpool, Barcelona!!”. After a tense exchange where I establish my Irish credentials “Oh ho - die Grüne Insel!” he point-blank refuses to accept what I’m doing (cycling from Cardiff to Prague). His head is completely blown for about 5 minutes until I break it down stage by stage. He’s not thrown for long though, and soon recovers his bants. Large obligatory breakfast done with, I hit the road. Today is shortish - 140km and flat too. I cross over from Hessen into Bayern and BOOM we are in the bible. There are Stations of the Cross, saints guarding bridges, crosses everywhere. It’s enough to make a bishop weep..
But another uneventful day, rolling farmland with some nice fast descents. Roll into Creglingen and set up shop at the Pension Herrgottstal. Dinner tonight: Italian - soup followed by a huge pizza and a nice Weizenbier on the side.
Day 8: Creglingen - Nuremberg
Started the day with a traditional Bayern breakfast in the Pension, including a soft-boiled egg on the side 😍.
The bike is running like a champ and with the dry weather, I’ve decided to lube the chain every second day, same with checking tyre pressures. That done, it’s time to hit the road.
I think today is actually the shortest day of the tour, so I’m ambling along just watching the world go by and generally taking the piss. Stop at a Backerei inside a Norma supermarket about 12 where I get my first rough sandwich of the tour. Eat half and bin the rest, make up for it with cheesecake which is an acceptable alternative form of fueling in my book.
From Fürth onwards into Nürnberg I’m on a river cycle path and things starts to get real. Cyclists tend to have a sixth sense for other shit cyclists - either at the individual level or group level. Nürnberg is shitty at the group level. This river path is dangerous - cyclists whizzing past walkers at speed barely tucking back over in time, not slowing down at Y or T junctions.
I start to cycle defensively, which counter-intuitively can often mean speeding up to get past a dangerous or shonky rider and into clear air. About 7km from the hotel I see my first and only accident of the tour - a cyclist down at a Y-junction with his head split open and claret all over the floor. Obviously got hit hard by another rider. Looks concussed, flat on the floor and not looking like he’s moving anytime soon. 3 other riders around him and a woman stops to give first-aid..
Nuremberg has “Disco Stadt” as their contribution towards Oktoberfest. Tried to cycle through it but after they’re already on it and after the 5th drunk guy stumbles out in front of me I give up and just walk to get over the river
Get a nice photo at a water wheel, visit Zeppelin Stadium where there used to be mad night-time parties back in the day (geddit?) and then to the Novotel Hotel.
Another massive doner kebap for dinner and two bags of sweets.
Day 9: Nuremberg - Plzen
Woke up feeling pretty rough for no good reason - not a good start with a big day ahead. Tried to eat a big breakfast but just had no appetite. Opposite me a big German dad was talking to his daughter, talking about how he spent 30 years working for Airbus or something and then it’s all suddenly over and he’s kicked out on his arse and she should do what makes her happy. “Try cycling 1,500 km Helmut and see how you feel” I mutter to myself as I gag on another semmel bread roll with shiny ham and plasticky cheese, washed down with generic machine coffee that doesn’t improve anything about this breakfast.
Roll out past Wordersee where Nuremberg has its Parkrun. If the segment was shorter I would have run it just for the parkrun tourism points but no parkrun heroics today.. I’ve got loads of sweets and chocolate on-board in the hope that my appetite will return once I get going.
And sure enough it does, 60 minutes in and I’m scoffing jelly babies and hazelnut chocolate by the side of the road like a crack addict in a train station. Push on and get to a nice Backerei, making good time. Over-order and in walking to my table manage to drop the whole f**king tray on the ground. The German lady earnestly asks if it was an accident - I assure her it was and she insists on replacements for no charge. If I told her I’m a lunatic and I did it on purpose it would probably be a swift journey to jail..
Push on again, today is just a day to eat up the miles and go from triple to double digits. The border into Czechia is a total non-event, marked only by a casino and hairdresser (?!) Straight away though the road surface degrades and my heart sinks when I get sent up a shitty logging road that rattles every tooth in my head as I go up it. Half-way up I’m into a deep, dark forest and hearing whistles behind the trees. “Never heard deer whistle like that before” I think to myself as the powermeter records an appreciable surge in output. The descent is equally sketchy but thankfully pops me out onto a main road with a PETROL STATION!!
I’m realising that Czech drivers are nowhere near as good or nice as German or Dutch drivers so it’s defence first and ask questions later. After a nice cultural exchange with a close-passing truck driver (alliteration always makes swearing more elegant I find), eventually I’m on the road into Plzen. My hotel is a timewarp from the 1980s but clean and comfortable. And that’s the penultimate and probably Queen stage too, done and in the bag.
Day 10: Plzen - Prague!
Hot again right from the start with peak temps of 33 degrees expected by mid-afternoon. Legs tired after the big segment yesterday but that was very much cancelled out by the knowing today was the last day. Got a good breakfast at the hotel airlifted out of the USSR and proceeded out of Plzen past the huge Skoda factory. I decided to get more aggressive with the map and stayed on main roads even though cycle.travel / RideWithGPS was sending me down narrow lanes. I still had the ancestral memory of that wolfhound in Oxfordshire even though he was now 1,400km away but still probably dreaming about me in his sleep. The Czechs love alsatians and alsatians like chasing cyclists so let’s not mix them eh?
About 40km south of Prague I got onto a river path that took me the whole way into the centre of Prague. A great opportunity to just switch off and enjoy the run-in. Charles bridge was hosting a Palestine protest march and lots of American tourists as usual but I got the pic I cycled 1,539 km for..