Skip to content

Commit

Permalink
feat: dynamic rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
Ashwath Krishnan authored and Ashwath Krishnan committed Feb 6, 2025
1 parent b47ead9 commit e9f1174
Show file tree
Hide file tree
Showing 2 changed files with 328 additions and 51 deletions.
162 changes: 111 additions & 51 deletions Dashboard/app.py
Original file line number Diff line number Diff line change
@@ -1,70 +1,123 @@
import datetime
import pandas as pd
import seaborn as sns
from pathlib import Path
from shiny import App, ui
import matplotlib.pyplot as plt
from pymongo import MongoClient
from shiny import App, ui, reactive, render_ui, render
from maidr.widget.shiny import render_maidr

file_path = Path(__file__).parent / "healthdata.csv"
df = pd.read_csv(file_path)

def parse_date(date_str):
"""Try parsing the date in two possible formats."""
try:
return pd.to_datetime(date_str, format="%b %d, %Y") # Format: "Jun 13, 2024"
return pd.to_datetime(date_str, format="%b %d, %Y") # e.g., "Jun 13, 2024"
except ValueError:
try:
return pd.to_datetime(date_str, format="%d %b %Y", dayfirst=True)
except ValueError:
return pd.NaT # Handle invalid dates
return pd.NaT # Return NaT for invalid dates

df['parsed_date'] = df['date'].apply(parse_date)
df = df.dropna(subset=['parsed_date']) # Remove rows with invalid parsed dates
def fetch_data():
"""Connect to Azure Cosmos DB, flatten the nested documents, and return a DataFrame."""
connection_string = (
"mongodb://pcha:DBQWfFLdaAwofXET3QyLDt1ndCAbJdGwoq8iF4u79P2A0QArmODzkbENAMqtobHZOhDn765q2dlmACDbeuMcHg=="
"@pcha.mongo.cosmos.azure.com:10255/?ssl=true&retrywrites=false&replicaSet=globaldb"
"&maxIdleTimeMS=120000&appName=@pcha@"
)
client = MongoClient(connection_string, tlsAllowInvalidCertificates=True)
db = client['pcha_db']
collection = db['health_data']
cursor = collection.find()

# min_date = df['parsed_date'].min()
# max_date = df['parsed_date'].max()
flattened_data = []
for document in cursor:
_id = document["_id"]
user_id = document["user_id"]
for date_entry in document["dates"]:
flattened_entry = {"_id": _id, "user_id": user_id, "date": date_entry["date"]}
# Unpack nested data values
for key, value in date_entry["data"].items():
flattened_entry[key] = value["value"]
flattened_data.append(flattened_entry)

df = pd.DataFrame(flattened_data)
# Parse dates and drop rows with invalid dates
df['parsed_date'] = df['date'].apply(parse_date)
df = df.dropna(subset=['parsed_date'])
return df

# Fetch the initial data when the app starts.
initial_df = fetch_data()
users = initial_df["user_id"].unique().tolist()

users = df["user_id"].unique().tolist()
# -------------------------------------------------------
# 2. Define the UI
# -------------------------------------------------------

