add Samenvatting and AGP Profiel pages (FR2, FR3, FR9)

Wires reporting.py's stats into two new pages: a summary panel (data
completeness, GMI, %CV, 5-band time-in-range vs. consensus targets) and
the standard AGP percentile chart (5th-95th and 25th-75th bands plus
median, aggregated by time-of-day across the selected period).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-07-26 20:09:25 +02:00
co-authored by Claude Sonnet 5
parent 3ef9a7666a
commit 1207ff536f
6 changed files with 277 additions and 0 deletions
+30
View File
@@ -2,6 +2,7 @@ import pandas as pd
import pytest
from reporting import (
agp_percentile_bands,
detect_events,
gmi_percent,
minutes_per_day,
@@ -213,6 +214,35 @@ def test_summarize_events_computes_expected_stats():
assert result["events_per_week"] == pytest.approx(2.0)
def test_agp_percentile_bands_groups_by_time_of_day_across_days():
# zelfde tijdstip (08:00) op twee verschillende dagen, met bekende waarden
glucose = _series(
[
("2026-01-01 08:00", 6.0),
("2026-01-02 08:00", 8.0),
("2026-01-01 20:00", 10.0),
("2026-01-02 20:00", 10.0),
]
)
result = agp_percentile_bands(glucose, bin_minutes=30)
assert list(result.columns) == ["minute_of_day", "p5", "p25", "p50", "p75", "p95"]
morning_bin = 8 * 60
row = result[result["minute_of_day"] == morning_bin].iloc[0]
assert row["p50"] == pytest.approx(7.0) # mediaan van 6.0 en 8.0
evening_bin = 20 * 60
evening_row = result[result["minute_of_day"] == evening_bin].iloc[0]
assert evening_row["p50"] == pytest.approx(10.0)
def test_agp_percentile_bands_handles_empty_input():
empty = pd.DataFrame(columns=["timestamp", "mmol"])
result = agp_percentile_bands(empty)
assert result.empty
assert list(result.columns) == ["minute_of_day", "p5", "p25", "p50", "p75", "p95"]
def test_summarize_events_handles_empty_input():
empty = pd.DataFrame(columns=["start", "end", "duration_minutes"])
result = summarize_events(empty, period_days=14)
+9
View File
@@ -0,0 +1,9 @@
from ui_common import hex_to_rgba
def test_hex_to_rgba_converts_correctly():
assert hex_to_rgba("#2a78d6", 0.3) == "rgba(42,120,214,0.3)"
def test_hex_to_rgba_handles_hash_optional():
assert hex_to_rgba("2a78d6", 0.3) == "rgba(42,120,214,0.3)"