Skip to content
andrew-farreyPublic

About

Generate polished, accessible one-page (front-and-back) PDF reports from analysis output, using a small set of fixed Typst templates and a swappable design-token theme system built using Quarto.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

onepagr onepagr logo

R-CMD-check Codecov test coverage DOI

Generate polished, accessible one-page (front-and-back) PDF reports from analysis output, using a small set of fixed Typst templates and a swappable design-token theme system.

Every template compiles under Typst's --pdf-standard ua-1 conformance check and is built to pass WCAG 2.2 AA color contrast and PDF/UA-1 structural tagging, not as a final pass but as a requirement checked at every step of development.

Full documentation, including function reference and vignettes, is available at https://andrew-farrey.github.io/onepagr/.

Why

Public health teams and similar analysis groups often need to turn a piece of analysis into a one-page fact sheet, surveillance brief, or alert bulletin: something that can be printed front-and-back, shared as a PDF, or read on a phone. Doing that by hand in a slide deck or word processor is slow to reproduce and makes accessibility easy to get wrong. onepagr turns a named list of values into a finished PDF with one function call, using templates whose layout and accessibility patterns are already solved.

Background

onepagr generalizes the design of two production one-pagers: an Emergency Medical Services (EMS) and Drug Overdose Fatality Surveillance System (DOFSS) record-linkage summary, and a Social Vulnerability Index by overdose-mortality county choropleth map series. Both were developed in 2026 by the Kentucky Injury Prevention and Research Center (KIPRC) at the University of Kentucky College of Public Health, as a bona fide agent of the Kentucky Department for Public Health (KDPH), in support of the Centers for Disease Control and Prevention's Overdose Data to Action in States grant. The layouts, shared Typst components, theme tokens, and accessibility patterns behind both were designed by the package author and generalized into this package.

Installation

Install the development version from GitHub:

# install.packages("pak")
pak::pak("andrew-farrey/onepagr")

onepagr also needs Quarto, which bundles Typst, installed on your system. Accessible PDF output needs Typst 0.14.0 or newer, the release that added PDF/UA-1 conformance and automatic tagged-PDF support in the first place. Older Typst versions simply cannot produce an accessible PDF, no matter what onepagr does. onepagr itself checks for Typst 0.15.1+ by default (a newer floor than the bare minimum, confirmed to be what's actually bundled by recent Quarto releases). Check whether your system's Typst is new enough, and get a clear message naming the actual version if it isn't:

onepagr::check_quarto()

If it's missing, onepagr::install_quarto() installs a user-local copy without needing admin rights (you must run it yourself; onepagr never installs software automatically). On macOS and Linux it also points onepagr at the copy it just installed for you: it sets QUARTO_PATH for your current session immediately, then asks whether to save that to your ~/.Renviron too, so every future R session picks it up automatically without you ever needing to know what a .Renviron file is. (On Windows it opens the official installer instead of extracting anything itself, so there's no path to point at until you finish that installer yourself.)

Already have a Quarto install somewhere else onepagr should use instead, for example an admin-managed one on Posit Workbench? Point onepagr at it the same way, without hand-editing anything:

onepagr::set_quarto_path("/path/to/quarto")

Quick start

library(onepagr)

data <- list(
  doc_title = "OVERDOSE SPIKE ALERT",
  doc_subtitle = "Sample County Surveillance",
  org_full = "Sample Health Department",
  contact_url = "https://example.org/",
  contact_email = "contact@example.org",
  # One logo is all a template needs. This path points at onepagr's own
  # bundled placeholder (staged automatically, no extra_assets needed):
  # swap in your own logo file once you have one. Co-branding partner
  # logos are optional; see vignette("theming").
  logo_primary_path = "assets/primary-org-white.png",
  logo_primary_alt = "Sample Health Department logo",
  severity_level = "critical",
  alert_area = "Sample County",
  alert_issued_at = "August 26, 2026, 9:00 AM",
  n_events = "14",
  window_days = "3",
  n_spikes = "2",
  spike_window_days = "30",
  threshold = "8",
  narrative_text = "Sample County has recorded 14 suspected overdoses...",
  geo_breakdown_text = "- Northside: 6 events\n- Downtown: 5 events",
  actions_text = "- Increase naloxone distribution in the affected area",
  show_resources = "true",
  resources_text = "Sample Health Department, (555) 123-4567.",
  footnote_sources = "Sample Overdose Detection Mapping System"
)

