karpathy-sleep / app.py
Hannah
fix thresholds
ff310de
import gradio as gr
import numpy as np
import pandas as pd
def load_health_data():
# Load the CSV file into a pandas DataFrame
df = pd.read_csv('healthdata.csv', header=2)
# Replace null values with empty strings
df = df.replace({np.nan: "", None: ""})
return df
def get_device_data(device):
df = load_health_data()
# Common columns for all devices
base_cols = ['Day', 'Date', 'Day of Week']
if device == "AppleWatch + AutoSleep":
# Get columns with AS suffix + base columns
device_cols = base_cols + [col for col in df.columns if 'AS' in col]
elif device == "8sleep Pod 4 Ultra":
# Get columns with 8S suffix + base columns
device_cols = base_cols + [col for col in df.columns if '8S' in col]
elif device == "Oura":
# Get columns with OU suffix + base columns
device_cols = base_cols + [col for col in df.columns if 'OU' in col]
elif device == "Whoop":
# Get columns with WH suffix + base columns
device_cols = base_cols + [col for col in df.columns if 'WH' in col]
else:
return df
# Add the Average and Notes columns if they exist
if 'Average' in df.columns:
device_cols.append('Average')
if 'Notes' in df.columns:
device_cols.append('Notes')
return df[device_cols]
def get_color_for_metric(val, metric_name):
"""Return a color based on the metric type and value"""
try:
val = float(val)
except (ValueError, TypeError):
return ""
# Define thresholds for different metrics
if "BPM" in metric_name:
# Lower is better for BPM
if val <= 50:
return "background-color: rgba(0, 180, 0, 0.3)" # Green
elif val >= 54:
return "background-color: rgba(180, 0, 0, 0.3)" # Red
else:
return "background-color: rgba(180, 180, 180, 0.1)" # Light gray for middle range
elif "Score" in metric_name:
# Higher is better for Score
if val >= 85:
return "background-color: rgba(0, 180, 0, 0.3)" # Dark green
elif val >= 75:
return "background-color: rgba(0, 140, 0, 0.2)" # Medium green
elif val <= 70:
return "background-color: rgba(180, 0, 0, 0.3)" # Red
else:
return "background-color: rgba(180, 180, 180, 0.1)" # Light gray
elif "HRV" in metric_name:
# Higher is better for HRV
if val >= 80:
return "background-color: rgba(0, 180, 0, 0.3)" # Dark green
elif val <= 55:
return "background-color: rgba(180, 0, 0, 0.3)" # Red
else:
return "background-color: rgba(180, 180, 180, 0.1)" # Light gray
elif "Deep" in metric_name:
# Higher might be better for Deep sleep
if val >= 1.0:
return "background-color: rgba(0, 180, 0, 0.3)" # Green
elif val <= 0.2:
return "background-color: rgba(180, 0, 0, 0.3)" # Red
else:
return "background-color: rgba(180, 180, 180, 0.1)" # Light gray
elif "REM" in metric_name:
# Higher might be better for REM
if val >= 1.5:
return "background-color: rgba(0, 180, 0, 0.3)" # Green
elif val <= 0.8:
return "background-color: rgba(180, 0, 0, 0.3)" # Red
else:
return "background-color: rgba(180, 180, 180, 0.1)" # Light gray
elif "Light" in metric_name:
# Medium values might be ideal for Light sleep
if 5.0 <= val <= 6.0:
return "background-color: rgba(0, 180, 0, 0.3)" # Green
elif val >= 6.3 or val <= 4.5:
return "background-color: rgba(180, 0, 0, 0.3)" # Red
else:
return "background-color: rgba(180, 180, 180, 0.1)" # Light gray
return "" # Default no color
def prepare_data_with_styling(df):
data = df.values.tolist()
headers = list(df.columns)
# Create styling
styling = []
for row in data:
row_styling = []
for i, val in enumerate(row):
if headers[i] in ['Day', 'Date', 'Day of Week', 'Notes'] or val == "":
row_styling.append(["", ""])
else:
style = get_color_for_metric(val, headers[i])
row_styling.append(["", f"width: var(--cell-width-3); left: auto; {style}"])
styling.append(row_styling)
return {
"data": data,
"headers": headers,
"metadata": {
"styling": styling
}
}
column_widths = [70,150,150,150,150]
# Create the Gradio application using Blocks
with gr.Blocks(title="@Andrej Karpathy's Sleep Data") as demo:
gr.Markdown("# @karpathy's Sleep Data")
gr.Markdown("This app displays Andrej Karpathy's sleep tracking data from multiple devices. See his [blog post](https://karpathy.bearblog.dev/finding-the-best-sleep-tracker/) to learn more about the data and the process of finding the best sleep tracker.")
with gr.Tabs():
with gr.TabItem("AppleWatch + AutoSleep"):
df = get_device_data("AppleWatch + AutoSleep")
gr.Dataframe(prepare_data_with_styling(df), show_search="search", column_widths=column_widths, show_copy_button=True, pinned_columns=1)
with gr.TabItem("8sleep Pod 4 Ultra"):
df = get_device_data("8sleep Pod 4 Ultra")
gr.Dataframe(prepare_data_with_styling(df), show_search="search", column_widths=column_widths, show_copy_button=True, pinned_columns=1)
with gr.TabItem("Oura"):
df = get_device_data("Oura")
gr.Dataframe(prepare_data_with_styling(df), show_search="search", column_widths=column_widths, show_copy_button=True, pinned_columns=1)
with gr.TabItem("Whoop"):
df = get_device_data("Whoop")
gr.Dataframe(prepare_data_with_styling(df), show_search="search", column_widths=column_widths, show_copy_button=True, pinned_columns=1)
with gr.TabItem("All Data"):
df = load_health_data()
gr.Dataframe(prepare_data_with_styling(df), show_search="search", column_widths=column_widths, show_copy_button=True, pinned_columns=1)
if __name__ == "__main__":
demo.launch()