Here is some updated R code from my previous post. It doesn't throw any warnings when importing tracks with and without heart rate information. Also, it is easier to distinguish types of tracks now (e.g., when you want to plot runs and rides separately). Another thing I changed: You get very basic information on the track when you click on it (currently the name of the track and the total length).

Have fun and leave a comment if you have any questions.



options(stringsAsFactors = F)

rm(list=ls())

library(httr)
library(rjson)
library(leaflet)
library(dplyr)

token <- "<your Strava API token>"

# Functions ---------------------------------------------------------------

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.activities2 <- 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)
  res.df <- data.frame()
  for (a in activities) {
    values <- sapply(c("name", "distance", "moving_time", "elapsed_time", "total_elevation_gain",
                       "type", "id", "start_date_local",
                       "location_country", "average_speed", "max_speed", "has_heartrate", "elev_high",
                       "elev_low", "average_heartrate", "max_heartrate"), FUN = function (x) {
                         if (is.null(a[[x]])) {
                           NA } else { a[[x]] }
                       })
    res.df <- rbind(res.df, values)
  }
  names(res.df) <- c("name", "distance", "moving_time", "elapsed_time", "total_elevation_gain",
                     "type", "id", "start_date_local",
                     "location_country", "average_speed", "max_speed", "has_heartrate", "elev_high",
                     "elev_low", "average_heartrate", "max_heartrate")
  res.df
}

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
}

activities <- get.activities2(token)

stream.list <- get.multiple.streams(activities$id, token)


# Leaflet -----------------------------------------------------------------

lons.range <- c(9.156572, 9.237580)
lats.range <- c(48.74085, 48.82079)

map <- leaflet() %>%
  addProviderTiles("OpenMapSurfer.Grayscale", # nice: CartoDB.Positron, OpenMapSurfer.Grayscale, CartoDB.DarkMatterNoLabels
                   options = providerTileOptions(noWrap = T)) %>%
  fitBounds(lng1 = min(lons.range), lat1 = max(lats.range), lng2 <- max(lons.range), lat2 = min(lats.range))

add.run <- function (act.id, color, act.name, act.dist, strlist = stream.list) {
  act.ind <- sapply(stream.list, USE.NAMES = F, FUN = function (x) {
    x$act.id == act.id
  })
  act.from.list <- strlist[act.ind][[1]]
  map <<- addPolylines(map, lng = act.from.list$coords$lon,
               lat = act.from.list$coords$lat,
               color = color, opacity = 1/3, weight = 2,
               popup = paste0(act.name, ", ", round(as.numeric(act.dist) / 1000, 2), " km"))
}

# plot all

for (i in 1:nrow(activities)) {
  add.run(activities[i, "id"], ifelse(activities[i, "type"] == "Run", "red",
                                      ifelse(activities[i, "type"] == "Ride", "blue", "black")),
          activities[i, "name"], activities[i, "distance"])
}

map
3

View comments

  1. Could you direct us to your previous post?

    ReplyDelete
    Replies
    1. Hi, it's linked under "previous post". The URL is http://rcrastinate.blogspot.com/2018/01/where-do-you-run-to-map-your-strava.html

      Delete
  2. This is great blog post i have read your others blog too. you can read my blog Spotify Error Code 3

    ReplyDelete
Rcrastinate is moving.
10 years of playback history on Last.FM: "Just sit back and listen"
3
This dance, it's like a weapon: Radiohead's and Beck's danceability, valence, popularity, and more from the LastFM and Spotify APIs
Network visualization of football transfers using the 'visNetwork' package
12
Get your tracks from the Strava API and plot them on Leaflet maps
3
Where do you run to? Map your Strava activities on static and Leaflet maps.
Substitute levels in a factor or character vector
Substitute levels in a factor or character vector
What's in the words? Comparing artists and lyrics with R.
4
Plotting GPX tracks with Shiny and Leaflet
9
Visualisation of Likert scale results
9
Troubles with cell labels in mosaic plots... and how to solve them.
3
Just plot this...
Just plot this...
Do basic R operations much faster in bash [Slightly off-topic]
Do basic R operations much faster in bash [Slightly off-topic]
Stop fiddling around with copied paths in Windows R
Stop fiddling around with copied paths in Windows R
4
Time series analysis with R: Testing stuff with NetAtmo data
5
Changing the font of R base graphic plots.
5
Stay on track: Plotting GPS tracks with R
5
Getting emotional in the absence of something: Using the Berlin Affective Word List to analyze emotional valence and arousal for nouns and adjectives.
Hyperthreading FTW? Testing parallelization performance in R.
4
Catching errors in R and trying something else
Catching errors in R and trying something else
The 'Deutsche Bahn' (German Railway Corp.) is always late!!1! Or is it? And if, why?
XML in R - A (German) tutorial / XML in R - ein Tutorial auf Deutsch
XML in R - A (German) tutorial / XML in R - ein Tutorial auf Deutsch
2
The rbinding race: for vs. do.call vs. rbind.fill
2
Funky music in funky months: Does my taste of music change over the year?
3
TeXing R tables: Save yourself a lot of typing...
Peace through Music. Country clustering using R and the last.fm API
"I don't wanna grow up": Age / value relationships for football players
The "golden age" of a football player
R-bloggers
R-bloggers
"The Dude" takes the Tarantino threshold
Fun stuff with subtitles or "The Tarantino Threshold"
Creating PDFs and websites with the "knitr" package
Creating PDFs and websites with the "knitr" package
Josh vs. himself (or: Firefly > all)
Going to the Movies...
Soccer is all about money (?) - Part 3: More plots & analyses
Soccer is all about money (?) - Part 2: Simple analyses
Soccer is all about money (?) - Part 1: Getting the Data
Soccer is all about money (?) - Part 1: Getting the Data
4
Let's go! (and Disclaimer)
Let's go! (and Disclaimer)
1
Blog Archive
BlogRoll
BlogRoll
Loading
Dynamic Views theme. Powered by Blogger. Report Abuse.