# Define the UI
app_ui = ui.page_fluid(
ui.h2("PCHA Health Dashboard"),
ui.page_sidebar(
ui.sidebar(ui.input_select("user_id", label="Select User", choices=users),
# ui.input_slider("start_date_slider", "Start Date", min_date, max_date, min_date),
# ui.input_slider("end_date_slider", "End Date", min_date, max_date, max_date),
ui.page_sidebar(
ui.sidebar(
# Render the user selection dynamically.
ui.input_select("user_id", label="Select User", choices=users),
# Button to refresh the data.
ui.input_action_button("refresh_data", "Refresh Data"),
# ui.input_action_button("reset_filter", "Reset Filters"),
# Additional inputs (e.g., for date filtering)
ui.input_text("start_day", label="Start Day", placeholder="DD"),
ui.input_text("start_month", label="Start Month", placeholder="MM"),
ui.input_text("start_year", label="Start Year", placeholder="YYYY"),
ui.input_text("end_day", label="End Day", placeholder="DD"),
ui.input_text("end_month", label="End Month", placeholder="MM"),
ui.input_text("end_year", label="End Year", placeholder="YYYY"),
bg="#f8f8f8"
),
ui.navset_card_tab(
ui.nav_panel("Step Count", ui.card(ui.output_ui("plot_stepCount"))),
ui.nav_panel("Distance Walking/Running", ui.card(ui.output_ui("plot_distance"))),
ui.nav_panel("Exercise Time", ui.card(ui.output_ui("plot_exerciseTime"))),
ui.nav_panel("Basal Energy Burned", ui.card(ui.output_ui("plot_basalEnergy")),),
ui.nav_panel("Active Energy Burned", ui.card(ui.output_ui("plot_activeEnergy"))),
),
)
bg="#f8f8f8"
),
ui.navset_card_tab(
ui.nav_panel("Step Count", ui.card(ui.output_ui("plot_stepCount"))),
ui.nav_panel("Distance Walking/Running", ui.card(ui.output_ui("plot_distance"))),
ui.nav_panel("Exercise Time", ui.card(ui.output_ui("plot_exerciseTime"))),
ui.nav_panel("Basal Energy Burned", ui.card(ui.output_ui("plot_basalEnergy")),),
ui.nav_panel("Active Energy Burned", ui.card(ui.output_ui("plot_activeEnergy"))),
),
)
)

def server(inp, _, __):

# -------------------------------------------------------
# 3. Define Server Logic
# -------------------------------------------------------

def server(input, output, session):
data_store = reactive.Value(initial_df)

@reactive.Effect
def refresh_data_effect():
_ = input.refresh_data()
new_df = fetch_data()
data_store.set(new_df)
print("Data refreshed at", datetime.datetime.now())

# @reactive.Effect
# def reset_filter_effect():
# _ = input.reset_filter()
# df = fetch_data()
# start_date = df['parsed_date'].min()
# end_date = df['parsed_date'].max()


@render_maidr
def plot_stepCount():
user_data = df[df["user_id"] == inp.user_id()]
user_id = inp.user_id() # Selected user

# Fetch start and end dates. If null, default to min and max dates
df_latest = data_store.get()
user_id = input.user_id()
df = df_latest[df_latest["user_id"] == user_id]
try:
start_date = pd.to_datetime(f"{inp.start_year()}-{inp.start_month()}-{inp.start_day()}")
start_date = pd.to_datetime(f"{input.start_year()}-{input.start_month()}-{input.start_day()}")
except ValueError:
start_date = df['parsed_date'].min() # Default to earliest date in the dataset

try:
end_date = pd.to_datetime(f"{inp.end_year()}-{inp.end_month()}-{inp.end_day()}")
end_date = pd.to_datetime(f"{input.end_year()}-{input.end_month()}-{input.end_day()}")
except ValueError:
end_date = df['parsed_date'].max()

Expand All @@ -74,6 +127,7 @@ def plot_stepCount():
(df["parsed_date"] >= start_date) &
(df["parsed_date"] <= end_date)
]
user_data = user_data.sort_values(by="parsed_date")

fig, ax = plt.subplots(figsize=(10, 8))
s_plot = sns.lineplot(data=user_data, x="date", y="stepCount", marker="o", ax=ax)
Expand All @@ -85,17 +139,18 @@ def plot_stepCount():

@render_maidr
def plot_distance():
user_data = df[df["user_id"] == inp.user_id()]
user_id = inp.user_id() # Selected user
df_latest = data_store.get()
user_id = input.user_id()
df = df_latest[df_latest["user_id"] == user_id]

# Fetch start and end dates. If null, default to min and max dates
try:
start_date = pd.to_datetime(f"{inp.start_year()}-{inp.start_month()}-{inp.start_day()}")
start_date = pd.to_datetime(f"{input.start_year()}-{input.start_month()}-{input.start_day()}")
except ValueError:
start_date = df['parsed_date'].min() # Default to earliest date in the dataset

