longitudinal
Longitudinal report models.
A longitudinal section is the flat report's boxplot with time bins in the row slot: one chart per metric and analysis configuration, each row the distribution of the studies that fell in one bin — split by group through the boxplot's series keys. The payload is constant in cohort size; the per-observation series it replaces grew with every night uploaded.
Bins have one of two bases. session-index bins a study by its position
in its subject's series (night 1, night 2 …): derived from recording
order when no subject in scope declares a position, declared when any
does — and then only subjects whose every study declares one are drawn.
calendar bins by recording start at a day, week or month granularity.
Whatever cannot be placed is excluded by name, never pooled silently.
A subject view draws the same metrics as lines, one per explicitly selected subject, over the same bins: boxes answer what a cohort did, a line answers what one person did.
Server-defined presentation: bin labels, series legends, box and line geometry and the SVG are decided by the API; clients render.
CalendarGranularity = Literal['day', 'week', 'month']
module-attribute
¶
The span of one calendar bin.
LongitudinalBasis = Literal['session-index', 'calendar']
module-attribute
¶
What a bin is: a position within the subject's series, or a calendar span.
LongitudinalRegime = Literal['derived', 'declared']
module-attribute
¶
Where session positions came from; set on session-index sections only.
LongitudinalBin
pydantic-model
¶
Bases: BaseModel
One time bin: a row slot every chart in the section shares.
Fields:
-
key(str) -
label(str) -
n(int) -
subject_count(int | None)
key
pydantic-field
¶
Stable bin identity within the section, e.g. '3' for night 3 or '2026-W12' for a calendar week.
label
pydantic-field
¶
Row label as drawn, e.g. 'Night 3' or 'Mar 2026'.
n
pydantic-field
¶
Studies observed in this bin, across every group.
subject_count = None
pydantic-field
¶
Distinct subjects behind n when any study in scope carries a subject key; None otherwise. Drawn beside n so attrition is readable in the figure.
LongitudinalChart
pydantic-model
¶
Bases: BaseModel
One metric from one analysis configuration, across the bins.
A metric several configurations produced yields one chart per configuration — the same shape the flat report gives a metric several configurations produced. A picker still lists the metric once; the charts under it are that metric from each source, each headed by the configuration that produced it, so no reader has to tell four pipelines apart inside one crowded figure.
Fields:
-
key(str) -
metric(str) -
label(str) -
unit_label(str | None) -
analysis_config_id(str) -
analysis_parameters(list[tuple[str, str | int | float | bool]]) -
config_label(str) -
research_parameters(list[str] | None) -
series(list[LongitudinalSeriesInfo]) -
chart(BoxplotModel) -
comparisons(list[LongitudinalComparison])
analysis_config_id
pydantic-field
¶
The analysis configuration whose output this chart draws.
analysis_parameters
pydantic-field
¶
The analysis parameters used in computation.
chart
pydantic-field
¶
The geometry: rows are bins in time order, one row per (bin, series), labelled with the bin and keyed with the series. A row below the section's min_box_n carries points instead of a box, and each row carries the studies and subjects behind it.
comparisons
pydantic-field
¶
Descriptive comparisons between the chart's groups, per bin: each group against the first in legend order. Empty when the chart is not split, or where a bin holds too few observations on either side for a comparison to describe anything.
config_label
pydantic-field
¶
Display name of the configuration, as the chart's heading — the parameters ride it when one configuration ran with more than one parameterisation.
key
pydantic-field
¶
Stable chart identity within the section (safe as a render/caching key), one per metric and configuration.
label
pydantic-field
¶
Display name of the metric, e.g. 'N1 (%)'.
metric
pydantic-field
¶
The metric drawn: a biomarker key or a stats dict key such as 'total-duration-ms'. Charts sharing a metric are the same quantity from different configurations.
research_parameters = None
pydantic-field
¶
Parameters outside the validated regime (exploratory output), same semantics as StatsOrigin.research_parameters.
series
pydantic-field
¶
The groups the chart's rows are split into, in legend order. Empty when the chart is not split — its rows then carry no series key, exactly as an ungrouped flat chart's rows do.
unit_label = None
pydantic-field
¶
Display unit, e.g. 'min' or '%'.
LongitudinalComparison
pydantic-model
¶
Bases: BaseModel
How one group's values in one bin sit against the reference group's.
Descriptive only: a difference and an effect size, never a test, a p-value, or a verdict. Two groups measured in the same bin differ by some amount and overlap to some degree; what that means for a decision is the reader's to judge, with the study design in front of them.
Fields:
-
bin_key(str) -
bin_label(str) -
reference(str) -
group(str) -
reference_n(int) -
group_n(int) -
median_difference(float) -
cliffs_delta(float)
bin_key
pydantic-field
¶
The bin compared, keyed as the section's bins are.
bin_label
pydantic-field
¶
Display label of that bin.
cliffs_delta
pydantic-field
¶
Cliff's delta over all pairs: how often a value from the group exceeds one from the reference, minus how often it falls below. 0 when the groups overlap evenly, 1 when every value is higher, -1 when every value is lower. Distribution-free, and no more than a description of the overlap.
group
pydantic-field
¶
The group being compared.
group_n
pydantic-field
¶
Observations behind the compared group in this bin.
median_difference
pydantic-field
¶
Group median minus reference median, in the chart's drawn unit — the axis unit, so it reads directly off the figure.
reference
pydantic-field
¶
The group compared AGAINST — the first in legend order, the same one for every bin of the chart.
reference_n
pydantic-field
¶
Observations behind the reference group in this bin.
LongitudinalExclusion
pydantic-model
¶
Bases: BaseModel
A subject or study the requested bins could not place, and why.
Fields:
-
subject_key(str | None) -
study_name(str | None) -
reason(str)
Validators:
-
_names_something
reason
pydantic-field
¶
Human-readable reason, ready to print.
study_name = None
pydantic-field
¶
The excluded study, when a single study is left out: a keyless study under declared positions, or a study whose recording carries no known start date under calendar bins.
subject_key = None
pydantic-field
¶
The excluded subject, when a whole subject is left out: one that declares no session index while others do, one that declares it on only some of its studies, or one whose recording order cannot be derived.
LongitudinalSection
pydantic-model
¶
Bases: BaseModel
The longitudinal half of a project report.
Fields:
-
basis(LongitudinalBasis) -
regime(LongitudinalRegime | None) -
granularity(CalendarGranularity | None) -
min_box_n(int) -
bins(list[LongitudinalBin]) -
charts(list[LongitudinalChart]) -
excluded(list[LongitudinalExclusion]) -
subject_view(LongitudinalSubjectView | None)
basis
pydantic-field
¶
What the bins are.
bins
pydantic-field
¶
The bins in time order; every chart's rows follow them.
charts
pydantic-field
¶
One chart per rendered metric and analysis configuration, in display order: metrics in their display order, and within a metric the configurations in the order the report lists them.
excluded
pydantic-field
¶
Subjects and studies the bins could not place — named explicitly, mirrored in the report's warnings.
granularity = None
pydantic-field
¶
On a calendar section: the span of one bin. None on a session-index section.
min_box_n
pydantic-field
¶
A row with fewer observations than this is drawn as points, not a box — configured on the server.
regime = None
pydantic-field
¶
On a session-index section: 'declared' when any subject in scope declares a session index (only fully declared subjects are drawn), 'derived' otherwise (positions follow recording order; a keyless study is its own single-session subject in bin 1). None on a calendar section.
subject_view = None
pydantic-field
¶
Set when the request selected subjects: the same metrics and configurations drawn as one line per person, over the same bins. None when none were selected.
LongitudinalSeriesInfo
pydantic-model
¶
Bases: BaseModel
One legended series in a longitudinal chart: a group, or the whole cohort.
Fields:
-
key(str) -
label(str) -
group(str | None) -
color_token(str | None)
color_token = None
pydantic-field
¶
Brand color token NAME the series' boxes use, matching the rows' color_token.
group = None
pydantic-field
¶
The tag group or stratum this series draws; None on an unsplit chart, whose single series is the whole cohort.
key
pydantic-field
¶
The value stamped on the chart's rows as series_key; a client selection key, not display text.
label
pydantic-field
¶
Legend text: the group's name, or the cohort's when the chart is not split.
LongitudinalSubjectChart
pydantic-model
¶
Bases: BaseModel
One metric from one analysis configuration, per subject over time.
Fields:
-
key(str) -
metric(str) -
label(str) -
unit_label(str | None) -
analysis_config_id(str) -
config_label(str) -
research_parameters(list[str] | None) -
chart(LineChartModel)
analysis_config_id
pydantic-field
¶
The analysis configuration whose output this chart draws.
chart
pydantic-field
¶
The geometry: one line per selected subject over the section's bins.
config_label
pydantic-field
¶
Display name of the configuration, as the chart's heading.
key
pydantic-field
¶
Stable chart identity within the view, one per metric and configuration.
label
pydantic-field
¶
Display name of the metric, e.g. 'TST'.
metric
pydantic-field
¶
The metric drawn.
research_parameters = None
pydantic-field
¶
Parameters outside the validated regime (exploratory output), same semantics as StatsOrigin.research_parameters.
unit_label = None
pydantic-field
¶
Display unit, e.g. 'min' or '%'.
LongitudinalSubjectView
pydantic-model
¶
Bases: BaseModel
The selected subjects, drawn one line each.
Boxes answer what a cohort did; a line answers what one person did. Selection is explicit and capped, because a figure with more lines than distinguishable colours shows nothing: past the cap the view comes back empty and the report says how many were asked for.
Fields:
-
subjects(list[str]) -
max_subjects(int) -
charts(list[LongitudinalSubjectChart]) -
excluded(list[LongitudinalExclusion])
charts
pydantic-field
¶
One chart per metric and analysis configuration, in the same order as the section's boxplots.
excluded
pydantic-field
¶
Selected subjects the view could not draw — a key that matches no study in scope, or one whose studies the bins exclude.
max_subjects
pydantic-field
¶
The most lines one figure draws — the number of distinguishable series colours the design system has.
subjects
pydantic-field
¶
The subject keys drawn, in legend order, as entered.