brood(): Vaccine Coverage Data Structures for All Study Designs

Pre-aggregated and cohort models including time-series for interrupted time series analysis

Overview

library(mudnester)

brood() constructs a brood_df object for vaccine coverage analysis. Unlike roost() which counts events over time, vaccine coverage requires an explicitly documented eligible-population denominator and a declared assessment window. brood() makes both explicit in every object it produces.

The output brood_df is designed for bowerbird::brood_plot().

Why “brood”?

A brood is the full clutch under a parent bird’s care – every egg counted, every hatchling tracked, none overlooked. The gap between the clutch and the hatchlings is not an absence; it is information.

Two population models

Model Use case Input
"pre_aggregated" Already-computed counts per stratum Summary data frame
"cohort" Record-level, one row per person Wide or long dose data

The "cohort" model covers single time-point snapshots, birth cohort designs with person-time, and time-series sweeps for interrupted time series analysis.


Model 1: Pre-aggregated denominator

Supply a data frame with n_vaccinated and n_eligible already computed. No per-person dose logic is performed.

cov_static <- brood(
  data.frame(
    stratum      = c("0-17", "18-49", "50-64", "65+"),
    n_vaccinated = c(480L,   3550L,   2370L,   1760L),
    n_eligible   = c(1000L,  5000L,   3000L,   2000L)
  ),
  denominator_notes = "ABS ERP 2024, Sunshine Coast LGA."
)
print(cov_static)
#>   stratum date vaccine_type dose_number n_vaccinated n_eligible person_time
#> 1    0-17 <NA>         <NA>        <NA>          480       1000          NA
#> 2   18-49 <NA>         <NA>        <NA>         3550       5000          NA
#> 3   50-64 <NA>         <NA>        <NA>         2370       3000          NA
#> 4     65+ <NA>         <NA>        <NA>         1760       2000          NA
#>   coverage reference_date intervention_period
#> 1     0.48           <NA>                <NA>
#> 2     0.71           <NA>                <NA>
#> 3     0.79           <NA>                <NA>
#> 4     0.88           <NA>                <NA>
#>                                  window_description
#> 1 Pre-aggregated: denominators supplied externally.
#> 2 Pre-aggregated: denominators supplied externally.
#> 3 Pre-aggregated: denominators supplied externally.
#> 4 Pre-aggregated: denominators supplied externally.
#> 
#> -- brood_meta --------------------------------------
#>  population_model : pre_aggregated 
#>  validity_days    : Inf (no expiry) 
#>  strata           : 4 
#>  coverage range   : 48% to 88% 
#>  window desc      : Pre-aggregated: denominators supplied externally. 
#>  denominator      : ABS ERP 2024, Sunshine Coast LGA.

Multi-vaccine product comparison

cov_multi <- brood(
  data.frame(
    stratum      = rep(c("18-49", "50-64", "65+"), each = 2),
    vaccine_type = rep(c("Moderna XBB.1.5", "Pfizer XBB.1.5"), 3),
    n_vaccinated = c(1800L, 1750L, 1100L, 1270L, 800L, 960L),
    n_eligible   = c(5000L, 5000L, 3000L, 3000L, 2000L, 2000L)
  ),
  vaccine_type_col  = "vaccine_type",
  denominator_notes = "AIR enrolled persons, SC HHS 2024."
)
print(cov_multi)
#>   stratum date    vaccine_type dose_number n_vaccinated n_eligible person_time
#> 1   18-49 <NA> Moderna XBB.1.5        <NA>         1800       5000          NA
#> 2   18-49 <NA>  Pfizer XBB.1.5        <NA>         1750       5000          NA
#> 3   50-64 <NA> Moderna XBB.1.5        <NA>         1100       3000          NA
#> 4   50-64 <NA>  Pfizer XBB.1.5        <NA>         1270       3000          NA
#> 5     65+ <NA> Moderna XBB.1.5        <NA>          800       2000          NA
#> 6     65+ <NA>  Pfizer XBB.1.5        <NA>          960       2000          NA
#>    coverage reference_date intervention_period
#> 1 0.3600000           <NA>                <NA>
#> 2 0.3500000           <NA>                <NA>
#> 3 0.3666667           <NA>                <NA>
#> 4 0.4233333           <NA>                <NA>
#> 5 0.4000000           <NA>                <NA>
#> 6 0.4800000           <NA>                <NA>
#>                                  window_description
#> 1 Pre-aggregated: denominators supplied externally.
#> 2 Pre-aggregated: denominators supplied externally.
#> 3 Pre-aggregated: denominators supplied externally.
#> 4 Pre-aggregated: denominators supplied externally.
#> 5 Pre-aggregated: denominators supplied externally.
#> 6 Pre-aggregated: denominators supplied externally.
#> 
#> -- brood_meta --------------------------------------
#>  population_model : pre_aggregated 
#>  validity_days    : Inf (no expiry) 
#>  strata           : 3 
#>  coverage range   : 35% to 48% 
#>  window desc      : Pre-aggregated: denominators supplied externally. 
#>  denominator      : AIR enrolled persons, SC HHS 2024.

