Biking and running and hiking, oh my!
Hello blog visitors!
I love September (my birthday month! back to school time! the best of both summer and autumn! basically the vibes of these few seconds of Tom Hanks). I am, however, always sad to see summer go! I relish the extra daylight hours to fit in a morning run and the warm evening weather for backpacking and car camping. In honor of all the miles logged outside this summer, I’m practicing visualizing spatial data using my Strava activities ☺
There are loads of people who have accomplished this already! Thanks to everyone doing the good work of blogging up their bikes and hikes. Conquering the Strava API was the most challenging bit, but I could not have done it without your sweet, sweet blog guides! I’ll drop the blogs I was inspired by here:
Let’s make some maps!
🚴🥾🏃
I found this blog from Tilde Ann Thurium helpful in figuring out how to get started with the Strava API.
My credentials are stored outside of my repository, and therefore not on Git, so that they remain mine, but if you have questions about how I write or call them, contact me. I am happy to help!
source("../../../credentials/strava_credentials.R")
I downloaded my activities data using the function
rStrava::get_activity_list()
which uses the token generated
in the previous code chunk.
Then, I compiled my activities data into a tidy dataframe. The
rStrava::compile_activites()
function creates a dataframe
in which each row is a single activity.
#download activities
my_data <- get_activity_list(stoken)
#compile activities
act_data <- compile_activities(my_data) %>%
write_csv(here("data/strava_data.csv"))
#check it out!
glimpse(act_data)
There are 201 columns in my compiled dataframe, and since I don’t pay for Strava, a lot of them are junk: full of NAs because free Strava doesn’t collect my heartrate, for example.
I select only the columns I am interested in mapping and tidy my dataframe to have more readable units of time, more straightforward column names, and to get rid of activities that have only a little data (that one time I used Strava skiing in Tahoe is not that interesting!).
columns_of_interest <- c('distance',
'elapsed_time',
'elev_high',
'elev_low',
'moving_time',
'start_date',
'start_date_local',
'type',
'map.summary_polyline',
'upload_id',
'start_latlng1',
'start_latlng2',
'total_elevation_gain',
'upload_id')
activities <- select(act_data, match(columns_of_interest,
names(act_data)))
activities <- activities %>%
mutate(elapsed_time = round(elapsed_time / 60 /60, digits = 2),
moving_time = round(moving_time / 60 / 60, digits = 2),
date = gsub("T.*$", '', start_date) %>%
as.POSIXct(., format = "%Y-%m-%d")) %>%
rename(latitude = "start_latlng1",
longitude = "start_latlng2") %>%
filter(type == c("Ride", "Run", "Hike"))
I decided to map my running, hiking, and biking activities in Northern California for this exercise. Most of the activities happen to be in the Bay Area, where I live, but some of my adventures in Napa, Marin, and Yosemite make it into the map with the bounding box I set.
With the Strava data good to go for mapping, a blank canvas is needed to visualize my activities.
The code chunk below creates a blank leaflet
map with a
legend on which I’ll add my activities data.
## Create blank map bounded by given lon and lat
lons.range <- c(-123, -121)
lats.range <- c(37, 38.7)
#create a blank map
map <- leaflet(options = leafletOptions(zoomControl = FALSE)) %>%
addProviderTiles('CartoDB.Positron',
options = providerTileOptions(noWrap = T,
minZoom = 7,
maxZoom = 15)) %>%
fitBounds(lng1 = min(lons.range),
lat1 = max(lats.range),
lng2 <- max(lons.range),
lat2 = min(lats.range)) %>%
addLegend(colors = c("#262d42", "#f7c267", "#591c19"),
labels = c("Ride", "Run", "Hike"),
position = "bottomright")
map
Finally, I loop through each activity in my compiled dataset. The for
loop plots each activity in a 1 of 3 colors depending on the activity
type, using an if else
statement series.
The for loop also adds a label to each ride. The label gives details about the trip, including the date of the activity, distance of the activity, duration of the activity, and elevation gain.
Also in the for loop is the decode_pl()
function from
the googleway
package for transforming polyline encoding to
latitude and longitude as a dataframe. Polyline
encoding stores a series of coordinates in a single string.
unique_activites <- unique(activities$upload_id)
for (i in unique_activites){
#get activity
activity <- filter(activities,
upload_id == i)
#decode polyline
coords <- decode_pl(activity$map.summary_polyline)
#labs
labs <- paste0('<p>',
'<b>',
"Activity Date: ",
'</b>',
activity$date,
'<p></p>',
'<b>',
"Distance (Miles): ",
'</b>',
activity$distance,
'<p></p>',
'<b>',
"Time (Hours): ",
'</b>',
activity$elapsed_time,
'<p></p>',
'<b>',
"Elevation Gain (Feet): ",
'</b>',
activity$total_elevation_gain,
'<p>') %>%
htmltools::HTML()
#plot activity!
map <- if (activity$type == "Ride") {
addPolylines(map,
lng = coords$lon,
lat = coords$lat,
color = "#262d42",
weight = 2,
opacity = 1/2,
label = labs,
labelOptions = labelOptions(style = list("font-family" = "serif",
"font-style" = "bold",
"box-shadow" = "3px 3px rgba(0, 0, 0, 0.25)")))
} else if (activity$type == "Run") {
addPolylines(map,
lng = coords$lon,
lat = coords$lat,
color = "#f7c267",
weight = 2,
opacity = 1/2,
label = labs,
labelOptions = labelOptions(style = list("font-family" = "serif",
"font-style" = "bold",
"box-shadow" = "3px 3px rgba(0, 0, 0, 0.25)")))
} else if (activity$type == "Hike") {
addPolylines(map,
lng = coords$lon,
lat = coords$lat,
color = "#591c19",
weight = 2,
opacity = 1/2,
label = labs,
labelOptions = labelOptions(style = list("font-family" = "serif",
"font-style" = "bold",
"box-shadow" = "3px 3px rgba(0, 0, 0, 0.25)")))
}
}
map
Distill is a publication format for scientific and technical writing, native to the web.
Learn more about using Distill at https://rstudio.github.io/distill.
For attribution, please cite this work as
Leonard (2022, Sept. 5). Scout Leonard (she/her): Mapping Fun With Strava Data. Retrieved from https://scoutcleonard.github.io/posts/2022-09-05-mapping-fun-with-strava-data/
BibTeX citation
@misc{leonard2022mapping, author = {Leonard, Scout}, title = {Scout Leonard (she/her): Mapping Fun With Strava Data}, url = {https://scoutcleonard.github.io/posts/2022-09-05-mapping-fun-with-strava-data/}, year = {2022} }