feat(reports): Statistics Summary (AGP) + modern report charts - #8542
Draft
tim2000s wants to merge 20 commits into
Draft
feat(reports): Statistics Summary (AGP) + modern report charts#8542tim2000s wants to merge 20 commits into
tim2000s wants to merge 20 commits into
Conversation
Master update
Update master
Update of NS
Update to 13.0.0
LAtest PR
UPdate to latest
Update local copy
Update to NS15
Bumps d3 from ^5.16.0 to ^7.9.0 and migrates all client D3 usage to the v7 API: the d3.event global was removed in v6, so every selection/brush/drag event handler now takes (event, datum); d3.mouse(node) -> d3.pointer(event, node) with touch-event unwrapping in the focus/context brush. Affects chart.js, renderer.js and the day-to-day report. No behavioural change to the charts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- New 'Statistics Summary' report plugin (ambulatory glucose profile): glucose stats (avg, GMI %/mmol-mol, CV, SD, % CGM active), vertical consensus TIR bar, 24h percentile chart (5/25/50/75/95, 15-min bins, target shading) and a daily glucose-profile grid. Registered as the first report tab. - Retire the abandoned Flot library from reports: percentile -> D3 v7 percentile chart; hourly stats candlestick -> D3 box-and-whisker; daily pie -> stacked TIR bar. Style refresh of the existing D3 charts (day-to-day, week-to-week, calibrations) and loopalyzer to a consistent modern palette. - Distribution report: selectable range metrics (TIR / Tight 70-140 / Normal 63-140 / Custom), TIR/TITR/TINR + GMI/CV summary, vertical band bar. - Reports UX: auto-render the default 7-day report on open; render each tab lazily from the loaded data on first view. - Modernize the reports page chrome (report.css): system fonts, pill tab nav, card-framed reports, cleaner tables. Kept light + print-friendly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds a Copy summary + Download control to the AGP report header that produces a clinician-friendly plain-text summary (date range, % CGM active, readings, average glucose, GMI %/mmol-mol, CV, SD, and the full Time-in-Range breakdown with %/time-per-day). Copy uses the async clipboard API with an execCommand fallback; Download writes a .txt via a Blob. Hidden when printing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t mean±SD) The hourly-stats chart drew the box from Q1-Q3 but kept the legacy Flot candlestick's mean±SD as 'whiskers', which for glucose data frequently fall inside the interquartile box -> whisker caps rendered inside the box. Use the 10th/90th percentile for the whiskers instead; these are always at or beyond the box edges (p10<=Q1, p90>=Q3), making it a correct box-and-whisker. Tooltip now shows 90%/10% alongside Q3/median/Q1 and min/max. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
d3 v7's package entry is ESM-only, so the test fixture's require('d3') threw
"Unexpected token 'export'" under Node's CommonJS require on Node 20/22/24
(it only worked locally on Node 25, which supports require(esm)). The webpack
bundle the harness already loads exposes a working window.d3, so reuse that
instead of requiring d3 from node_modules. Fixes CI for the D3 v7 upgrade.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
admintools.test.js has its own benv setup (separate from the headless fixture)
with its own require('d3'), which hits d3 v7's ESM-only entry and fails under
Node < 25. Reuse the window.d3 the bundle (loaded just above) already exposes,
matching the headless fixture fix.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat(reports): Statistics Summary (AGP) + modern report charts
What this adds
These change displayed numbers/visuals on purpose, to fix pre-existing anomalies. Flagged explicitly for review:
Hourly stats — box-and-whisker whiskers. Upstream draws the box from Q1–Q3 but the candlestick "wicks" from mean ± standard deviation — two incommensurable statistics.
flotcandle.jsonly drew a wick when it extended beyond the body (if (highY < y + height)/if (lowY > y)), so for glucose data, where mean±SD usually sits inside the interquartile range, most hours rendered as a box with no whiskers at all and the anomaly stayed hidden. This PR makes it a correct box-and-whisker with whiskers at the 10th/90th percentile (by definition p10 ≤ Q1 and p90 ≥ Q3, so whiskers are always at or beyond the box edges). This is a deliberate correction, not a faithful port.Distribution — duplicate readings were double-counted. Upstream's dedup guard (
seen.includes(item.displayTime)against an array that only ever receives string-keyed properties) never actually removes anything, so readings sharing a timestamp were counted multiple times in the band percentages and per-band statistics. This PR dedupes bydisplayTimein O(n) (matching the new AGP report and the main-view widget). For data containing duplicate-timestamp uploads, the reported percentages will shift slightly toward the correct values.Distribution — PGS in-range fraction (minor). In the consensus modes, PGS now uses the 70–180 in-range fraction rather than the report-target band;
Custommode is unchanged.The auto-render-on-open issues a default 7-day query whenever the reports page is opened (previously a manual "Show" click). It's a nice glanceable default but adds DB load on large/shared instances. Happy to gate it behind a setting if you'd prefer it opt-in.
Clinical correctness (verified)
GMI =
3.31 + 0.02392 × mean(mg/dL); CV =SD/mean × 100; SD viasimple-statisticsstandard_deviation. TIR/TITR/TINR band boundaries follow the consensus definitions and are non-overlapping. AGP percentile binning is O(n). No$.plot(Flot) call remains in any report plugin.Testing
reportsintegration suite passes.🤖 Generated with Claude Code
Screenshots
Statistics Summary (AGP) — glucose stats, vertical Time-in-Range bar, 24h percentile profile, daily grid, and the Copy/Download export:
Distribution — summary metrics on top, TIR/TITR/TINR/Custom mode selector, vertical band bar beside the per-band statistics, variability metrics below: