This repository aims to be a multi feature tool for locally manipulating Strava's bulk export archive file. The main features are:
- Unzip compressed (.gz) activities files.
- Remove leading first line blank spaces of .tcx activities files for properly importing it (feature not yet available directly in the
sweatpy
package, see here). - Import multiple .fit/.gpx/.tcx activities files at once (without the need of conversion) and create local highly customizable heatmaps with different colors by activity type with the use of the
folium
library. - Increment your Strava activities metadata by adding country, state, city, postal code, latitude, longitude geolocation information for each activity given the start recorded point (first non-missing latitude/longitude).
Additionally, it is possible to apply a series of filters to select the desired activities before performing the heatmap, such as activities that started inside a bounding box (within 4 corner latitude/longitude points) or activities realized in specific countries or states.
Although similar projects already exist (see here), some of the features implemented in this project were partial or non-existent.
Munich Heatmap (rides in orange; runs in blue)
Vienna Heatmap (rides in orange; runs in blue)
Map interaction (option to navigate through the map, click in a line and get an activity summary pop-up)
Strava's bulk export process documentation can be found here.
Note: Please keep in mind that Strava's bulk export is language sensitive, i.e. the activities column labels will depend on users' defined language preferences. This project assumes that your bulk export was realized in English (US)
. To change the language, log in to Strava and on the bottom right-hand corner of any page, select English (US)
from the drop-down menu (more on this here).
In essence, the process is as follows:
- Log in to Strava.
- Open the Account Download and Deletion. Then press
Request Your Archive
button (Important: Don't press anything else on that page, particularly not theRequest Account Deletion
button). - Wait until Strava notifies you that your archive is ready via email. Download the archive file and unzip it to
Downloads/Strava
folder (or alternatively set a different working directory in the strava-local-heatmap-tool.py code).
python -m pip install folium geopy pandas plotnine python-dateutil sweat
activities_import()
- Imports Strava activities assuming that the current working directory is the Strava data bulk export.
- None.
activities_filter(activities_df=activities, activity_type=None, activity_state=None, bounding_box={'latitude_top_right': None, 'longitude_top_right': None, 'latitude_top_left': None, 'longitude_top_left': None, 'latitude_bottom_left': None, 'longitude_bottom_left': None, 'latitude_bottom_right': None, 'longitude_bottom_right': None})
- Filter Strava activities DataFrame.
activities_df
: Strava activities DataFrame. Imported fromactivities_import()
function.activity_type
: str list. If None, no activity type filter will be applied.activity_state
: str list. If None, no state location filter will be applied.bounding_box
: dict. If None, no bounding box will be applied.
Examples of bounding_box
:
# Munich
bounding_box={
'latitude_top_right': 48.2316, 'longitude_top_right': 11.7170, # Top right boundary
'latitude_top_left': 48.2261, 'longitude_top_left': 11.4521, # Top left boundary
'latitude_bottom_left': 48.0851, 'longitude_bottom_left': 11.4022, # Bottom left boundary
'latitude_bottom_right': 48.0696, 'longitude_bottom_right': 11.7688 # Bottom right boundary
}
# Greater Munich
bounding_box={
'latitude_top_right': 48.4032, 'longitude_top_right': 11.8255, # Top right boundary
'latitude_top_left': 48.3924, 'longitude_top_left': 11.3082, # Top left boundary
'latitude_bottom_left': 47.9008, 'longitude_bottom_left': 11.0703, # Bottom left boundary
'latitude_bottom_right': 47.8609, 'longitude_bottom_right': 12.1105, # Bottom right boundary
}
# Southern Bavaria
bounding_box={
'latitude_top_right': 47.7900, 'longitude_top_right': 12.2692, # Top right boundary
'latitude_top_left': 47.7948, 'longitude_top_left': 10.9203, # Top left boundary
'latitude_bottom_left': 47.4023, 'longitude_bottom_left': 10.9779, # Bottom left boundary
'latitude_bottom_right': 47.4391, 'longitude_bottom_right': 12.3187, # Bottom right boundary
}
heatmap(activities_df=activities, activities_coordinates_df=activities_coordinates, activity_colors={'Hike': '#00AD43', 'Ride': '#FF5800', 'Run': '#00A6FC'}, map_tile='dark_all', map_zoom_start=12, line_weight=1.0, line_opacity=0.6, line_smooth_factor=1.0)
- Create Heatmap based on inputted activities DataFrame.
activities_df
: Strava activities DataFrame, default: activities. Imported fromactivities_import()
function.activities_coordinates_df
: Strava activities coordinates DataFrame, default: activities_coordinates. Imported fromactivities_import()
function.activity_colors
: dict, default: {'Hike': '#00AD43', 'Ride': '#FF5800', 'Run': '#00A6FC'}. Depending on how many distinctactivity_type
are contained in theactivities
DataFrame, more dictionaries objects need to be added.map_tile
: str, options: 'dark_all', 'dark_nolabels', 'light_all', 'light_nolabels', 'terrain_background', 'toner_lite' and 'ocean_basemap', default: 'dark_all'.map_zoom_start
: int, default: 12. Initial zoom level for the map (for more details, check zoom_start parameter for folium.folium.Map documentation).line_weight
: float, default: 1.0. Stroke width in pixels (for more details, check weight parameter for folium.vector_layers.PolyLine).line_opacity
: float, default: 0.6. Stroke opacity (for more details, check opacity parameter for folium.vector_layers.PolyLine).line_smooth_factor
: float, default: 1.0. How much to simplify the polyline on each zoom level. More means better performance and smoother look, and less means more accurate representation (for more details, check smooth_factor parameter for folium.vector_layers.PolyLine).
copy_activities(activities_files=activities['filename'])
- Copies a given .fit/.gpx/.tcx list of files to 'output\activities' folder.
activities_files
: list, default: activities['filename'].
Unfortunately Folium does not natively export a rendered map to .png.
A workaround is to open the rendered .html Folium map in Chrome, then open Chrome's Inspector, changing the width and high dimensions to 3500 x 3500 px, setting the zoom to 22% and the DPR to 3.0. Then capture a full size screenshot.
The canvas.xcf is a Gimp template for printing a canvas in 30 x 30 cm. Its design is similar to this Reddit discussion:
The statistics shown in the lower right corner are printed once the heatmap
function is executed.
Strava API v3: Definition of activities variables.
These repositories have a similar or additional purpose to this project:
Strava local heatmap browser: Code to reproduce the Strava Global Heatmap with local .gpx files (Python).
Visualization of activities from Garmin Connect: Code for processing activities with .gpx files from Garmin Connect (Python).
Create artistic visualisations with your Strava exercise data: Code for creating artistic visualizations with your Strava exercise data (Python; a R version is available here).
strava-offline: Tool to keep a local mirror of Strava activities for further analysis/processing.
dérive - Generate a heatmap from GPS tracks: Generate heatmap by drag and dropping one or more .gpx/.tcx/.fit/.igc/.skiz file(s) (JavaScript, HTML).
Data Science For Cycling - How to Visualize GPX Strava Routes With Python and Folium (GitHub).
Build Interactive GPS activity maps from GPX files using Folium (GitHub).
StatsHunters: Connect your Strava account and show all your sport activities and added photos on one map.
Recommended settings:
- Receive monthly statistics by email
- Hide my data in club heatmaps
Cultureplot Custom Strava Heatmap Generator: Connect to Strava to see your activity heatmap. Includes the possibility to filter the activities (by date, time and type) and to customize the map (map type, background color, line color (also by activity), thickness and opacity).