try:
end_date = pd.to_datetime(f"{inp.end_year()}-{inp.end_month()}-{inp.end_day()}")
end_date = pd.to_datetime(f"{input.end_year()}-{input.end_month()}-{input.end_day()}")
except ValueError:
end_date = df['parsed_date'].max()

Expand All @@ -117,17 +172,18 @@ def plot_distance():

@render_maidr
def plot_basalEnergy():
user_data = df[df["user_id"] == inp.user_id()]
user_id = inp.user_id() # Selected user
df_latest = data_store.get()
user_id = input.user_id()
df = df_latest[df_latest["user_id"] == user_id]

# Fetch start and end dates. If null, default to min and max dates
try:
start_date = pd.to_datetime(f"{inp.start_year()}-{inp.start_month()}-{inp.start_day()}")
start_date = pd.to_datetime(f"{input.start_year()}-{input.start_month()}-{input.start_day()}")
except ValueError:
start_date = df['parsed_date'].min() # Default to earliest date in the dataset

try:
end_date = pd.to_datetime(f"{inp.end_year()}-{inp.end_month()}-{inp.end_day()}")
end_date = pd.to_datetime(f"{input.end_year()}-{input.end_month()}-{input.end_day()}")
except ValueError:
end_date = df['parsed_date'].max()

Expand All @@ -148,17 +204,18 @@ def plot_basalEnergy():

@render_maidr
def plot_activeEnergy():
user_data = df[df["user_id"] == inp.user_id()]
user_id = inp.user_id() # Selected user
df_latest = data_store.get()
user_id = input.user_id()
df = df_latest[df_latest["user_id"] == user_id]

# Fetch start and end dates. If null, default to min and max dates
try:
start_date = pd.to_datetime(f"{inp.start_year()}-{inp.start_month()}-{inp.start_day()}")
start_date = pd.to_datetime(f"{input.start_year()}-{input.start_month()}-{input.start_day()}")
except ValueError:
start_date = df['parsed_date'].min() # Default to earliest date in the dataset

try:
end_date = pd.to_datetime(f"{inp.end_year()}-{inp.end_month()}-{inp.end_day()}")
end_date = pd.to_datetime(f"{input.end_year()}-{input.end_month()}-{input.end_day()}")
except ValueError:
end_date = df['parsed_date'].max()

Expand All @@ -179,17 +236,18 @@ def plot_activeEnergy():

@render_maidr
def plot_exerciseTime():
user_data = df[df["user_id"] == inp.user_id()]
user_id = inp.user_id() # Selected user
df_latest = data_store.get()
user_id = input.user_id()
df = df_latest[df_latest["user_id"] == user_id]

# Fetch start and end dates. If null, default to min and max dates
try:
start_date = pd.to_datetime(f"{inp.start_year()}-{inp.start_month()}-{inp.start_day()}")
start_date = pd.to_datetime(f"{input.start_year()}-{input.start_month()}-{input.start_day()}")
except ValueError:
start_date = df['parsed_date'].min() # Default to earliest date in the dataset

try:
end_date = pd.to_datetime(f"{inp.end_year()}-{inp.end_month()}-{inp.end_day()}")
end_date = pd.to_datetime(f"{input.end_year()}-{input.end_month()}-{input.end_day()}")
except ValueError:
end_date = df['parsed_date'].max()

Expand All @@ -209,9 +267,11 @@ def plot_exerciseTime():
ax.tick_params(axis="x", rotation=90, labelsize=5)
return s_plot

# Create the app
# -------------------------------------------------------
# 4. Create and Run the App
# -------------------------------------------------------

app = App(app_ui, server)

# Run the app
if __name__ == "__main__":
app.run()
app.run()
Loading

0 comments on commit e9f1174

Please sign in to comment.