Spaces:
Running
Running
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() | |