added getting data from nightscout
This commit is contained in:
+42
-32
@@ -3,50 +3,60 @@ Data processing logic voor het glucose-dashboard.
|
||||
|
||||
Bewust gescheiden van app.py: Streamlit-UI-code kun je niet zomaar los
|
||||
unit-testen (die heeft een draaiende Streamlit-context nodig). Door de
|
||||
logica (inladen, aggregeren) in een los module te zetten, kun je die
|
||||
logica (classificeren, samenvatten) in een los module te zetten, kun je die
|
||||
logica wel gewoon met pytest testen, en blijft app.py alleen de UI-laag.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from __future__ import annotations
|
||||
|
||||
import pandas as pd
|
||||
|
||||
DATA_PATH = Path(__file__).parent / "data" / "glucose_readings.csv"
|
||||
from nightscout_client import SENSOR_CHANGE_EVENT_TYPES, SITE_CHANGE_EVENT_TYPES
|
||||
|
||||
# Streefbereik in mmol/L — pas aan naar je eigen behandeldoelen.
|
||||
TARGET_LOW = 3.9
|
||||
TARGET_HIGH = 10.0
|
||||
|
||||
|
||||
def load_data(path: Path = DATA_PATH) -> pd.DataFrame:
|
||||
"""Laad de ruwe metingen in.
|
||||
def classify_treatments(treatments: pd.DataFrame) -> dict[str, pd.DataFrame]:
|
||||
"""Splits ruwe Nightscout-treatments op in aparte, tijd-gesorteerde subsets.
|
||||
|
||||
Verwacht kolommen: 'timestamp' (parsebaar als datetime) en
|
||||
'glucose_value' (numeriek). Vervang deze functie later door je
|
||||
eigen databron (database, CGM-export, API-call, etc.) — de rest
|
||||
van de app blijft dan ongewijzigd werken.
|
||||
Een insuline- en koolhydraat-registratie kunnen dezelfde treatment zijn
|
||||
(bijv. een "Meal Bolus" met zowel insuline als carbs) en verschijnen dan
|
||||
in beide subsets.
|
||||
"""
|
||||
df = pd.read_csv(path, parse_dates=["timestamp"])
|
||||
return df
|
||||
insulin = treatments[treatments["insulin"].fillna(0) > 0]
|
||||
carbs = treatments[treatments["carbs"].fillna(0) > 0]
|
||||
site_changes = treatments[treatments["eventType"].isin(SITE_CHANGE_EVENT_TYPES)]
|
||||
sensor_changes = treatments[treatments["eventType"].isin(SENSOR_CHANGE_EVENT_TYPES)]
|
||||
return {
|
||||
"insulin": insulin.reset_index(drop=True),
|
||||
"carbs": carbs.reset_index(drop=True),
|
||||
"site_changes": site_changes.reset_index(drop=True),
|
||||
"sensor_changes": sensor_changes.reset_index(drop=True),
|
||||
}
|
||||
|
||||
|
||||
def filter_by_date(df: pd.DataFrame, selected_date) -> pd.DataFrame:
|
||||
"""Filter de dataset op een enkele kalenderdag."""
|
||||
return df[df["timestamp"].dt.date == selected_date]
|
||||
def glucose_status(mmol: float, low: float = TARGET_LOW, high: float = TARGET_HIGH) -> str:
|
||||
"""Classificeer een glucosewaarde t.o.v. het streefbereik."""
|
||||
if mmol < low:
|
||||
return "low"
|
||||
if mmol > high:
|
||||
return "high"
|
||||
return "in_range"
|
||||
|
||||
|
||||
def hourly_average(df: pd.DataFrame) -> pd.DataFrame:
|
||||
"""Groepeer per uur (0-23) en bereken de gemiddelde waarde.
|
||||
def summarize_time_in_range(
|
||||
glucose: pd.DataFrame, low: float = TARGET_LOW, high: float = TARGET_HIGH
|
||||
) -> dict[str, float]:
|
||||
"""Bereken het percentage metingen onder/in/boven het streefbereik."""
|
||||
if glucose.empty:
|
||||
return {"low": 0.0, "in_range": 0.0, "high": 0.0}
|
||||
|
||||
Geeft een DataFrame terug met kolommen 'hour' en 'glucose_value',
|
||||
één rij per uur waarin daadwerkelijk data zit.
|
||||
"""
|
||||
if df.empty:
|
||||
return pd.DataFrame(columns=["hour", "glucose_value"])
|
||||
|
||||
working = df.copy()
|
||||
working["hour"] = working["timestamp"].dt.hour
|
||||
result = (
|
||||
working.groupby("hour")["glucose_value"]
|
||||
.mean()
|
||||
.round(1)
|
||||
.reset_index()
|
||||
.sort_values("hour")
|
||||
)
|
||||
return result
|
||||
statuses = glucose["mmol"].apply(lambda v: glucose_status(v, low, high))
|
||||
counts = statuses.value_counts(normalize=True) * 100
|
||||
return {
|
||||
"low": round(counts.get("low", 0.0), 1),
|
||||
"in_range": round(counts.get("in_range", 0.0), 1),
|
||||
"high": round(counts.get("high", 0.0), 1),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user