Details for quantified-flu-oura.ipynb

Published by gedankenstuecke


A notebook that visualizes your heart rate & body temperature before & after flu/cold events


Tags & Data Sources

quantifiedflu Oura Connect


Please log in to comment.

Last updated 3 weeks, 5 days ago

Heart rate & body temperature variations when sick

The Oura Ring allows you to measure vital signs during sleep such as heart rate and body temperature changes. Here we will use this data to see if there are any patterns that emerge before falling sick. This is part of the #quantifiedflu project that came out of one of the Open Humans community calls!

If you haven't connected your Oura account to Open Humans this notebook will fail. Go here to connect your account.

There are three parameters you can easily change for this notebook in the cell below:

  • The first one, sick_dates, is a list of dates on which you fell sick. Enter dates as YYYY-MM-DD format, e.g. 2019-11-29 for the 29th of November 2019. You can provide as many sick dates as you remember as a comma-separated ist.
  • The second one, weeks_before_sick, decides how many weeks before the actual falling sick you want to have shown in your graphs. By default it is 3.
  • The third one, weeks_after_sick, decides how many weeks after the event you want to see in your graph. By default it's 1.
In [1]:
sick_dates = ['2019-11-29', '2019-09-29', '2018-12-31']
weeks_before_sick = 3
weeks_after_sick = 1

The code below will now get your data from Open Humans and create a table with all the data points in the date ranges you specified above:

In [2]:
from ohapi import api
import os
import requests
import tempfile
import arrow

user_details = api.exchange_oauth2_member(os.environ.get('OH_ACCESS_TOKEN'))
for i in user_details['data']:
    if i['source'] == 'direct-sharing-184' and i['basename'] == 'oura-data.json':
import json 
oura = json.loads(requests.get(i['download_url']).content)

sd_dict = {}

for sd in sick_dates:
    sdd = arrow.get(sd)
    period_start = sdd.shift(weeks=weeks_before_sick*-1).format('YYYY-MM-DD')
    period_end = sdd.shift(weeks=weeks_after_sick).format('YYYY-MM-DD')
    sd_dict[sd] = {'period_start': period_start, 'period_end': period_end}

period = []
timestamp = []
heart_rate = []
temperature_delta = []

for p in sd_dict.keys():
    for entry in oura['sleep']:
        sdate = arrow.get(entry['summary_date'])
        if (sdate >= arrow.get(sd_dict[p]['period_start'])) and (sdate <= arrow.get(sd_dict[p]['period_end'])):
            temperature = entry['temperature_delta']
            bedtime_start = arrow.get(entry['bedtime_start'])
            for hr in entry['hr_5min']:
                bedtime_start = bedtime_start.shift(minutes=+5)

import pandas as pd
dataframe = pd.DataFrame(
    data = {
        'period': period,
        'timestamp': timestamp,
        'heart_rate': heart_rate,
        'temperature_delta': temperature_delta

Visualizing heart rate & temperature changes around the sick dates:

Temperature changes

Each sick-period will be it's own little sub-graph, with the date of falling sick being highlighted by a vertical, red bar. Each sick-period shows the nightly temperature changes, as well as a fitted line for the data. As there's only one nightly temperature data point, most days get a single point.

In [3]:
%load_ext rpy2.ipython
In [4]:
%%R -i dataframe -w 15 -h 4 --units in -r 200

ggplot(subset(dataframe,dataframe$heart_rate > 0), aes(x=as.POSIXct(timestamp),y=temperature_delta,color=period)) + 
    geom_vline(aes(xintercept=as.POSIXct(period)),alpha=0.3,color='red') + 
    geom_point(alpha=0.2) + 
    geom_smooth(method='loess') + theme_minimal() + scale_x_datetime('timestamp') + 
    facet_grid(. ~ period, scales='free')
/opt/conda/lib/python3.6/site-packages/rpy2/robjects/ UserWarning: Error while trying to convert the column "timestamp". Fall back to string conversion. The error is: Conversion 'py2ri' not defined for objects of type '<class 'arrow.arrow.Arrow'>'
  (name, str(e)))

Heart rate changes

These graphs follow the same pattern, but as Oura records a heart rate value every 5 minutes during sleep, we'll see lots of points per night, giving us a pattern for each day. The red, vertical line again shows the day of the incident and the fit-line tries to show how the points distribute for each day.

In [5]:
%%R -w 15 -h 4 --units in -r 200

ggplot(subset(dataframe,dataframe$heart_rate > 0), aes(x=as.POSIXct(timestamp),y=heart_rate,color=period)) + 
    geom_vline(aes(xintercept=as.POSIXct(period)),alpha=0.3,color='red') + 
    geom_point(alpha=0.2) + 
    geom_smooth(method='loess') + theme_minimal() + scale_x_datetime('timestamp') + 
    facet_grid(. ~ period, scales='free')

Can you observe clear patterns? Is there something unexpected in your data? You can publish your own notebook after running it via the menu above: Click File -> Share Notebook -> Upload to Open Humans to share it with others.