Model 2: Cohort – single time point

One row per person in data. Use entry_date_col and one of the five assessment windows. Inputs come from starling::murmuration() in wide format.

set.seed(99)
n <- 120L
dialysis_cohort <- data.frame(
  patient_id          = paste0("D", seq_len(n)),
  dialysis_start_date = seq(as.Date("2022-01-01"), by = "week", length.out = n),
  dialysis_end_date   = seq(as.Date("2022-01-01"), by = "week", length.out = n) +
    sample(90:900, n, replace = TRUE),
  age_group           = sample(c("45-64","65-74","75+"), n, replace = TRUE,
                               prob = c(0.25, 0.45, 0.30)),
  vax_date_1          = as.Date(ifelse(
    sample(c(TRUE, FALSE), n, replace = TRUE, prob = c(0.65, 0.35)),
    as.character(seq(as.Date("2022-01-01"), by = "week", length.out = n) +
                   sample(-400:400, n, replace = TRUE)),
    NA_character_)),
  vax_type_1          = sample(c("Influenza","COVID-19",NA), n, replace = TRUE,
                               prob = c(0.5, 0.3, 0.2)),
  stringsAsFactors = FALSE
)

Window 2a: Vaccination status at exit

cov_exit <- brood(
  dialysis_cohort,
  data_format      = "wide",
  population_model = "cohort",
  vax_date_cols    = "vax_date_1",
  entry_date_col   = "dialysis_start_date",
  exit_date_col    = "dialysis_end_date",
  window           = "at_exit",
  stratum_col      = "age_group",
  denominator_notes = "Dialysis cohort SC HHS. At-exit = vaccinated by dialysis end date."
)
print(cov_exit)
#>   stratum n_vaccinated n_eligible person_time  coverage vaccine_type
#> 1   45-64            9         34          NA 0.2647059         <NA>
#> 2   65-74            8         45          NA 0.1777778         <NA>
#> 3     75+           11         41          NA 0.2682927         <NA>
#>   dose_number reference_date intervention_period
#> 1        <NA>           <NA>                <NA>
#> 2        <NA>           <NA>                <NA>
#> 3        <NA>           <NA>                <NA>
#>                           window_description
#> 1 Cohort: vaccinated at or before exit date.
#> 2 Cohort: vaccinated at or before exit date.
#> 3 Cohort: vaccinated at or before exit date.
#> 
#> -- brood_meta --------------------------------------
#>  population_model : cohort 
#>  window           : at_exit 
#>  validity_days    : Inf (no expiry) 
#>  strata           : 3 
#>  coverage range   : 17.8% to 26.8% 
#>  window desc      : Cohort: vaccinated at or before exit date. 
#>  denominator      : Dialysis cohort SC HHS. At-exit = vaccinated by dialysis end date.

Window 2b: Baseline (pre-entry) vaccination status

cov_pre <- brood(
  dialysis_cohort,
  data_format       = "wide",
  population_model  = "cohort",
  vax_date_cols     = "vax_date_1",
  vax_type_cols     = "vax_type_1",
  vax_target        = "Influenza",
  entry_date_col    = "dialysis_start_date",
  window            = "pre_entry",
  stratum_col       = "age_group",
  denominator_notes = "Dialysis cohort. Pre-entry = vaccinated before dialysis start."
)
print(cov_pre)
#>   stratum n_vaccinated n_eligible person_time   coverage vaccine_type
#> 1   45-64            3         34          NA 0.08823529         <NA>
#> 2   65-74            7         45          NA 0.15555556         <NA>
#> 3     75+           13         41          NA 0.31707317         <NA>
#>   dose_number reference_date intervention_period
#> 1        <NA>           <NA>                <NA>
#> 2        <NA>           <NA>                <NA>
#> 3        <NA>           <NA>                <NA>
#>                                   window_description
#> 1 Cohort: valid dose before cohort entry (baseline).
#> 2 Cohort: valid dose before cohort entry (baseline).
#> 3 Cohort: valid dose before cohort entry (baseline).
#> 
#> -- brood_meta --------------------------------------
#>  population_model : cohort 
#>  window           : pre_entry 
#>  validity_days    : Inf (no expiry) 
#>  vax_target       : Influenza 
#>  strata           : 3 
#>  coverage range   : 8.8% to 31.7% 
#>  window desc      : Cohort: valid dose before cohort entry (baseline). 
#>  denominator      : Dialysis cohort. Pre-entry = vaccinated before dialysis start.

