Converting GPX to SVG

After manually visualizing a GPX running track and inspired by Nathan Rooy’s fantastic Bike Exploring NYC project, I planned to build a Python script that

  1. scrapes all my running activities from Garmin,
  2. converts them to SVG files,
  3. and displays them on my website.

I scripted everything inside a Jupyter notebook which is definitely overkill, but I wanted to be prepared for future data wrangling tasks. I am using Docker and Docker Compose to spin everything up. While I’m in slight overkill territory again, it feels cozy to have Docker Compose handy in case I need more services, like a database.

Connecting to Garmin and grabbing all my running activities in question was super simple thanks to garminconnect. After a couple lines of code I had persisted my Garmin activity data as a collection of GPX files.

I manually converted some of them to SVG using gpx2svg to get a feeling for these two XML-based formats. Although this produced decent results ready to be thrown on a website, I wanted to go further and understand the conversion process. After realizing that the core of the conversion from latitude/longitude coordinates to SVG point coordinates—the simplified Mercator projection—is three lines of code, I decided to implement it myself.

That allowed me to add some extra measures to drastically reduce the file size of my produced SVG files:

My produced SVG of today’s run weighs 582 bytes as opposed to the whopping 😉 7518 bytes of gpx2svg’s result (after gzip compression). That’s an oddly satisfying reduction of 92%! This kind of optimization does not fit every use case, especially when you want your SVG to work on different zoom levels. But for displaying little SVG thumbnails it is perfect.

Converted SVG path from a GPX file Converted SVG path from a GPX file Converted SVG path from a GPX file

Comparison of different conversions (zoomed viewBox)

You can find my code on Sourcehut.