<- httr::config(token = readRDS('.httr-oauth')[[1]]) stoken
When the winds blows, it’s time for bike.
Strava and R
Cycling is my way of daily commuting. It’s also a way to go here and there, usually with panniers and hammock in them. I though it would be nice to illustrate the post with track on map. Started to looking around what’s available to process GPX
tracks in R and found a few examples; there were attempts using XML
package (Lizarazo 2018; Wolfer 2014), there are some promising functions: readGPX()
in plotKLM
or read_GPX()
in tmaptools
package.
I’m using Strava for long time as odometer and track logger. How I was surprised when found rStrava
package. (Villarroel et al. 2021). It allows you to get the Strava activities, run couple of analysis, and together with Google API key — create a heat maps. But let’s see what’s inside (and how to use it). To get the access to Strava you have to create Strava API key - the whole procedure is well described in readme
After creating API key and configuring the token, we can access the data:
Let’s grab basic information about myself :)
<- get_athlete(stoken, id = '16504523')
myinfo $username myinfo
[1] "gsapijaszko"
Most functions of rStrava
package depends on Google Maps API, however I would like to show a bit different approach. As we can get the activities and process it independently, let’s get some data:
<- get_activity_list(stoken,
my_acts after = as.Date("2021-08-07"),
before = as.Date("2021-08-15"))
The output of get_activity_list()
returns a list
of activities. We can convert it to more easy to work with format like data.table
with compile_activities()
function. The resulting data frame has 54 variables, just showing few of them:
<- compile_activities(my_acts)
my_data 1:2, c("id", "distance", "average_speed", "max_speed", "total_photo_count")] my_data[
id distance average_speed max_speed total_photo_count
1 5792096677 66.4123 15.3900 37.80 3
2 5786872981 38.4768 11.0592 31.32 0
The activity geometry received from Strava is encoded by Google polyline algorithm. To decode it we will use googlePolylines
package (Cooley 2020a). To apply calculation to all polylines in data frame we will build a small function. It takes polyline as argument, decode it, converts to linestring (using sf_linestring()
from sfheaders
package (Cooley 2020b)) and assigning proper CRS by st_crs()
from sf
package:
<- function (polyline) {
decPolilineAsLinestring <- as.data.frame(googlePolylines::decode(polyline))
b <- sfheaders::sf_linestring(b, x="lon", y="lat")
c ::st_crs(c) <- 4326
sfreturn (c$geometry)
}
Let’s apply the function to our data:
<- my_data |>
my_data ::rowwise() |>
dplyr::mutate(geometry = decPolilineAsLinestring(map.summary_polyline)) dplyr
And finally, we can plot it using leaflet
package:
library(leaflet)
leaflet(my_data$geometry) |>
addTiles() |>
addPolylines()
Easy, isn’t it?
But what about photos? Why not to add them to the map? We could reuse the photos which are uploaded to Strava (do you remember total_photo_count
variable from my_data
table?), however for some reasons Strava not always keeps the exif coordinates within the photo. Therefore photos will be stored locally, and we will use exiftoolr
package (O’Brien 2021) to access their coordinates.
library(exiftoolr)
<- exif_read(path = "photos", recursive = TRUE) photos
Using ExifTool version 12.49
And extend our map:
<- leaflet(my_data$geometry)
map <- addTiles(map)
map <- addPolylines(map, color = "#0000FF")
map for (i in 1:nrow(photos)) {
<- addMarkers(map,
map lng = photos[i,"GPSLongitude"],
lat = photos[i,"GPSLatitude"],
popup = paste0("<a href = photos/", photos[i, "FileName"],
" target = \"_blank\">", "<img src = photos/",
"FileName"], " width = \"300\">", "</a>"))
photos[i,
} map