Window 2c: Vaccination within 1 year of cohort entry

cov_post <- brood(
  dialysis_cohort,
  data_format       = "wide",
  population_model  = "cohort",
  vax_date_cols     = "vax_date_1",
  vax_type_cols     = "vax_type_1",
  vax_target        = "Influenza",
  entry_date_col    = "dialysis_start_date",
  window            = "post_entry_days",
  window_days       = 365L,
  stratum_col       = "age_group",
  denominator_notes = "Dialysis cohort. Post-entry window = 365 days from dialysis start."
)
print(cov_post)
#>   stratum n_vaccinated n_eligible person_time  coverage vaccine_type
#> 1   45-64            5         34          NA 0.1470588         <NA>
#> 2   65-74           10         45          NA 0.2222222         <NA>
#> 3     75+           12         41          NA 0.2926829         <NA>
#>   dose_number reference_date intervention_period
#> 1        <NA>           <NA>                <NA>
#> 2        <NA>           <NA>                <NA>
#> 3        <NA>           <NA>                <NA>
#>                                    window_description
#> 1 Cohort: valid dose within 365 days of cohort entry.
#> 2 Cohort: valid dose within 365 days of cohort entry.
#> 3 Cohort: valid dose within 365 days of cohort entry.
#> 
#> -- brood_meta --------------------------------------
#>  population_model : cohort 
#>  window           : post_entry_days 
#>  validity_days    : Inf (no expiry) 
#>  vax_target       : Influenza 
#>  strata           : 3 
#>  coverage range   : 14.7% to 29.3% 
#>  window desc      : Cohort: valid dose within 365 days of cohort entry. 
#>  denominator      : Dialysis cohort. Post-entry window = 365 days from dialysis start.

Window 2d: Post-intervention vaccination

cov_intervention <- brood(
  dialysis_cohort,
  data_format       = "wide",
  population_model  = "cohort",
  vax_date_cols     = "vax_date_1",
  vax_type_cols     = "vax_type_1",
  vax_target        = "Influenza",
  entry_date_col    = "dialysis_start_date",
  exit_date_col     = "dialysis_end_date",
  window            = "post_intervention",
  intervention_date = as.Date("2023-06-01"),
  stratum_col       = "age_group",
  denominator_notes = paste0(
    "Dialysis cohort. Post-intervention = vaccinated on or after 2023-06-01."
  )
)
print(cov_intervention)
#>   stratum n_vaccinated n_eligible person_time  coverage vaccine_type
#> 1   45-64            4         34          NA 0.1176471         <NA>
#> 2   65-74            6         45          NA 0.1333333         <NA>
#> 3     75+            7         41          NA 0.1707317         <NA>
#>   dose_number reference_date intervention_period
#> 1        <NA>           <NA>                <NA>
#> 2        <NA>           <NA>                <NA>
#> 3        <NA>           <NA>                <NA>
#>                           window_description
#> 1 Cohort: valid dose on or after 2023-06-01.
#> 2 Cohort: valid dose on or after 2023-06-01.
#> 3 Cohort: valid dose on or after 2023-06-01.
#> 
#> -- brood_meta --------------------------------------
#>  population_model : cohort 
#>  window           : post_intervention 
#>  validity_days    : Inf (no expiry) 
#>  vax_target       : Influenza 
#>  strata           : 3 
#>  coverage range   : 11.8% to 17.1% 
#>  window desc      : Cohort: valid dose on or after 2023-06-01. 
#>  denominator      : Dialysis cohort. Post-intervention = vaccinated on or after 2023-06-01.

Model 3: Cohort – birth cohort with person-time

Birth cohort is a special case of the cohort model. Set entry_date_col = "dob" and supply eligibility_days to define the age-based eligibility window. Person-time (days at risk from birth until vaccinated or window expired) is computed automatically.

set.seed(42)
n <- 200L
birth_records <- data.frame(
  baby_id    = paste0("B", seq_len(n)),
  dob        = seq(as.Date("2024-01-01"), by = "day", length.out = n),
  gestation  = sample(c("Term","Preterm"), n, replace = TRUE, prob = c(0.85, 0.15)),
  vax_date_1 = as.Date(ifelse(
    sample(c(TRUE, FALSE), n, replace = TRUE, prob = c(0.55, 0.45)),
    as.character(seq(as.Date("2024-01-01"), by = "day", length.out = n) +
                   sample(30:200, n, replace = TRUE)),
    NA_character_)),
  vax_type_1 = "nirsevimab",
  stringsAsFactors = FALSE
)
cov_birth <- brood(
  birth_records,
  data_format       = "wide",
  population_model  = "cohort",
  vax_date_cols     = "vax_date_1",
  vax_type_cols     = "vax_type_1",
  vax_target        = "nirsevimab",
  entry_date_col    = "dob",       # DOB is the cohort entry date
  eligibility_days  = 180L,        # eligible from birth until 6 months
  censor_date       = as.Date("2024-12-31"),
  stratum_col       = "gestation",
  denominator_notes = paste0(
    "SCPHU birth cohort 2024-01-01 to 2024-12-31. ",
    "Eligible = live births in SC LGA. ",
    "Eligibility window = 180 days from birth. ",
    "Administrative censor date = 2024-12-31."
  )
)
print(cov_birth)
#>   stratum n_vaccinated n_eligible person_time  coverage vaccine_type
#> 1 Preterm           13         29        4350 0.4482759         <NA>
#> 2    Term           95        171       23980 0.5555556         <NA>
#>   dose_number reference_date intervention_period
#> 1        <NA>           <NA>                <NA>
#> 2        <NA>           <NA>                <NA>
#>                           window_description
#> 1 Cohort: vaccinated at or before exit date.
#> 2 Cohort: vaccinated at or before exit date.
#> 
#> -- brood_meta --------------------------------------
#>  population_model : cohort 
#>  window           : at_exit 
#>  validity_days    : Inf (no expiry) 
#>  vax_target       : nirsevimab 
#>  strata           : 2 
#>  coverage range   : 44.8% to 55.6% 
#>  window desc      : Cohort: vaccinated at or before exit date. 
#>  denominator      : SCPHU birth cohort 2024-01-01 to 2024-12-31. Eligible = live births in SC LGA. Eligibility window = 180 days from birth. Administrative censor date = 2024-12-31.

The person_time column shows days at risk. coverage = proportion vaccinated among those who had at least one eligible day.


Model 4: Cohort – time series (interrupted time series analysis)

This is the backbone of brood(). Set time_series = TRUE and supply ts_start, ts_end, and ts_by to sweep window = "current_at_date" across monthly (or other) intervals automatically. Returns one row per stratum per time point – the right shape for bowerbird::brood_plot().

When intervention_date is supplied, an intervention_period column is automatically added, labelling each row as "Pre-intervention" or "Post-intervention".

set.seed(7)
n <- 120L
jak_cohort <- data.frame(
  patient_id          = paste0("P", seq_len(n)),
  entry_date_nominal  = as.Date("2000-01-01"),  # placeholder entry date
  age_group           = sample(c("18-49","50-64","65+"), n, replace = TRUE),
  vax_date_1          = as.Date(ifelse(
    sample(c(TRUE, FALSE), n, replace = TRUE, prob = c(0.45, 0.55)),
    as.character(as.Date("2024-01-01") + sample(0:730, n, replace = TRUE)),
    NA_character_)),
  vax_type_1          = "Shingrix",
  vax_date_2          = as.Date(ifelse(
    sample(c(TRUE, FALSE), n, replace = TRUE, prob = c(0.25, 0.75)),
    as.character(as.Date("2024-06-01") + sample(0:365, n, replace = TRUE)),
    NA_character_)),
  vax_type_2          = "Shingrix",
  stringsAsFactors = FALSE
)
cov_ts <- brood(
  jak_cohort,
  data_format       = "wide",
  population_model  = "cohort",
  vax_date_cols     = c("vax_date_1", "vax_date_2"),
  vax_type_cols     = c("vax_type_1", "vax_type_2"),
  vax_target        = "Shingrix",
  validity_days     = Inf,
  entry_date_col    = "entry_date_nominal",
  time_series       = TRUE,
  ts_start          = as.Date("2024-12-01"),
  ts_end            = as.Date("2026-06-01"),
  ts_by             = "month",
  intervention_date = as.Date("2025-12-01"),
  denominator_notes = "JAK-inhibitor cohort. Shingrix only, no expiry."
)
#> (*)> mudnester::brood() — time_series: 19 month time points from 2024-12-01 to 2026-06-01
print(cov_ts)
#>    stratum n_vaccinated n_eligible person_time  coverage reference_date
#> 1  Overall           33        120          NA 0.2750000     2024-12-01
#> 2  Overall           41        120          NA 0.3416667     2025-01-01
#> 3  Overall           47        120          NA 0.3916667     2025-02-01
#> 4  Overall           52        120          NA 0.4333333     2025-03-01
#> 5  Overall           55        120          NA 0.4583333     2025-04-01
#> 6  Overall           56        120          NA 0.4666667     2025-05-01
#> 7  Overall           59        120          NA 0.4916667     2025-06-01
#> 8  Overall           60        120          NA 0.5000000     2025-07-01
#> 9  Overall           61        120          NA 0.5083333     2025-08-01
#> 10 Overall           62        120          NA 0.5166667     2025-09-01
#> 11 Overall           67        120          NA 0.5583333     2025-10-01
#> 12 Overall           72        120          NA 0.6000000     2025-11-01
#> 13 Overall           73        120          NA 0.6083333     2025-12-01
#> 14 Overall           74        120          NA 0.6166667     2026-01-01
#> 15 Overall           74        120          NA 0.6166667     2026-02-01
#> 16 Overall           74        120          NA 0.6166667     2026-03-01
#> 17 Overall           74        120          NA 0.6166667     2026-04-01
#> 18 Overall           74        120          NA 0.6166667     2026-05-01
#> 19 Overall           74        120          NA 0.6166667     2026-06-01
#>    intervention_period vaccine_type dose_number
#> 1     Pre-intervention         <NA>        <NA>
#> 2     Pre-intervention         <NA>        <NA>
#> 3     Pre-intervention         <NA>        <NA>
#> 4     Pre-intervention         <NA>        <NA>
#> 5     Pre-intervention         <NA>        <NA>
#> 6     Pre-intervention         <NA>        <NA>
#> 7     Pre-intervention         <NA>        <NA>
#> 8     Pre-intervention         <NA>        <NA>
#> 9     Pre-intervention         <NA>        <NA>
#> 10    Pre-intervention         <NA>        <NA>
#> 11    Pre-intervention         <NA>        <NA>
#> 12    Pre-intervention         <NA>        <NA>
#> 13   Post-intervention         <NA>        <NA>
#> 14   Post-intervention         <NA>        <NA>
#> 15   Post-intervention         <NA>        <NA>
#> 16   Post-intervention         <NA>        <NA>
#> 17   Post-intervention         <NA>        <NA>
#> 18   Post-intervention         <NA>        <NA>
#> 19   Post-intervention         <NA>        <NA>
#>                                                                                                 window_description
#> 1  Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 2  Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 3  Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 4  Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 5  Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 6  Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 7  Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 8  Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 9  Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 10 Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 11 Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 12 Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 13 Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 14 Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 15 Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 16 Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 17 Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 18 Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 19 Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01.
#> 
#> -- brood_meta --------------------------------------
#>  population_model : cohort 
#>  time_series      : TRUE
#>  time_series_by   : month 
#>  n_time_points    : 19 
#>  intervention     : 2025-12-01 
#>  validity_days    : Inf (no expiry) 
#>  vax_target       : Shingrix 
#>  strata           : 1 
#>  coverage range   : 27.5% to 61.7% 
#>  window desc      : Time series: monthly 'current_at_date' coverage from 2024-12-01 to 2026-06-01, intervention line at 2025-12-01. 
#>  denominator      : JAK-inhibitor cohort. Shingrix only, no expiry.

The result is 19 rows: one per month ( 19 time points) across 1 stratum (“Overall”). With stratum_col supplied, each stratum gets its own row at every time point.

Stratified time series

cov_ts_strat <- brood(
  jak_cohort,
  data_format       = "wide",
  population_model  = "cohort",
  vax_date_cols     = c("vax_date_1", "vax_date_2"),
  vax_type_cols     = c("vax_type_1", "vax_type_2"),
  vax_target        = "Shingrix",
  validity_days     = Inf,
  entry_date_col    = "entry_date_nominal",
  stratum_col       = "age_group",
  time_series       = TRUE,
  ts_start          = as.Date("2024-12-01"),
  ts_end            = as.Date("2026-06-01"),
  ts_by             = "month",
  intervention_date = as.Date("2025-12-01"),
  denominator_notes = "JAK-inhibitor cohort by age group. Shingrix only."
)
#> (*)> mudnester::brood() — time_series: 19 month time points from 2024-12-01 to 2026-06-01
cat("Rows:", nrow(cov_ts_strat),
    "= ", attr(cov_ts_strat, "n_time_points"), "months x",
    attr(cov_ts_strat, "n_strata"), "age groups\n")
#> Rows: 57 =  19 months x 3 age groups
print(head(cov_ts_strat[, c("stratum","reference_date","intervention_period",
                              "n_vaccinated","n_eligible","coverage")], 9))
#>   stratum reference_date intervention_period n_vaccinated n_eligible  coverage
#> 1   18-49     2024-12-01    Pre-intervention           12         35 0.3428571
#> 2   50-64     2024-12-01    Pre-intervention            8         45 0.1777778
#> 3     65+     2024-12-01    Pre-intervention           13         40 0.3250000
#> 4   18-49     2025-01-01    Pre-intervention           13         35 0.3714286
#> 5   50-64     2025-01-01    Pre-intervention           13         45 0.2888889
#> 6     65+     2025-01-01    Pre-intervention           15         40 0.3750000
#> 7   18-49     2025-02-01    Pre-intervention           16         35 0.4571429
#> 8   50-64     2025-02-01    Pre-intervention           15         45 0.3333333
#> 9     65+     2025-02-01    Pre-intervention           16         40 0.4000000
#> 
#> -- brood_meta --------------------------------------
#>  population_model : 
#>  strata           : 
#>  coverage range   : 17.8% to 45.7%

Passing to bowerbird::brood_plot()

All models return brood_df objects accepted by bowerbird::brood_plot(). The time-series output auto-detects as a line chart:

# Pre-aggregated: bar chart with target line
bowerbird::brood_plot(cov_static, target_line = 0.80,
                       title = "COVID-19 booster coverage by age group")

# Time series: line chart with vertical intervention line (auto-detected)
bowerbird::brood_plot(cov_ts,
                       title = "Monthly Shingrix coverage, JAK-inhibitor cohort")

# Stratified time series: one line per stratum
bowerbird::brood_plot(cov_ts_strat,
                       title = "Shingrix coverage by age group")

The denominator_notes requirement

Every brood() call should include denominator_notes documenting:

brood() stores these notes as a metadata attribute. print.brood_df() displays them and bowerbird::brood_plot() can use them as a plot caption.


Session info

sessionInfo()
#> R version 4.5.2 (2025-10-31 ucrt)
#> Platform: x86_64-w64-mingw32/x64
#> Running under: Windows 11 x64 (build 26100)
#> 
#> Matrix products: default
#>   LAPACK version 3.12.1
#> 
#> locale:
#> [1] LC_COLLATE=C                       LC_CTYPE=English_Australia.utf8   
#> [3] LC_MONETARY=English_Australia.utf8 LC_NUMERIC=C                      
#> [5] LC_TIME=English_Australia.utf8    
#> 
#> time zone: Australia/Brisbane
#> tzcode source: internal
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] dplyr_1.2.0     mudnester_0.7.8
#> 
#> loaded via a namespace (and not attached):
#>  [1] vctrs_0.7.1       cli_3.6.5         knitr_1.51        rlang_1.2.0      
#>  [5] xfun_0.56         otel_0.2.0        generics_0.1.4    jsonlite_2.0.0   
#>  [9] glue_1.8.0        htmltools_0.5.9   sass_0.4.10       rmarkdown_2.31   
#> [13] evaluate_1.0.5    jquerylib_0.1.4   tibble_3.3.1      fastmap_1.2.0    
#> [17] yaml_2.3.12       lifecycle_1.0.5   compiler_4.5.2    pkgconfig_2.0.3  
#> [21] rstudioapi_0.18.0 digest_0.6.39     R6_2.6.1          utf8_1.2.6       
#> [25] tidyselect_1.2.1  pillar_1.11.1     magrittr_2.0.4    bslib_0.10.0     
#> [29] tools_4.5.2       cachem_1.1.0