Where do you run to? Map your Strava activities on static and Leaflet maps.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
So, Strava’s heatmap made quite a stir the last few weeks. I decided to give it a try myself. I wanted to create some kind of “personal heatmap” of my runs, using Strava’s API. Also, combining the data with Leaflet maps allows us to make use of the beautiful map tiles supported by Leaflet and to zoom and move the maps around – with the runs on it, of course.
So, let’s get started. First, you will need an access token for Strava’s API. I found all the necessary information for this in this helpful “Getting started” post. As soon as you have the token, you have access to your own data.
Now, let’s load some packages and define functions for getting and handling the data. For the get.activities() function, I adapted code from here.
library(httr)
library(rjson)
library(OpenStreetMap)
library(leaflet)
library(scales)
library(dplyr)
token <- "
get.coord.df.from.stream <- function (stream.obj) {
data.frame(lat = sapply(stream.obj[[1]]$data, USE.NAMES = F, FUN = function (x) x[[1]]),
lon = sapply(stream.obj[[1]]$data, USE.NAMES = F, FUN = function (x) x[[2]]))
}
get.stream.from.activity <- function (act.id, token) {
stream <- GET("https://www.strava.com/",
path = paste0(“api/v3/activities/”, act.id, “/streams/latlng”),
query = list(access_token = token))
content(stream)
}
get.activities <- function (token) {
activities <- GET("https://www.strava.com/", path = "api/v3/activities",
query = list(access_token = token, per_page = 200))
activities <- content(activities, "text")
activities <- fromJSON(activities)
activities <- lapply(activities, function(x) {
x[sapply(x, is.null)] <- NA
unlist(x)
})
data.frame(do.call(“rbind”, activities))
}
get.multiple.streams <- function (act.ids, token) {
res.list <- list()
for (act.id.i in 1:length(act.ids)) {
if (act.id.i %% 5 == 0) cat(“Actitivy no.”, act.id.i, “of”, length(act.ids), “\n”)
stream <- get.stream.from.activity(act.ids[act.id.i], token)
coord.df <- get.coord.df.from.stream(stream)
res.list[[length(res.list) + 1]] <- list(act.id = act.ids[act.id.i],
coords = coord.df)
}
res.list
}
We have all the functions we need to get and parse the APIs output available now. Let’s apply them. The logic is: First, we get all activities. This dataframe has a column called ‘id’ which we can use to get all the raw data for all activities (called ‘streams’ in the Strava API). The function get.coord.df.from.stream() creates a dataframe with lat/lon coordinates for one stream.
activities <- get.activities(token)
stream.list <- get.multiple.streams(activities$id, token)
We might want to get the boundaries of the cumulated set of all streams. We can use these boundaries as a bounding box for plotting the data. This means that all activities are going to be in the plotted map section.
all.lats <- unlist(sapply(stream.list, USE.NAMES = F, FUN = function (x) {
x$coords$lat
}))
all.lons <- unlist(sapply(stream.list, USE.NAMES = F, FUN = function (x) {
x$coords$lon
}))
lats.range <- range(all.lats)
lons.range <- range(all.lons)
We start by plotting the tracks in red against a black background. You can play around with the alpha value and the lwd parameter to change the appearance. By plotting several tracks over each other, thicker lines represent routes I took more often.
# Setting up the plot
par(bg = “black”)
plot(x = lons.range, y = lats.range, type = “n”, bty = “n”, xlab = “”, ylab = “”, xaxt = “n”, yaxt = “n”)
# Plotting tracks one by one
for (el in stream.list) {
lines(el$coords$lon, el$coords$lat,
col = alpha(“darkred”, .4), lwd = 2)
}
With the leaflet functions, we could even associate each track with a little mouseover text (like total distance or the date). I did not include this here because quite a few tracks have been plotted over each other and mouseover texts might just confuse us here.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.