How to analyse Garmin or Strava activities using Python
With the Python bikeride package, you can analyse rides, runs or other activities recorded with a gps device. Things you can do with it include:
- Analyse how crosswinds affect your cycling speed;
- Show the route (or the direction) of one or more activities on a map;
- Create a speed or elevation chart of your ride, or for example a chart that shows where you had a headwind;
- Create and analyse a list of all your activities, for example to find your worst-weather rides, you longest rides or rides that started near a specific location.
As the name suggests, the package was developed for analysing bicycle rides, but it can be used for other types of activities just as well.
Installation
The package can be installed using pip:
pip install pybikeride
Note that you install the package using its PyPi name: pybikeride
(not bikeride
).
Creating a BikeRide object
The basis of any subsequent analysis will be a BikeRide
object. This can be created simply by passing the path to a .gpx
or .fit
file:
from bikeride import BikeRide
ride = BikeRide('../data/ride.fit')
However, to fully use the capabilities of the bikeride
package, you may also want to pass weather data. This should be in the form of a .csv
file that contains timestamped weather data for the location of your activity. It might look like this:
date,hour,wind_direction,wind_speed,temperature
20210108,8,10,1.0,2.7
20210108,9,30,2.0,3.6
20210108,10,50,3.0,3.8
20210108,11,50,3.0,3.9
If you have a weather file, then you can pass it to the BikeRide
object like this:
from bikeride import BikeRide
path_ride = '../data/ride.fit'
path_weather = '../data/weather.csv'
ride = BikeRide(path_ride, path_weather=path_weather)
What’s in the BikeRide object
The BikeRide
object will contain three main datasets:
ride.records
: the datapoints collected by your gps device, including coordinates and timestamp;ride.segments
: the package creates segments between records; calculates segment statistics like length, direction and speed; and adds weather data if available;ride.summary
: summary statistics for the entire activity. These include start location; length, duration, speed, ascent and descent. If available, they also include weather data for the activity.
These three datasets are all in the form of lists of dicts, that can easily be turned into a pandas DataFrame, as will be seen below. (If you’re not familiar with pandas: a pandas DataFrame is a bit like an Excel sheet, but better.)
Create a chart of your activity
You can turn segment data into a pandas DataFrame and use that to visualise your activity. For example:
import pandas as pd
from bikeride import BikeRide
ride = BikeRide('../data/ride.fit')
sgms = pd.DataFrame(ride.segments)
sgms = sgms.set_index('distance_recorded_start')
sgms.headwind.plot(title='Headwind')
The result may look something like this (from the frequent changes, you can tell that this was on a bendy route):
This example uses matplotlib (through pandas). Of course, you can also use a different package to visualise your data.
Create a table of your activities
If you have a number of activity files, for example from a Strava bulk download, then you can create a table containing summary statistics for all those activities. The way to do this is to create a BikeRide object for each activity file, convert those into a list of summary statistics, and create a pandas DataFrame from that list.
Here’s how to do it:
from pathlib import Path
import pandas as pd
from bikeride import BikeRide
DIR_FIT = Path('../data/')
rides = [BikeRide(path) for path in DIR_FIT.glob('*.fit')]
df = pd.DataFrame([ride.summary for ride in rides])
Note that parsing a large number of activity files will take quite a bit of time.
With this dataframe, you can for example find your longest rides, filter rides by where you went, or find your worst-weather rides (the latter option of course requires that you pass a weather file to each BikeRide object).
Plot your activity on a map
In a Jupyter notebook, you can plot a ride using the ipyleaflet
package. This is easy:
ride.plot()
The result may look something like this:
More options and caveats
For details on using the bikeride package, see the documentation.