Redesign PDF report: landscape pages, headers/footers, icon, daily stats #31

Merged
willemjan merged 1 commits from feature/pdf-report-redesign into feature/treatment-overlays 2026-09-05 20:45:16 +00:00
Owner

Summary

Stacked on #30 (base branch is feature/treatment-overlays) — merge after #30 (and #29), or retarget to main once those land.

  • pdf_export.py: new GlucoseReportPDF(FPDF) subclass — every section is its own landscape A4 page (Dagoverzicht: one page per day), with a real header (icon, section title, report version, insulin/pump/sensor type) and footer (page number, generation timestamp, Nightscout link) via fpdf2's header()/footer() hooks and alias_nb_pages().
  • New Insulineprofiel PDF section (mirrors the dashboard page from #29): basal bar chart, ISF/carb-ratio segments, DIA.
  • Each Dagoverzicht day now draws the same basal/bolus/carb/target overlays as the interactive charts from #30 (matplotlib port: twinx() secondary axis for basal area + carb bars, scatter for sized/labeled bolus dots, step line for the profile target), plus a new stats block per day.
  • reporting.py: new daily_stats() — average/min/max glucose, total/basal/bolus/SMB insulin, hypo/hyper counts and total durations for one calendar day.
  • New original SVG icon (assets/icon.svg — droplet + glucose-trend line) embedded in the PDF header via fpdf2's native SVG support.
  • New optional env vars REPORT_INSULIN_TYPE/REPORT_PUMP_TYPE/REPORT_SENSOR_TYPE (documented in .env.example/README) for the header's device line; all default to "Onbekend ..." if unset.
  • pages/8_Export.py now threads treatments/profile through to build_report_pdf (previously fetched but discarded).

Test plan

  • ruff check . passes
  • pytest tests/ -v passes (139 tests, +17 new: daily_stats in test_reporting.py, page-count/section/config tests in test_pdf_export.py using a black-box /Type /Page counting technique — no pixel comparisons, consistent with this project's existing PDF-testing philosophy)
  • Generated a real report against the configured Nightscout instance (all 5 sections, 90-day period → 12 pages) and visually inspected every page: cover page, Insulineprofiel, Samenvatting, AGP profiel, 7× Dagoverzicht (glucose+basal+bolus+carbs+target overlay rendering correctly with full legend and daily stats), Hypo-/hyperevents — header/footer/icon/pagination correct on every page
  • Manually exercised the real Export page in the browser (90-day period, all sections) end-to-end through Streamlit with no errors

🤖 Generated with Claude Code

## Summary Stacked on #30 (base branch is `feature/treatment-overlays`) — merge after #30 (and #29), or retarget to `main` once those land. - `pdf_export.py`: new `GlucoseReportPDF(FPDF)` subclass — every section is its own **landscape A4 page** (Dagoverzicht: one page per day), with a real **header** (icon, section title, report version, insulin/pump/sensor type) and **footer** (page number, generation timestamp, Nightscout link) via fpdf2's `header()`/`footer()` hooks and `alias_nb_pages()`. - New **Insulineprofiel** PDF section (mirrors the dashboard page from #29): basal bar chart, ISF/carb-ratio segments, DIA. - Each **Dagoverzicht** day now draws the same basal/bolus/carb/target overlays as the interactive charts from #30 (matplotlib port: `twinx()` secondary axis for basal area + carb bars, scatter for sized/labeled bolus dots, step line for the profile target), plus a new stats block per day. - `reporting.py`: new `daily_stats()` — average/min/max glucose, total/basal/bolus/SMB insulin, hypo/hyper counts and total durations for one calendar day. - New original SVG icon (`assets/icon.svg` — droplet + glucose-trend line) embedded in the PDF header via fpdf2's native SVG support. - New optional env vars `REPORT_INSULIN_TYPE`/`REPORT_PUMP_TYPE`/`REPORT_SENSOR_TYPE` (documented in `.env.example`/README) for the header's device line; all default to "Onbekend ..." if unset. - `pages/8_Export.py` now threads `treatments`/`profile` through to `build_report_pdf` (previously fetched but discarded). ## Test plan - [x] `ruff check .` passes - [x] `pytest tests/ -v` passes (139 tests, +17 new: `daily_stats` in `test_reporting.py`, page-count/section/config tests in `test_pdf_export.py` using a black-box `/Type /Page` counting technique — no pixel comparisons, consistent with this project's existing PDF-testing philosophy) - [x] Generated a real report against the configured Nightscout instance (all 5 sections, 90-day period → 12 pages) and visually inspected every page: cover page, Insulineprofiel, Samenvatting, AGP profiel, 7× Dagoverzicht (glucose+basal+bolus+carbs+target overlay rendering correctly with full legend and daily stats), Hypo-/hyperevents — header/footer/icon/pagination correct on every page - [x] Manually exercised the real Export page in the browser (90-day period, all sections) end-to-end through Streamlit with no errors 🤖 Generated with [Claude Code](https://claude.com/claude-code)
willemjan added 1 commit 2026-09-05 20:44:31 +00:00
Every report section now gets its own landscape A4 page (or, for
Dagoverzicht, one page per day) via a GlucoseReportPDF(FPDF) subclass
with a real header (section title, report version, insulin/pump/sensor
type from new REPORT_* env vars) and footer (page number, generation
timestamp, Nightscout link) on every page, plus an original SVG icon
in the header — inspired by the LibreView AGP report.

New "Insulineprofiel" PDF section mirrors the dashboard page (basal
bar chart, ISF/carb-ratio segments, DIA). Each Dagoverzicht day now
draws the same basal/bolus/carb/target overlays as the interactive
charts (matplotlib port of the Plotly helpers from #30) plus a new
per-day stats block (reporting.daily_stats: avg/min/max glucose,
total/basal/bolus/SMB insulin, hypo/hyper counts and durations).

Builds on #29 (profile data) and #30 (overlay logic/colors).
willemjan merged commit a3d89c4d21 into feature/treatment-overlays 2026-09-05 20:45:16 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: willemjan/glucose-dashboard#31