Oura Plot Replication
#install libraries
!pip install pandas
!pip install numpy
!pip install plotly
Requirement already satisfied: pandas in /shared-libs/python3.9/py/lib/python3.9/site-packages (1.2.5)
Requirement already satisfied: python-dateutil>=2.7.3 in /shared-libs/python3.9/py-core/lib/python3.9/site-packages (from pandas) (2.8.2)
Requirement already satisfied: pytz>=2017.3 in /shared-libs/python3.9/py/lib/python3.9/site-packages (from pandas) (2022.5)
Requirement already satisfied: numpy>=1.16.5 in /shared-libs/python3.9/py/lib/python3.9/site-packages (from pandas) (1.23.4)
Requirement already satisfied: six>=1.5 in /shared-libs/python3.9/py-core/lib/python3.9/site-packages (from python-dateutil>=2.7.3->pandas) (1.16.0)
WARNING: You are using pip version 22.0.4; however, version 23.0.1 is available.
You should consider upgrading via the '/root/venv/bin/python -m pip install --upgrade pip' command.
Requirement already satisfied: numpy in /shared-libs/python3.9/py/lib/python3.9/site-packages (1.23.4)
WARNING: You are using pip version 22.0.4; however, version 23.0.1 is available.
You should consider upgrading via the '/root/venv/bin/python -m pip install --upgrade pip' command.
Requirement already satisfied: plotly in /shared-libs/python3.9/py/lib/python3.9/site-packages (5.10.0)
Requirement already satisfied: tenacity>=6.2.0 in /shared-libs/python3.9/py/lib/python3.9/site-packages (from plotly) (8.1.0)
WARNING: You are using pip version 22.0.4; however, version 23.0.1 is available.
You should consider upgrading via the '/root/venv/bin/python -m pip install --upgrade pip' command.
#import libraries
import pandas as pd
import numpy as np
import plotly.express as px
#generate synthetic data
#function to create linear changes over time (ups and downs)
def linear_cycles(changes, begin):
"""
Linear Cycles: Function to generate arrays that have up and down changes over time
changes: list, specify each change that occurs over time, will generate 25 data points for each linear change
begin: int, data point that changes will start from
"""
appended_cycles = [] #initiate list
for change in changes: #loop through changes list
#create linear array starting with begin or from where changes ended, 25 total data points per array
cycle = list(np.linspace(start = begin, stop = begin + change, num = 25))
#combine lists
appended_cycles = appended_cycles + cycle
#create new starting point for next iteration through the loop
begin = begin + change
return appended_cycles #return the combined linear cycles
awake = linear_cycles(changes=[10, -10, 20, -35, 0, 0, 0], begin = 20) #awake cylce
rem = linear_cycles(changes=[0, 0, 30, -10, 20, 10, 40], begin = 10) #rem cycle
light = linear_cycles(changes=[55, -20, 20, -30, 65, -50, -40], begin = 10) #light cycle
deep = linear_cycles(changes=[55, -20, 20, -30, 65, -50, -40], begin = 10) #deep cycle
#create data frame with all sleep cycles
sleepdata = pd.DataFrame({'Deep': deep,
'Light': light,
'REM': rem,
'Awake': awake})
#create column day based on the index (arbitrary for plotting purposes)
sleepdata['Day'] = sleepdata.index
#melt the data frame for plotting purposes
data = pd.melt(sleepdata,
id_vars = ['Day'],
value_vars=["Awake", "REM", "Light", "Deep"],
value_name= "Proportion of Time",
var_name = "Sleep Cycle")
display(data)
Dayint64
0 - 174
Sleep Cycleobject
Awake25%
REM25%
2 others50%
0
0
Awake
1
1
Awake
2
2
Awake
3
3
Awake
4
4
Awake
5
5
Awake
6
6
Awake
7
7
Awake
8
8
Awake
9
9
Awake
#begin with generic plot, color coded and correctly ordered to match image
fig = px.area(data, x = 'Day', y = 'Proportion of Time',
color = 'Sleep Cycle', line_group='Sleep Cycle',
color_discrete_map={'REM': '#77c9f1', 'Light': '#438fc3', 'Deep': '#1b497d', 'Awake': '#fcfbfc'},
category_orders={"Sleep Cycle": ["Deep", "Light", "REM", "Awake"]})
fig.show()
#change background to match image
fig.update_layout(paper_bgcolor="#e5ddd2", plot_bgcolor="#e5ddd2")
fig.show()
#update axes, remove the grid and tick labels and expand the range of x and y, remove the zeroline
fig.update_xaxes(showgrid=False, showticklabels=False, title = ' ', range = [-10, 185], zeroline=False)
fig.update_yaxes(showgrid=False, showticklabels=False, title = ' ', range = [-25, 455], zeroline=False)
fig.show()
#add the title
fig.update_layout(
title={
'text' : 'REM sleep trends to decrease in summer' + '<br>' + 'and increase in winter.',
'x':0.5,
'xanchor': 'center',
'font': {'size': 30}
})
#move the legend to the correct position
fig.update_layout(legend=dict(
orientation="h",
yanchor="bottom",
y=-0.15,
xanchor="right",
x=0.8
))
fig.show()
from PIL import Image
#upload summer and winter images
summer = Image.open("summer.png")
winter = Image.open("winter.png")
#add images to the plot
fig.add_layout_image(
dict(
source=summer,
xref="x",
yref="y",
x=0,
y=430,
sizex=150,
sizey=150,
opacity=1,
layer="above")
)
fig.add_layout_image(
dict(
source=winter,
xref="x",
yref="y",
x=145,
y=430,
sizex=150,
sizey=150,
opacity=1,
layer="below")
)
fig.show()
#add annotations to highlight the changes
fig.add_annotation(text = 'Decreased', x = 10, y = 70, xref='x', bgcolor='lightblue')
fig.add_annotation(text = 'Increased', x = 170, y = 120, xref='x', bgcolor = 'lightblue')
fig.show()