Write an application that allows me to track my baby sleep
Drop files here
or click to upload
import streamlit as st
import pandas as pd
import numpy as np
import datetime
import matplotlib.pyplot as plt
import plotly.express as px
from datetime import timedelta
import os
# Set page config
st.set_page_config(
page_title="Baby Sleep Tracker",
page_icon="👶",
layout="wide"
)
# Initialize database and tables
from database import init_db, add_sleep_session, get_all_sleep_sessions, delete_sleep_session
# Initialize the database
init_db()
def format_duration(minutes):
"""Format duration in minutes to hours and minutes"""
hours = minutes // 60
mins = minutes % 60
return f"{hours}h {mins}m"
def calculate_sleep_duration(start_time, end_time):
"""Calculate sleep duration in minutes"""
duration = end_time - start_time
return int(duration.total_seconds() / 60)
# App title
st.title("👶 Baby Sleep Tracker")
# Sidebar
st.sidebar.header("Navigation")
page = st.sidebar.radio("Go to", ["Log Sleep", "Sleep History", "Analytics"])
if page == "Log Sleep":
st.header("Log Baby's Sleep")
col1, col2 = st.columns(2)
with col1:
baby_name = st.text_input("Baby's Name", value="Baby")
sleep_date = st.date_input("Date", value=datetime.date.today())
with col2:
sleep_type = st.selectbox("Sleep Type", ["Nap", "Night Sleep"])
sleep_quality = st.select_slider("Sleep Quality", options=["Poor", "Fair", "Good", "Excellent"], value="Good")
col3, col4 = st.columns(2)
with col3:
sleep_start_time = st.time_input("Sleep Start Time", value=datetime.time(20, 0))
start_datetime = datetime.datetime.combine(sleep_date, sleep_start_time)
with col4:
sleep_end_time = st.time_input("Sleep End Time", value=datetime.time(6, 0))
end_datetime = datetime.datetime.combine(sleep_date, sleep_end_time)
# Handle overnight sleep
if end_datetime <= start_datetime:
end_datetime = end_datetime + datetime.timedelta(days=1)
sleep_duration = calculate_sleep_duration(start_datetime, end_datetime)
st.write(f"Sleep Duration: **{format_duration(sleep_duration)}**")
notes = st.text_area("Notes", placeholder="Any observations during sleep...")
if st.button("Save Sleep Session", type="primary"):
sleep_data = {
"baby_name": baby_name,
"date": sleep_date.isoformat(),
"start_time": start_datetime.isoformat(),
"end_time": end_datetime.isoformat(),
"duration_minutes": sleep_duration,
"sleep_type": sleep_type,
"sleep_quality": sleep_quality,
"notes": notes
}
add_sleep_session(sleep_data)
st.success("Sleep session saved successfully!")
st.balloons()
elif page == "Sleep History":
st.header("Sleep History")
sleep_data = get_all_sleep_sessions()
if not sleep_data:
st.info("No sleep sessions recorded yet. Go to 'Log Sleep' to add your first entry.")
else:
# Convert data to DataFrame
df = pd.DataFrame(sleep_data)
# Convert string dates to datetime
df['date'] = pd.to_datetime(df['date']).dt.date
df['start_time'] = pd.to_datetime(df['start_time'])
df['end_time'] = pd.to_datetime(df['end_time'])
# Format the display of times
df['start_time_display'] = df['start_time'].dt.strftime('%I:%M %p')
df['end_time_display'] = df['end_time'].dt.strftime('%I:%M %p')
# Add duration as formatted string
df['duration_display'] = df['duration_minutes'].apply(format_duration)
# Filter options
col1, col2 = st.columns(2)
with col1:
date_filter = st.date_input("Filter by date", value=None)
with col2:
sleep_type_filter = st.multiselect("Filter by sleep type", options=["Nap", "Night Sleep"], default=["Nap", "Night Sleep"])
# Apply filters
filtered_df = df.copy()
if date_filter:
filtered_df = filtered_df[filtered_df['date'] == date_filter]
if sleep_type_filter:
filtered_df = filtered_df[filtered_df['sleep_type'].isin(sleep_type_filter)]
# Display data
if filtered_df.empty:
st.info("No sleep sessions match the selected filters.")
else:
# Display summary
total_sleep = filtered_df['duration_minutes'].sum()
st.subheader(f"Total Sleep: {format_duration(total_sleep)}")
# Prepare display dataframe
display_df = filtered_df[['id', 'baby_name', 'date', 'start_time_display', 'end_time_display', 'duration_display', 'sleep_type', 'sleep_quality', 'notes']]
display_df.columns = ['ID', 'Baby Name', 'Date', 'Start Time', 'End Time', 'Duration', 'Sleep Type', 'Quality', 'Notes']
st.dataframe(display_df, use_container_width=True)
# Delete functionality
with st.expander("Delete Sleep Session"):
session_to_delete = st.selectbox(
"Select session to delete",
options=filtered_df['id'].tolist(),
format_func=lambda x: f"ID: {x} - {filtered_df[filtered_df['id']==x]['date'].values[0]} - {filtered_df[filtered_df['id']==x]['start_time_display'].values[0]}"
)
if st.button("Delete Selected Session", key="delete_btn"):
delete_sleep_session(session_to_delete)
st.success(f"Session ID: {session_to_delete} deleted successfully!")
st.rerun()
elif page == "Analytics":
st.header("Sleep Analytics")
sleep_data = get_all_sleep_sessions()
if not sleep_data:
st.info("No sleep sessions recorded yet. Go to 'Log Sleep' to add your first entry.")
else:
# Convert data to DataFrame
df = pd.DataFrame(sleep_data)
# Convert string dates to datetime
df['date'] = pd.to_datetime(df['date'])
df['start_time'] = pd.to_datetime(df['start_time'])
df['end_time'] = pd.to_datetime(df['end_time'])
# Date range filter
col1, col2 = st.columns(2)
with col1:
start_date = st.date_input("Start Date", value=df['date'].min().date())
with col2:
end_date = st.date_input("End Date", value=df['date'].max().date())
# Filter data by date range
mask = (df['date'].dt.date >= start_date) & (df['date'].dt.date <= end_date)
filtered_df = df[mask]
if filtered_df.empty:
st.info("No sleep sessions in the selected date range.")
else:
# Calculate daily sleep totals
daily_sleep = filtered_df.groupby([filtered_df['date'].dt.date, 'sleep_type'])['duration_minutes'].sum().unstack().fillna(0)
if 'Nap' not in daily_sleep.columns:
daily_sleep['Nap'] = 0
if 'Night Sleep' not in daily_sleep.columns:
daily_sleep['Night Sleep'] = 0
daily_sleep['Total'] = daily_sleep.sum(axis=1)
# Plot daily sleep
st.subheader("Daily Sleep Duration")
fig = px.bar(
daily_sleep,
y=['Nap', 'Night Sleep'],
labels={'value': 'Sleep Duration (minutes)', 'date': 'Date', 'variable': 'Sleep Type'},
title="Daily Sleep Breakdown",
barmode='stack'
)
# Add a line for total sleep
fig.add_scatter(
x=daily_sleep.index,
y=daily_sleep['Total'],
mode='lines+markers',
name='Total Sleep',
line=dict(color='black')
)
# Customize layout
fig.update_layout(
xaxis_title="Date",
yaxis_title="Duration (minutes)",
legend_title="Sleep Type",
height=500
)
st.plotly_chart(fig, use_container_width=True)
# Sleep quality distribution
st.subheader("Sleep Quality Distribution")
quality_counts = filtered_df['sleep_quality'].value_counts().reset_index()
quality_counts.columns = ['Quality', 'Count']
fig_quality = px.pie(
quality_counts,
values='Count',
names='Quality',
title="Sleep Quality Distribution",
color='Quality',
color_discrete_map={
'Poor': 'red',
'Fair': 'orange',
'Good': 'lightgreen',
'Excellent': 'darkgreen'
}
)
st.plotly_chart(fig_quality, use_container_width=True)
# Sleep patterns by hour of day
st.subheader("Sleep Patterns by Hour")
# Create a list to track when baby is asleep for each hour
sleep_hours = []
for _, row in filtered_df.iterrows():
start = row['start_time']
end = row['end_time']
current = start
while current < end:
sleep_hours.append({
'hour': current.hour,
'date': current.date(),
'sleep_type': row['sleep_type']
})
current += timedelta(hours=1)
# Convert to DataFrame
if sleep_hours:
sleep_hours_df = pd.DataFrame(sleep_hours)
hour_counts = sleep_hours_df.groupby(['hour', 'sleep_type']).size().unstack(fill_value=0)
# Plot
fig_hours = px.imshow(
hour_counts.T,
labels=dict(x="Hour of Day", y="Sleep Type", color="Frequency"),
x=hour_counts.index,
y=hour_counts.columns,
color_continuous_scale="Viridis",
aspect="auto"
)
fig_hours.update_layout(
xaxis=dict(
tickmode='array',
tickvals=list(range(24)),
ticktext=[f"{h}:00" for h in range(24)]
),
height=300
)
st.plotly_chart(fig_hours, use_container_width=True)
# Show average sleep stats
st.subheader("Sleep Statistics")
avg_duration = filtered_df['duration_minutes'].mean()
avg_nap_duration = filtered_df[filtered_df['sleep_type'] == 'Nap']['duration_minutes'].mean() if 'Nap' in filtered_df['sleep_type'].values else 0
avg_night_duration = filtered_df[filtered_df['sleep_type'] == 'Night Sleep']['duration_minutes'].mean() if 'Night Sleep' in filtered_df['sleep_type'].values else 0
col1, col2, col3 = st.columns(3)
col1.metric("Average Total Sleep", format_duration(int(daily_sleep['Total'].mean())))
col2.metric("Average Nap Duration", format_duration(int(avg_nap_duration)) if not np.isnan(avg_nap_duration) else "N/A")
col3.metric("Average Night Sleep", format_duration(int(avg_night_duration)) if not np.isnan(avg_night_duration) else "N/A")
Hi! I can help you with any questions about Streamlit and Python. What would you like to know?