File size: 6,378 Bytes
addc7dc
33ecdbc
 
addc7dc
 
33ecdbc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ff310de
 
 
 
 
 
33ecdbc
ff310de
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33ecdbc
 
 
 
 
 
 
 
 
 
ff310de
33ecdbc
ff310de
 
 
33ecdbc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
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()