Skip to content

Analyze Strava Training By Zones With Python

Example diagram - title image
Example diagram – title image

Effective training is key to build a strong foundation for competition. That’s why I am using the Strava API with Python to analyze Strava training activities. I started my winter training recently and wanted to make sure I’m training effectively. Especially, I want to see if I stay in the right zones during the training. I have set up my Forerunner alarms appropriate, but I train outdoor, so it goes up and down during the run and I can’t control everything during the ride. Human. Not robot.

I started with the stravalib library, for reading the data from the API. As usual in data science, I need to transform and prepare the data for visualization. I end up storing the generated plots and build a quick & dirty HTML-file to display the stuff. I will now guide you through the example. I will explain the important steps. You can find the complete code on

The basic mechanics to get access

At first, I struggled with the stravalib. I found a nice working example Ryan Baumann’s blog post “Strava API – Cycling Data for Visualization” (#kudos).

Strava uses OAuth to gain 3rd party services access to the user’s data. It involves that the service calls Strava with a pre-generated client ID (and with a callback URL), the user authenticates at Strava, Strava redirects the browser back to the service with an access token. Therefore you need a web server. Thankfully Python comes with a suitable system.

The Client ID (and secret) need to be generated, you can do this in your Strava settings page. Store the client ID and the access token in a file named ‘client.secret’ next to the script (clientid:token). Let’s start with the script. In line 327, the client.secret file get’s read and prepared to generate the authorization URL on line 331. Next, the script opens the URL in a local browser window. The OAuth process starts and in the meantime, the local web server starts to process requests. The browser gets redirected to the local server, which processes the requests and starts the access to the API. The browser window can be closed.

Data Extraction

The MyHandler2 gets the callback from Strava OAuth process and parses the access code from the URL parameters. With the code, the script logs into the Strava API (line 301) and gets the Athlete (= user) data. I was interested in the Activities, so the script retrieves a list of them (line 285). In the final step, the detailed data for each activity is requested. There are 11 types of data available, e.g. ‘time’, ‘latlng’, ‘heartrate’, etc. To analyze Strava training activities, I need ‘time’, ‘heartrate’, ‘velocity_smooth’ and ‘cadence’. After retrieving and parsing the data, the script hands it over to the main scope (line 315). Of course, this could be done better.

Data Visualization

Now, we come to the most interesting part, the data visualization. What I can’t see in the Strava stats, on Veloviewer nor on Garmin Connect is the distribution work in the heart rate zones. This way I can check how effectively I trained. Additionally, I wanted to see some details of the population of velocity and cadence in the heart rate in the zones. This is just explorative, I wanted to find out if there are any patterns visible. The third graph is a boxplot of the heart rate values grouped by the zones.

I used plain simple matplotlib to generate the graphs. Matplotlib needs the data prepared in data structures. Of course, the data structure from Strava is not compatible, so data preparation is needed. The script iterates over the activities (line 373-381) and calls function prepareOneActivity for each (ignore the html for the moment).

At first, the heart rate is grouped by zones: recovery, basic endurance 1. basic endurance 2, development area, peak area. After that, the values of velocity and cadence is grouped by heart rate zones. After the data structures are prepared, the plots are created (line 109-165). The first diagram is a simple bar plot. Besides the plot itself, it just needs some labeling and it is done (line 170-183). The second diagram is a little bit more tricky, I wanted to have box plots of velocity and cadence over the bars of the heart rates. Have a look on the header image, this is an example plot. To make it readable in the end, it needs to customize the axes of the box plots. In that way, it is necessary to create a host plot (host_subplot) and two subplots (twinx). So there are three y-scales, but just two sides in the diagram. The y-scale of the second subplot ax3 needs some offset to be readable. Both axis of the box plots ax2 and ax3 should be on the right. To prevent overlay of the two box plots, scale limits are tweaked in line 208-210. In the lines 218-243 the readability is improved, with y-ticks and colors.

Finally, it can be plotted. All the diagrams were plotted into files. To compare them on screen, the script creates a simple website with tables [1999 sic!] of diagrams.


Conclusion – Analyze Strava Training Activities

With the generated diagrams at hand, I can check if my training was effective. I found out, that if I set the alarms to the basic endurance 1 limits, I end up in 60% BA1 and nearly 40% BA2. So I updated the heart rate alert, dropping the upper limit one a little bit. That way I get notified earlier and can adapt to it before the I leave the zone.

Analyze Strava Training - Basic endurance before
Analyze Strava Training – Basic endurance before
Analyze Strava Training - Basic endurance after
Analyze Strava Training – Basic endurance after

The heart rate box plots confirm the information gained from the zone distribution. If heart rate alarms are set exactly, the third quartile is placed much higher and fourth quartile much smaller. I didn’t found a pattern in the cadence & velocity data yet.

Analyze Strava Training - Heart rate before
Analyze Strava Training – Heart rate before
Analyze Strava Training - Heart rate after
Analyze Strava Training – Heart rate after

Analyze Strava training was the goal. With this little helper, I can analyze Strava training data and optimize my training. I hope, you can use the code for your projects too. Again, you can find the complete code on

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.