Resting Heart Rate Over Time.ipynb
A long-term picture of my daily resting heart rate, as measured by Apple Watch.
Also compare day-to-day with previous years to help eliminate any seasonal variation.
Resting heart rate seems to be an indicator of overall health. All else being equal, a lower average resting heart rate is generally better. Higher rates may reflect poorer overall physical fitness, higher levels of stress, or a latent infection.
This notebook uses data from my Apple Watch, uploaded to Open Humans through the OH uploader app.
Read all my heart rate data into the dataframe hr
. The code may look a little convoluted, but you don't need to understand how it works. Just trust that it pulls data from your OH Uploader results and places them into the dataframe.
Plot the resting heart rate for the past fifteen months. Obviously you can pick any number of months you like by changing the months(15)
section below
As you can see, there seems to be clear rising trend. What's going on?
Maybe it's just a seasonal thing. Maybe I don't exercise enough in the winter, so my resting heart rate goes up.
To find out, let's compare by day across years. Because my Apple Watch data starts in March 2019, I only have a few months of direct comparison
We can see the same pattern if, instead of daily flucutations, we look at weekly averages:
No matter how we do the analysis, it looks like my resting heart rate has increased substantially since last year.
Just to double-check I'm getting the most recent data
Resting heart rate seems to be an indicator of overall health. All else being equal, a lower average resting heart rate is generally better. Higher rates may reflect poorer overall physical fitness, higher levels of stress, or a latent infection.
This notebook uses data from my Apple Watch, uploaded to Open Humans through the OH uploader app.
library(tidyverse)
library(dplyr)
library(lubridate)
options(repr.plot.width=15, repr.plot.height=8)
Read all my heart rate data into the dataframe hr
. The code may look a little convoluted, but you don't need to understand how it works. Just trust that it pulls data from your OH Uploader results and places them into the dataframe.
library(httr)
access_token <- Sys.getenv("OH_ACCESS_TOKEN")
url <- paste("https://www.openhumans.org/api/direct-sharing/project/exchange-member/?access_token=",access_token,sep="")
resp <- GET(url)
user <- content(resp, "parsed")
user_data <- user$data
while (!is.null(user$`next`)) {
resp <- GET(user$`next`)
user <- content(resp, "parsed")
user_data <- append(user_data, user$data)
}
for (data_source in user_data){
if (data_source$source == 'direct-sharing-453'){
hr <- readr::read_csv(url(data_source$download_url),col_names=c("hr","date","type"))
}
}
Plot the resting heart rate for the past fifteen months. Obviously you can pick any number of months you like by changing the months(15)
section below
hr %>% dplyr::filter(date>today()-months(15),type=="R") %>%
ggplot(aes(x=date,y=hr)) +
geom_line() +
geom_point(color="red") +
# geom_label(aes(label=hr)) +
scale_x_datetime( date_labels = "%B", date_breaks = "1 month" ) +
geom_smooth(formula = y~x, method="loess") +
labs(title="Resting Heart Rate", x=element_blank()) +
theme(plot.title = element_text(color = "red", size = 24, face = "bold"),
axis.text.x = element_text(angle = 90, hjust = 1))
As you can see, there seems to be clear rising trend. What's going on?
Maybe it's just a seasonal thing. Maybe I don't exercise enough in the winter, so my resting heart rate goes up.
To find out, let's compare by day across years. Because my Apple Watch data starts in March 2019, I only have a few months of direct comparison
hr_years <- tibble(year = year(hr$date),
month = month(hr$date),
month_name = month.abb[month],
day = day(hr$date),
date = make_date(year,month,day),
type = factor(hr$type),
hr = hr$hr
)
hr_years %>% dplyr::filter(type=="R" & month %in% 3:11) %>% ggplot(aes(x=yday(date),y=hr, color=factor(year))) +
geom_line(size=1) +
labs(title = "Resting Heart Rate",x = element_blank()) +
scale_x_continuous(breaks = seq(1,365, length.out=12), labels = month.abb[floor(seq(1,365,by=30)/30)]) +
guides(color=guide_legend("Year"))+
theme(plot.title = element_text(color = "red", size = 24, face = "bold"),
axis.text.x = element_text(angle = 90, hjust = 1))