Analyzing Oura Sleep Data
I woke up feeling pretty refreshed yesterday for the first time in a while. I wear an Oura ring to monitor my sleep, but of course I wanted to extract and graph the data myself. 😁 🤓
I'm now averaging the most sleep per night since my daughter was born last year. 😅
You can see a short video of how I made this in EMR Studio using a combination of my own personal #docker data extractors and a fun charting library I found for Python called cutecharts. https://youtu.be/aU6b70BTYUY
note: I replaced cutecharts with Plotly in this notebook so it would render in HTML
Define a Docker extension
import subprocess
from io import StringIO
from IPython.core.magic import (register_line_magic, register_cell_magic)
import pandas as pd
def docker_pull(image):
subprocess.call("docker pull f{image}", shell=True)
def docker_run(args):
result = subprocess.run(["docker", "run", "--rm"] + args, capture_output=True)
return result.stdout
def read_from_docker(docker_args, image_args):
result = docker_run(docker_args + image_args)
return pd.read_json(result, lines=True)
@register_cell_magic
def docker_data(line, cell):
"""
line is the image and args to be used. Provided independently so we can always docker pull it
cell is the arguments to be provided to docker run
"""
image_args = line.split(" ")
docker_args = StringIO(cell).getvalue().split()
return read_from_docker(docker_args, image_args)
%%docker_data ghcr.io/dacort/crates-oura sleep
-e OURA_PAT
-e start=2020-07-01
df = _
df.describe()
Summarize data by month
import pandas
df.index = pandas.to_datetime(df['summary_date'],format='%Y-%m-%d')
dfGrouped = df.groupby(pandas.Grouper(freq='M')).mean()
dfGrouped.total
dfGrouped.index.strftime("%b %Y").tolist()
(dfGrouped.total/60/60).round(2).tolist()
Draw a chart!
import plotly.offline as py
import plotly.graph_objects as go
# Create traces
fig = go.Figure()
fig.add_trace(go.Scatter(x=dfGrouped.index.strftime("%b %Y").tolist(), y=(dfGrouped.total/60/60).round(2).tolist(),
mode='lines',
name='Total Sleep'))
fig.add_trace(go.Scatter(x=dfGrouped.index.strftime("%b %Y").tolist(), y=(dfGrouped.awake/60/60).round(2).tolist(),
mode='lines',
name='Awake'))
# fig.show()
#py.iplot(fig)
# Add title, x axis label, and specify template which is defined above
fig.update_layout(title='Average Sleep per Night (hrs)',
xaxis_title='Month',
yaxis_title='Hours',
template='plotly_white',
margin_l=0,
width=825,
autosize=False,
legend=dict(
yanchor="bottom",
y=1.1,
xanchor="right",
x=1
))
# Use jupyterlab renderer for great exporting
fig.show(renderer="jupyterlab")