Plotting Strava rides with Cartopy

For a long time I was thinking of improving my GitHub profile. I wanted to show something cool. Maybe map of my last ride would do the trick. Last time I was playing with Strava data I used interactive maps but this time I wanted to create nice static image.

This led me to cartopy. Cartopy is a Python package designed for geospatial data processing in order to produce maps. Comming from academia this package is not easy to use and required quite a lot tweaking to produce maps I wanted.

Drawing the path itself is quite simple, the problematic part are the tiles. I needed to determine apropriate zoom level for the ride I was trying to display. Another constraint is that some tiles are provided with restricted set of zoom levels when rendering outside of city. For example stamen.

These are the steps required draw a map with a route.

    # Configure tiler to render map tiles on background
    tiler = GoogleTiles()
    mercator = tiler.crs # CRS means coordinate reference system
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1, projection=mercator)

    # Resolution refers to google maps zoom level
    ax.add_image(tiler, params["resolution"])

    # Set map bounds
    bounding_box = [
        parsed_activity["min_lon"],
        parsed_activity["max_lon"],
        parsed_activity["min_lat"],
        parsed_activity["max_lat"],
    ]
    ax.set_extent(bounding_box, crs=ccrs.PlateCarree())

    # Prepare lists of longitudes and latitudes
    ride_longitudes = [coordinate[1] for coordinate in parsed_activity["coordinates"]]
    ride_latitudes = [coordinate[0] for coordinate in parsed_activity["coordinates"]]

    ax.plot(
        ride_longitudes,
        ride_latitudes,
        color="#fc5200",
        alpha=1,
        linewidth=0.5,
        transform=ccrs.PlateCarree(),
        antialiased=True,
        path_effects=[
            # White "border"
            pe.Stroke(linewidth=params["linewidth"] * 2.5, foreground="w"),
            # "Strava orange" route line
            pe.Normal(),
        ]
    )

    output_path = root / "output.png"
    # To remove border I had to set `bbox_inches='tight'` and negative padding
    plt.savefig(output_path, dpi=400, bbox_inches='tight', pad_inches=-0.02)
    plt.show()

Setting up the environment

Cartopy was not easy to install for me. It has a bunch of C dependencies and it took me several tries to do it right. On the first try I was getting strange tuple errors and it took me few hours to realize it's because version mismatch. Before I managed to install latest version I had to learn about Conda Forge first. But after picking the right docker image it all started working.

The code is at https://github.com/stlk/strava_cartopy