render_onepager(data, template = "overdose_spike_alert", theme = "uk", output = "alert.pdf")

That's it: alert.pdf is a finished, accessible PDF. By default, render_onepager() also leaves the resolved .typ source next to the output (alert_typst/), so it's never hidden away, even if you never need to look at it. That's deliberate: it's useful for troubleshooting, and it means a real, working template is always sitting somewhere you can hand it to an AI coding assistant (or a collaborator) to build out further, which is part of the point of how onepagr is structured. Set keep_typst = FALSE to skip that and get only the PDF.

Don't want to hand-type a data list at all? template_data() returns a complete, working one for any built-in template, every value already a real example rather than a blank to guess the shape of:

data <- template_data("overdose_spike_alert")

See ?render_onepager for every argument, or run vignette("getting-started", package = "onepagr") for a fuller walkthrough. For a realistic, worked example that starts from real public data and runs a small analysis before rendering (rather than a hand-typed values list), see vignette("end-to-end-workflow", package = "onepagr").

Built-in templates

Each template is a distinct informational shape, not a variation on the same layout:

Template Shape Pages
cohort_summary Contrasts two groups at a point in time Fixed, 2
trend_snapshot Tracks one metric across several periods Fixed, 2
overdose_spike_alert Anomaly/threshold alert (ODMAP-style) 1-2, natural
syndromic_alert Anomaly/threshold alert, any syndrome (ESSENCE-style) 1-2, natural
county_choropleth Geographic bivariate comparison across counties Fixed, 2

List them programmatically with list_templates(). Want to see one without any real data yet? export_template("cohort_summary", "my-report/") copies the template plus everything it needs to compile, into your own project, ready to read, hand-edit, or extend.

Gallery

Every image below is an actual render_onepager() output (sample data, default theme), not a mock-up. For the fixed two-page templates, the front page is on the left and the back page on the right.

cohort_summary

Cohort Summary template: a two-page one-pager contrasting a linked cohort against all cases across region, demographics, and encounter history, with a lessons-learned callout and implementation timeline.

trend_snapshot

Trend Snapshot template: a two-page one-pager tracking a single metric across several time periods with period-over-period comparison bars.

county_choropleth

County Choropleth template: a two-page one-pager with a bivariate choropleth map on the front and four component-factor maps on the back.

overdose_spike_alert

Overdose Spike Alert template: a single-page anomaly alert bulletin with headline stat cards, a narrative section, geographic breakdown, and recommended actions.

syndromic_alert

Syndromic Alert template: a single-page anomaly alert bulletin generalized to any syndrome, structured like the overdose spike alert.

Themes

onepagr ships three built-in themes, which can be selected by name: default (a brand-neutral palette built on Bootstrap's own color variables), uk (University of Kentucky and KIPRC branding), and kdph (Kentucky Department for Public Health colors and fonts, following the department's 2026 Data Visualization Style Guidelines; unofficial and not endorsed by KDPH).

render_onepager(data, template = "trend_snapshot", theme = "default", output = "report.pdf")

Your own project can supply a completely custom theme instead of a built-in name:

render_onepager(data, template = "trend_snapshot", theme_path = "my-theme.typ", output = "report.pdf")

A theme is a single Typst dictionary of colors, typography, and spacing tokens. See any file in inst/typst/themes/ for the full schema, or list_themes() to see what's built in.

Type size and spacing are adjustable too: a theme can set a minimum text size (min-font-size) plus a font scale and a spacing scale, and any of them can be overridden for one render. See vignette("theming").

