Creating a Heatmap in R with Google Polylines
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.
First, I load in all the necessary packages.
# Code written by Daniel Cullen
# Using code from the following sources:
# https://padpadpadpad.github.io/post/animate-your-strava-activities-using-rstrava-and-gganimate/
# https://medium.com/@annthurium/getting-started-with-the-strava-api-a-tutorial-f3909496cd2d
# https://www.r-bloggers.com/where-do-you-run-to-map-your-strava-activities-on-static-and-leaflet-maps/
# http://www.databrew.cc/posts/strava.html
# https://github.com/fawda123/rStrava
library(rStrava) # devtools::install_github('fawda123/rStrava')
library(dplyr)
library(leaflet)
library(htmlwidgets)
library(googleway) # to convert google polyline format to lat and long
Then I will enter my personal Strava API information which can be found here after you apply for API access.
## Necessary info from Strava api https://www.strava.com/settings/api
app_name <- '<>' # chosen by user
app_client_id <- '<>' # an integer, assigned by Strava
app_secret <- '<>' # an alphanumeric secret, assigned by Strava
stoken <- 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.
## Load my activities and compile activities with rStrava library
my_data <- get_activity_list(stoken)
act_data <- compile_activities(my_data)
The activity data contains 56 variables. We only need to keep two, the map data called 'map.summary_polyline'
and the 'upload_id'
.
## Keep only activity id and map line
keeps <- 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.
## Create blank map bounded by given lon and lat
lons.range <- c(-119.9, -119.6)
lats.range <- c(34.3, 34.58)
## tile options CartoDB.Positron , CartoDB.DarkMatter , Stamen.Toner
map <- leaflet(options = leafletOptions(zoomControl = FALSE)) %>%
addProviderTiles('CartoDB.Positron',
options = providerTileOptions(noWrap = T, minZoom=12, maxZoom=12)) %>%
fitBounds(lng1 = min(lons.range), lat1 = max(lats.range), lng2 <- max(lons.range), lat2 = min(lats.range))
map #save using mapshot(map, file="sbmap.png")
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.
loop <- unique(my_acts$upload_id)
for (i in loop) {
activity <- filter(my_acts, upload_id == i)
coords <- googleway::decode_pl(activity$map.summary_polyline)
map <- addPolylines(map, lng = coords$lon, lat = coords$lat,
color = 'blue', opacity = 1/4, weight = 2)
}
map
Finally, to export the final interactive map as seen at the top of the page I use the saveWidget
command from the htmlwidgets
package.
saveWidget(map, file="runningmap.html")