A Quarto shortcode extension that renders participant-flow diagrams for five reporting guidelines from structured YAML in your document frontmatter. Diagrams are emitted as inline SVG for HTML output and as native TikZ for LaTeX/PDF output, with no runtime dependencies beyond Quarto itself.
type: |
Guideline | Used for |
|---|---|---|
consort |
CONSORT 2025 (supersedes 2010) | Randomised controlled trials |
strobe |
STROBE | Observational studies |
prisma |
PRISMA 2020 | Systematic reviews |
tripod |
TRIPOD+AI 2024 (supersedes 2015) | Clinical prediction models |
stard |
STARD 2015 | Diagnostic accuracy studies |
| CONSORT 2025 | PRISMA 2020 | STARD 2015 |
|---|---|---|
![]() |
![]() |
![]() |
| TRIPOD+AI 2024 | STROBE |
|---|---|
![]() |
![]() |
quarto add tiagojct/quarto-study-flowThis will install the extension under the _extensions subdirectory. If
you're using version control, you will want to check in this directory.
To update an existing install:
quarto update tiagojct/quarto-study-flowTo remove:
quarto remove tiagojct/quarto-study-flowDeclare the diagram in your document's YAML frontmatter under the
study-flow key, then drop the shortcode {{< study-flow >}} wherever
you want the figure to appear. Minimal CONSORT example:
---
title: "My trial"
format: html
study-flow:
type: consort
enrollment:
assessed: 350
excluded: 120
exclusion_reasons:
- "Did not meet inclusion criteria: 80"
- "Declined to participate: 40"
randomised: 230
groups:
- label: "Intervention"
allocated: 115
lost_followup: 8
analysed: 107
- label: "Control"
allocated: 115
lost_followup: 10
analysed: 105
---
The flow of participants is shown below.
{{< study-flow >}}Render with:
quarto render my-trial.qmd --to html
quarto render my-trial.qmd --to pdfstudy-flow:
type: consort
enrollment:
assessed: 350
excluded: 120
exclusion_reasons:
- "Did not meet inclusion criteria: 80"
- "Declined to participate: 40"
randomised: 230
groups:
- label: "Intervention"
allocated: 115
received: 110 # optional
lost_followup: 8
lost_reasons:
- "Withdrew consent: 5"
- "Lost to follow-up: 3"
analysed: 107
excluded_analysis: 3 # optional
excluded_analysis_reasons:
- "Protocol deviation: 3"
- label: "Control"
allocated: 115
lost_followup: 10
analysed: 105The CONSORT layout follows the four canonical rows from the CONSORT 2025 statement, which supersedes CONSORT 2010 with no structural change to the flow diagram: Enrolment, Allocation, Follow-up, Analysis. A side arrow connects Enrolment to the Excluded box, and Randomised splits into N parallel columns, one per arm.
study-flow:
type: strobe
source:
label: "Source population"
n: 12500
eligible:
label: "Eligible cohort"
n: 8400
excluded: 4100
exclusion_reasons:
- "Outside age range: 2600"
- "Insufficient follow-up: 1100"
enrolled:
n: 7200
excluded: 1200
groups:
- label: "Exposed"
n: 3100
lost_followup: 220
analysed: 2880
- label: "Unexposed"
n: 4100
lost_followup: 310
analysed: 3790The STROBE flow runs Source, Eligible, Enrolled as a vertical spine, each stage with an optional Excluded sidebar. Below the spine the diagram splits into N exposure or case-control columns with optional follow-up loss and analysis rows, mirroring how cohort flow is conventionally drawn under the STROBE statement.
source, eligible, enrolled, and groups are all individually
optional. Omit any stage you don't need. At least one stage or group is
required.
study-flow:
type: prisma
identification:
databases: 1842
registers: 167
duplicates_removed: 612
ineligible_automation: 88
other_removed: 14
screening:
screened: 1295
excluded: 1024
sought_retrieval: 271
not_retrieved: 23
assessed: 248
excluded_with_reasons:
- "Wrong population (n=46)"
- "Wrong intervention (n=31)"
- "Wrong outcome (n=22)"
other_methods: # optional parallel column (grey literature etc.)
websites: 12
organisations: 8
citation_searching: 25
sought_retrieval: 41
not_retrieved: 3
assessed: 38
excluded_with_reasons:
- "Wrong population (n=5)"
included:
studies: 134
reports: 142The PRISMA layout follows the canonical PRISMA 2020 flow with five rows on the main spine: Records identified, Records screened, Reports sought, Reports assessed, Studies included. Excluded and Removed boxes branch to the right at each step. Any field you omit collapses the corresponding box.
For reviews that also search grey literature, citation chains, or
organisational websites, add an other_methods block. It renders as a
parallel column on the right that converges into the final Studies
included box, matching the PRISMA 2020 v2 template.
study-flow:
type: tripod
source:
label: "Source population"
n: 18450
eligibility:
n: 14210
excluded: 4240
exclusion_reasons:
- "Outside age range: 1850"
- "No baseline measurement: 1620"
cohorts:
- label: "Development cohort"
n: 9420
excluded_missing: 380
analysed: 9040
events: 412
no_events: 8628
- label: "External validation cohort"
n: 4790
analysed: 4695
events: 233
no_events: 4462TRIPOD+AI 2024 supersedes TRIPOD 2015 and applies to studies developing, validating, or updating a clinical prediction model (whether regression or machine-learning based). The diagram puts an optional Source, Eligible spine at the top, then splits into 1+ parallel cohort columns (typically development and external validation), each with its own outcome breakdown row.
study-flow:
type: stard
assessed: 612
excluded: 137
exclusion_reasons:
- "Did not meet inclusion criteria: 92"
- "Declined consent: 34"
enrolled: 475
index_test: 461
not_index: 14
not_index_reasons:
- "Equipment malfunction: 8"
- "Sample not collected: 6"
reference_standard: 442
not_reference: 19
not_reference_reasons:
- "Refused reference test: 12"
outcomes:
true_positive: 148
false_positive: 41
false_negative: 27
true_negative: 226The STARD layout follows the canonical STARD 2015 prototypical diagram
with a four-row spine: Assessed for eligibility, Enrolled, Received
index test, Received reference standard. Each row can have an optional
right-side Excluded or Did not receive sidebar. Below the spine sits
a 2×2 contingency grid (TP, FP, FN, TN) with Reference standard +/−
column headers and Index test +/− row headers.
Wrap the shortcode in a Quarto figure div to give the diagram a caption, a number, and a cross-referenceable label:
::: {#fig-trial}
{{< study-flow >}}
Participant flow following CONSORT 2025.
:::
See @fig-trial for the participant flow.This is the same :::{#fig-id} syntax Quarto uses for any custom figure
content, and it produces a numbered figure with a working @fig-trial
reference in both HTML and PDF.
| Format | Renderer | Notes |
|---|---|---|
html |
inline SVG | Scales to container; uses text-anchor="middle" and preserveAspectRatio="xMidYMid meet" for clean responsive layout. |
revealjs |
inline SVG | Same SVG output as html. |
pdf / latex |
TikZ | Auto-loads tikz, graphicx, and the arrows.meta library. Wrapped in \resizebox{\linewidth}{!}{...} so it always fits the text width. Works with any LaTeX engine; rsvg-convert is not needed. |
| anything else | inline SVG (fallback) |
For PDF output, pdf-engine: xelatex is recommended in your document YAML
so that Unicode characters in box labels (bullets, en-dashes, the minus
sign in STARD's 2×2 grid) render natively without configuration.
This repository ships ready-to-render examples:
example-consort.qmd: two-arm RCTexample-strobe.qmd: cohort studyexample-prisma.qmd: systematic reviewexample-tripod.qmd: prediction model with development and external validation cohortsexample-stard.qmd: diagnostic accuracy study with a 2×2 contingency grid
Render any of them with:
quarto render example-consort.qmd --to html
quarto render example-consort.qmd --to pdftype: consort
enrollment:
assessed: number # required
excluded: number # required
exclusion_reasons: [string] # optional
randomised: number # required
groups: # required, 1+ entries
- label: string # required
allocated: number # required
received: number # optional
not_received: number # optional
lost_followup: number # optional (defaults to 0)
lost_reasons: [string]
discontinued: number # optional
discontinued_reasons: [string]
analysed: number # required
excluded_analysis: number # optional
excluded_analysis_reasons: [string]
type: strobe
source: { label: string, n: number } # optional
eligible: { label: string, n: number,
excluded: number, exclusion_reasons: [string] } # optional
enrolled: { label: string, n: number,
excluded: number, exclusion_reasons: [string] } # optional
groups: # optional
- label: string
n: number
lost_followup: number # optional
lost_reasons: [string]
analysed: number
excluded_analysis: number # optional
excluded_analysis_reasons: [string]
type: prisma
identification:
databases: number
registers: number # optional
duplicates_removed: number # optional
ineligible_automation: number # optional
other_removed: number # optional
screening:
screened: number # optional
excluded: number # optional (sidebar to screened)
sought_retrieval: number # optional
not_retrieved: number # optional (sidebar to sought_retrieval)
assessed: number # optional
excluded_with_reasons: [string] # optional (sidebar to assessed)
other_methods: # optional parallel right-side column
websites: number # optional
organisations: number # optional
citation_searching: number # optional
sought_retrieval: number # optional
not_retrieved: number # optional
assessed: number # optional
excluded_with_reasons: [string] # optional
included:
studies: number # optional
reports: number # optional
type: tripod
source: # optional
label: string
n: number
eligibility: # optional
label: string
n: number
excluded: number # optional
exclusion_reasons: [string] # optional
cohorts: # required, 1+ entries
- label: string
n: number
excluded_missing: number # optional
excluded_missing_reasons: [string] # optional
analysed: number # optional
events: number # optional
no_events: number # optional
type: stard
assessed: number # required
excluded: number # optional (sidebar)
exclusion_reasons: [string]
enrolled: number # required
index_test: number # optional, defaults to enrolled
not_index: number # optional (sidebar)
not_index_reasons: [string]
reference_standard: number # optional, defaults to index_test
not_reference: number # optional (sidebar)
not_reference_reasons: [string]
outcomes: # required
true_positive: number
false_positive: number
false_negative: number
true_negative: number
- CONSORT 2025: Hopewell S et al. CONSORT 2025 statement: updated guideline for reporting randomised trials. The Lancet, 2025. https://www.consort-spirit.org
- STROBE: von Elm E et al. Strengthening the Reporting of Observational Studies in Epidemiology (STROBE). Ann Intern Med, 2007. https://www.strobe-statement.org
- PRISMA 2020: Page MJ et al. The PRISMA 2020 statement: an updated guideline for reporting systematic reviews. BMJ, 2021. https://www.prisma-statement.org
- TRIPOD+AI 2024: Collins GS et al. TRIPOD+AI statement: updated guidance for reporting clinical prediction models that use regression or machine learning methods. BMJ, 2024. https://www.tripod-statement.org
- STARD 2015: Bossuyt PM et al. STARD 2015: an updated list of essential items for reporting diagnostic accuracy studies. BMJ, 2015. https://www.equator-network.org/reporting-guidelines/stard/
MIT © Tiago Jacinto