Logos are separate from theming: every template takes a primary logo (always shown) plus two optional partner logos, off by default and switched on independently via show_partner_a/show_partner_b. A single organization needs only the primary logo; a two-agency partnership and a three-organization lockup are first-class cases too, with no template editing required. A font_dir argument to render_onepager() makes a directory of font files available to Typst for a compile, for a theme's font that isn't installed system-wide. See vignette("theming") for all of the above.

Accessibility

Every built-in template and theme has been verified with PAC (PDF Accessibility Checker) against both the PDF/UA and WCAG tabs, not just Typst's own --pdf-standard ua-1 compile-time check. If you write your own theme or template, re-run that check yourself. A color or layout choice that passes for one template's usage isn't automatically safe for another (see the package's own development notes on why large-text-safe colors aren't automatically small-text-safe).

If you run PAC yourself, its "AI-assisted" tab (a heuristic advisory, not a conformance check) may flag two findings on the built-in templates that are already investigated and are not accessibility defects:

  • "H/P element detected, but no corresponding structural element exists," on the header/footer logos. A false positive: each logo is a raster image with the organization's name already carried as its alt text, and the heuristic appears to independently read that same name from the image's pixels, expecting matching text that correctly doesn't exist.
  • "Table element detected, but no table structure exists," on a template's bar-chart rows. Technically correct: those rows use Typst's #grid(), not #table(), so there is no /Table tag. Left as-is for now, since real table semantics need Typst primitives this version documents as preliminary and possibly removed.

Neither affects the PDF/UA or WCAG tabs, which is the actual conformance bar every built-in template is held to and where "100% passing" refers to.

Development

This package was developed with the assistance of AI coding tools (Claude Code). Every accessibility claim in this README and in the package's own comments reflects an actual verification run (a real Typst --pdf-standard ua-1 compile, a real PAC check, or a real computed WCAG contrast ratio), not an assumption, whichever tool did the typing. AI-assisted development is also part of why onepagr is structured the way it is: render_onepager() never hides the .typ source it compiles from, and export_template() exists specifically so a real, working template is always available to hand to an AI assistant, or a human collaborator, to extend.

License

MIT. See LICENSE.md.

The package logo (man/figures/logo.png) incorporates Microsoft's Fluent System Icon Accessibility Checkmark 20 Regular (MIT). See data-raw/hex-sticker/ICON-LICENSE.md for full attribution and the unmodified source SVG.

Citation

citation("onepagr")

Acknowledgements

onepagr is a thin layer over other people's work, and it would not exist without it.

  • Typst is the typesetting system every template is written in. Its support for tagged, PDF/UA-1 accessible output (Typst 0.14 onward) is what makes an accessible one-page report possible in the first place.
  • Quarto bundles the Typst compiler and gives onepagr a dependable way to find and run it, and the quarto R package is how onepagr locates a Quarto installation from R.
  • whisker implements Mustache templating in R and fills every template's {{{token}}} placeholders with your data.
  • jsonlite reads Typst's own view of a theme when check_theme() validates one, scales formats the numbers and percentages, and pdftools reads page counts and text geometry from the finished PDFs.
  • PAC, the PDF Accessibility Checker from the Access for All foundation, is what the accessibility claims above were checked against.
  • The default theme's palette is built on the color variables from Bootstrap 5.3.

Thank you to everyone who builds and maintains these.

Funding

This project is supported by the Centers for Disease Control and Prevention (CDC) of the U.S. Department of Health and Human Services (HHS) as part of cooperative agreement 1 NU17CE010186 totaling $5,769,396 with 0% financed with nongovernmental sources. The contents are those of the author(s) and do not necessarily represent the official views of, nor an endorsement by, CDC, HHS, or the U.S. government. For more information, please visit CDC.gov.

Machine-readable citation metadata is also available in CITATION.cff.

About

Generate polished, accessible one-page (front-and-back) PDF reports from analysis output, using a small set of fixed Typst templates and a swappable design-token theme system built using Quarto.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages