Overview
bayesma_report() renders a parameterised Quarto template into a publication-style statistical report. The template structure follows the workflow guide (data prep → fitting → comparison → bias → sensitivity → interpretation) and the prose style of a full systematic review (Introduction → Methods → Results → Overall Interpretation).
You supply the data, a few measure-specific column names, and a handful of narrative strings; the function fills the template, fits the requested models, and writes a .qmd (and optionally a rendered .html) to disk.
The split is:
- Inputs — data, columns, priors, null range. Always required.
- Narrative slots — Background, Hypothesis, Inclusion/Exclusion, etc. Optional; sensible defaults.
- Section toggles — turn whole analyses (RoBMA, meta-regression, INSPECT-SR, …) on or off.
Once rendered, the output is a normal .qmd you can edit by hand.
Quick start
library(bayesma)
bayesma_report(
data = eeg_data,
studyvar = "Author",
yearvar = "Year",
estimand = "OR",
event_ctrl = "c_event",
event_int = "i_event",
n_ctrl = "c_n",
n_int = "i_n",
outcome_name = "Postoperative Delirium",
null_range = c(0.9, 1.1),
title = "EEG-guided anaesthesia and POD",
author = "Dr Benjamin Moran",
output_file = "eeg_pod_report.qmd",
render = TRUE
)The call returns the path to the generated .qmd. Alongside it, a companion *_bundle.rds is written containing data, rob_data, and priors — the template reads from this at render time.
With render = TRUE, the .qmd is rendered to HTML next to itself.
Required arguments
| Argument | Purpose |
|---|---|
data |
A data frame with one row per study (or per arm). |
studyvar |
Column with study identifiers. |
yearvar |
Column with publication year. |
estimand |
Target effect: "OR", "RR", "HR", "IRR", "MD", "SMD" (relative / mean-difference) or "RD" / "ARR", "ATE", "ATT", "CATE" (marginal — computed via bayesma_marginal()). |
outcome_name |
Human-readable outcome label (used in titles and prose). |
null_range |
Numeric length-2 vector. ROPE / null range on the natural scale (e.g. c(0.9, 1.1) for an OR). |
output_file |
Path for the generated .qmd. |
Estimand-specific columns — pass whichever set matches the data shape implied by estimand. Names match bayesma() itself:
# Binary / count estimands (OR, RR, HR, IRR, RD, ARR, ATE, ATT, CATE)
event_ctrl = "c_event", event_int = "i_event",
n_ctrl = "c_n", n_int = "i_n"
# Continuous estimands (MD, SMD)
mean_ctrl = "c_mean", mean_int = "i_mean",
sd_ctrl = "c_sd", sd_int = "i_sd",
n_ctrl = "c_n", n_int = "i_n"Narrative slots
These are character strings (or character vectors) that fill prose blocks. All are optional; defaults are generic.
| Slot | Where it appears |
|---|---|
background |
Introduction → Background. One or more paragraphs. |
hypothesis |
Methods → Hypothesis and Aims. |
inclusion_criteria |
Methods → Trial Design → Inclusion. Bulleted list (character vector). |
exclusion_criteria |
Methods → Trial Design → Exclusion. |
quality_tool |
Methods → Quality Assessment (default: "Cochrane RoB 2"). |
prospero_id |
Methods → Trial Design (registration paragraph). |
software_note |
Methods → Software (default cites bayesma, cmdstanr, R version). |
Example:
bayesma_report(
...,
background = c(
"Postoperative delirium (POD) is a common complication ...",
"Processed EEG monitors have been proposed to ..."
),
hypothesis = "pEEG-guided anaesthesia reduces the incidence of POD compared to usual care.",
inclusion_criteria = c(
"Randomised controlled trials (parallel-group or crossover)",
"Adults undergoing general anaesthesia for any surgery",
"EEG-guided anaesthesia versus standard care"
),
exclusion_criteria = c(
"Non-RCT or no full text",
"Sedation other than general anaesthesia",
"Non-EEG depth-of-anaesthesia monitors"
),
prospero_id = "CRD420251081478"
)Section toggles
Each toggle defaults to a sensible value (TRUE for primary analyses, FALSE for the heavier optional ones). Setting a toggle to FALSE removes both the Methods description and the Results section for that analysis — there are no orphan headings.
| Toggle | Default | Adds |
|---|---|---|
run_inspect_sr |
FALSE |
INSPECT-SR trustworthiness assessment |
run_rob |
FALSE |
RoB 2 traffic-light + summary |
run_egger |
TRUE |
Bayesian Egger regression + funnel plot |
run_robma |
TRUE |
Single-component bias-adjusted models + RoBMA |
run_metareg |
FALSE |
Meta-regression on moderators
|
run_subgroup |
FALSE |
Subgroup analyses on subgroup_var
|
run_sensitivity_priors |
TRUE |
Prior sensitivity (vague / weakly-regularising / informative) |
Toggles that take companion arguments:
bayesma_report(
...,
run_metareg = TRUE, moderators = c("MeanAge", "PercentFemale"),
run_subgroup = TRUE, subgroup_var = c("SurgeryType", "Region"),
run_rob = TRUE, rob_data = my_rob_df
)subgroup_var accepts a character vector — one heading is generated per variable, with sub-headings per level.
Models fitted automatically
Regardless of toggles, the primary analysis section fits this candidate suite:
- One-stage common-effect (
one_stage_ce) - Two-stage common-effect (
two_stage_ce) - One-stage random-effects (
one_stage_re) - Two-stage random-effects (
two_stage_re) - Two-stage random-effects with HKSJ (
two_stage_re_hksj) - Two-stage random-effects with mixture RE distribution (
two_stage_re_mixture)
The primary model is selected via LOSO-CV (compare_models()), with diagnostics shown alongside. The selected model drives the forest plot, posterior, and any downstream sensitivity / RoBMA work.
To override automatic selection:
bayesma_report(..., primary_model = "two_stage_re_hksj")When run_robma = TRUE, an additional set of single-component bias-adjusted models is fitted alongside RoBMA itself:
-
bias_corrected— parametric bias-correction (Verde 2021) -
bc_bnp— Bias-Corrected Bayesian Non-Parametric (Verde 2025) -
selection_copas— Robust Bayesian Copas selection model (Bai et al. 2020) -
selection_weight— Vevea-Hedges weight-function selection model -
pet_peese— small-study adjustment via funnel-plot regression -
mixture_model— Bayesian meta-analytic mixture (Maier 2024)
Priors
By default the report fits with bayesma’s weakly-regularising priors and reports a prior sensitivity panel covering vague, weak_reg, and informative specifications.
To pass custom priors:
my_priors <- list(
weak_reg = list(
mu_prior = normal(0, 1),
tau_prior = half_student_t(3, 0, 0.5)
),
informative = list(
mu_prior = normal(-0.3, 0.3),
tau_prior = half_normal(0, 0.3)
)
)
bayesma_report(..., priors = my_priors)Priors are stashed in the companion *_bundle.rds and read by the template — no need to inline them into YAML.
Marginal estimands (RD / ATE / ATT / CATE)
When estimand is one of "RD"/"ARR", "ATE", "ATT", or "CATE", each fitted model also carries a $marginal element produced by bayesma_marginal():
- RD / ARR and ATE for one-stage binomial fits are computed from posterior draws of the per-arm linear predictor.
-
RD / ARR and ATE for two-stage binomial fits require a reference baseline. Pass
baseline_risk = 0.15(numeric) orbaseline_risk = "study_mean"(the unweighted mean of observed control rates). - ATT is computed as the ATE weighted by treated-arm sample size; without IPD this is an arm-size-weighted ATE rather than a true causal ATT.
-
CATE routes to a meta-regression on
cate_covariate. Setcate_covariate = "MeanAge"(or similar). The user evaluates the posterior at the covariate value of interest downstream.
The relative-effect estimands (OR/RR/HR/IRR/MD/SMD) behave exactly as before.
Risk of bias
Pass a pre-scored RoB data frame via rob_data when run_rob = TRUE:
bayesma_report(..., run_rob = TRUE, rob_data = rob_2_scored)If rob_data is NULL but data itself contains rob_* columns, those are used instead. Otherwise the RoB section is skipped with a message.
Worked example
Reproducing an EEG-guided anaesthesia report:
library(bayesma)
library(readxl)
eeg <- read_excel("EEG_POD_data.xlsx", sheet = "delirium")
bayesma_report(
data = eeg,
studyvar = "Author",
yearvar = "Year",
estimand = "OR",
event_ctrl = "c_event", event_int = "i_event",
n_ctrl = "c_n", n_int = "i_n",
outcome_name = "Postoperative Delirium",
null_range = c(0.9, 1.1),
title = "EEG-guided anaesthesia for reducing POD",
subtitle = "A Bayesian meta-analysis",
author = "Dr Benjamin Moran",
prospero_id = "CRD420251081478",
background = c(
"Postoperative delirium is a common complication of surgery in older adults ...",
"Processed EEG monitors have been proposed to guide anaesthetic depth ..."
),
hypothesis = "pEEG-guided anaesthesia reduces the incidence of POD compared to usual care.",
inclusion_criteria = c(
"Randomised controlled trials",
"Adults undergoing general anaesthesia",
"pEEG-guided versus standard care"
),
exclusion_criteria = c(
"Non-RCT or no full text",
"Sedation other than general anaesthesia",
"Non-EEG depth monitors"
),
run_inspect_sr = FALSE,
run_rob = TRUE,
run_egger = TRUE,
run_robma = TRUE,
run_subgroup = TRUE,
subgroup_var = c("SurgeryType", "Region"),
run_sensitivity_priors = TRUE,
output_file = "eeg_pod_report.qmd",
render = TRUE
)Editing the output
The generated .qmd is a regular Quarto document. Common post-render edits:
- Tighten the prose slots (Background, Limitations, Conclusion) — these are the parts a templated report cannot get exactly right.
- Reorder Results sections, drop a model that didn’t converge, add domain-specific commentary.
- Swap the
format:block forpdfordocxwhen submitting.
Re-rendering after edits is just quarto render eeg_pod_report.qmd — bayesma_report() does not need to be called again. (The companion *_bundle.rds must remain alongside the .qmd.)
What bayesma_report() does not do
- It does not write your Background / Discussion / Limitations for you. The slots accept your prose verbatim; the function does not generate clinical narrative.
- It does not assess study quality. Pass a pre-scored RoB data frame via
rob_data =ifrun_rob = TRUE. - It does not search literature, screen studies, or extract data — it starts from a clean tibble.
See also
-
workflow-guide— full walk-through of the underlying functions. -
robma— RoBMA-specific details. -
primed— preliminary data exploration.
