Details for Resting Heart Rate Over Time.ipynb

Published by sprague

Description

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.

1

Tags & Data Sources

heartrate apple watch OH Data Port for Apple Health

Comments

Please log in to comment.

Notebook
Last updated 3 years, 4 months ago

Resting Heart Rate Over Time

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.

── Attaching packages ─────────────────────────────────────── tidyverse 1.3.0 ──

 ggplot2 3.3.0      purrr   0.3.4
 tibble  3.0.1      dplyr   0.8.5
 tidyr   1.1.0      stringr 1.4.0
 readr   1.3.1      forcats 0.5.0

── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
 dplyr::filter() masks stats::filter()
 dplyr::lag()    masks stats::lag()


Attaching package: ‘lubridate’


The following objects are masked from ‘package:dplyr’:

    intersect, setdiff, union


The following objects are masked from ‘package:base’:

    date, intersect, setdiff, union


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.

Parsed with column specification:
cols(
  hr = col_double(),
  date = col_datetime(format = ""),
  type = col_character()
)

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.

Resting Heart Rate By Year

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.

Last few values of my resting heart rate

Just to double-check I'm getting the most recent data

A tibble: 6 × 3
hrdatetype
<dbl><dttm><chr>
632020-12-04 00:03:07R
612020-12-03 00:02:38R
642020-12-02 00:03:07R
622020-12-01 00:02:25R
592020-11-30 00:02:36R
612020-11-29 00:04:17R

Notebook
Last updated 3 years, 4 months ago

Resting Heart Rate Over Time

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.

In [3]:
library(tidyverse)
library(dplyr)
library(lubridate)
── Attaching packages ─────────────────────────────────────── tidyverse 1.3.0 ──

 ggplot2 3.3.0      purrr   0.3.4
 tibble  3.0.1      dplyr   0.8.5
 tidyr   1.1.0      stringr 1.4.0
 readr   1.3.1      forcats 0.5.0

── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
 dplyr::filter() masks stats::filter()
 dplyr::lag()    masks stats::lag()


Attaching package: ‘lubridate’


The following objects are masked from ‘package:dplyr’:

    intersect, setdiff, union


The following objects are masked from ‘package:base’:

    date, intersect, setdiff, union


In [8]:
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.

In [4]:
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"))
  }
}
Parsed with column specification:
cols(
  hr = col_double(),
  date = col_datetime(format = ""),
  type = col_character()
)

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

In [5]:
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.

Resting Heart Rate By Year

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

In [6]:
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
                   )
In [9]:
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))

We can see the same pattern if, instead of daily flucutations, we look at weekly averages:

In [10]:
hr_years %>% filter(type == "R") %>% group_by(week=week(date), year=factor(year)) %>% summarize(week_ave = mean(hr)) %>% 
  ggplot(aes(x=week,y=week_ave, color = year, label = as.integer(week_ave) )) + geom_line() +
    geom_point() + geom_text(size=6, hjust=-1) +
  labs(title = "Resting Heart Rate (Weekly Ave)", y = "Weekly Average", x = element_blank()) + 
  scale_x_continuous(breaks = seq(1,52, length.out=12), labels = month.abb[floor(seq(1,52,by=4)/4)]) +
  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))

No matter how we do the analysis, it looks like my resting heart rate has increased substantially since last year.

Last few values of my resting heart rate

Just to double-check I'm getting the most recent data

In [11]:
hr  %>% arrange(desc(date)) %>% mutate(date=lubridate::with_tz(date,"US/Pacific"))   %>% filter(type=="R") %>% head()
A tibble: 6 × 3
hrdatetype
<dbl><dttm><chr>
632020-12-04 00:03:07R
612020-12-03 00:02:38R
642020-12-02 00:03:07R
622020-12-01 00:02:25R
592020-11-30 00:02:36R
612020-11-29 00:04:17R
In [ ]:

In [ ]: