Alert I am available for a postdoctoral position starting July 2025. Feel free to contact me for opportunities or collaborations 😉
Strava Dashboard
A personal project to explore my Strava data
Strava
Perso
Author
Corentin Maslard
Published
August 31, 2024
Motivation
There’s nothing better than having fun with data that’s close to your heart. For me, it’s my Strava data (yes, I admit that sounds a bit silly). For my sanity and to decompress after work I like to spend my free time for hicking, running or cycling. It’s also allowed me to learn more about APIs, graph creation…
The project is still a work in progress, but the first version already includes total mileage for hiking, biking, and running, as well as a heat map of all my activities.
There are many more visualizations and features I’d love to add, but finding the time has been a challenge. For now, I manually retrieve new activities using the Strava API via the {rstrava} package, but I plan to automate this in the next version. Stay tuned!
Code written by me, Corentin Maslard and inspired by various websites:
The rStrava package allows easy access to your Strava data using the Strava API. Combined with leaflet I can easily create a heatmap of all of my Strava activities. One interesting challenge does arise when doing this. Strava stores the coordinates of the activity as a Google Polyline, so I will use the googleway package to decode the data in to latitude and longitude coordinates.
Data importation
Then I will enter my personal Strava API information which can be found here after you apply for API access.
Code
## Necessary info from Strava api https://www.strava.com/settings/api app_name <-'website'# chosen by userapp_client_id <-'133545'# an integer, assigned by Stravaapp_secret <-'e606d239de2a102bf125357c62641af7b2c39e04'# an alphanumeric secret, assigned by Stravastoken <- httr::config(token =strava_oauth(app_name, app_client_id, app_secret, app_scope="activity:read_all"))
Next, I load in my activity list and compile my activities into a data frame using the rStrava library.
Code
## Load my activities and compile activities with rStrava librarymy_data <-get_activity_list(stoken)act_data <-compile_activities(my_data)save(my_data, act_data,stoken, file ="perso_projects/media/strava_report/data_strava.RData")
The activity data contains 56 variables. We only need to keep two, the map data called ‘map.summary_polyline’ and the ‘upload_id’.
Code
load(here::here("perso_projects/media/strava_report/data_strava.RData"))## Keep only activity id and map linekeeps <-c('map.summary_polyline', 'upload_id')my_acts <- dplyr::select(act_data, match(keeps, names(act_data)))
Now that the data is prepared I want to create a blank map of the area I want to include in my map. I create longitude and latitude bounds to create the map area I want. This will take some trial and error to get the exact bounds that you want.
Next I loop through all my activities and convert them from Google Polylines to a dataframe of longitudes and latitudes each loop through will add one activity to the map.
Below is a heat map of all my recorded activities, created using leaflet.
Code
# my_acts<-my_acts %>% # drop_na() %>% # dplyr::filter(map.summary_polyline!="")# loop <- unique(my_acts$upload_id)# for (i in loop) {# activity <- dplyr::filter(my_acts, upload_id == i)# coords <- googleway::decode_pl(activity$map.summary_polyline)# map <- addPolylines(map, lng = coords$lon, lat = coords$lat,# color = 'red', opacity = 1/4, weight = 2)# }# # map
Change color depending of the different activity
Code
my_acts_select <-get_activity_list(stoken, after =as.Date('2021-01-01'))act_data <-compile_activities(my_acts_select) %>% dplyr::filter(map.summary_polyline!="") %>%mutate(type2 =ifelse(type %in%c("Ride", "Run", "Hike"), type, "Other"))loop <-unique(act_data$upload_id)for (i in loop) { activity <- dplyr::filter(act_data, upload_id == i) coords <- googleway::decode_pl(activity$map.summary_polyline) color <-switch(activity$type2,"Ride"='#007FE0',"Run"='#fc4c02',"Hike"='#08AF93',"Other"='#F15BB5') # Default color map <-addPolylines(map, lng = coords$lon, lat = coords$lat,color = color, opacity =1/4, weight =2,group = activity$type2) # Ajouter la polyligne à un groupe}# Ajouter les contrôles JavaScript pour le filtragemap <- map %>%addLayersControl(overlayGroups =unique(act_data$type2),options =layersControlOptions(collapsed =FALSE))map
Code
#athl_fun(133545, trace = FALSE)my_acts_select <-get_activity_list(stoken, after =as.Date('2021-01-01'))act_data <-compile_activities(my_acts_select)act_data<- act_data %>% dplyr::filter(type %in%c("Hike","Ride","Run","Workout")) %>% dplyr::mutate(cumulative_distance =cumsum(distance),cumulative_duration =cumsum(moving_time),Year =format(as.Date(start_date), "%Y"),month =format(as.Date(start_date), "%m-%d") ) %>% dplyr::group_by(Year, type) %>% dplyr::mutate(cumulative_duration_years =cumsum(moving_time),cumulative_distance_years =cumsum(distance)) %>% dplyr::ungroup() %>%mutate(Hours = cumulative_duration_years/3600)#test=act_data %>% dplyr::select(cumulative_duration_years,Hours,year,month)Years <-unique(act_data$Year)n_years <-length(Years)my_gradient <-colorRampPalette(colors =c("#230007","#7F9CC7","#FFBA08", "#fc4c02"))(n_years)p1<-act_data %>%ggplot(aes(x=as.Date(month,"%m-%d"),y=Hours, col=Year, group = Year))+geom_line()+facet_wrap(type~., scales ="free_y")+ylab("Cumulative duration (h)")+xlab("Month")+scale_x_date(date_labels ="%m", date_breaks ="1 month") +# Format pour les labels des moistheme_minimal()+scale_color_manual(values = my_gradient)p2<-act_data %>%ggplot(aes(x=as.Date(month,"%m-%d"),y=cumulative_distance_years, col=Year, group = Year))+geom_line()+facet_wrap(type~., scales ="free_y")+ylab("Distance (km)")+xlab("Month")+scale_x_date(date_labels ="%m", date_breaks ="1 month") +# Format pour les labels des moistheme_minimal()+scale_color_manual(values = my_gradient)#p1ggplotly(p1)