Content not found. Please use links in the navbar. # Page not found (404) # Data in: the cards → tabular pipeline tabular displays a **wide** frame; clinical aggregation produces a **long** Analysis Results Dataset (ARD). [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) is the bridge — it widens an ARD into the frame [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) consumes. ![An ADaM dataset is aggregated into a long ARD, which pivot_across widens into a wide data frame consumed by tabular.](../reference/figures/data-pipeline.svg) From analysis data to a display-ready frame: aggregate upstream into a long ARD, then [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) widens it into the wide frame [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) consumes. The ARDs used below ship with the package, so these examples run without cards/cardx installed; each is shown next to the code that produced it. ## The one rule: key `statistic` by the ARD’s `context` `pivot_across(statistic = list(...))` matches its list names against the ARD’s `context` column **verbatim**. That value depends on which function built the ARD — use the wrong key and those rows are dropped **silently**. Always check `unique(ard$context)` first. | Generating function | `context` | |-----------------------------------|-----------------------------| | `cards::ard_summary()` | `summary` | | `cards::ard_tabulate()` | `tabulate` | | `cards::ard_continuous()` | `continuous` | | `cards::ard_categorical()` | `categorical` | | `cards::ard_stack_hierarchical()` | `tabulate` + `hierarchical` | | `cardx::ard_categorical_ci()` | `proportion_ci` | | `cardx::ard_continuous_ci()` | `continuous_ci` | A single string, or `statistic = list(default = ...)`, applies one format to every context. ## Mixed continuous + categorical `cdisc_saf_demo_ard` was stacked from a continuous and a categorical block, so it carries the `continuous` and `categorical` contexts: ``` r # how it was built (data-raw): cdisc_saf_demo_ard <- cards::ard_stack( adsl, .by = TRT01A, cards::ard_continuous( variables = c(AGE, BMI), statistic = ~ cards::continuous_summary_fns(c( "N", "mean", "sd", "median", "min", "max" )) ), cards::ard_categorical(variables = c(AGEGR1, SEX, RACE)) ) ``` ``` r data(cdisc_saf_demo_ard, package = "tabular") unique(cdisc_saf_demo_ard$context) #> [1] "continuous" "categorical" "tabulate" wide <- pivot_across( cdisc_saf_demo_ard, statistic = list( continuous = c( N = "{N}", "Mean (SD)" = "{mean} ({sd})", Median = "{median}", "Min, Max" = "{min}, {max}" ), categorical = "{n} ({p}%)" ), # CDISC precision: SD carries one more decimal than the mean. AGE/BMI are # whole numbers here (raw precision d = 0), so mean = d + 1 = 1, sd = d + 2 = 2, # median = d + 1 = 1, and min/max keep the raw precision (0). decimals = c(mean = 1, sd = 2, median = 1, min = 0, max = 0, p = 0) ) head(wide, 8) #> variable stat_label Placebo Xanomeline High Dose Xanomeline Low Dose #> 1 AGE N 86 72 96 #> 2 AGE Mean (SD) 75.2 (8.59) 73.8 (7.94) 76.0 (8.11) #> 3 AGE Median 76.0 75.5 78.0 #> 4 AGE Min, Max 52, 89 56, 88 51, 88 #> 5 WEIGHT N 86 72 95 #> 6 WEIGHT Mean (SD) 62.8 (12.77) 69.5 (14.35) 68.0 (14.50) #> 7 WEIGHT Median 60.6 69.0 66.7 #> 8 WEIGHT Min, Max 34, 86 44, 108 42, 106 #> Total #> 1 254 #> 2 75.1 (8.25) #> 3 77.0 #> 4 51, 89 #> 5 253 #> 6 66.6 (14.13) #> 7 66.7 #> 8 34, 108 ``` `decimals = c(p = 0)` gives integer percent with the pharma `<1` / `>99` thresholds; `n = 0` cells collapse to a bare `"0"` automatically. The widened frame is now ready for [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) — see [Structure](https://vthanik.github.io/tabular/articles/structure.md). ## Confidence-interval cells (and hand-built ARDs) cardx CI functions emit their own contexts (`proportion_ci`, `continuous_ci`) with `estimate` / `conf.low` / `conf.high` stats. [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) consumes **any frame that follows the cards long-format**, so you can feed it a cardx ARD *or* build the few rows by hand — useful when a statistic is computed outside cards: ``` r # from cardx: orr_ard <- cardx::ard_categorical_ci( resp, by = "TRT01A", variables = "RESP", method = "clopper-pearson", conf.level = 0.95 ) ``` ``` r # equivalent hand-built ARD (one row group, proportion_ci context). # tribble() lays the long ARD out as a literal table: one row per # (arm, stat), with the estimate and its CI bounds visible inline. orr_ard <- tibble::tribble( ~group1, ~group1_level, ~variable, ~variable_level, ~context, ~stat_name, ~stat, "TRT01A", "Placebo", "RESP", "Responders", "proportion_ci", "estimate", 0.62, "TRT01A", "Placebo", "RESP", "Responders", "proportion_ci", "conf.low", 0.50, "TRT01A", "Placebo", "RESP", "Responders", "proportion_ci", "conf.high", 0.73, "TRT01A", "Xanomeline Low Dose", "RESP", "Responders", "proportion_ci", "estimate", 0.55, "TRT01A", "Xanomeline Low Dose", "RESP", "Responders", "proportion_ci", "conf.low", 0.42, "TRT01A", "Xanomeline Low Dose", "RESP", "Responders", "proportion_ci", "conf.high", 0.67, "TRT01A", "Xanomeline High Dose", "RESP", "Responders", "proportion_ci", "estimate", 0.48, "TRT01A", "Xanomeline High Dose", "RESP", "Responders", "proportion_ci", "conf.low", 0.36, "TRT01A", "Xanomeline High Dose", "RESP", "Responders", "proportion_ci", "conf.high", 0.60, ) pivot_across( orr_ard, statistic = list(proportion_ci = "{estimate} ({conf.low}, {conf.high})"), decimals = c(estimate = 3, conf.low = 3, conf.high = 3) ) #> variable stat_label Placebo Xanomeline Low Dose #> 1 RESP Responders 0.620 (0.500, 0.730) 0.550 (0.420, 0.670) #> Xanomeline High Dose #> 1 0.480 (0.360, 0.600) ``` ## Hierarchical SOC / PT A hierarchical ARD widens to a `soc` / `label` / `row_type` triple (not a single `variable`), ready for an indented SOC ▸ PT layout: ``` r data(cdisc_saf_aesocpt_ard, package = "tabular") ae <- pivot_across(cdisc_saf_aesocpt_ard, statistic = "{n} ({p}%)") ae$indent_level <- as.integer(ae$row_type == "pt") # depth for col_spec(indent = "indent_level") head(ae, 6) #> soc label #> 1 Overall Overall #> 2 SKIN AND SUBCUTANEOUS TISSUE DISORDERS SKIN AND SUBCUTANEOUS TISSUE DISORDERS #> 3 SKIN AND SUBCUTANEOUS TISSUE DISORDERS PRURITUS #> 4 SKIN AND SUBCUTANEOUS TISSUE DISORDERS ERYTHEMA #> 5 SKIN AND SUBCUTANEOUS TISSUE DISORDERS RASH #> 6 SKIN AND SUBCUTANEOUS TISSUE DISORDERS HYPERHIDROSIS #> row_type Placebo Xanomeline High Dose Xanomeline Low Dose indent_level #> 1 overall 52 (60%) 66 (92%) 81 (84%) 0 #> 2 soc 19 (22%) 35 (49%) 36 (38%) 0 #> 3 pt 8 (9%) 25 (35%) 21 (22%) 1 #> 4 pt 8 (9%) 14 (19%) 14 (15%) 1 #> 5 pt 5 (6%) 8 (11%) 13 (14%) 1 #> 6 pt 2 (2%) 8 (11%) 4 (4%) 1 ``` (Turning `soc`/`label`/`indent_level` into the indented stub is in [Structure](https://vthanik.github.io/tabular/articles/structure.md).) ## A two-variable `.by` `ard_stack(.by = c(ARM, SEX))` carries a second grouping variable. Name it with `row_group =` and [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) widens it into a **leading row column** (rather than mis-reading it as a SOC/PT hierarchy). Here is the cards long shape such a stack produces (RACE by ARM within SEX), built by hand so the example runs without cards: ``` r # RACE by ARM within SEX, laid out as a literal tribble: one row per # (sex, race, arm, stat). Stats are placeholders (n = 10, p = 0.25). two_by_ard <- tibble::tribble( ~group1, ~group1_level, ~group2, ~group2_level, ~variable, ~variable_level, ~context, ~stat_name, ~stat, "ARM", "Placebo", "SEX", "F", "RACE", "WHITE", "categorical", "n", 10, "ARM", "Placebo", "SEX", "F", "RACE", "WHITE", "categorical", "p", 0.25, "ARM", "Drug", "SEX", "F", "RACE", "WHITE", "categorical", "n", 10, "ARM", "Drug", "SEX", "F", "RACE", "WHITE", "categorical", "p", 0.25, "ARM", "Placebo", "SEX", "F", "RACE", "BLACK", "categorical", "n", 10, "ARM", "Placebo", "SEX", "F", "RACE", "BLACK", "categorical", "p", 0.25, "ARM", "Drug", "SEX", "F", "RACE", "BLACK", "categorical", "n", 10, "ARM", "Drug", "SEX", "F", "RACE", "BLACK", "categorical", "p", 0.25, "ARM", "Placebo", "SEX", "M", "RACE", "WHITE", "categorical", "n", 10, "ARM", "Placebo", "SEX", "M", "RACE", "WHITE", "categorical", "p", 0.25, "ARM", "Drug", "SEX", "M", "RACE", "WHITE", "categorical", "n", 10, "ARM", "Drug", "SEX", "M", "RACE", "WHITE", "categorical", "p", 0.25, "ARM", "Placebo", "SEX", "M", "RACE", "BLACK", "categorical", "n", 10, "ARM", "Placebo", "SEX", "M", "RACE", "BLACK", "categorical", "p", 0.25, "ARM", "Drug", "SEX", "M", "RACE", "BLACK", "categorical", "n", 10, "ARM", "Drug", "SEX", "M", "RACE", "BLACK", "categorical", "p", 0.25, ) pivot_across( two_by_ard, column = "ARM", row_group = "SEX", statistic = list(categorical = "{n} ({p}%)") ) #> SEX variable stat_label Placebo Drug #> 1 F RACE WHITE 10 (25%) 10 (25%) #> 2 F RACE BLACK 10 (25%) 10 (25%) #> 3 M RACE WHITE 10 (25%) 10 (25%) #> 4 M RACE BLACK 10 (25%) 10 (25%) ``` When a 2-variable `.by` is present you must say which variable is the arm column (`column =`) and which is the row dimension (`row_group =`); the `SEX` column then composes with [`subgroup()`](https://vthanik.github.io/tabular/reference/subgroup.md) or [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) downstream. cards encodes a crossing factor and a real hierarchy identically, so the declaration is what disambiguates them — leave `row_group` unset for a genuine SOC/PT hierarchy. ## Variables as column bands Two analysis variables side by side — `AVAL` (“Value”) and `PCHG` (“Percent Change from Baseline”) — is the canonical “value and change” shell. Make the **variable** a column band with the reserved `.variable` token in `column`. Each band keys its own `statistic` / `decimals`, so the bands may carry different (even different-length) stat lists; ragged bands pad with `NA`. ``` r # AVAL + PCHG by AVISIT x TRTA, built by hand so the example runs without cards. valchg_ard <- tibble::tribble( ~group1, ~group1_level, ~group2, ~group2_level, ~variable, ~context, ~stat_name, ~stat, "AVISIT", "DAY 1", "TRTA", "Drug", "AVAL", "continuous", "N", 20, "AVISIT", "DAY 1", "TRTA", "Drug", "AVAL", "continuous", "mean", 324, "AVISIT", "DAY 1", "TRTA", "Drug", "AVAL", "continuous", "sd", 106, "AVISIT", "DAY 1", "TRTA", "Drug", "AVAL", "continuous", "median", 315, "AVISIT", "DAY 1", "TRTA", "Placebo", "AVAL", "continuous", "N", 20, "AVISIT", "DAY 1", "TRTA", "Placebo", "AVAL", "continuous", "mean", 318, "AVISIT", "DAY 1", "TRTA", "Placebo", "AVAL", "continuous", "sd", 98, "AVISIT", "DAY 1", "TRTA", "Placebo", "AVAL", "continuous", "median", 310, "AVISIT", "DAY 1", "TRTA", "Drug", "PCHG", "continuous", "N", 20, "AVISIT", "DAY 1", "TRTA", "Drug", "PCHG", "continuous", "mean", -16, "AVISIT", "DAY 1", "TRTA", "Drug", "PCHG", "continuous", "sd", 5, "AVISIT", "DAY 1", "TRTA", "Placebo", "PCHG", "continuous", "N", 20, "AVISIT", "DAY 1", "TRTA", "Placebo", "PCHG", "continuous", "mean", -14, "AVISIT", "DAY 1", "TRTA", "Placebo", "PCHG", "continuous", "sd", 5, ) ``` **Stats as rows** — `column = c(".variable", "")`. Each variable becomes a band of arm columns; the statistics stack as rows and cells are combined strings. The emitted columns are named `".."`: ``` r pivot_across( valchg_ard, column = c(".variable", "TRTA"), row_group = "AVISIT", statistic = list( AVAL = c(N = "{N}", "Mean (SD)" = "{mean} ({sd})", Median = "{median}"), PCHG = c(N = "{N}", "Mean (SD)" = "{mean} ({sd})") ), decimals = list(AVAL = c(mean = 1, sd = 2, median = 1), PCHG = c(mean = 1, sd = 2)) ) #> AVISIT stat_label AVAL..Drug AVAL..Placebo PCHG..Drug PCHG..Placebo #> 1 DAY 1 N 20 20 20 20 #> 2 DAY 1 Mean (SD) 324.0 (106.00) 318.0 (98.00) -16.0 (5.00) -14.0 (5.00) #> 3 DAY 1 Median 315.0 310.0 ``` **Stats as columns** — `column = c(".variable", ".stat")`. Each statistic entry becomes its own column (the landscape shell) and the arm drops to a leading row stub. The emitted columns are named `".."`: ``` r pivot_across( valchg_ard, column = c(".variable", ".stat"), row_group = "AVISIT", statistic = list( AVAL = c(N = "{N}", Mean = "{mean}", SD = "{sd}"), PCHG = c(N = "{N}", Mean = "{mean}") ), decimals = c(mean = 1, sd = 2) ) #> AVISIT TRTA AVAL..N AVAL..Mean AVAL..SD PCHG..N PCHG..Mean #> 1 DAY 1 Drug 20 324.0 106.00 20 -16.0 #> 2 DAY 1 Placebo 20 318.0 98.00 20 -14.0 ``` You reference the emitted `".."` / `".."` names verbatim in a manual [`headers()`](https://vthanik.github.io/tabular/reference/headers.md) call to draw the band spanners — [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) never builds spanners itself. ## Auxiliary comparison columns A between-arm comparison (difference, hazard ratio, p-value) is **not** a pivot of the main ARD’s rows — it is a separate ARD (e.g. from `cardx`). Bind it with `aux =`, aligned 1:1 on the `row_group` key; the entry name becomes the column. ``` r resp_main <- tibble::tribble( ~group1, ~group1_level, ~group2, ~group2_level, ~variable, ~context, ~stat_name, ~stat, "PARAM", "ORR", "TRTA", "Exp", "AVAL", "continuous", "mean", 2.2, "PARAM", "ORR", "TRTA", "Ctl", "AVAL", "continuous", "mean", 1.9, "PARAM", "DCR", "TRTA", "Exp", "AVAL", "continuous", "mean", 2.4, "PARAM", "DCR", "TRTA", "Ctl", "AVAL", "continuous", "mean", 2.0, ) diff_ard <- tibble::tribble( ~group1, ~group1_level, ~variable, ~context, ~stat_name, ~stat, "PARAM", "ORR", "d", "continuous", "mean", 0.12, "PARAM", "DCR", "d", "continuous", "mean", 0.20, ) pivot_across( resp_main, column = "TRTA", row_group = "PARAM", statistic = list(continuous = "{mean}"), aux = list( "Difference" = list(ard = diff_ard, statistic = "{mean}", decimals = c(mean = 2)) ) ) #> PARAM variable stat_label Exp Ctl Difference #> 1 ORR AVAL AVAL 2.2 1.9 0.12 #> 2 DCR AVAL AVAL 2.4 2.0 0.20 ``` One `aux` entry is one column; add more entries (estimate then p-value) for several comparison columns. The auxiliary ARD must reduce to one row per `row_group` key — a many-to-many alignment aborts rather than fabricate rows. ## Key `statistic` by the context The one thing to get right: key `statistic` by the ARD’s `context`. Inspect `unique(ard$context)` and key the list to match (or pass a single string / `default =`). If an explicitly-supplied `statistic` matches **no** context, [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) warns rather than silently falling back to `{n}`. # Articles ### Articles - [Data in: the cards → tabular pipeline](https://vthanik.github.io/tabular/articles/data-in.md): - [Structure: columns, headers, and pagination](https://vthanik.github.io/tabular/articles/structure.md): - [Presentation: titles, footnotes, page chrome, and styling](https://vthanik.github.io/tabular/articles/presentation.md): - [Recipes: the CDISC-pilot tables, end to end](https://vthanik.github.io/tabular/articles/recipes.md): - [Output & qualification: backends, requirements, and the CDISC pilot](https://vthanik.github.io/tabular/articles/output.md): # Output & qualification: backends, requirements, and the CDISC pilot This article is about *rendering and proving* — choosing a backend, meeting its system requirements, and the cross-backend validation. It does not cover building or styling a table (see the other articles). ## `emit()` and `as_grid()` [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) writes a file, dispatching on the extension: ``` r emit(spec, "table.rtf") # RTF emit(spec, "table.html") # HTML emit(spec, "table.docx") # Word emit(spec, "table.tex") # LaTeX source emit(spec, "table.typ") # Typst source emit(spec, "table.pdf") # PDF (LaTeX engine, or typst without a TeX) emit(spec, "table.md") # Markdown ``` A `.pdf` target compiles through one of **two engines**. With no `format =`, [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) probes the machine LaTeX-first: a usable TeX keeps the LaTeX path; otherwise a discoverable typst binary (standalone `typst`, or the copy bundled inside Quarto ≥ 1.4) takes over; with neither, the call aborts up front naming both remedies. Pick an engine explicitly with `format = "latex"` or `format = "typst"`: ``` r emit(spec, "table.pdf", format = "latex") # force the TeX compile emit(spec, "table.pdf", format = "typst") # force typst — no TeX needed ``` It returns the written path invisibly, so the emit is chainable into scripted batch runs. One spec, any backend: ``` r data(cdisc_saf_demo, package = "tabular") spec <- tabular(cdisc_saf_demo, titles = "Demographics") |> cols( variable = col_spec(label = ""), stat_label = col_spec(label = "") ) |> group_rows(by = "variable") path <- emit(spec, tempfile(fileext = ".rtf")) file.exists(path) #> [1] TRUE ``` `as_grid(spec)` resolves the fully-laid-out grid **without** writing a file — useful for testing or programmatic inspection. The grid carries the resolved pages plus a metadata block (pagination counts, resolved column names, the effective preset): ``` r grid <- as_grid(spec) length(grid@pages) #> [1] 1 grid@metadata$col_names #> [1] "variable" "stat_label" "placebo" "drug_50" "drug_100" #> [6] "Total" ``` ## Backend capability matrix One spec renders to every backend, but the page-oriented features differ: | Capability | RTF | HTML | DOCX | PDF/LaTeX | PDF/Typst | MD | |----|:--:|:--:|:--:|:--:|:--:|:--:| | Vertical pagination | ✓ | n/a¹ | ✓ | ✓ | ✓ | n/a | | Horizontal panels (`panels=`) | ✓ | n/a¹ | ✓ | ✓ | ✓ | n/a | | Per-page running header/footer | ✓ | – | ✓ | ✓ | ✓ | – | | [`subgroup()`](https://vthanik.github.io/tabular/reference/subgroup.md) per-page BigN | ✓ | row² | ✓ | ✓ | ✓ | row² | | Continuation marker | panels only | – | – | ✓ | panels only | – | | Keep-together / orphan control | ✓ | n/a¹ | ✓ | ✓ | ✓ | n/a | | Decimal alignment (NBSP) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | System dependency | none | none | none | TeX install | typst³ | none | ¹ HTML/MD are one continuous document; the browser repeats `` on print. ² On HTML/MD the per-page N renders as a row under each subgroup banner instead of in the repeating header. ³ The standalone `typst` binary, or the copy bundled inside Quarto ≥ 1.4 — so machines with RStudio / Posit Workbench typically need nothing. The `.tex` and `.typ` *source* backends have no system dependency at all; only the compile to PDF does. ## System requirements **RTF, HTML, DOCX, LaTeX source, Typst source, Markdown need nothing beyond the R package.** Only the compile to PDF has a system dependency, and either engine satisfies it: - **LaTeX engine.** The two packages missing from common TeX distributions (`tabularray`, `ninecolors`) ship *with* `tabular` and are staged next to the generated `.tex` whenever the local TeX cannot resolve them, so a locked-down server (Domino, Posit Workbench) needs no `tlmgr install`. - **Typst engine.** No TeX at all: [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) runs the standalone `typst` binary, or Quarto’s bundled copy (`quarto typst`). Fonts are typst’s one quiet failure mode — a missing family substitutes silently — so [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) warns when a family you explicitly named cannot be found, and [`check_typst()`](https://vthanik.github.io/tabular/reference/check_typst.md) names the face PDFs actually render in. Check readiness and, on a fresh machine, install an engine once: ``` r check_latex() # LaTeX engine: probes via kpsewhich — what a compile will find check_typst() # Typst engine: binary, version floor, font chain tinytex::install_tinytex(bundle = "TinyTeX") # one-time, fresh machines only # or install Quarto (https://quarto.org), which bundles the typst engine ``` > **OS-managed TeX Live (RHEL/dnf, Debian/apt):** `tlmgr` is locked and > refuses to install (“will likely destroy the … TeXLive install”). Do > **not** force it with `--ignore-warning`. Usually nothing is needed > anyway — the bundled copies cover the gap; if > [`check_latex()`](https://vthanik.github.io/tabular/reference/check_latex.md) > still reports a missing package, install a user-space TinyTeX you > control: `tinytex::install_tinytex(bundle = "TinyTeX")`, then restart > R. On images whose TeX Live is frozen on a pre-2023 kernel (too old > for `tabularray`), > [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) skips > LaTeX automatically and compiles through typst instead. For decimal alignment in paper backends, metric-compatible fonts matter — check with `check_fonts(spec)`. ## Troubleshooting - **A relative DOCX path works.** `emit(spec, "out/x.docx")` resolves the path against your working directory like every other backend (the output path is absolutised before the OOXML zip is staged). No [`normalizePath()`](https://rdrr.io/r/base/normalizePath.html) dance is needed. - **If a PDF build appears to hang,** it is the LaTeX engine stopping at an interactive error prompt — fix the underlying LaTeX dependency (run [`check_latex()`](https://vthanik.github.io/tabular/reference/check_latex.md)), or sidestep TeX entirely with `emit(spec, "out.pdf", format = "typst")`; render RTF/HTML to keep working in the meantime. - **If a typst-compiled PDF renders in an unexpected font,** run [`check_typst()`](https://vthanik.github.io/tabular/reference/check_typst.md) — it names the first available family of the chain, i.e. the face typst actually uses. Missing *later* members of the built-in fallback chain are normal cross-OS variance and are not warned about; only a family you explicitly named triggers the [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) warning. ## Cross-backend qualification (CDISC pilot) The package ships a qualification (`inst/qualification/`) that rebuilds representative CDISC-pilot tables (demographics, populations, AE overview, AE by SOC/PT) from the public PHUSE Test Data Factory ADaM and renders **each to every backend**, checking three things per cell: it emits without error, the file is structurally valid, and an **independent count computed from the ADaM appears in the rendered text of that backend** (cross-backend content parity). The four pilot tables across all four file backends give a 16/16 PASS matrix: | Table | RTF | HTML | DOCX | PDF¹ | |------------------------|:----:|:----:|:----:|:----:| | 14-2.01 Demographics | PASS | PASS | PASS | PASS | | 14-1.01 Populations | PASS | PASS | PASS | PASS | | 14-3.01 TEAE overview | PASS | PASS | PASS | PASS | | 14-3.04 TEAE by SOC/PT | PASS | PASS | PASS | PASS | ¹ The PDF column is verified **manually in a local environment** with a LaTeX engine ([`check_latex()`](https://vthanik.github.io/tabular/reference/check_latex.md)) and `pdftotext` for the text-parity check. It is **not run in continuous integration**, which carries no TeX install; CI exercises the RTF, HTML, and DOCX backends. The runnable script (`inst/qualification/qualify_tabular_cdisc.R`) and how to fetch the data are in the qualification README in that same `inst/qualification/` folder; it is the most direct evidence that one `tabular` spec produces consistent, correct output across all backends. # Presentation: titles, footnotes, page chrome, and styling This article is about the *look* — titles, footnotes, the running page header / footer, and cell styling. It assumes the table’s shape is already built (see [Structure](https://vthanik.github.io/tabular/articles/structure.md)) and never explains data prep or pagination for its own sake. ## Titles and footnotes Multi-line titles and static footnotes are arguments to [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md): ``` r tabular( cdisc_saf_demo, titles = c( "Table 14-2.01", "Demographic and Baseline Characteristics", "ITT Population" ), footnotes = c( "Percentages are based on the number of ITT subjects per arm.", "BMI = body mass index." ) ) |> cols( variable = col_spec(label = ""), stat_label = col_spec(label = "") ) |> group_rows(by = "variable") |> cols_apply(arms, col_spec(align = "decimal")) ``` | | placebo | drug_50 | drug_100 | Total | |----|----|----|----|----| | **Age (years)** | | | | | | n | 86          | 96          | 72          | 254          | | Mean (SD) | 75.2 (8.59) | 76.0 (8.11) | 73.8 (7.94) |  75.1 (8.25) | | Median | 76.0        | 78.0        | 75.5        |  77.0        | | Q1, Q3 | 69.2, 81.8  | 71.0, 82.0  | 70.5, 79.0  |  70.0, 81.0  | | Min, Max | 52  , 89    | 51  , 88    | 56  , 88    |  51  , 89    | |   | | | | | | **Sex, n (%)** | | | | | | F | 53 (61.6)   | 55 (57.3)   | 35 (48.6)   | 143 (56.3)   | | M | 33 (38.4)   | 41 (42.7)   | 37 (51.4)   | 111 (43.7)   | |   | | | | | | **Race, n (%)** | | | | | | WHITE | 78 (90.7)   | 90 (93.8)   | 62 (86.1)   | 230 (90.6)   | | BLACK OR AFRICAN AMERICAN |  8 ( 9.3)   |  6 ( 6.2)   |  9 (12.5)   |  23 ( 9.1)   | | ASIAN |  0          |  0          |  0          |   0          | | AMERICAN INDIAN OR ALASKA NATIVE |  0          |  0          |  1 ( 1.4)   |   1 ( 0.4)   | Percentages are based on the number of ITT subjects per arm. BMI = body mass index.   Table 14-2.01 Demographic and Baseline Characteristics ITT Population   For an **anchored** footnote (an auto-numbered superscript on a specific cell or header) use [`footnote()`](https://vthanik.github.io/tabular/reference/footnote.md) with a `cells_*()` location: ``` r base |> footnote( "Excludes one subject withdrawn before dosing.", .at = cells_headers(j = "Total") ) ``` | | placebo | drug_50 | drug_100 | Total^(a) | |----|----|----|----|----| | **Age (years)** | | | | | | n | 86          | 96          | 72          | 254          | | Mean (SD) | 75.2 (8.59) | 76.0 (8.11) | 73.8 (7.94) |  75.1 (8.25) | | Median | 76.0        | 78.0        | 75.5        |  77.0        | | Q1, Q3 | 69.2, 81.8  | 71.0, 82.0  | 70.5, 79.0  |  70.0, 81.0  | | Min, Max | 52  , 89    | 51  , 88    | 56  , 88    |  51  , 89    | |   | | | | | | **Sex, n (%)** | | | | | | F | 53 (61.6)   | 55 (57.3)   | 35 (48.6)   | 143 (56.3)   | | M | 33 (38.4)   | 41 (42.7)   | 37 (51.4)   | 111 (43.7)   | |   | | | | | | **Race, n (%)** | | | | | | WHITE | 78 (90.7)   | 90 (93.8)   | 62 (86.1)   | 230 (90.6)   | | BLACK OR AFRICAN AMERICAN |  8 ( 9.3)   |  6 ( 6.2)   |  9 (12.5)   |  23 ( 9.1)   | | ASIAN |  0          |  0          |  0          |   0          | | AMERICAN INDIAN OR ALASKA NATIVE |  0          |  0          |  1 ( 1.4)   |   1 ( 0.4)   | a Excludes one subject withdrawn before dosing. ## The running page header / footer Regulatory TFLs carry a header on every page (protocol, page X of Y, data-cut). That is preset page chrome, not a title. `pagehead` / `pagefoot` each take `left` / `right` (and `center`) vectors; the tokens `{page}`, `{npages}`, `{program}`, `{datetime}` resolve at render time: ``` r chrome <- base |> preset( pagehead = list( left = c("Analysis Set: Safety", "Protocol: XYZ-123"), right = c("Data cut: 2026-01-15", "Page {page} of {npages}") ) ) chrome ``` Protocol: XYZ-123 Analysis Set: Safety Page 1 of 1 Data cut: 2026-01-15 | | placebo | drug_50 | drug_100 | Total | |----|----|----|----|----| | **Age (years)** | | | | | | n | 86          | 96          | 72          | 254          | | Mean (SD) | 75.2 (8.59) | 76.0 (8.11) | 73.8 (7.94) |  75.1 (8.25) | | Median | 76.0        | 78.0        | 75.5        |  77.0        | | Q1, Q3 | 69.2, 81.8  | 71.0, 82.0  | 70.5, 79.0  |  70.0, 81.0  | | Min, Max | 52  , 89    | 51  , 88    | 56  , 88    |  51  , 89    | |   | | | | | | **Sex, n (%)** | | | | | | F | 53 (61.6)   | 55 (57.3)   | 35 (48.6)   | 143 (56.3)   | | M | 33 (38.4)   | 41 (42.7)   | 37 (51.4)   | 111 (43.7)   | |   | | | | | | **Race, n (%)** | | | | | | WHITE | 78 (90.7)   | 90 (93.8)   | 62 (86.1)   | 230 (90.6)   | | BLACK OR AFRICAN AMERICAN |  8 ( 9.3)   |  6 ( 6.2)   |  9 (12.5)   |  23 ( 9.1)   | | ASIAN |  0          |  0          |  0          |   0          | | AMERICAN INDIAN OR ALASKA NATIVE |  0          |  0          |  1 ( 1.4)   |   1 ( 0.4)   | The running header/footer is page chrome — it repeats on every page of the **paged backends** (RTF, PDF, DOCX) and does not appear in the single-page HTML preview above. Emit to a paged backend to see it: ``` r emit(chrome, "demographics.pdf") # protocol + page x of y on every page ``` > **Stacking direction.** Each vector stacks **outward from the table**: > index 1 is the line nearest the table body, later elements move toward > the page edge. For a header that reads “Analysis Set” on top and > “Protocol” just above the table, put `"Protocol…"` first. (Easy to > invert — check the rendered page.) ## Cell styling [`style()`](https://vthanik.github.io/tabular/reference/style.md) appends one location + attribute layer. Target a region with a `cells_*()` constructor; attributes include `bold`, `italic`, `underline`, `color`, `background`, and borders via [`brdr()`](https://vthanik.github.io/tabular/reference/brdr.md): ``` r base |> # the column-header band is bold by default, so style it with colour / # background for a visible change rather than re-applying bold style(color = "#1F3B5C", background = "#DBE4F0", .at = cells_headers()) |> style(italic = TRUE, .at = cells_group_headers()) |> # italic section rows style(background = "#F2F2F2", .at = cells_body(j = "Total")) # shade the Total column ``` | | placebo | drug_50 | drug_100 | Total | |----|----|----|----|----| | **Age (years)** | | | | | | n | 86          | 96          | 72          | 254          | | Mean (SD) | 75.2 (8.59) | 76.0 (8.11) | 73.8 (7.94) |  75.1 (8.25) | | Median | 76.0        | 78.0        | 75.5        |  77.0        | | Q1, Q3 | 69.2, 81.8  | 71.0, 82.0  | 70.5, 79.0  |  70.0, 81.0  | | Min, Max | 52  , 89    | 51  , 88    | 56  , 88    |  51  , 89    | |   | | | | | | **Sex, n (%)** | | | | | | F | 53 (61.6)   | 55 (57.3)   | 35 (48.6)   | 143 (56.3)   | | M | 33 (38.4)   | 41 (42.7)   | 37 (51.4)   | 111 (43.7)   | |   | | | | | | **Race, n (%)** | | | | | | WHITE | 78 (90.7)   | 90 (93.8)   | 62 (86.1)   | 230 (90.6)   | | BLACK OR AFRICAN AMERICAN |  8 ( 9.3)   |  6 ( 6.2)   |  9 (12.5)   |  23 ( 9.1)   | | ASIAN |  0          |  0          |  0          |   0          | | AMERICAN INDIAN OR ALASKA NATIVE |  0          |  0          |  1 ( 1.4)   |   1 ( 0.4)   | Body filters live on [`cells_body()`](https://vthanik.github.io/tabular/reference/cells.md): `i =` (row index), `j =` (column name), `where =` (an expression over the data). A border attribute takes a [`brdr()`](https://vthanik.github.io/tabular/reference/brdr.md) value — width, line style, colour. Here a hairline rule separates the pooled Total column from the per-arm columns: ``` r base |> style( border_left = brdr("hairline", "solid", "#ADB5BD"), .at = cells_body(j = "Total") ) ``` | | placebo | drug_50 | drug_100 | Total | |----|----|----|----|----| | **Age (years)** | | | | | | n | 86          | 96          | 72          | 254          | | Mean (SD) | 75.2 (8.59) | 76.0 (8.11) | 73.8 (7.94) |  75.1 (8.25) | | Median | 76.0        | 78.0        | 75.5        |  77.0        | | Q1, Q3 | 69.2, 81.8  | 71.0, 82.0  | 70.5, 79.0  |  70.0, 81.0  | | Min, Max | 52  , 89    | 51  , 88    | 56  , 88    |  51  , 89    | |   | | | | | | **Sex, n (%)** | | | | | | F | 53 (61.6)   | 55 (57.3)   | 35 (48.6)   | 143 (56.3)   | | M | 33 (38.4)   | 41 (42.7)   | 37 (51.4)   | 111 (43.7)   | |   | | | | | | **Race, n (%)** | | | | | | WHITE | 78 (90.7)   | 90 (93.8)   | 62 (86.1)   | 230 (90.6)   | | BLACK OR AFRICAN AMERICAN |  8 ( 9.3)   |  6 ( 6.2)   |  9 (12.5)   |  23 ( 9.1)   | | ASIAN |  0          |  0          |  0          |   0          | | AMERICAN INDIAN OR ALASKA NATIVE |  0          |  0          |  1 ( 1.4)   |   1 ( 0.4)   | `border` styles all four sides at once; `border_top` / `border_bottom` / `border_left` / `border_right` target one. The table-wide rules (toprule, midrule, bottomrule) are preset territory — see the `rules` knob on [`preset()`](https://vthanik.github.io/tabular/reference/preset.md). ## Inline markup Plain strings render as plain text — a stray `**` never silently bolds the surrounding span. Wrap a string in [`md()`](https://vthanik.github.io/tabular/reference/md.md) (CommonMark plus `^sup^` / `~sub~`) or [`html()`](https://vthanik.github.io/tabular/reference/html.md) (a constrained inline tag set) to opt in, the same convention gt uses. Every string slot accepts them: titles, footnotes, [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) labels, and [`style()`](https://vthanik.github.io/tabular/reference/style.md) pretext / posttext: ``` r tabular( cdisc_saf_demo, titles = c( "Table 14-2.01", "Demographic and Baseline Characteristics", md("*ITT Population*") ), footnotes = c( md("BMI = body mass index (kg/m^2^)."), html("Source: ADSL, data cut 15JAN2026.") ) ) |> cols( variable = col_spec(label = ""), stat_label = col_spec(label = "") ) |> group_rows(by = "variable") |> cols_apply(arms, col_spec(align = "decimal")) ``` | | placebo | drug_50 | drug_100 | Total | |----|----|----|----|----| | **Age (years)** | | | | | | n | 86          | 96          | 72          | 254          | | Mean (SD) | 75.2 (8.59) | 76.0 (8.11) | 73.8 (7.94) |  75.1 (8.25) | | Median | 76.0        | 78.0        | 75.5        |  77.0        | | Q1, Q3 | 69.2, 81.8  | 71.0, 82.0  | 70.5, 79.0  |  70.0, 81.0  | | Min, Max | 52  , 89    | 51  , 88    | 56  , 88    |  51  , 89    | |   | | | | | | **Sex, n (%)** | | | | | | F | 53 (61.6)   | 55 (57.3)   | 35 (48.6)   | 143 (56.3)   | | M | 33 (38.4)   | 41 (42.7)   | 37 (51.4)   | 111 (43.7)   | |   | | | | | | **Race, n (%)** | | | | | | WHITE | 78 (90.7)   | 90 (93.8)   | 62 (86.1)   | 230 (90.6)   | | BLACK OR AFRICAN AMERICAN |  8 ( 9.3)   |  6 ( 6.2)   |  9 (12.5)   |  23 ( 9.1)   | | ASIAN |  0          |  0          |  0          |   0          | | AMERICAN INDIAN OR ALASKA NATIVE |  0          |  0          |  1 ( 1.4)   |   1 ( 0.4)   | BMI = body mass index (kg/m²). Source: *ADSL*, data cut 15JAN2026.   Table 14-2.01 Demographic and Baseline Characteristics *ITT Population*   The marked string survives [`c()`](https://rdrr.io/r/base/c.html) concatenation, so plain and marked lines mix freely in one titles or footnotes vector. Raw HTML inside [`md()`](https://vthanik.github.io/tabular/reference/md.md) passes through the same tag whitelist as [`html()`](https://vthanik.github.io/tabular/reference/html.md); tags outside it drop their wrapper and keep the text. ## Presets: cosmetics and fit [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) carries the cosmetic defaults — fonts, rules, padding, `na_text`, paper/orientation/margins — and the **`width_mode`** that decides how the table fills the page: | `width_mode` | Effect | |----|----| | `"content"` *(default)* | columns sized to their content | | `"window"` | `"auto"` columns **stretch to fill** the printable width (Word “Auto-fit Window”) | | `"fixed"` | only the widths you pin are used | ``` r base |> preset( font_size = 9, orientation = "landscape", paper_size = "letter", margins = c(1, 0.75, 1, 0.75), width_mode = "window", na_text = "-" ) ``` | | placebo | drug_50 | drug_100 | Total | |----|----|----|----|----| | **Age (years)** | | | | | | n | 86          | 96          | 72          | 254          | | Mean (SD) | 75.2 (8.59) | 76.0 (8.11) | 73.8 (7.94) |  75.1 (8.25) | | Median | 76.0        | 78.0        | 75.5        |  77.0        | | Q1, Q3 | 69.2, 81.8  | 71.0, 82.0  | 70.5, 79.0  |  70.0, 81.0  | | Min, Max | 52  , 89    | 51  , 88    | 56  , 88    |  51  , 89    | |   | | | | | | **Sex, n (%)** | | | | | | F | 53 (61.6)   | 55 (57.3)   | 35 (48.6)   | 143 (56.3)   | | M | 33 (38.4)   | 41 (42.7)   | 37 (51.4)   | 111 (43.7)   | |   | | | | | | **Race, n (%)** | | | | | | WHITE | 78 (90.7)   | 90 (93.8)   | 62 (86.1)   | 230 (90.6)   | | BLACK OR AFRICAN AMERICAN |  8 ( 9.3)   |  6 ( 6.2)   |  9 (12.5)   |  23 ( 9.1)   | | ASIAN |  0          |  0          |  0          |   0          | | AMERICAN INDIAN OR ALASKA NATIVE |  0          |  0          |  1 ( 1.4)   |   1 ( 0.4)   | Use [`set_preset()`](https://vthanik.github.io/tabular/reference/set_preset.md) once at the top of a study to make these defaults apply to every table without restating them. > **Decimal alignment** (`col_spec(align = "decimal")`) pads numeric > cells with non-breaking spaces so the decimal points line up. Padding > is measured with the built-in font metrics > (`preset(decimal_metrics = "afm")`, the default), so alignment is > exact in Courier and exact to within one padding space in proportional > fonts such as Times New Roman or Arial. Markdown output pads by > character count instead — the right geometry for a text medium. # Recipes: the CDISC-pilot tables, end to end These are the canonical safety and efficacy tables a programmer builds from the shell — each one rendered **live** below from the bundled demo data, so what you see is exactly what the code produces. They mirror the package’s cross-backend qualification (`inst/qualification/`), which rebuilds the same displays from the real PHUSE Test Data Factory ADaM and checks them across every backend. Each recipe ends on the spec (the live HTML you see); the closing line shows how to **ship the same spec** to a submission backend — just change the extension. ## Demographics and baseline characteristics The reference safety table: a grouped parameter stub, indented statistic rows, decimal-aligned arm columns, and the population BigN folded into each header from `cdisc_saf_n`. ``` r n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) demo_tbl <- tabular( cdisc_saf_demo, titles = c( "Table 14.1.1", "Demographic and Baseline Characteristics", "Safety Population" ), footnotes = "Percentages are based on the number of subjects per treatment group." ) |> cols( variable = col_spec(label = "Parameter"), stat_label = col_spec(label = "Statistic"), placebo = col_spec( label = "Placebo\nN={n['placebo']}", align = "decimal" ), drug_50 = col_spec( label = "Drug 50\nN={n['drug_50']}", align = "decimal" ), drug_100 = col_spec( label = "Drug 100\nN={n['drug_100']}", align = "decimal" ), Total = col_spec(label = "Total\nN={n['Total']}", align = "decimal") ) |> group_rows(by = "variable") demo_tbl ``` [TABLE] Percentages are based on the number of subjects per treatment group.   Table 14.1.1 Demographic and Baseline Characteristics Safety Population   ``` r emit(demo_tbl, "t_14_1_1.rtf") # ship: or .pdf / .docx / .html / .md ``` ## Adverse-event overview A flat overview: `stat_label` is a plain display column carrying both the high-level flag rows and the two-space-indented maximum-severity detail rows (the indent is baked into the label strings), so each category sits on one line with its counts. ``` r ae_tbl <- tabular( cdisc_saf_ae, titles = c( "Table 14.3.0", "Overview of Treatment-Emergent Adverse Events", "Safety Population" ) ) |> cols( stat_label = col_spec(label = ""), placebo = col_spec( label = "Placebo\nN={n['placebo']}", align = "decimal" ), drug_50 = col_spec( label = "Drug 50\nN={n['drug_50']}", align = "decimal" ), drug_100 = col_spec( label = "Drug 100\nN={n['drug_100']}", align = "decimal" ), Total = col_spec(label = "Total\nN={n['Total']}", align = "decimal") ) ae_tbl ``` [TABLE]   Table 14.3.0 Overview of Treatment-Emergent Adverse Events Safety Population   ``` r emit(ae_tbl, "t_14_3_0.rtf") # ship: or .pdf / .docx / .html / .md ``` ## Adverse events by SOC and preferred term The two-level hierarchy: `label` holds SOC text on SOC rows and PT text on PT rows, indented by `indent_level`; the hidden `soc` / `row_type` / `n_total` / `soc_n` columns ride along as partition and sort keys. [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md) clusters PTs under their parent SOC and orders both levels by descending frequency. ``` r aesocpt_tbl <- tabular( cdisc_saf_aesocpt, titles = c( "Table 14.3.1", "Adverse Events by System Organ Class and Preferred Term", "Safety Population" ) ) |> cols( label = col_spec( label = "SOC / Preferred Term", indent = "indent_level" ), soc = col_spec(visible = FALSE), row_type = col_spec(visible = FALSE), n_total = col_spec(visible = FALSE), soc_n = col_spec(visible = FALSE), placebo = col_spec( label = "Placebo\nN={n['placebo']}", align = "decimal" ), drug_50 = col_spec( label = "Drug 50\nN={n['drug_50']}", align = "decimal" ), drug_100 = col_spec( label = "Drug 100\nN={n['drug_100']}", align = "decimal" ), Total = col_spec(label = "Total\nN={n['Total']}", align = "decimal") ) |> sort_rows(by = c("soc_n", "n_total"), descending = c(TRUE, TRUE)) aesocpt_tbl ``` [TABLE]   Table 14.3.1 Adverse Events by System Organ Class and Preferred Term Safety Population   This table is long, so a real deliverable paginates it — keeping each SOC and its preferred terms together. Pagination materialises in the paged backends (RTF, PDF, DOCX), so add [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md) and emit to one of those: ``` r aesocpt_tbl |> paginate(keep_together = "soc", continuation = "(continued)") |> emit("t_14_3_1.pdf") ``` ## Best overall response and response rates The efficacy companion: `group_label` synthesises one bold section band per analysis block (best overall response, ORR, CBR, DCR) via the default `"section"` display, with indented response rows beneath. Denominators come from `cdisc_eff_n`. ``` r ne <- stats::setNames(cdisc_eff_n$n, cdisc_eff_n$arm_short) resp_tbl <- tabular( cdisc_eff_resp, titles = c( "Table 14.2.1", "Best Overall Response and Response Rates", "Efficacy Evaluable Population" ) ) |> cols( stat_label = col_spec(label = "Response"), groupid = col_spec(visible = FALSE), row_type = col_spec(visible = FALSE), placebo = col_spec( label = "Placebo\nN={ne['placebo']}", align = "decimal" ), drug_50 = col_spec( label = "Drug 50\nN={ne['drug_50']}", align = "decimal" ), drug_100 = col_spec( label = "Drug 100\nN={ne['drug_100']}", align = "decimal" ) ) |> group_rows(by = "group_label") resp_tbl ``` [TABLE]   Table 14.2.1 Best Overall Response and Response Rates Efficacy Evaluable Population   ``` r emit(resp_tbl, "t_14_2_1.rtf") # ship: or .pdf / .docx / .html / .md ``` ## A figure in the same chrome The “F” in TFL. [`figure()`](https://vthanik.github.io/tabular/reference/figure.md) wraps a ggplot, a recorded base-R plot, a zero-argument drawing function, or a PNG / JPG file in the *same* submission chrome as a table — titles, footnotes, and the per-page header and footer — so a graph ships alongside its tables with identical page furniture. Here is the companion plot to the vitals table: mean diastolic blood pressure over visits, by arm, read straight from the bundled summary. ``` r # Mean (SD) rows from the bundled vitals summary, read as numeric means. diabp <- cdisc_saf_vital[ cdisc_saf_vital$paramcd == "DIABP" & cdisc_saf_vital$stat_label == "Mean (SD)", ] visit_order <- c("Baseline", "Week 8", "Week 16", "End of Treatment") diabp <- diabp[match(visit_order, diabp$visit), ] mean_of <- function(x) as.numeric(sub(" .*", "", x)) arms <- c(placebo = "Placebo", drug_50 = "Drug 50 mg", drug_100 = "Drug 100 mg") draw_diabp <- function() { ys <- do.call(cbind, lapply(names(arms), function(a) mean_of(diabp[[a]]))) matplot( seq_along(visit_order), ys, type = "b", pch = 16, lty = 1, col = seq_along(arms), xaxt = "n", xlab = "Visit", ylab = "Mean DIABP (mmHg)" ) axis(1, at = seq_along(visit_order), labels = visit_order, cex.axis = 0.8) legend( "topright", legend = unname(arms), pch = 16, lty = 1, col = seq_along(arms), bty = "n" ) } vital_fig <- figure( draw_diabp, titles = c( "Figure 7.1", "Mean Diastolic Blood Pressure by Visit", "Safety Population" ), footnotes = "Means are taken from the summary table; error bars omitted for clarity." ) vital_fig ``` ![Figure](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAACowAAAYiCAIAAACDy8tJAAAACXBIWXMAAC4jAAAuIwF4pT92AAAgAElEQVR4nOzdd3xV5eH48XNvBgGSALKFAspQw0gUsW7q3lats1qt+vVrHXWPr/1V695abR21Wq11t4pSkVaUClVcoBKBIAKyhLDCyCAh457fHyGXoBDC8ITxfv8F5NznPvfecJPX/ZznObEwDAMAAAAAAAAA4IcXb+oJAAAAAAAAAMD2QqQHAAAAAAAAgIiI9AAAAAAAAAAQEZEeAAAAAAAAACIi0gMAAAAAAABARER6AAAAAAAAAIiISA8AAAAAAAAAERHpAQAAAAAAACAiIj0AAAAAAAAARESkBwAAAAAAAICIiPQAAAAAAAAAEBGRHgAAAAAAAAAiItIDAAAAAAAAQEREegAAAAAAAACIiEgPAAAAAAAAABER6QEAAAAAAAAgIiI9AAAAAAAAAEREpAcAAAAAAACAiIj0AAAAAAAAABARkR4AAAAAAAAAIiLSAwAAAAAAAEBERHoAAAAAAAAAiIhIDwAAAAAAAAAREekBAAAAAAAAICIiPQAAAAAAAABERKQHAAAAAAAAgIiI9AAAAAAAAAAQEZEeAAAAAAAAACIi0gMAAAAAAABARER6AAAAAAAAAIiISA8AAAAAAAAAERHpAQAAAAAAACAiIj0AAAAAAAAARESkBwAAAAAAAICIiPQAAAAAAAAAEBGRHgAAAAAAAAAiItIDAAAAAAAAQEREegAAAAAAAACIiEgPAAAAAAAAABER6QEAAAAAAAAgIiI9AAAAAAAAAEREpAcAAAAAAACAiIj0AAAAAAAAABARkR4AAAAAAAAAIiLSAwAAAAAAAEBERHoAAAAAAAAAiIhIDwAAAAAAAAAREekBAAAAAAAAICIiPQAAAAAAAABERKQHAAAAAAAAgIiI9AAAAAAAAAAQEZEeAAAAAAAAACIi0gMAAAAAAABARER6AAAAAAAAAIiISA8AAAAAAAAAERHpAQAAAAAAACAiIj0AAAAAAAAARESkBwAAAAAAAICIiPQAAAAAAAAAEBGRHgAAAAAAAAAiItIDAAAAAAAAQEREegAAAAAAAACIiEgPAAAAAAAAABER6QEAAAAAAAAgIiI9AAAAAAAAAEREpAcAAAAAAACAiIj0AAAAAAAAABARkR4AAAAAAAAAIiLSAwAAAAAAAEBERHoAAAAAAAAAiIhIDwAAAAAAAAAREekBAAAAAAAAICIiPQAAAAAAAABERKQHAAAAAAAAgIiI9AAAAAAAAAAQEZEeAAAAAAAAACIi0gMAAAAAAABARER6AAAAAAAAAIiISA8AAAAAAAAAERHpAQAAAAAAACAiIj0AAAAAAAAARESkBwAAAAAAAICIiPQAAAAAAAAAEBGRHgAAAAAAAAAiItIDAAAAAAAAQEREegAAAAAAAACIiEgPAAAAAAAAABER6QEAAAAAAAAgIiI9AAAAAAAAAEREpAcAAAAAAACAiIj0AAAAAAAAABARkR4AAAAAAAAAIiLSAwAAAAAAAEBERHoAAAAAAAAAiIhIDwAAAAAAAAAREekBAAAAAAAAICIiPQAAAAAAAABERKQHAAAAAAAAgIiI9AAAAAAAAAAQEZEeAAAAAAAAACIi0gMAAAAAAABARER6AAAAAAAAAIiISA8AAAAAAAAAERHpAQAAAAAAACAiIj0AAAAAAAAARESkBwAAAAAAAICIiPQAAAAAAAAAEBGRHgAAAAAAAAAiItIDAAAAAAAAQEREegAAAAAAAACIiEgPAAAAAAAAABER6QEAAAAAAAAgIiI9AAAAAAAAAEREpAcAAAAAAACAiIj0AAAAAAAAABARkR4AAAAAAAAAIiLSAwAAAAAAAEBERHoAAAAAAAAAiIhIDwAAAAAAAAAREekBAAAAAAAAICIiPQAAAAAAAABERKQHAAAAAAAAgIiI9AAAAAAAAAAQEZEeAAAAAAAAACIi0gMAAAAAAABARER6AAAAAAAAAIiISA8AAAAAAAAAERHpAQAAAAAAACAiIj0AAAAAAAAARESkBwAAAAAAAICIiPQAAAAAAAAAEBGRHgAAAAAAAAAiItIDAAAAAAAAQEREegAAAAAAAACIiEgPAAAAAAAAABER6QEAAAAAAAAgIiI9AAAAAAAAAEREpAcAAAAAAACAiIj0AAAAAAAAABARkR4AAAAAAAAAIiLSAwAAAAAAAEBERHoAAAAAAAAAiIhIDwAAAAAAAAAREekBAAAAAAAAICIiPQAAAAAAAABERKQHAAAAAAAAgIiI9AAAAAAAAAAQEZEeAAAAAAAAACIi0gMAAAAAAABARER6AAAAAAAAAIiISA8AAAAAAAAAERHpAQAAAAAAACAiIj0AAAAAAAAARESkBwAAAAAAAICIiPQAAAAAAAAAEBGRHgAAAAAAAAAiItIDAAAAAAAAQEREegAAAAAAAACIiEgPAAAAAAAAABER6QEAAAAAAAAgIiI9AAAAAAAAAEREpAcAAAAAAACAiIj0AAAAAAAAABARkR4AAAAAAAAAIiLSAwAAAAAAAEBERHoAAAAAAAAAiIhIDwAAAAAAAAAREekBAAAAAAAAICIiPQAAAAAAAABERKQHAAAAAAAAgIiI9AAAAAAAAAAQEZEeAAAAAAAAACIi0gMAAAAAAABARER6AAAAAAAAAIiISA8AAAAAAAAAERHpAQAAAAAAACAiIj0AAAAAAAAARESkBwAAAAAAAICIiPQAAAAAAAAAEBGRHgAAAAAAAAAiItIDAAAAAAAAQEREegAAAAAAAACIiEgPAAAAAAAAABER6QEAAAAAAAAgIiI9AAAAAAAAAEREpAcAAAAAAACAiIj0AAAAAAAAABARkR4AAAAAAAAAIiLSAwAAAAAAAEBERHoAAAAAAAAAiIhIDwAAAAAAAAAREekBAAAAAAAAICIiPQAAAAAAAABERKQHAAAAAAAAgIiI9AAAAAAAAAAQEZEeAAAAAAAAACIi0gMAAAAAAABARER6AAAAAAAAAIiISA8AAAAAAAAAERHpAQAAAAAAACAiIj0AAAAAAAAARESkBwAAAAAAAICIiPQAAAAAAAAAEBGRHgAAAAAAAAAiItIDAAAAAAAAQEREegAAAAAAAACIiEgPAAAAAAAAABER6QEAAAAAAAAgIiI9AAAAAAAAAEREpAcAAAAAAACAiIj0AAAAAAAAABARkR4AAAAAAAAAIiLSAwAAAAAAAEBERHoAAAAAAAAAiIhIDwAAAAAAAAAREekBAAAAAAAAICIiPQAAAAAAAABERKQHAAAAAAAAgIiI9AAAAAAAAAAQEZEeAAAAAAAAACIi0gMAAAAAAABARER6AAAAAAAAAIiISA8AAAAAAAAAERHpAQAAAAAAACAiIj0AAAAAAAAARESkBwAAAAAAAICIiPQAAAAAAAAAEBGRHgAAAAAAAAAiItIDAAAAAAAAQEREegAAAAAAAACIiEgPAAAAAAAAABER6QEAAAAAAAAgIiI9AAAAAAAAAEREpAcAAAAAAACAiIj0AAAAAAAAABARkR4AAAAAAAAAIiLSAwAAAAAAAEBERHoA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) Means are taken from the summary table; error bars omitted for clarity.   Figure 7.1 Mean Diastolic Blood Pressure by Visit Safety Population   [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) writes a figure to any backend exactly like a table; on the paged backends (RTF, PDF, DOCX) the plot is placed in the body box by `halign` / `valign`, and a list of plots emits one figure per page. ``` r emit(vital_fig, "g_7_1.rtf") # ship: or .pdf / .docx / .html / .md ``` ## See also - [Data in](https://vthanik.github.io/tabular/articles/data-in.md) — produce these wide frames from a cards/cardx ARD with [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md). - [Structure](https://vthanik.github.io/tabular/articles/structure.md) and [Presentation](https://vthanik.github.io/tabular/articles/presentation.md) — the column, pagination, and styling verbs each recipe draws on. - [Output & qualification](https://vthanik.github.io/tabular/articles/output.md) — the cross-backend validation these recipes mirror. # Structure: columns, headers, and pagination This article is about *shape*: which column does what, multi-level headers, and how a table that is too long or too wide is split across pages. It assumes you already have a wide frame (see [Data in](https://vthanik.github.io/tabular/articles/data-in.md)) and does not cover cosmetics (see [Presentation](https://vthanik.github.io/tabular/articles/presentation.md)). ## Row grouping: `group_rows()` Row structure is a fact about the whole table, so it is declared once with [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) — not per column. `by` names only the **structural** grouping key columns (section headers and hidden break keys), ordered outer to inner. The visible row-label column (the statistic stub) is an ordinary [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) column, not a grouping key — it is indented automatically. `display` (a single value) picks how the keys render: | `display` | Use it for | Behaviour | |----|----|----| | `"section"` *(default)* | section variable (e.g. parameter) | each value becomes a **section-header row**; the key column is hidden | | `"collapse"` | a visible row label | column stays; repeated values are suppressed | | `"repeat"` | a visible row label | column stays; every row repeats the value | A **break-only key** — hidden, contributing only group transitions (the blank spacer and decimal-section reset) — is not a `display` mode: mark the key `col_spec(visible = FALSE)` and list it in `by`. [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) handles the per-column cosmetics — labels (`x = "Label"` is shorthand for `col_spec(label = )`), alignment, widths, and `.hide =` for helper columns. Indentation is the separate `col_spec(indent = …)` argument (a fixed integer level, or a column name for per-row depth). ``` r data(cdisc_saf_demo, package = "tabular") arms <- c("placebo", "drug_50", "drug_100", "Total") tabular(cdisc_saf_demo, titles = "Demographics") |> cols(variable = "", stat_label = "") |> cols_apply(arms, col_spec(align = "decimal")) |> group_rows(by = "variable") ``` | | placebo | drug_50 | drug_100 | Total | |----|----|----|----|----| | **Age (years)** | | | | | | n | 86          | 96          | 72          | 254          | | Mean (SD) | 75.2 (8.59) | 76.0 (8.11) | 73.8 (7.94) |  75.1 (8.25) | | Median | 76.0        | 78.0        | 75.5        |  77.0        | | Q1, Q3 | 69.2, 81.8  | 71.0, 82.0  | 70.5, 79.0  |  70.0, 81.0  | | Min, Max | 52  , 89    | 51  , 88    | 56  , 88    |  51  , 89    | |   | | | | | | **Sex, n (%)** | | | | | | F | 53 (61.6)   | 55 (57.3)   | 35 (48.6)   | 143 (56.3)   | | M | 33 (38.4)   | 41 (42.7)   | 37 (51.4)   | 111 (43.7)   | |   | | | | | | **Race, n (%)** | | | | | | WHITE | 78 (90.7)   | 90 (93.8)   | 62 (86.1)   | 230 (90.6)   | | BLACK OR AFRICAN AMERICAN |  8 ( 9.3)   |  6 ( 6.2)   |  9 (12.5)   |  23 ( 9.1)   | | ASIAN |  0          |  0          |  0          |   0          | | AMERICAN INDIAN OR ALASKA NATIVE |  0          |  0          |  1 ( 1.4)   |   1 ( 0.4)   |   Demographics   [`cols_apply()`](https://vthanik.github.io/tabular/reference/cols_apply.md) attaches one shared `col_spec` to **all** the arm columns at once — use it instead of repeating `cols(placebo = …, drug_50 = …)` for a variable number of arms. > **Indent from exactly one source.** `display = "section"` already > indents its child rows one level, so the stub column (here > `stat_label`) needs **no** `indent` — the section supplies it. (An > explicit `indent` on the host *overrides* that auto-indent rather than > stacking, so `indent = 1` there still yields a single level.) The same > care applies to labels from > [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md), > which come out with a leading indent baked into the string: keep them > as-is or [`trimws()`](https://rdrr.io/r/base/trimws.html) them and set > `indent` yourself — don’t double up. ### Display modes and spacing The default `display = "section"` is the submission shape. For a listing, `display = "collapse"` keeps the keys as visible columns and suppresses the repeats, so only the first row of each run carries the label — swap in `"repeat"` when every row must be self-describing (an export or QC view): ``` r data(cdisc_saf_vital, package = "tabular") tabular(cdisc_saf_vital, titles = "Vital Signs Listing") |> cols( paramcd = col_spec(visible = FALSE), param = "Parameter", visit = "Visit", stat_label = "Statistic" ) |> cols_apply( c("placebo", "drug_50", "drug_100"), col_spec(align = "decimal") ) |> group_rows(by = c("param", "visit"), display = "collapse", skip = FALSE) ``` | Parameter | Visit | Statistic | placebo | drug_50 | drug_100 | |----|----|----|----|----|----| | Diastolic Blood Pressure (mmHg) | Baseline | n | 340          | 384          | 288          | | | | Mean (SD) |  77.1 (10.7) |  76.6 ( 9.8) |  78.2 (10.3) | | | | Median |  77.7        |  76.7        |  78.8        | | | | Min, Max |  40  , 110   |  48  , 108   |  51  , 108   | | | Week 8 | n | 292          | 240          | 224          | | | | Mean (SD) |  75.2 ( 9.1) |  75.4 (10.6) |  77.4 ( 9.1) | | | | Median |  76.0        |  74.0        |  78.3        | | | | Min, Max |  49  , 101   |  52  , 100   |  54  , 98    | | | Week 16 | n | 272          | 168          | 148          | | | | Mean (SD) |  75.1 (10.9) |  75.2 (10.0) |  76.0 ( 9.0) | | | | Median |  76.0        |  75.7        |  77.3        | | | | Min, Max |  49  , 98    |  55  , 98    |  50  , 92    | | | End of Treatment | n | 222          | 177          | 168          | | | | Mean (SD) |  74.4 (10.7) |  76.0 (11.2) |  76.0 ( 9.9) | | | | Median |  73.5        |  76.0        |  78.0        | | | | Min, Max |  49  , 104   |  50  , 100   |  56  , 98    | | Pulse Rate (beats/min) | Baseline | n | 340          | 384          | 288          | | | | Mean (SD) |  73.5 (11.6) |  72.1 (10.8) |  72.4 ( 9.7) | | | | Median |  72.3        |  70.0        |  71.7        | | | | Min, Max |  51  , 134   |  50  , 104   |  52  , 100   | | | Week 8 | n | 292          | 240          | 224          | | | | Mean (SD) |  71.8 ( 9.0) |  72.6 (11.1) |  74.0 ( 8.9) | | | | Median |  72.0        |  72.0        |  73.2        | | | | Min, Max |  52  , 102   |  49  , 104   |  50  , 104   | | | Week 16 | n | 272          | 168          | 148          | | | | Mean (SD) |  70.6 ( 8.8) |  68.8 ( 9.4) |  73.2 ( 9.5) | | | | Median |  70.2        |  68.0        |  72.0        | | | | Min, Max |  50  , 90    |  48  , 104   |  51  , 96    | | | End of Treatment | n | 222          | 177          | 168          | | | | Mean (SD) |  75.2 (11.5) |  74.1 ( 9.4) |  73.6 ( 9.6) | | | | Median |  74.0        |  75.0        |  73.0        | | | | Min, Max |  51  , 106   |  50  , 94    |  50  , 98    | | Systolic Blood Pressure (mmHg) | Baseline | n | 340          | 384          | 288          | | | | | | | | | | | Mean (SD) | 136.8 (17.6) | 137.9 (18.5) | 137.8 (17.2) | | | | Median | 136.3        | 138.0        | 138.0        | | | | Min, Max |  80  , 184   | 100  , 194   | 100  , 192   | | | Week 8 | n | 292          | 240          | 224          | | | | Mean (SD) | 136.3 (17.0) | 134.9 (17.8) | 135.1 (15.5) | | | | Median | 136.5        | 132.3        | 134.0        | | | | Min, Max |  90  , 189   |  92  , 200   |  91  , 198   | | | Week 16 | n | 272          | 168          | 148          | | | | Mean (SD) | 134.6 (18.3) | 132.5 (14.3) | 133.7 (16.0) | | | | Median | 134.0        | 130.0        | 132.0        | | | | Min, Max |  76  , 190   | 100  , 168   |  99  , 186   | | | End of Treatment | n | 222          | 177          | 168          | | | | Mean (SD) | 132.7 (15.4) | 133.0 (17.1) | 132.3 (15.6) | | | | Median | 131.0        | 130.0        | 131.0        | | | | Min, Max |  78  , 172   |  92  , 178   | 100  , 177   | | Temperature (C) | Baseline | n | 172          | 190          | 144          | | | | Mean (SD) |  36.6 ( 0.4) |  36.5 ( 0.4) |  36.6 ( 0.4) | | | | Median |  36.7        |  36.6        |  36.6        | | | | Min, Max |  35  , 37    |  35  , 37    |  36  , 37    | | | Week 8 | n | 146          | 118          | 112          | | | | Mean (SD) |  36.6 ( 0.4) |  36.6 ( 0.4) |  36.6 ( 0.4) | | | | Median |  36.6        |  36.7        |  36.7        | | | | Min, Max |  36  , 37    |  36  , 37    |  36  , 37    | | | Week 16 | n | 136          |  82          |  74          | | | | Mean (SD) |  36.7 ( 0.3) |  36.6 ( 0.4) |  36.6 ( 0.4) | | | | Median |  36.7        |  36.6        |  36.7        | | | | Min, Max |  36  , 37    |  36  , 37    |  36  , 37    | | | End of Treatment | n |  74          |  59          |  56          | | | | Mean (SD) |  36.7 ( 0.4) |  36.6 ( 0.4) |  36.6 ( 0.4) | | | | Median |  36.8        |  36.7        |  36.7        | | | | Min, Max |  35  , 37    |  35  , 38    |  36  , 37    |   Vital Signs Listing   `skip` places the blank spacer rows between groups and follows the `readr::read_csv(col_names = )` pattern: `TRUE` (the default) derives it — a `"section"` key or a hidden break-only key breaks, a visible column key runs continuous; `FALSE` inserts none (as in the listing above); a character subset of `by` breaks on exactly those keys. Here a blank line separates parameters but not the visits within one: ``` r tabular(cdisc_saf_vital, titles = "Vital Signs by Parameter and Visit") |> cols( paramcd = col_spec(visible = FALSE), param = "Parameter", visit = "Visit", stat_label = "Statistic" ) |> cols_apply( c("placebo", "drug_50", "drug_100"), col_spec(align = "decimal") ) |> group_rows(by = c("param", "visit"), skip = "param") ``` | Statistic | placebo | drug_50 | drug_100 | |-------------------------------------|--------------|--------------|--------------| | **Diastolic Blood Pressure (mmHg)** | | | | | **Baseline** | | | | | n | 340          | 384          | 288          | | Mean (SD) |  77.1 (10.7) |  76.6 ( 9.8) |  78.2 (10.3) | | Median |  77.7        |  76.7        |  78.8        | | Min, Max |  40  , 110   |  48  , 108   |  51  , 108   | | **Week 8** | | | | | n | 292          | 240          | 224          | | Mean (SD) |  75.2 ( 9.1) |  75.4 (10.6) |  77.4 ( 9.1) | | Median |  76.0        |  74.0        |  78.3        | | Min, Max |  49  , 101   |  52  , 100   |  54  , 98    | | **Week 16** | | | | | n | 272          | 168          | 148          | | Mean (SD) |  75.1 (10.9) |  75.2 (10.0) |  76.0 ( 9.0) | | Median |  76.0        |  75.7        |  77.3        | | Min, Max |  49  , 98    |  55  , 98    |  50  , 92    | | **End of Treatment** | | | | | n | 222          | 177          | 168          | | Mean (SD) |  74.4 (10.7) |  76.0 (11.2) |  76.0 ( 9.9) | | Median |  73.5        |  76.0        |  78.0        | | Min, Max |  49  , 104   |  50  , 100   |  56  , 98    | |   | | | | | **Pulse Rate (beats/min)** | | | | | **Baseline** | | | | | n | 340          | 384          | 288          | | Mean (SD) |  73.5 (11.6) |  72.1 (10.8) |  72.4 (9.7)  | | Median |  72.3        |  70.0        |  71.7        | | Min, Max |  51  , 134   |  50  , 104   |  52  , 100   | | **Week 8** | | | | | n | 292          | 240          | 224          | | Mean (SD) |  71.8 ( 9.0) |  72.6 (11.1) |  74.0 (8.9)  | | Median |  72.0        |  72.0        |  73.2        | | Min, Max |  52  , 102   |  49  , 104   |  50  , 104   | | **Week 16** | | | | | n | 272          | 168          | 148          | | Mean (SD) |  70.6 ( 8.8) |  68.8 ( 9.4) |  73.2 (9.5)  | | Median |  70.2        |  68.0        |  72.0        | | Min, Max |  50  , 90    |  48  , 104   |  51  , 96    | | **End of Treatment** | | | | | n | 222          | 177          | 168          | | Mean (SD) |  75.2 (11.5) |  74.1 ( 9.4) |  73.6 (9.6)  | | Median |  74.0        |  75.0        |  73.0        | | Min, Max |  51  , 106   |  50  , 94    |  50  , 98    | |   | | | | | **Systolic Blood Pressure (mmHg)** | | | | | **Baseline** | | | | | n | 340          | 384          | 288          | | | | | | | Mean (SD) | 136.8 (17.6) | 137.9 (18.5) | 137.8 (17.2) | | Median | 136.3        | 138.0        | 138.0        | | Min, Max |  80  , 184   | 100  , 194   | 100  , 192   | | **Week 8** | | | | | n | 292          | 240          | 224          | | Mean (SD) | 136.3 (17.0) | 134.9 (17.8) | 135.1 (15.5) | | Median | 136.5        | 132.3        | 134.0        | | Min, Max |  90  , 189   |  92  , 200   |  91  , 198   | | **Week 16** | | | | | n | 272          | 168          | 148          | | Mean (SD) | 134.6 (18.3) | 132.5 (14.3) | 133.7 (16.0) | | Median | 134.0        | 130.0        | 132.0        | | Min, Max |  76  , 190   | 100  , 168   |  99  , 186   | | **End of Treatment** | | | | | n | 222          | 177          | 168          | | Mean (SD) | 132.7 (15.4) | 133.0 (17.1) | 132.3 (15.6) | | Median | 131.0        | 130.0        | 131.0        | | Min, Max |  78  , 172   |  92  , 178   | 100  , 177   | |   | | | | | **Temperature (C)** | | | | | **Baseline** | | | | | n | 172          | 190          | 144          | | Mean (SD) |  36.6 (0.4)  |  36.5 (0.4)  |  36.6 (0.4)  | | Median |  36.7        |  36.6        |  36.6        | | Min, Max |  35  , 37    |  35  , 37    |  36  , 37    | | **Week 8** | | | | | n | 146          | 118          | 112          | | Mean (SD) |  36.6 (0.4)  |  36.6 (0.4)  |  36.6 (0.4)  | | Median |  36.6        |  36.7        |  36.7        | | Min, Max |  36  , 37    |  36  , 37    |  36  , 37    | | **Week 16** | | | | | n | 136          |  82          |  74          | | Mean (SD) |  36.7 (0.3)  |  36.6 (0.4)  |  36.6 (0.4)  | | Median |  36.7        |  36.6        |  36.7        | | Min, Max |  36  , 37    |  36  , 37    |  36  , 37    | | **End of Treatment** | | | | | n |  74          |  59          |  56          | | Mean (SD) |  36.7 (0.4)  |  36.6 (0.4)  |  36.6 (0.4)  | | Median |  36.8        |  36.7        |  36.7        | | Min, Max |  35  , 37    |  35  , 38    |  36  , 37    |   Vital Signs by Parameter and Visit   ## BigN in the column headers The `(N=…)` denominator goes in each arm’s header label. Build it from a BigN table and interpolate with glue: ``` r data(cdisc_saf_n, package = "tabular") N <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) tabular(cdisc_saf_demo, titles = "Demographics") |> group_rows(by = "variable") |> cols( stat_label = col_spec(label = ""), placebo = col_spec( label = "Placebo\n(N={N['placebo']})", align = "decimal" ), drug_50 = col_spec( label = "Drug 50\n(N={N['drug_50']})", align = "decimal" ), drug_100 = col_spec( label = "Drug 100\n(N={N['drug_100']})", align = "decimal" ), Total = col_spec(label = "Total\n(N={N['Total']})", align = "decimal") ) ``` [TABLE]   Demographics   > **Clinical convention:** BigN is the population denominator (from > ADSL), **not** the number of rows in the domain dataset — compute it > from the population, not from the summarised data. For a **variable** number of arms, the per-arm label is one [`cols_apply()`](https://vthanik.github.io/tabular/reference/cols_apply.md) call instead of a hand-written line each: the `{.name}` token resolves to each matched column’s name, and the rest of the `{…}` evaluates in the calling environment, so the BigN looks itself up: ``` r arm_cols <- c("placebo", "drug_50", "drug_100", "Total") tabular(cdisc_saf_demo, titles = "Demographics") |> group_rows(by = "variable") |> cols(stat_label = col_spec(label = "")) |> cols_apply( arm_cols, col_spec(label = "{.name}\n(N={N[.name]})", align = "decimal") ) ``` [TABLE]   Demographics   ## Multi-level headers and widths [`headers()`](https://vthanik.github.io/tabular/reference/headers.md) builds spanning bands over groups of columns: ``` r tabular(cdisc_saf_demo, titles = "Demographics") |> group_rows(by = "variable") |> cols(stat_label = col_spec(label = "", width = "2.2in")) |> cols_apply(arms, col_spec(align = "decimal", width = "1in")) |> headers("Treatment Group" = c("placebo", "drug_50", "drug_100", "Total")) ``` | | Treatment Group | | | | |----|----|----|----|----| | | placebo | drug_50 | drug_100 | Total | | **Age (years)** | | | | | | n | 86          | 96          | 72          | 254          | | Mean (SD) | 75.2 (8.59) | 76.0 (8.11) | 73.8 (7.94) |  75.1 (8.25) | | Median | 76.0        | 78.0        | 75.5        |  77.0        | | Q1, Q3 | 69.2, 81.8  | 71.0, 82.0  | 70.5, 79.0  |  70.0, 81.0  | | Min, Max | 52  , 89    | 51  , 88    | 56  , 88    |  51  , 89    | |   | | | | | | **Sex, n (%)** | | | | | | F | 53 (61.6)   | 55 (57.3)   | 35 (48.6)   | 143 (56.3)   | | M | 33 (38.4)   | 41 (42.7)   | 37 (51.4)   | 111 (43.7)   | |   | | | | | | **Race, n (%)** | | | | | | WHITE | 78 (90.7)   | 90 (93.8)   | 62 (86.1)   | 230 (90.6)   | | BLACK OR AFRICAN AMERICAN |  8 ( 9.3)   |  6 ( 6.2)   |  9 (12.5)   |  23 ( 9.1)   | | ASIAN |  0          |  0          |  0          |   0          | | AMERICAN INDIAN OR ALASKA NATIVE |  0          |  0          |  1 ( 1.4)   |   1 ( 0.4)   |   Demographics   Widths: `"auto"` (default) sizes to content; a pinned value (`"1in"`, `1.0`, `"20%"`) wraps within that width. **Set the shared arm width via [`cols_apply()`](https://vthanik.github.io/tabular/reference/cols_apply.md) last** — its non-default `width` then wins the field-merge; a later [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) call carrying the default `width = "auto"` would otherwise be ambiguous. ## Sorting rows Display cells are formatted strings — `"54 (21.3)"` sorts lexically, not numerically. The idiom: carry one hidden **numeric key** per sort level, hide it with `col_spec(visible = FALSE)`, and hand the keys to [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md). `descending` takes one value per key, so mixed-direction sorts are a single call. The bundled AE table ships its keys precomputed: `soc_n` (events in the parent SOC, constant down each SOC block) and `n_total` (events on the row). Sorting on both, descending, clusters every preferred term under its SOC and orders both levels by frequency — the standard SAP ordering: ``` r data(cdisc_saf_aesocpt, package = "tabular") tabular(cdisc_saf_aesocpt, titles = "AEs by SOC and PT, descending frequency") |> cols( label = col_spec( label = "SOC / Preferred Term", indent = "indent_level" ), .hide = c("soc", "row_type", "n_total", "soc_n") ) |> cols_apply(arms, col_spec(align = "decimal")) |> sort_rows(by = c("soc_n", "n_total"), descending = c(TRUE, TRUE)) ``` | SOC / Preferred Term | placebo | drug_50 | drug_100 | Total | |----|----|----|----|----| | TOTAL SUBJECTS WITH AN EVENT | 52 (60.5) | 81 (84.4) | 66 (91.7) | 199 (78.3) | | SKIN AND SUBCUTANEOUS TISSUE DISORDERS | 19 (22.1) | 36 (37.5) | 35 (48.6) |  90 (35.4) | | PRURITUS |  8 ( 9.3) | 21 (21.9) | 25 (34.7) |  54 (21.3) | | ERYTHEMA |  8 ( 9.3) | 14 (14.6) | 14 (19.4) |  36 (14.2) | | RASH |  5 ( 5.8) | 13 (13.5) |  8 (11.1) |  26 (10.2) | | HYPERHIDROSIS |  2 ( 2.3) |  4 ( 4.2) |  8 (11.1) |  14 ( 5.5) | | SKIN IRRITATION |  3 ( 3.5) |  6 ( 6.2) |  5 ( 6.9) |  14 ( 5.5) | | GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS | 15 (17.4) | 36 (37.5) | 30 (41.7) |  81 (31.9) | | APPLICATION SITE PRURITUS |  6 ( 7.0) | 23 (24.0) | 21 (29.2) |  50 (19.7) | | APPLICATION SITE ERYTHEMA |  3 ( 3.5) | 13 (13.5) | 14 (19.4) |  30 (11.8) | | APPLICATION SITE DERMATITIS |  5 ( 5.8) |  9 ( 9.4) |  7 ( 9.7) |  21 ( 8.3) | | APPLICATION SITE IRRITATION |  3 ( 3.5) |  9 ( 9.4) |  9 (12.5) |  21 ( 8.3) | | APPLICATION SITE VESICLES |  1 ( 1.2) |  5 ( 5.2) |  5 ( 6.9) |  11 ( 4.3) | | GASTROINTESTINAL DISORDERS | 13 (15.1) | 12 (12.5) | 17 (23.6) |  42 (16.5) | | DIARRHOEA |  9 (10.5) |  5 ( 5.2) |  3 ( 4.2) |  17 ( 6.7) | | VOMITING |  3 ( 3.5) |  4 ( 4.2) |  6 ( 8.3) |  13 ( 5.1) | | NAUSEA |  3 ( 3.5) |  3 ( 3.1) |  6 ( 8.3) |  12 ( 4.7) | | ABDOMINAL PAIN |  1 ( 1.2) |  3 ( 3.1) |  1 ( 1.4) |   5 ( 2.0) | | SALIVARY HYPERSECRETION |  0        |  0        |  4 ( 5.6) |   4 ( 1.6) | | NERVOUS SYSTEM DISORDERS |  6 ( 7.0) | 18 (18.8) | 17 (23.6) |  41 (16.1) | | DIZZINESS |  2 ( 2.3) |  9 ( 9.4) | 10 (13.9) |  21 ( 8.3) | | HEADACHE |  3 ( 3.5) |  3 ( 3.1) |  5 ( 6.9) |  11 ( 4.3) | | SYNCOPE |  0        |  5 ( 5.2) |  2 ( 2.8) |   7 ( 2.8) | | SOMNOLENCE |  2 ( 2.3) |  3 ( 3.1) |  1 ( 1.4) |   6 ( 2.4) | | TRANSIENT ISCHAEMIC ATTACK |  0        |  2 ( 2.1) |  1 ( 1.4) |   3 ( 1.2) | | CARDIAC DISORDERS |  7 ( 8.1) | 12 (12.5) | 14 (19.4) |  33 (13.0) | | SINUS BRADYCARDIA |  2 ( 2.3) |  7 ( 7.3) |  8 (11.1) |  17 ( 6.7) | | MYOCARDIAL INFARCTION |  4 ( 4.7) |  2 ( 2.1) |  4 ( 5.6) |  10 ( 3.9) | | ATRIAL FIBRILLATION |  1 ( 1.2) |  2 ( 2.1) |  2 ( 2.8) |   5 ( 2.0) | | SUPRAVENTRICULAR EXTRASYSTOLES |  1 ( 1.2) |  1 ( 1.0) |  1 ( 1.4) |   3 ( 1.2) | | VENTRICULAR EXTRASYSTOLES |  0        |  2 ( 2.1) |  1 ( 1.4) |   3 ( 1.2) | | INFECTIONS AND INFESTATIONS | 12 (14.0) |  6 ( 6.2) | 11 (15.3) |  29 (11.4) | | NASOPHARYNGITIS |  2 ( 2.3) |  4 ( 4.2) |  6 ( 8.3) |  12 ( 4.7) | | | | | | | | UPPER RESPIRATORY TRACT INFECTION |  6 ( 7.0) |  1 ( 1.0) |  3 ( 4.2) |  10 ( 3.9) | | INFLUENZA |  1 ( 1.2) |  1 ( 1.0) |  1 ( 1.4) |   3 ( 1.2) | | URINARY TRACT INFECTION |  2 ( 2.3) |  0        |  1 ( 1.4) |   3 ( 1.2) | | CYSTITIS |  1 ( 1.2) |  0        |  1 ( 1.4) |   2 ( 0.8) | | RESPIRATORY, THORACIC AND MEDIASTINAL DISORDERS |  5 ( 5.8) |  8 ( 8.3) |  9 (12.5) |  22 ( 8.7) | | COUGH |  1 ( 1.2) |  5 ( 5.2) |  5 ( 6.9) |  11 ( 4.3) | | NASAL CONGESTION |  3 ( 3.5) |  1 ( 1.0) |  3 ( 4.2) |   7 ( 2.8) | | DYSPNOEA |  1 ( 1.2) |  1 ( 1.0) |  1 ( 1.4) |   3 ( 1.2) | | EPISTAXIS |  0        |  1 ( 1.0) |  2 ( 2.8) |   3 ( 1.2) | | PHARYNGOLARYNGEAL PAIN |  0        |  1 ( 1.0) |  1 ( 1.4) |   2 ( 0.8) | | PSYCHIATRIC DISORDERS |  7 ( 8.1) |  9 ( 9.4) |  3 ( 4.2) |  19 ( 7.5) | | CONFUSIONAL STATE |  2 ( 2.3) |  3 ( 3.1) |  1 ( 1.4) |   6 ( 2.4) | | AGITATION |  2 ( 2.3) |  3 ( 3.1) |  0        |   5 ( 2.0) | | INSOMNIA |  2 ( 2.3) |  0        |  2 ( 2.8) |   4 ( 1.6) | | ANXIETY |  0        |  3 ( 3.1) |  0        |   3 ( 1.2) | | DELUSION |  1 ( 1.2) |  0        |  1 ( 1.4) |   2 ( 0.8) | | MUSCULOSKELETAL AND CONNECTIVE TISSUE DISORDERS |  3 ( 3.5) |  6 ( 6.2) |  5 ( 6.9) |  14 ( 5.5) | | BACK PAIN |  1 ( 1.2) |  1 ( 1.0) |  3 ( 4.2) |   5 ( 2.0) | | ARTHRALGIA |  1 ( 1.2) |  2 ( 2.1) |  1 ( 1.4) |   4 ( 1.6) | | SHOULDER PAIN |  1 ( 1.2) |  2 ( 2.1) |  0        |   3 ( 1.2) | | MUSCLE SPASMS |  0        |  1 ( 1.0) |  1 ( 1.4) |   2 ( 0.8) | | ARTHRITIS |  0        |  0        |  1 ( 1.4) |   1 ( 0.4) | | INVESTIGATIONS |  5 ( 5.8) |  4 ( 4.2) |  3 ( 4.2) |  12 ( 4.7) | | ELECTROCARDIOGRAM ST SEGMENT DEPRESSION |  4 ( 4.7) |  1 ( 1.0) |  0        |   5 ( 2.0) | | ELECTROCARDIOGRAM T WAVE INVERSION |  2 ( 2.3) |  1 ( 1.0) |  1 ( 1.4) |   4 ( 1.6) | | BLOOD GLUCOSE INCREASED |  0        |  1 ( 1.0) |  1 ( 1.4) |   2 ( 0.8) | | ELECTROCARDIOGRAM T WAVE AMPLITUDE DECREASED |  1 ( 1.2) |  1 ( 1.0) |  0        |   2 ( 0.8) | | BIOPSY |  0        |  0        |  1 ( 1.4) |   1 ( 0.4) |   AEs by SOC and PT, descending frequency   Because `soc_n` is constant within a SOC block and never smaller than any PT’s `n_total` inside it, each SOC’s summary row sorts to the top of its own block — no separate “parent first” switch needed. ## Pagination — long tables [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md) derives the rows-per-page budget from the preset (paper, font, margins) and the title/footnote/header line counts — you never set rows-per-page by hand. `keep_together` stops a page break landing inside a section’s run: ``` r data(cdisc_saf_aesocpt, package = "tabular") ae_pages <- tabular(cdisc_saf_aesocpt, titles = "AEs by SOC and PT") |> cols( label = col_spec( label = "SOC / Preferred Term", indent = "indent_level" ), .hide = c("soc", "row_type", "n_total", "soc_n") ) |> cols_apply( c("placebo", "drug_50", "drug_100", "Total"), col_spec(align = "decimal") ) |> paginate( keep_together = "soc", orphan_floor = 4, widow_floor = 2, continuation = "(continued)" ) ae_pages ``` | SOC / Preferred Term | placebo | drug_50 | drug_100 | Total | |----|----|----|----|----| | TOTAL SUBJECTS WITH AN EVENT | 52 (60.5) | 81 (84.4) | 66 (91.7) | 199 (78.3) | | SKIN AND SUBCUTANEOUS TISSUE DISORDERS | 19 (22.1) | 36 (37.5) | 35 (48.6) |  90 (35.4) | | PRURITUS |  8 ( 9.3) | 21 (21.9) | 25 (34.7) |  54 (21.3) | | ERYTHEMA |  8 ( 9.3) | 14 (14.6) | 14 (19.4) |  36 (14.2) | | RASH |  5 ( 5.8) | 13 (13.5) |  8 (11.1) |  26 (10.2) | | HYPERHIDROSIS |  2 ( 2.3) |  4 ( 4.2) |  8 (11.1) |  14 ( 5.5) | | SKIN IRRITATION |  3 ( 3.5) |  6 ( 6.2) |  5 ( 6.9) |  14 ( 5.5) | | GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS | 15 (17.4) | 36 (37.5) | 30 (41.7) |  81 (31.9) | | APPLICATION SITE PRURITUS |  6 ( 7.0) | 23 (24.0) | 21 (29.2) |  50 (19.7) | | APPLICATION SITE ERYTHEMA |  3 ( 3.5) | 13 (13.5) | 14 (19.4) |  30 (11.8) | | APPLICATION SITE DERMATITIS |  5 ( 5.8) |  9 ( 9.4) |  7 ( 9.7) |  21 ( 8.3) | | APPLICATION SITE IRRITATION |  3 ( 3.5) |  9 ( 9.4) |  9 (12.5) |  21 ( 8.3) | | APPLICATION SITE VESICLES |  1 ( 1.2) |  5 ( 5.2) |  5 ( 6.9) |  11 ( 4.3) | | GASTROINTESTINAL DISORDERS | 13 (15.1) | 12 (12.5) | 17 (23.6) |  42 (16.5) | | DIARRHOEA |  9 (10.5) |  5 ( 5.2) |  3 ( 4.2) |  17 ( 6.7) | | VOMITING |  3 ( 3.5) |  4 ( 4.2) |  6 ( 8.3) |  13 ( 5.1) | | NAUSEA |  3 ( 3.5) |  3 ( 3.1) |  6 ( 8.3) |  12 ( 4.7) | | ABDOMINAL PAIN |  1 ( 1.2) |  3 ( 3.1) |  1 ( 1.4) |   5 ( 2.0) | | SALIVARY HYPERSECRETION |  0        |  0        |  4 ( 5.6) |   4 ( 1.6) | | NERVOUS SYSTEM DISORDERS |  6 ( 7.0) | 18 (18.8) | 17 (23.6) |  41 (16.1) | | DIZZINESS |  2 ( 2.3) |  9 ( 9.4) | 10 (13.9) |  21 ( 8.3) | | HEADACHE |  3 ( 3.5) |  3 ( 3.1) |  5 ( 6.9) |  11 ( 4.3) | | SYNCOPE |  0        |  5 ( 5.2) |  2 ( 2.8) |   7 ( 2.8) | | SOMNOLENCE |  2 ( 2.3) |  3 ( 3.1) |  1 ( 1.4) |   6 ( 2.4) | | TRANSIENT ISCHAEMIC ATTACK |  0        |  2 ( 2.1) |  1 ( 1.4) |   3 ( 1.2) | | CARDIAC DISORDERS |  7 ( 8.1) | 12 (12.5) | 14 (19.4) |  33 (13.0) | | SINUS BRADYCARDIA |  2 ( 2.3) |  7 ( 7.3) |  8 (11.1) |  17 ( 6.7) | | MYOCARDIAL INFARCTION |  4 ( 4.7) |  2 ( 2.1) |  4 ( 5.6) |  10 ( 3.9) | | ATRIAL FIBRILLATION |  1 ( 1.2) |  2 ( 2.1) |  2 ( 2.8) |   5 ( 2.0) | | SUPRAVENTRICULAR EXTRASYSTOLES |  1 ( 1.2) |  1 ( 1.0) |  1 ( 1.4) |   3 ( 1.2) | | VENTRICULAR EXTRASYSTOLES |  0        |  2 ( 2.1) |  1 ( 1.4) |   3 ( 1.2) | | | | | | | | INFECTIONS AND INFESTATIONS | 12 (14.0) |  6 ( 6.2) | 11 (15.3) |  29 (11.4) | | NASOPHARYNGITIS |  2 ( 2.3) |  4 ( 4.2) |  6 ( 8.3) |  12 ( 4.7) | | UPPER RESPIRATORY TRACT INFECTION |  6 ( 7.0) |  1 ( 1.0) |  3 ( 4.2) |  10 ( 3.9) | | INFLUENZA |  1 ( 1.2) |  1 ( 1.0) |  1 ( 1.4) |   3 ( 1.2) | | URINARY TRACT INFECTION |  2 ( 2.3) |  0        |  1 ( 1.4) |   3 ( 1.2) | | CYSTITIS |  1 ( 1.2) |  0        |  1 ( 1.4) |   2 ( 0.8) | | RESPIRATORY, THORACIC AND MEDIASTINAL DISORDERS |  5 ( 5.8) |  8 ( 8.3) |  9 (12.5) |  22 ( 8.7) | | COUGH |  1 ( 1.2) |  5 ( 5.2) |  5 ( 6.9) |  11 ( 4.3) | | NASAL CONGESTION |  3 ( 3.5) |  1 ( 1.0) |  3 ( 4.2) |   7 ( 2.8) | | DYSPNOEA |  1 ( 1.2) |  1 ( 1.0) |  1 ( 1.4) |   3 ( 1.2) | | EPISTAXIS |  0        |  1 ( 1.0) |  2 ( 2.8) |   3 ( 1.2) | | PHARYNGOLARYNGEAL PAIN |  0        |  1 ( 1.0) |  1 ( 1.4) |   2 ( 0.8) | | PSYCHIATRIC DISORDERS |  7 ( 8.1) |  9 ( 9.4) |  3 ( 4.2) |  19 ( 7.5) | | CONFUSIONAL STATE |  2 ( 2.3) |  3 ( 3.1) |  1 ( 1.4) |   6 ( 2.4) | | AGITATION |  2 ( 2.3) |  3 ( 3.1) |  0        |   5 ( 2.0) | | INSOMNIA |  2 ( 2.3) |  0        |  2 ( 2.8) |   4 ( 1.6) | | ANXIETY |  0        |  3 ( 3.1) |  0        |   3 ( 1.2) | | DELUSION |  1 ( 1.2) |  0        |  1 ( 1.4) |   2 ( 0.8) | | MUSCULOSKELETAL AND CONNECTIVE TISSUE DISORDERS |  3 ( 3.5) |  6 ( 6.2) |  5 ( 6.9) |  14 ( 5.5) | | BACK PAIN |  1 ( 1.2) |  1 ( 1.0) |  3 ( 4.2) |   5 ( 2.0) | | ARTHRALGIA |  1 ( 1.2) |  2 ( 2.1) |  1 ( 1.4) |   4 ( 1.6) | | SHOULDER PAIN |  1 ( 1.2) |  2 ( 2.1) |  0        |   3 ( 1.2) | | MUSCLE SPASMS |  0        |  1 ( 1.0) |  1 ( 1.4) |   2 ( 0.8) | | ARTHRITIS |  0        |  0        |  1 ( 1.4) |   1 ( 0.4) | | INVESTIGATIONS |  5 ( 5.8) |  4 ( 4.2) |  3 ( 4.2) |  12 ( 4.7) | | ELECTROCARDIOGRAM ST SEGMENT DEPRESSION |  4 ( 4.7) |  1 ( 1.0) |  0        |   5 ( 2.0) | | ELECTROCARDIOGRAM T WAVE INVERSION |  2 ( 2.3) |  1 ( 1.0) |  1 ( 1.4) |   4 ( 1.6) | | BLOOD GLUCOSE INCREASED |  0        |  1 ( 1.0) |  1 ( 1.4) |   2 ( 0.8) | | ELECTROCARDIOGRAM T WAVE AMPLITUDE DECREASED |  1 ( 1.2) |  1 ( 1.0) |  0        |   2 ( 0.8) | | BIOPSY |  0        |  0        |  1 ( 1.4) |   1 ( 0.4) |   AEs by SOC and PT   The preview above is one continuous table: row pagination, `keep_together`, and the `continuation` marker materialise only in the **paged backends** (RTF, PDF, DOCX), not in HTML. Emit to one of those to see the page breaks: ``` r emit(ae_pages, "ae_soc_pt.pdf") # continuation marker repeats on each continued page ``` ## Panels — wide tables When the columns don’t fit one page, `paginate(panels = N)` splits the **non-stub** columns into `N` chunks and repeats the stub on each panel (so the row labels reappear). The stub defaults to the [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) keys; name it explicitly with `repeat_cols` to carry the row label too: ``` r wide_split <- tabular(cdisc_saf_demo, titles = "Demographics (wide split)") |> cols(variable = "", stat_label = "") |> cols_apply(arms, col_spec(align = "decimal")) |> group_rows(by = "variable") |> paginate( panels = 2, repeat_cols = c("variable", "stat_label"), # both ride every panel continuation = "(continued)" ) wide_split ``` | | Panel 1 | | Panel 2 | | |----|----|----|----|----| | | placebo | drug_50 | drug_100 | Total | | **Age (years)** | | | | | | n | 86          | 96          | 72          | 254          | | Mean (SD) | 75.2 (8.59) | 76.0 (8.11) | 73.8 (7.94) |  75.1 (8.25) | | Median | 76.0        | 78.0        | 75.5        |  77.0        | | Q1, Q3 | 69.2, 81.8  | 71.0, 82.0  | 70.5, 79.0  |  70.0, 81.0  | | Min, Max | 52  , 89    | 51  , 88    | 56  , 88    |  51  , 89    | |   | | | | | | **Sex, n (%)** | | | | | | F | 53 (61.6)   | 55 (57.3)   | 35 (48.6)   | 143 (56.3)   | | M | 33 (38.4)   | 41 (42.7)   | 37 (51.4)   | 111 (43.7)   | |   | | | | | | **Race, n (%)** | | | | | | WHITE | 78 (90.7)   | 90 (93.8)   | 62 (86.1)   | 230 (90.6)   | | BLACK OR AFRICAN AMERICAN |  8 ( 9.3)   |  6 ( 6.2)   |  9 (12.5)   |  23 ( 9.1)   | | ASIAN |  0          |  0          |  0          |   0          | | AMERICAN INDIAN OR ALASKA NATIVE |  0          |  0          |  1 ( 1.4)   |   1 ( 0.4)   |   Demographics (wide split)   Panels are a paged-backend feature: in HTML and Markdown the table stays one continuous block (the preview above), while RTF, PDF, and DOCX place each panel on its own page with the stub columns repeated. Emit to a paged backend to see the split: ``` r emit(wide_split, "demographics_wide.pdf") # panel 2 carries the (continued) marker ``` Two things to know: - **`panels = N` splits into `N` *equal* chunks** — there is no explicit split position (no “first 5, then the rest”). Equal split is fine for page-fit; if you need a specific boundary, that is a known limitation. - **`panels` is a positive integer** (default `1` = no split). Width-aware automatic splitting is a planned future feature, not a current option. ## Subgroups and per-page BigN [`subgroup()`](https://vthanik.github.io/tabular/reference/subgroup.md) partitions the table — one page block per value, with a banner and a hard page break. A partition-constant column can ride into the banner: ``` r data(cdisc_saf_subgroup, package = "tabular") tabular(cdisc_saf_subgroup, titles = "Vital signs by sex") |> cols( param = "Parameter", visit = "Visit", stat_label = "Statistic", .hide = c("sex", "sex_n", "paramcd") ) |> group_rows(by = c("param", "visit")) |> cols_apply( c("placebo", "drug_50", "drug_100", "Total"), col_spec(align = "decimal") ) |> subgroup(by = "sex", label = "Sex: {sex} (N = {sex_n})") # page total in banner ``` | Statistic | placebo | drug_50 | drug_100 | Total | |-------------------------|--------------|--------------|--------------|--------------| | **Sex: F (N = 143)** | | | | | | **Diastolic BP (mmHg)** | | | | | | **Baseline** | | | | | | n | 208          | 220          | 140          | 568          | | Mean (SD) |  77.1 (11.2) |  76.3 (10.5) |  78.0 (10.8) |  77.0 (10.8) | | Median |  78.0        |  77.3        |  78.3        |  78.0        | | Min, Max |  40  , 110   |  48  , 100   |  51  , 108   |  40  , 110   | |   | | | | | | **Week 8** | | | | | | n | 168          | 148          | 104          | 420          | | Mean (SD) |  75.1 (9.4)  |  77.1 (11.0) |  76.0 (10.0) |  76.0 (10.1) | | Median |  76.0        |  79.7        |  78.0        |  78.0        | | Min, Max |  49  , 98    |  55  , 98    |  54  , 98    |  49  , 98    | |   | | | | | | **Week 16** | | | | | | n | 156          | 100          |  68          | 324          | | Mean (SD) |  74.9 (11.1) |  75.6 (10.8) |  77.8 (8.9)  |  75.8 (10.6) | | Median |  77.7        |  76.0        |  79.0        |  78.0        | | Min, Max |  49  , 98    |  55  , 98    |  56  , 92    |  49  , 98    | |   | | | | | | **End of Treatment** | | | | | | n | 129          | 108          |  81          | 318          | | Mean (SD) |  74.0 (10.7) |  77.2 (11.9) |  76.5 (11.7) |  75.7 (11.5) | | Median |  74.0        |  79.5        |  80.0        |  78.0        | | Min, Max |  49  , 100   |  50  , 100   |  56  , 98    |  49  , 100   | |   | | | | | | **Systolic BP (mmHg)** | | | | | | **Baseline** | | | | | | n | 208          | 220          | 140          | 568          | | Mean (SD) | 141.1 (16.9) | 139.2 (18.2) | 140.4 (19.5) | 140.2 (18.0) | | Median | 141.8        | 140.0        | 140.0        | 140.0        | | Min, Max | 100  , 184   | 100  , 194   | 100  , 192   | 100  , 194   | |   | | | | | | **Week 8** | | | | | | n | 168          | 148          | 104          | 420          | | Mean (SD) | 138.1 (16.5) | 137.9 (17.8) | 139.6 (19.0) | 138.4 (17.6) | | Median | 139.5        | 135.7        | 140.0        | 138.7        | | Min, Max | 100  , 184   |  92  , 200   |  91  , 198   |  91  , 200   | |   | | | | | | **Week 16** | | | | | | n | 156          | 100          |  68          | 324          | | Mean (SD) | 137.9 (17.4) | 134.8 (15.0) | 142.0 (15.3) | 137.8 (16.4) | | Median | 139.5        | 130.5        | 140.0        | 138.0        | | Min, Max | 106  , 190   | 100  , 168   | 107  , 186   | 100  , 190   | |   | | | | | | **End of Treatment** | | | | | | n | 129          | 108          |  81          | 318          | | Mean (SD) | 135.8 (15.3) | 137.0 (16.1) | 138.0 (17.4) | 136.8 (16.1) | | Median | 133.0        | 133.0        | 140.0        | 136.0        | | Min, Max |  95  , 172   |  98  , 178   | 100  , 177   |  95  , 178   | | | | | | | | **Sex: M (N = 111)** | | | | | | **Diastolic BP (mmHg)** | | | | | | **Baseline** | | | | | | n | 132          | 164          | 148          | 444          | | Mean (SD) |  77.1 (10.0) |  77.1 (8.8)  |  78.5 (9.8)  |  77.6 (9.5)  | | Median |  76.0        |  76.3        |  80.0        |  76.8        | | Min, Max |  54  , 102   |  58  , 108   |  58  , 100   |  54  , 108   | |   | | | | | | **Week 8** | | | | | | n | 124          |  92          | 120          | 336          | | Mean (SD) |  75.4 (8.8)  |  72.7 (9.3)  |  78.5 (8.1)  |  75.8 (9.0)  | | Median |  76.0        |  72.0        |  79.7        |  76.0        | | Min, Max |  50  , 101   |  52  , 100   |  57  , 94    |  50  , 101   | |   | | | | | | **Week 16** | | | | | | n | 116          |  68          |  80          | 264          | | Mean (SD) |  75.4 (10.7) |  74.6 (8.7)  |  74.5 (8.8)  |  74.9 (9.7)  | | Median |  76.0        |  73.7        |  75.5        |  75.3        | | Min, Max |  50  , 98    |  59  , 94    |  50  , 90    |  50  , 98    | |   | | | | | | **End of Treatment** | | | | | | n |  93          |  69          |  87          | 249          | | Mean (SD) |  75.1 (10.6) |  74.0 (9.6)  |  75.6 (7.8)  |  75.0 (9.4)  | | Median |  73.0        |  74.0        |  76.0        |  74.0        | | Min, Max |  58  , 104   |  52  , 94    |  57  , 90    |  52  , 104   | |   | | | | | | **Systolic BP (mmHg)** | | | | | | **Baseline** | | | | | | n | 132          | 164          | 148          | 444          | | Mean (SD) | 130.0 (16.5) | 136.1 (18.7) | 135.3 (14.4) | 134.0 (16.9) | | Median | 130.3        | 134.0        | 137.2        | 132.0        | | Min, Max |  80  , 170   | 100  , 188   | 104  , 170   |  80  , 188   | |   | | | | | | **Week 8** | | | | | | n | 124          |  92          | 120          | 336          | | Mean (SD) | 133.7 (17.5) | 130.1 (16.9) | 131.2 (10.3) | 131.8 (15.2) | | Median | 131.0        | 131.0        | 131.2        | 131.0        | | Min, Max |  90  , 189   |  98  , 180   | 110  , 158   |  90  , 189   | |   | | | | | | **Week 16** | | | | | | n | 116          |  68          |  80          | 264          | | Mean (SD) | 130.2 (18.6) | 129.0 (12.5) | 126.5 (12.8) | 128.8 (15.6) | | Median | 130.0        | 129.7        | 126.0        | 128.0        | | Min, Max |  76  , 178   | 100  , 158   |  99  , 154   |  76  , 178   | |   | | | | | | **End of Treatment** | | | | | | n |  93          |  69          |  87          | 249          | | Mean (SD) | 128.5 (14.7) | 126.8 (16.8) | 127.0 (11.6) | 127.5 (14.3) | | Median | 130.0        | 124.0        | 130.0        | 130.0        | | Min, Max |  78  , 164   |  92  , 162   | 100  , 156   |  78  , 164   |   Vital signs by sex   For a **different `(N=)` per arm on each page** (the column headers re-resolving per subgroup), pass `big_n` — a small table of N per page × arm. No bundled dataset carries per-arm-per-page counts, so build it inline (this is also the shape `big_n` expects): ``` r big_n <- tibble::tribble( ~sex, ~placebo, ~drug_50, ~drug_100, ~Total, "F", 53L, 55L, 35L, 143L, "M", 33L, 41L, 37L, 111L ) tabular(cdisc_saf_subgroup, titles = "Vital signs by sex") |> cols( param = "Parameter", visit = "Visit", stat_label = "Statistic", .hide = c("sex_n", "paramcd") ) |> group_rows(by = c("param", "visit")) |> cols_apply( c("placebo", "drug_50", "drug_100", "Total"), col_spec(align = "decimal") ) |> subgroup(by = "sex", label = "Sex: {sex}", big_n = big_n) # per-page (N=) per arm ``` | Statistic | placebo | drug_50 | drug_100 | Total | |-------------------------|--------------|--------------|--------------|--------------| | **Sex: F** | | | | | | | (N=53) | (N=55) | (N=35) | (N=143) | | **Diastolic BP (mmHg)** | | | | | | **Baseline** | | | | | | n | 208          | 220          | 140          | 568          | | Mean (SD) |  77.1 (11.2) |  76.3 (10.5) |  78.0 (10.8) |  77.0 (10.8) | | Median |  78.0        |  77.3        |  78.3        |  78.0        | | Min, Max |  40  , 110   |  48  , 100   |  51  , 108   |  40  , 110   | |   | | | | | | **Week 8** | | | | | | n | 168          | 148          | 104          | 420          | | Mean (SD) |  75.1 (9.4)  |  77.1 (11.0) |  76.0 (10.0) |  76.0 (10.1) | | Median |  76.0        |  79.7        |  78.0        |  78.0        | | Min, Max |  49  , 98    |  55  , 98    |  54  , 98    |  49  , 98    | |   | | | | | | **Week 16** | | | | | | n | 156          | 100          |  68          | 324          | | Mean (SD) |  74.9 (11.1) |  75.6 (10.8) |  77.8 (8.9)  |  75.8 (10.6) | | Median |  77.7        |  76.0        |  79.0        |  78.0        | | Min, Max |  49  , 98    |  55  , 98    |  56  , 92    |  49  , 98    | |   | | | | | | **End of Treatment** | | | | | | n | 129          | 108          |  81          | 318          | | Mean (SD) |  74.0 (10.7) |  77.2 (11.9) |  76.5 (11.7) |  75.7 (11.5) | | Median |  74.0        |  79.5        |  80.0        |  78.0        | | Min, Max |  49  , 100   |  50  , 100   |  56  , 98    |  49  , 100   | |   | | | | | | **Systolic BP (mmHg)** | | | | | | **Baseline** | | | | | | n | 208          | 220          | 140          | 568          | | Mean (SD) | 141.1 (16.9) | 139.2 (18.2) | 140.4 (19.5) | 140.2 (18.0) | | Median | 141.8        | 140.0        | 140.0        | 140.0        | | Min, Max | 100  , 184   | 100  , 194   | 100  , 192   | 100  , 194   | |   | | | | | | **Week 8** | | | | | | n | 168          | 148          | 104          | 420          | | Mean (SD) | 138.1 (16.5) | 137.9 (17.8) | 139.6 (19.0) | 138.4 (17.6) | | Median | 139.5        | 135.7        | 140.0        | 138.7        | | Min, Max | 100  , 184   |  92  , 200   |  91  , 198   |  91  , 200   | |   | | | | | | **Week 16** | | | | | | n | 156          | 100          |  68          | 324          | | Mean (SD) | 137.9 (17.4) | 134.8 (15.0) | 142.0 (15.3) | 137.8 (16.4) | | Median | 139.5        | 130.5        | 140.0        | 138.0        | | Min, Max | 106  , 190   | 100  , 168   | 107  , 186   | 100  , 190   | |   | | | | | | **End of Treatment** | | | | | | n | 129          | 108          |  81          | 318          | | Mean (SD) | 135.8 (15.3) | 137.0 (16.1) | 138.0 (17.4) | 136.8 (16.1) | | Median | 133.0        | 133.0        | 140.0        | 136.0        | | Min, Max |  95  , 172   |  98  , 178   | 100  , 177   |  95  , 178   | | | | | | | | **Sex: M** | | | | | | | (N=33) | (N=41) | (N=37) | (N=111) | | **Diastolic BP (mmHg)** | | | | | | **Baseline** | | | | | | n | 132          | 164          | 148          | 444          | | Mean (SD) |  77.1 (10.0) |  77.1 (8.8)  |  78.5 (9.8)  |  77.6 (9.5)  | | Median |  76.0        |  76.3        |  80.0        |  76.8        | | Min, Max |  54  , 102   |  58  , 108   |  58  , 100   |  54  , 108   | |   | | | | | | **Week 8** | | | | | | n | 124          |  92          | 120          | 336          | | Mean (SD) |  75.4 (8.8)  |  72.7 (9.3)  |  78.5 (8.1)  |  75.8 (9.0)  | | Median |  76.0        |  72.0        |  79.7        |  76.0        | | Min, Max |  50  , 101   |  52  , 100   |  57  , 94    |  50  , 101   | |   | | | | | | **Week 16** | | | | | | n | 116          |  68          |  80          | 264          | | Mean (SD) |  75.4 (10.7) |  74.6 (8.7)  |  74.5 (8.8)  |  74.9 (9.7)  | | Median |  76.0        |  73.7        |  75.5        |  75.3        | | Min, Max |  50  , 98    |  59  , 94    |  50  , 90    |  50  , 98    | |   | | | | | | **End of Treatment** | | | | | | n |  93          |  69          |  87          | 249          | | Mean (SD) |  75.1 (10.6) |  74.0 (9.6)  |  75.6 (7.8)  |  75.0 (9.4)  | | Median |  73.0        |  74.0        |  76.0        |  74.0        | | Min, Max |  58  , 104   |  52  , 94    |  57  , 90    |  52  , 104   | |   | | | | | | **Systolic BP (mmHg)** | | | | | | **Baseline** | | | | | | n | 132          | 164          | 148          | 444          | | Mean (SD) | 130.0 (16.5) | 136.1 (18.7) | 135.3 (14.4) | 134.0 (16.9) | | Median | 130.3        | 134.0        | 137.2        | 132.0        | | Min, Max |  80  , 170   | 100  , 188   | 104  , 170   |  80  , 188   | |   | | | | | | **Week 8** | | | | | | n | 124          |  92          | 120          | 336          | | Mean (SD) | 133.7 (17.5) | 130.1 (16.9) | 131.2 (10.3) | 131.8 (15.2) | | Median | 131.0        | 131.0        | 131.2        | 131.0        | | Min, Max |  90  , 189   |  98  , 180   | 110  , 158   |  90  , 189   | |   | | | | | | **Week 16** | | | | | | n | 116          |  68          |  80          | 264          | | Mean (SD) | 130.2 (18.6) | 129.0 (12.5) | 126.5 (12.8) | 128.8 (15.6) | | Median | 130.0        | 129.7        | 126.0        | 128.0        | | Min, Max |  76  , 178   | 100  , 158   |  99  , 154   |  76  , 178   | |   | | | | | | **End of Treatment** | | | | | | n |  93          |  69          |  87          | 249          | | Mean (SD) | 128.5 (14.7) | 126.8 (16.8) | 127.0 (11.6) | 127.5 (14.3) | | Median | 130.0        | 124.0        | 130.0        | 130.0        | | Min, Max |  78  , 164   |  92  , 162   | 100  , 156   |  78  , 164   |   Vital signs by sex   `big_n` accepts this wide shape (page column + one column per arm) or a long `count()`-style table (page, arm, n). ## Empty tables: no data to report A table whose data has zero rows still renders — the full page chrome and the column headers stay intact, and an empty-data placeholder takes the place of the body. This is the correct output for a population that produced no records (a cohort with no subjects, a serious-AE table with no events), rather than an error or a blank page. The per-table message is `tabular(empty_text = ...)`; set a house default for every table with `preset(empty_text = ...)`. The message renders as a single horizontally centred row in the table body, where the first data row would sit. ``` r # Same demographics shell, but the population filter has left no rows. empty_demo <- cdisc_saf_demo[0, ] tabular( empty_demo, titles = c( "Table 14.1.1", "Demographic and Baseline Characteristics", "Safety Population" ), footnotes = "No subjects met the inclusion criteria for this cohort.", empty_text = "No data available to report" ) |> group_rows(by = "variable") |> cols( stat_label = col_spec(label = "Statistic"), placebo = col_spec(label = "Placebo", align = "decimal"), drug_50 = col_spec(label = "Drug 50 mg", align = "decimal"), drug_100 = col_spec(label = "Drug 100 mg", align = "decimal"), Total = col_spec(align = "decimal") ) ``` | variable | Statistic | Placebo | Drug 50 mg | Drug 100 mg | Total | |:---------------------------:|:---------:|:-------:|:----------:|:-----------:|:-----:| | No data available to report | | | | | | No subjects met the inclusion criteria for this cohort.   Table 14.1.1 Demographic and Baseline Characteristics Safety Population   The same applies under [`subgroup()`](https://vthanik.github.io/tabular/reference/subgroup.md): a zero-N crossing is dropped by default, but `subgroup(..., keep_empty = TRUE)` keeps it and renders its banner above the empty-data page — so every level in the shell appears even when one has no data. # Get started with tabular `tabular` turns one **pre-summarised, wide data frame** into a publication-ready table and renders it natively to **RTF, HTML, DOCX, PDF (LaTeX- or typst-compiled), LaTeX, Typst and Markdown** — from a single spec, with no Java or Office dependency. Two things to internalise up front: 1. **tabular is display-only.** It never aggregates, filters, or computes statistics. You bring a summarised data frame (one input row = one display row); tabular lays it out and renders it. (Producing that frame from a cards ARD is the [*Data in*](https://vthanik.github.io/tabular/articles/data-in.html) article.) 2. **One immutable spec, built with verbs.** You pipe a [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) object through verbs ([`cols()`](https://vthanik.github.io/tabular/reference/cols.md), [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md), [`preset()`](https://vthanik.github.io/tabular/reference/preset.md), …) and finish with [`emit()`](https://vthanik.github.io/tabular/reference/emit.md). Each verb returns a new spec; nothing renders until [`emit()`](https://vthanik.github.io/tabular/reference/emit.md). ## Your first table Start from a wide frame — here the bundled demographics summary, one row per statistic, one column per treatment arm: ``` r data(cdisc_saf_demo, package = "tabular") head(cdisc_saf_demo) #> variable stat_label placebo drug_50 drug_100 Total #> 1 Age (years) n 86 96 72 254 #> 2 Age (years) Mean (SD) 75.2 (8.59) 76.0 (8.11) 73.8 (7.94) 75.1 (8.25) #> 3 Age (years) Median 76.0 78.0 75.5 77.0 #> 4 Age (years) Q1, Q3 69.2, 81.8 71.0, 82.0 70.5, 79.0 70.0, 81.0 #> 5 Age (years) Min, Max 52, 89 51, 88 56, 88 51, 89 #> 6 Sex, n (%) F 53 (61.6) 55 (57.3) 35 (48.6) 143 (56.3) ``` Describe the columns. The spec prints as a live HTML table — this is the same render [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) produces, shown inline: ``` r spec <- tabular( cdisc_saf_demo, titles = c( "Table 14-2.01", "Demographic and Baseline Characteristics", "ITT Population" ) ) |> cols( variable = col_spec(label = ""), stat_label = col_spec(label = "") ) |> group_rows(by = "variable") spec ``` | | placebo | drug_50 | drug_100 | Total | |----|----|----|----|----| | **Age (years)** | | | | | | n | 86 | 96 | 72 | 254 | | Mean (SD) | 75.2 (8.59) | 76.0 (8.11) | 73.8 (7.94) | 75.1 (8.25) | | Median | 76.0 | 78.0 | 75.5 | 77.0 | | Q1, Q3 | 69.2, 81.8 | 71.0, 82.0 | 70.5, 79.0 | 70.0, 81.0 | | Min, Max | 52, 89 | 51, 88 | 56, 88 | 51, 89 | |   | | | | | | **Sex, n (%)** | | | | | | F | 53 (61.6) | 55 (57.3) | 35 (48.6) | 143 (56.3) | | M | 33 (38.4) | 41 (42.7) | 37 (51.4) | 111 (43.7) | |   | | | | | | **Race, n (%)** | | | | | | WHITE | 78 (90.7) | 90 (93.8) | 62 (86.1) | 230 (90.6) | | BLACK OR AFRICAN AMERICAN | 8 (9.3) | 6 (6.2) | 9 (12.5) | 23 (9.1) | | ASIAN | 0 (0.0) | 0 (0.0) | 0 (0.0) | 0 (0.0) | | AMERICAN INDIAN OR ALASKA NATIVE | 0 (0.0) | 0 (0.0) | 1 (1.4) | 1 (0.4) |   Table 14-2.01 Demographic and Baseline Characteristics ITT Population   To write a file, hand the spec to [`emit()`](https://vthanik.github.io/tabular/reference/emit.md); the backend is chosen by the file extension (or an explicit `format =`): ``` r out <- tempfile(fileext = ".rtf") emit(spec, out) # RTF here; swap to .docx / .pdf / .html / .tex / .typ / .md file.exists(out) #> [1] TRUE ``` That is the whole loop: **wide frame → [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) → [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) → [`emit()`](https://vthanik.github.io/tabular/reference/emit.md)** — one spec, any backend. ## The pipeline at a glance Read it left to right. You **summarise upstream** — with cards/cardx, dplyr, or SAS — into a long ARD, widen that to a display-ready frame with [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md), then hand it to tabular. Inside the package the work happens in three phases (**Build → Resolve → Emit**), and the *same* resolved spec emits to every backend, so the HTML you preview and the RTF you ship can never disagree. ![An ADaM dataset is aggregated into a long ARD, widened by pivot_across into a wide data frame, then Build, Resolve, and Emit render that one spec to RTF, PDF, HTML, LaTeX, and DOCX.](../reference/figures/workflow.svg) tabular’s pipeline: summarise upstream into a long ARD, widen it with [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md), then build, resolve, and emit one immutable spec to every backend. ## Anatomy of a clinical table page A submission table is not just a grid of numbers — it is a page with four stacked sections, and a reviewer expects each one in its place. Every tabular verb maps onto a piece of this picture: ![A clinical table page split into header section, title lines, data section, and footnote lines, each annotated with the tabular verb that produces it.](../reference/figures/anatomy.svg) The four-section clinical page and the verb that fills each section. - **Header section** — the running protocol, optional status, and *page x of y*, set as page chrome with `preset(pagehead =, pagefoot =)`. - **Title lines** — the table number and up to four centred titles, passed to `tabular(titles =)`. - **Data section** — an optional [`subgroup()`](https://vthanik.github.io/tabular/reference/subgroup.md) banner, the column-header band built by [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) and [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), then the decimal-aligned data. - **Footnote lines** — your static `footnotes =` plus any auto-numbered [`footnote()`](https://vthanik.github.io/tabular/reference/footnote.md) markers, then the program path, name, and timestamp. [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) frames all four by controlling the page geometry (paper, orientation, margins, fonts). ## Where to next The rest of the docs are task-oriented — read the one that matches what you are doing: - **[Data in](https://vthanik.github.io/tabular/articles/data-in.html)** — turn a cards/cardx ARD (or any long ARD) into the wide frame, with [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md). - **[Structure](https://vthanik.github.io/tabular/articles/structure.html)** — columns, headers, BigN, and splitting wide or long tables across pages ([`cols()`](https://vthanik.github.io/tabular/reference/cols.md), [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md), [`subgroup()`](https://vthanik.github.io/tabular/reference/subgroup.md)). - **[Presentation](https://vthanik.github.io/tabular/articles/presentation.html)** — titles, footnotes, running headers, and cell styling ([`footnote()`](https://vthanik.github.io/tabular/reference/footnote.md), [`preset()`](https://vthanik.github.io/tabular/reference/preset.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md)). - **[Recipes](https://vthanik.github.io/tabular/articles/recipes.html)** — the canonical CDISC-pilot safety and efficacy tables built end to end, each rendered live. - **[Output & qualification](https://vthanik.github.io/tabular/articles/output.html)** — the backends, their system requirements, and the CDISC-pilot cross-backend validation. # Authors and Citation ## Authors - **[Vignesh Thanikachalam](https://github.com/vthanik)**. Author, maintainer, copyright holder. ## Citation Source: [`inst/CITATION`](https://github.com/vthanik/tabular/blob/v0.3.2/inst/CITATION) Thanikachalam V (2026). *tabular: Render Tables and Listings for Clinical Submissions*. R package version 0.3.2, . @Manual{, title = {{tabular}: Render Tables and Listings for Clinical Submissions}, author = {Vignesh Thanikachalam}, year = {2026}, note = {R package version 0.3.2}, url = {https://vthanik.github.io/tabular/}, } # tabular **tabular** turns a pre-summarised data frame into a submission-grade clinical table and emits it natively to **RTF, PDF, HTML, LaTeX, Typst, and DOCX** — no Java, no LibreOffice, no Word automation. One short pipeline gives you decimal alignment via real font metrics, multi-level column headers, predicate-targeted styling, and group-aware pagination, built for CDISC ADaM workflows and FDA / EMA / PMDA submissions. It is the only R table package that pairs a **live HTML preview** with a **paginated print deliverable**: the same spec you eyeball in a notebook is the one that paginates into the RTF you ship. > **Scope.** `tabular` renders the full set of clinical outputs – > **tables, listings, and figures** (the “T”, “L”, and “F” of TFL) – to > RTF, LaTeX, Typst, HTML, PDF, and DOCX from one verb pipeline. A > zero-row table renders an empty-data placeholder (“No data available > to report”) in the body, with the page chrome and column headers > intact. ## Installation Install the released version from CRAN: ``` r install.packages("tabular") ``` Or the development version from GitHub: ``` r # install.packages("pak") pak::pak("vthanik/tabular") # or remotes::install_github("vthanik/tabular") ``` R dependencies install automatically. The backends differ in what *else* they need: | Backend | Extra requirement | |----|:---| | RTF, DOCX, HTML, Markdown | none — pure R, no Java, no `pandoc`, no Office | | LaTeX (`.tex` source), Typst (`.typ` source) | none — `tabular` writes the source | | PDF | one of two engines: a TeX install (xelatex), **or** a typst binary — Quarto ≥ 1.4 bundles one, so most machines already qualify | PDF is the only backend that shells out, and it has **two engines**: - **LaTeX** — `emit(spec, "out.pdf")` compiles via `xelatex` when a usable TeX is found. `tabularray` + `ninecolors` ship with `tabular`, so no `tlmgr_install()` step is needed even on locked-down servers (Domino, Posit Workbench) where `tlmgr install` is impossible. - **Typst** — with no usable TeX, [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) falls back to the `typst` compiler (the standalone binary, or the copy bundled inside Quarto, which ships with RStudio / Posit Workbench). No TeX installation at all, and compiles in well under a second. Pass `format = "latex"` or `format = "typst"` to pick an engine explicitly; with neither engine present, install one: ``` r install.packages("tinytex") tinytex::install_tinytex(bundle = "TinyTeX") # one-time TeX setup # or: install Quarto (https://quarto.org) — it bundles the typst engine ``` [`check_latex()`](https://vthanik.github.io/tabular/reference/check_latex.md) reports which LaTeX packages resolve (probed through `kpsewhich`, the same resolver `xelatex` uses) and prints the remedy for anything genuinely missing; [`check_typst()`](https://vthanik.github.io/tabular/reference/check_typst.md) does the same for the typst engine (binary, version floor, and the font chain PDFs render in); `check_fonts(spec)` audits the fonts a spec asks for, per backend. ``` r tabular::check_latex() # LaTeX-PDF readiness, with the install remedy tabular::check_typst() # Typst-PDF readiness (no TeX needed) ``` > **TeX Live on a managed OS.** If TeX Live came from the system package > manager (RHEL `dnf`, Debian/Ubuntu `apt`), its `tlmgr` is usually > locked and `tlmgr_install()` fails on permissions. Install user-space > TinyTeX alongside it rather than fighting the system copy — and never > reach for `--ignore-warning` to force it. ## A table in one pipeline The pipeline starts from a pre-summarised wide data frame (one row in = one display row — `tabular` does no aggregation) and chains one verb per concern. Every verb returns an updated, immutable `tabular_spec`; the engine resolves it at render time. ``` r library(tabular) # BigN denominators, keyed by arm n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) # columns render in data-frame order, so put them in dose order first; # subset to Age / Sex / Race for a compact display keep <- c("Age (years)", "Sex, n (%)", "Race, n (%)") demo <- cdisc_saf_demo[ cdisc_saf_demo$variable %in% keep, c("variable", "stat_label", "placebo", "drug_50", "drug_100", "Total") ] tab <- tabular( demo, titles = c( "Table 14.1.1", "Demographic and Baseline Characteristics", "Safety Population" ), footnotes = "Percentages are based on the number of subjects per treatment group." ) |> cols( variable = "Characteristic", stat_label = "Statistic", placebo = col_spec( label = "Placebo (N={n['placebo']})", align = "decimal" ), drug_50 = col_spec( label = "Drug 50 (N={n['drug_50']})", align = "decimal" ), drug_100 = col_spec( label = "Drug 100 (N={n['drug_100']})", align = "decimal" ), Total = col_spec(label = "Total (N={n['Total']})", align = "decimal") ) |> group_rows(by = "variable") # render to any backend by file extension (or format = "...") path <- emit(tab, tempfile(fileext = ".rtf")) # submission deliverable ``` The same `tab` emits to every backend from the one spec. The table below is tabular’s own HTML render — the identical spec also produces RTF, a paginated PDF (LaTeX- or typst-compiled), a `tabularray` LaTeX fragment, a native Typst document, and native OOXML `.docx`: ![Demographic and baseline characteristics table rendered by tabular: decimal-aligned arm columns, a centred multi-line caption, and a single footnote.](reference/figures/README-hero.png) ## Why tabular? - **Every native backend, one spec.** [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) dispatches on the file extension to RTF 1.9.1, self-contained Bootstrap HTML, `tabularray` LaTeX, native Typst, native OOXML DOCX, and PDF — compiled through LaTeX when a TeX is installed, or through the typst engine (bundled with Quarto) on TeX-less machines. No JVM, no Office round-trip. - **Decimal alignment that survives the page.** Numbers align on the decimal using the backend’s real font metrics, not guessed padding — so columns stay aligned in print, not just on screen. - **Submission chrome built in.** Multi-line titles, up to eleven footnote lines, page header/footer slots, and the four-section page layout regulatory reviewers expect. - **Auto-numbered footnotes.** [`footnote()`](https://vthanik.github.io/tabular/reference/footnote.md) anchors a marker to any cell, header, or title; the engine assigns the glyph once, in reading order, deduped by `id`, and byte-identical across every backend and page. - **Group-aware pagination.** Keep a SOC and its preferred terms on one page, repeat titles/headers/footnotes per page, control orphan/widow rows, and split wide tables into horizontal panels. - **Display-only by design.** `tabular` styles and renders; it never filters, aggregates, or weights. Pair it with `cards` / `gtsummary` / `dplyr` / SAS upstream and feed it a tidy wide frame. - **A QC trail.** `emit(data_file = ...)` writes the resolved wide data beside the render, and a CDISC ARS audit manifest documents the display. ## Where tabular fits `tabular` is a *renderer* for pre-summarised clinical tables, not a statistics engine. Compute the summary upstream — with `cards`, `gtsummary`, `dplyr`, or SAS — then hand the finished wide frame to [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md). Reach for `gtsummary` or `rtables` when you want the package to *compute* the summary; reach for `tabular` to *render* a summary you already have to submission-grade output. The matrix reflects each package’s documented export surface (verified against their namespaces; `via gt` means `gtsummary` renders through `gt`): | | tabular | gt | rtables | gtsummary | flextable | huxtable | |----|:--:|:--:|:--:|:--:|:--:|:--:| | Computes statistics | — | — | ✓ | ✓ | — | — | | Live HTML preview | ✓ | ✓ | — | ✓ | ✓ | ✓ | | Native RTF | ✓ | ✓ | — | via gt | ✓ | ✓ | | Native DOCX | ✓ | ✓ | — | via gt | ✓ | ✓ | | LaTeX | ✓ | ✓ | — | via gt | — | ✓ | | PDF | ✓ | ✓ | ✓ | via gt | — | ✓ | | Paginated submission output | ✓ | — | ✓ | — | — | — | | Decimal align via font metrics | ✓ | — | — | — | — | — | | CDISC ARS audit manifest | ✓ | — | — | — | — | — | Two notes on the marks: - **Live HTML preview** means the table renders as HTML *inline* when you print it in a Quarto / R Markdown chunk or the RStudio viewer (a `knit_print` method). `rtables` prints a monospace ASCII table by default and ships no `knit_print` method, so it is `—` here; it can still emit HTML through an explicit `as_html()` call. - **PDF** is compiled through LaTeX, so it needs a TeX installation — see [Installation](#installation) above. Every other backend is pure R. ## Documentation - [Get started](https://vthanik.github.io/tabular/articles/tabular.html) — the mental model and your first table - [Data in](https://vthanik.github.io/tabular/articles/data-in.html) — turn a cards/cardx ARD into the wide frame with [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) - [Structure](https://vthanik.github.io/tabular/articles/structure.html) — columns, headers, BigN, and pagination - [Presentation](https://vthanik.github.io/tabular/articles/presentation.html) — titles, footnotes, page chrome, and styling - [Output & qualification](https://vthanik.github.io/tabular/articles/output.html) — backends, requirements, and the CDISC-pilot validation - [Reference](https://vthanik.github.io/tabular/reference/index.html) — every verb, grouped by role ## License MIT © Vignesh Thanikachalam # License YEAR: 2026 COPYRIGHT HOLDER: Vignesh Thanikachalam # MIT License Copyright (c) 2026 Vignesh Thanikachalam Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # Changelog ## tabular 0.3.2 ### Minor improvements and bug fixes - A [`check_latex()`](https://vthanik.github.io/tabular/reference/check_latex.md) unit test that verifies TinyTeX resolution off the `PATH` now carries `skip_on_cran()`, so it no longer errors on CRAN machines that expose a TinyTeX root without a functional TeX at it (the CRAN macOS arm64 check). Package code is unchanged. ## tabular 0.3.1 CRAN release: 2026-07-20 ### Improvements - [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md) and [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) are 11-24% faster on long tables across every backend: cell inline-markup ASTs are parsed once per distinct string, style layers extract their overrides once per layer instead of per cell, subgroup splitting / decimal alignment / pagination keys are single-pass, XML/HTML escaping is vectorised, and body rows are assembled without quadratic append. ### New features - `preset(font_family = )` generic chains (`"mono"` / `"serif"` / `"sans"`) gained the URW/Nimbus Core-35 clone (Nimbus Mono PS / Nimbus Roman / Nimbus Sans) between the PostScript name and the Liberation face, so the default still renders as Courier / Times / Helvetica on Linux images that ship only the ghostscript fonts (and whose Type 1 Courier the Typst compiler cannot read); all links are metric-compatible, so layout is unchanged wherever the chain resolves. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to `.tex`, `.typ`, and PDF now re-expresses plain group-separator blank rows as discardable space (a white tabularray hline band on LaTeX, a `row-gutter` entry on Typst), so a page never ends on a stray blank line above the repeated closing rule when the native page break lands at a group boundary, matching how Word renders the RTF/DOCX output; mid-page the gap keeps the blank row’s exact height, and styled or ruled tables (rowrules, side frames, striped separators) keep the real blank row. - `preset(decimal_metrics = "afm")` now measures a `font_family` with no bundled metric table (e.g. a system-installed face such as Courier 10 Pitch) through a temporary graphics device, so decimal alignment and width measurement stay exact whenever the host can resolve the font; the Times-fallback fidelity warning now fires only when that device probe also fails, and the probe can be disabled with `options(tabular.device_metrics = FALSE)`. - [`check_typst()`](https://vthanik.github.io/tabular/reference/check_typst.md) is a new diagnostic that audits the Typst PDF toolchain: which typst binary is discoverable (standalone `typst`, or the copy bundled inside Quarto), whether its version meets the 0.11 floor, and which families of the configured font chain the compiler can see; the chain is a fallback chain, so the check reports ready as soon as any family resolves and names the face PDFs render in. [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) warns after a Typst compile only when a family the user explicitly named cannot be found — missing members of the built-in cross-OS fallback chains substitute silently, matching the other backends. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) gained a Typst backend: `emit(spec, "out.typ")` writes a standalone Typst document (native `#table` with repeating `table.header`/`table.footer`, page chrome via `#set page()` counters, native per-cell borders), and `emit(spec, "out.pdf", format = "typst")` compiles it through the standalone typst binary or Quarto’s bundled copy, so PDF output no longer requires any TeX installation. The table centres on the page, the running header and footer anchor to the body edges (the header grows upward into the top margin, the footer downward, tracking the configured margins), and [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md)’s keep-with-next mask is enforced through unbreakable rowspans in a hidden zero-width column. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) on a bare `.pdf` target now selects its compile engine by probing the machine, LaTeX first: a usable TeX (resolved the way the compile resolves it, and not frozen on a pre-2023 TeX Live kernel) keeps the historical LaTeX path byte-stable, a discoverable typst binary takes over otherwise, and with neither engine the call aborts up front naming both remedies; `format = "latex"` / `format = "typst"` pick the engine explicitly. - [`check_latex()`](https://vthanik.github.io/tabular/reference/check_latex.md) now reports the TeX Live release year of the active `xelatex` and fails the check when it predates 2023, the first release whose LaTeX kernel (2022-11-01) can load the bundled tabularray; the report and the [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) PDF compile error both explain the update / user-space TinyTeX remedy for images frozen on an old TeX Live. - [`check_latex()`](https://vthanik.github.io/tabular/reference/check_latex.md) and the PDF pre-compile staging now resolve TeX the same way the compile does, preferring a TinyTeX at the standard root (installed by either [`tinytex::install_tinytex()`](https://rdrr.io/pkg/tinytex/man/install_tinytex.html) or `quarto install tinytex`) over the `PATH`, so the diagnostic can no longer describe a different TeX than the one [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) actually runs; remediation hints name the `quarto install tinytex` route, which downloads from GitHub and therefore works behind proxies that block CTAN. - [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) accepts a bare string as label shorthand (`soc = "SOC / PT"` is `soc = col_spec(label = "SOC / PT")`, including glue interpolation and the deferred `{.name}` token) and a `.hide` argument that hides the named columns in one flat vector. - [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md) keep-together protection on the natively-paginating backends (RTF, DOCX) now emits edge-only row glue instead of gluing a whole fitting block, so a block that fits a fresh page but not the space left on the current one no longer bumps wholesale and strands a near-empty page; widow/orphan floors count content rows only, with trailing blank spacer rows still riding with their block. - `paginate(keep_together = )` now accepts any column of `data` (including hidden block-key columns), not only `usage = "group"` columns. ### Breaking changes - [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) no longer has `usage`, `group_display`, or `group_skip` arguments; row grouping is a table-level fact and is now declared once with the new [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) verb. The inert-knob warning for `group_display`/`group_skip` on non-group columns is gone with them. - [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) is the new structural verb: `group_rows(by, display, skip)` names only the structural grouping keys outer to inner (the section headers and any hidden break keys, not the visible label column, which stays an ordinary [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) column and is auto-indented). `display` is a single value applied to every key (`"section"`, `"collapse"`, or `"repeat"`); a hidden break-only key is expressed with `col_spec(visible = FALSE)` rather than a display mode. `skip` follows the `readr::read_csv(col_names = )` pattern: `TRUE` (the default) derives the blank spacers from `display` and key visibility, `FALSE` inserts none, and a character subset of `by` breaks on exactly those keys (e.g. `skip = "param"`). Nesting is just listing the header keys (`by = c("param", "visit")`). It replaces a prior declaration wholesale, and its keys may not overlap `subgroup(by = )`. - [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md) gained `repeat_cols`, replacing the `usage = "id"` role: the horizontal-panel stub defaults to the visible [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) keys, and an explicit `repeat_cols` vector replaces that default. ### Minor improvements and bug fixes - DESCRIPTION’s SystemRequirements no longer contains the bare word “LaTeX”, which pak’s system-requirements scraper matched and answered by force-installing the `texlive` OS package (a sudo failure on locked-down hosts such as Domino); the TeX distribution remains optional for PDF output. - Fidelity warnings now render their feature string as inline code instead of a quoted value, so a feature that itself contains quotes (`decimal_metrics = "afm"`) no longer prints with escaped quotes. - [`check_latex()`](https://vthanik.github.io/tabular/reference/check_latex.md) now probes package availability through `kpsewhich` (the resolver xelatex itself uses) instead of the tlmgr package database, fixing all-missing false negatives on apt-installed TeX Live and frozen TinyTeX images, no longer requires the tinytex R package, and reports a new `bundled` column. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to DOCX now stamps the body’s left/right cell margins on section-header, blank-spacer, column-header, and subgroup-banner cells, so their text aligns with body text exactly as in RTF (section headers previously sat one cell margin further left, making nested indents read one character too wide in Word). - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to Typst now folds 2+ space runs in body cells under `preset(whitespace = "collapse")`; the no-wrap hardening previously rewrote the run to non-breaking spaces first, so the knob was a silent no-op on Typst while every other backend honoured it. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to Typst now stamps the header surface background and padding on the column-label cells, so `preset(colors = list(header = ...))`, `preset(padding = list(header = ...))`, and the equivalent [`style()`](https://vthanik.github.io/tabular/reference/style.md) at [`cells_headers()`](https://vthanik.github.io/tabular/reference/cells.md) render as they do on RTF, HTML, LaTeX, and DOCX. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to LaTeX/PDF and Typst now places the running header band so its bottom edge sits exactly on the top-margin line, growing upward into the margin, and keeps the body at exactly the configured top margin — matching the RTF and DOCX placement; the LaTeX head lengths moved onto the `geometry` option list (a post-load `\setlength{\headsep}` shifted the body off the margin instead of moving the header) and every band row now carries a `\strut` so the band’s bottom edge no longer depends on descenders in its content. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to HTML and Markdown no longer drops a [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) blank spacer when a group transition coincides with a page boundary; the continuous flow keeps every spacer and only the very first row of the table suppresses one. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to Markdown now renders the indent of nested section headers as ` ` before the bold markers instead of spaces inside them, which CommonMark refused to parse as bold (literal `**` showed in the render). - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to PDF now writes to a relative `file` path correctly; the path was previously resolved after switching into the temporary compile directory, so the output landed there and was deleted with it. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to RTF now resolves the row cell gap of header-band, column-label, blank-spacer, section-header, banner, and title rows from `preset(cell_padding = )` like body rows do (previously hardcoded, so a non-default padding skewed header text relative to body text). - [`figure()`](https://vthanik.github.io/tabular/reference/figure.md) output no longer spills onto a blank trailing page in Word: the RTF closing paragraph after the full-page image row now carries the body font size (a bare paragraph rendered at RTF’s 12pt default, taller than the reserved row), and the page-size model now budgets the `preset(pagefoot = )` slot rows (and any `pagehead` rows that overflow the top margin), which intrude into the body exactly like footnote lines. The same budget applies to table pagination. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) PDF output now works on TeX installations that lack `tabularray` / `ninecolors` and cannot run `tlmgr install` (locked-down Domino / Posit Workbench images): tabular ships verbatim CTAN copies of both single-file packages in `inst/tex/` and stages them next to the generated `.tex` at compile time whenever the local TeX cannot resolve them. ## tabular 0.2.0 CRAN release: 2026-07-06 ### New features - The documentation site gained an AI / Agents section linking a tabular skill (for LLM coding agents), the auto-generated `llms.txt`, and a concatenated `llms-full.txt`, mirroring the LLM-friendly documentation pattern. - `col_spec(group_display = "header_row")` now collapses a single-member group to one flush-left row (the group value becomes the row label, still carrying any [`cells_group_headers()`](https://vthanik.github.io/tabular/reference/cells.md) styling) instead of emitting a redundant header plus a lone indented child, and no longer emits an empty header for a blank or `NA` group value. Multi-member groups are unchanged. - [`figure()`](https://vthanik.github.io/tabular/reference/figure.md) renders a figure (the “F” in TFL) to every backend (RTF, LaTeX, PDF, HTML, DOCX, and Markdown), wrapping a ggplot, a recorded base-R plot, a zero-argument drawing function, or a PNG / JPG file in the same submission chrome as a table (titles, footnotes, page header and footer). The image is placed in the body content-box by `halign` and `valign` (both default to centred), exact on the paged backends and approximate on the continuous ones. A list input emits one figure per page, optionally driven by a `meta` data frame whose columns become per-page `{token}` values. On the continuous backends (HTML and Markdown) a multi-page figure’s shared titles and footnotes render once above the stacked plots; supplying `meta` switches to per-page chrome. [`is_figure_spec()`](https://vthanik.github.io/tabular/reference/tabular_predicates.md) tests for the new spec, and [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) writes it to a file. A figure’s titles, footnotes, and page header / footer honour [`style()`](https://vthanik.github.io/tabular/reference/style.md) and the [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) cosmetic knobs (fonts, colours, alignment, padding) and the `preset(spacing = ...)` inter-section gaps, just like a table; styling its (absent) body, headers, or subgroup is an error. A drawing function that raises an error aborts with a clear message naming the failing page. No new package dependency: plots rasterise through base `grDevices` and ggplot2 (Suggests) only when a ggplot is passed. - [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) gained an `aux` argument to bind auxiliary comparison columns (difference, hazard ratio, p-value) from a second ARD, aligned 1:1 on the `row_group` key and appended as trailing columns. - [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md)’s `column` argument now accepts the reserved tokens `.variable` and `.stat` to make an analysis variable a column band: `c(".variable", "")` lays variables side by side with statistics as rows, and `c(".variable", ".stat")` spreads each statistic into its own column with the arm as a row stub. Per-variable `statistic` / `decimals` resolve inside each band. - [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md)’s `decimals` may now be a list keyed by `row_group` values, for per-group precision in one call. - `preset(font_family = ...)` generic chains (`"mono"` / `"sans"` / `"serif"`) now lead with the ubiquitous Microsoft Office face (Courier New / Arial / Times New Roman) and keep the metric-compatible Liberation face as the last fallback, so Word shows a font the reader actually has installed on Windows / macOS instead of a phantom “Liberation Mono” in its font menu. The faces are metric-compatible, so layout, line breaks, and decimal alignment are unchanged. A bare `font_family = "Courier New"` now also leads with Courier New (previously resolved led by Liberation Mono). The package bundles no fonts; an arbitrary named face (`"IBM Plex Mono"`, `"Source Code Pro"`, etc.) is emitted verbatim for the consuming application to resolve. ### Breaking changes - [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) gained a single `indent` argument (an integer for a fixed level on every body row, or a column name for per-row depth); the previous `indent_by` argument and the `usage = "indent"` value were removed in favour of it. An explicit `indent` on a `group_display = "header_row"` host now suppresses the section auto-indent, yielding a single rather than double indent. - [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md) removed the no-op `panels = "auto"`; `panels` is now a positive integer. - [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) no longer pre-indents `stat_label` with two leading spaces; indentation is applied downstream by the renderer via `col_spec(usage = "group")` / `group_display`, so a `header_row` stub no longer double-indents. ### Minor improvements and bug fixes - Every warning now carries a `tabular_warning_` class (`input`, `runtime`, `layout`, `fidelity`) mirroring the `tabular_error_` error taxonomy, so warnings can be caught selectively; the former `tabular_warn_layout` class was renamed to `tabular_warning_layout`. - [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) now warns when `group_display` or `group_skip` is set on a non-group column (the knobs are inert unless `usage = "group"`). - [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) / [`cols_apply()`](https://vthanik.github.io/tabular/reference/cols_apply.md) now restore a column’s visibility and reset `group_display` on a later call, and merge every column attribute field-completely (previously a default value could not be merged back and some fields could be dropped). - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) now centres decimal-aligned columns on every backend instead of right-aligning the uniformly NBSP-padded block, so the values sit under the centred column header (cross-backend parity). - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to DOCX now declares an in-class `` fallback for each font, so a reader missing the primary face substitutes a metric-compatible face in the same class (mono stays mono) instead of panose-guessing to a serif. This brings DOCX in line with the RTF (`\*\falt`) and PDF / LaTeX (`\IfFontExistsTF` cascade) backends, which already declared the same in-class fallback chain. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to HTML now applies per-cell body alignment through a specificity-bumped `.tabular-table td.text-*` rule, so decimal, centred and right-aligned columns actually render aligned; previously the base `.tabular-table td { text-align: left }` rule outranked the plain alignment class and every body cell silently fell back to left. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to HTML now aligns the running page header and footer to the table width via a centred fit-content container, instead of spanning the full document width. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to HTML and Markdown no longer repeats a [`subgroup()`](https://vthanik.github.io/tabular/reference/subgroup.md) banner mid-table when a group is taller than one estimated page. The continuous backends draw one banner per subgroup value; the print-only page-break markers within a group are unchanged, and the paged backends (RTF, LaTeX, DOCX) still repeat the banner on every continuation page by design. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to PDF / LaTeX no longer renders the table wider than the printable area: tabularray adds per-column separation outside each column’s `wd`, so the column widths are now reduced by that separation and the rendered table total matches the resolved width (and the RTF / DOCX cell widths) instead of bleeding into the right margin. ([\#27](https://github.com/vthanik/tabular/issues/27)) - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to PDF / LaTeX now renders column headers in bold, matching the DOCX, RTF and HTML backends. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to PDF / LaTeX now sets the body font size after `\begin{document}` (where it survives) and re-asserts it inside the running header / footer, so an 8pt table no longer renders its body or page chrome at the 10pt document-class default. ([\#27](https://github.com/vthanik/tabular/issues/27)) - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to PDF / LaTeX now tightens the gap between a running page header and the title (and body to a running footer) to one line via `\headsep` and `\footskip`, instead of the wide document-class default. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to PDF / LaTeX no longer overflows a figure onto a second page: the image is placed with flexible `\vfill` glue rather than a fixed-height box that reconstructed to just over the page height, so a multi-page figure (for example one Kaplan-Meier plot per treatment arm) now fits one page per plot. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to RTF and DOCX no longer emits a phantom blank page after each figure plot. The figure box reserves a line for the closing paragraph every paged backend appends after the exact-height image, RTF exits table context with `\pard\par` before the next section break, and DOCX starts each continuation page with a structural `` instead of a standalone page-break paragraph that stranded a blank page. A multi-page figure driven by per-page `meta` also sizes each page’s image box from that page’s interpolated footnotes, so a longer-footnote page no longer overflows. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) aborts with a clear `tabular_error_layout` message when a figure’s titles and footnotes alone exceed the printable height, instead of failing with an opaque graphics-device error. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to RTF now leads the body font slot with the first face of an explicit `font_family` stack instead of the Linux-first default chain, and classes a mono stack `\fmodern` (fixed pitch) the same way DOCX classes it `modern`. A `font_family = c("Courier New", "Liberation Mono", "Courier")` request now renders as Courier New mono in Word instead of substituting a serif, because the named primary face leads the font table rather than being demoted to a `\*\falt` alternate. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to RTF now emits a section break only BETWEEN panels (n-1 breaks for n panels) rather than after every panel, so a single-panel table no longer ends with a trailing section break that Word renders as a phantom blank page. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to RTF now reserves one line per running-header row in `\headery`, so a multi-row page header (for example a protocol row plus an analysis-set row) no longer bleeds back into the body and tips the last table rows, or the table’s trailing paragraph, onto a phantom second page. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) now renders a zero-row empty-state page as a normal table whose body is a single full-span, horizontally centred “no data” message row, where the first data row would sit: the table chrome (titles, column header) leads, the message follows in the body, and the footnote trails immediately, all flowing compactly at the top of the page with blank space below. The message is centred by each backend’s native cell alignment on every backend (RTF, LaTeX, PDF, HTML, DOCX, Markdown); it is no longer vertically centred or relocated into the page margins. A natural-height message row plus trailing footnote cannot overflow, so the recurring phantom-page bug stays fixed. A `subgroup(keep_empty = TRUE)` empty crossing renders the same way, as one message row in its own panel. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) now closes a zero-row empty-state table’s data region with the body bottom rule on every backend, so the “no data” page carries the same closing rule a populated table does. The rule follows the `rules` preset (a custom `bottomrule` width / style / colour is honoured, and `bottomrule = "none"` drops it) instead of being absent (RTF / DOCX) or a fixed default. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to PDF / LaTeX now wraps a table footnote to the table width rather than overrunning it: the footnote minipage no longer double-counts the column separation that the column widths already fold in, so on a narrow table the footnote text stays within the table-width footnote rule instead of spilling past it (and past the printable width). - [`figure()`](https://vthanik.github.io/tabular/reference/figure.md) and paged-table pagination now size the body box from the number of wrapped chrome lines a long title or footnote actually occupies at the printable width, not the element count, so a wrapped footnote no longer pushes content onto a second page on DOCX (and any paged backend). Wrapping is computed by greedy word packing against the font metrics. ([\#26](https://github.com/vthanik/tabular/issues/26)) - [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md) now collapses a zero-row table to a single empty-state page; horizontal `panels` no longer multiply an empty table into several identical blank pages. - [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) now resolves a keyed `statistic` (e.g. `list(hierarchical = "{n} ({p}%)")`) against each row’s real ARD context on the hierarchical path, so a list keyed by `hierarchical` no longer falls through to the bare `{n}` default and silently drops the percent. - [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) now warns when the `overall` label collides with an existing arm name, instead of silently merging the pooled rows into that arm’s column. - [`preset()`](https://vthanik.github.io/tabular/reference/preset.md)’s `decimal_metrics` knob gained `"afm"` (now the default), making decimal alignment width-exact in proportional fonts via the bundled font metrics; Markdown output keeps character padding. - [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) gained an `empty_text` knob, a house-style default for the zero-row message that a per-table `tabular(empty_text = ...)` still overrides. - `preset(spacing = ...)` now drives the blank lines around a subgroup banner (the `subgroup` region) and around a [`figure()`](https://vthanik.github.io/tabular/reference/figure.md) title and footnote; the Markdown table title and footnote gaps now follow the same knob. - `preset(width_mode = "window")` now sizes auto columns proportionally to their content width to fill the page, instead of giving every column an equal share. - [`subgroup()`](https://vthanik.github.io/tabular/reference/subgroup.md) gained a `keep_empty` argument; with `keep_empty = TRUE` a zero-N crossing is retained and rendered as an empty-state page carrying its banner instead of being dropped. - [`subgroup()`](https://vthanik.github.io/tabular/reference/subgroup.md) no longer errors on a zero-row input; the table renders the empty-state placeholder once with no subgroup banner. - [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) gained `empty_text`, the message shown when a table has zero data rows (default “No data available to report”). Zero-row tables now render the full page chrome and the column headers with the message placed in the body, replacing the previous bare “(no rows)” marker. ## tabular 0.1.0 CRAN release: 2026-06-11 First release. `tabular` renders pre-summarised clinical tables and listings to RTF, LaTeX, HTML, PDF, and DOCX from one immutable verb pipeline, with no external Java or SAS dependency. This initial CRAN version consolidates the entire pre-release development cycle: every feature and bug fix below was designed, implemented, and tested before this first release. **Scope.** This release covers tables and listings. Figure (graph) output is not yet supported and is the focus of the next release. ### Build pipeline - [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) takes a pre-summarised wide data frame (one input row is one display row) plus multi-line `titles` and `footnotes`. - [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) / [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) set per-column usage, label, format, width, alignment (including decimal alignment via bundled font metrics), visibility, NA text, per-row indent (`indent_by`), and group display. [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) takes a `.default` fallback [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md), and [`cols_apply()`](https://vthanik.github.io/tabular/reference/cols_apply.md) applies one [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) to many columns (by name or predicate), resolving a `{.name}` token in a label to each matched column. - [`headers()`](https://vthanik.github.io/tabular/reference/headers.md) builds multi-level column-header bands with passthrough leaves; [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md) sorts on hidden numeric keys; [`subgroup()`](https://vthanik.github.io/tabular/reference/subgroup.md) partitions with a `{col}` banner template and optional per-page `big_n`. - [`style()`](https://vthanik.github.io/tabular/reference/style.md) applies predicate-targeted cell styling through the `cells_*()` location helpers; [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) / [`set_preset()`](https://vthanik.github.io/tabular/reference/set_preset.md) / [`get_preset()`](https://vthanik.github.io/tabular/reference/get_preset.md) set cosmetic defaults (fonts, colours, rules, padding, alignment, page chrome) per table or per session, with reusable house styles via [`style_template()`](https://vthanik.github.io/tabular/reference/style_template.md). - [`footnote()`](https://vthanik.github.io/tabular/reference/footnote.md) attaches auto-numbered footnotes (letters, numbers, or symbols) to any cell, column header, or title, deduped by `id` and byte-identical across backends. - [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md) does group-aware pagination with an auto-computed per-page row budget; [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) writes the chosen backend (creating parent directories with `create_dir`), and [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md) resolves the grid without I/O. ### Rendering - Native emission to RTF, LaTeX, HTML, PDF (via LaTeX), and DOCX from a single resolved grid; output is verified by per-backend byte snapshots and a cross-backend CDISC-pilot qualification (`inst/qualification/`). - Inline markup via [`md()`](https://vthanik.github.io/tabular/reference/md.md) and [`html()`](https://vthanik.github.io/tabular/reference/html.md). - Glue-style `{expr}` interpolation in static labels, titles, footnotes, and header band labels, evaluated in the calling environment at build time. - Significant-whitespace preservation across all backends (`preset(whitespace = "preserve")`, the default). - [`check_latex()`](https://vthanik.github.io/tabular/reference/check_latex.md) reports LaTeX-package availability for PDF output and prints the exact `tlmgr_install()` remedy for anything missing — including a CTAN-mirror pin (`tinytex::tlmgr_repo("auto")`) when an install stalls behind the redirecting default mirror (commonly on Windows); [`check_fonts()`](https://vthanik.github.io/tabular/reference/check_fonts.md) does the same for fonts, per backend. ### Data - Bundled synthetic CDISC-pilot demo data (`cdisc_saf_demo`, `cdisc_saf_ae`, `cdisc_saf_aesocpt`, `cdisc_saf_vital`, `cdisc_eff_resp`, the BigN frames `cdisc_saf_n` / `cdisc_eff_n`, and the long-format ARD companions `cdisc_saf_demo_ard` / `cdisc_saf_aesocpt_ard`) for examples and vignettes. # Resolve a `tabular_spec` into a `tabular_grid` Runs the full engine pipeline against `spec` and returns the resolved `tabular_grid` — the same intermediate object [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) hands to a backend. Pure function: no files written, no global state touched. Use this during development to inspect what [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) will pass downstream, when building a custom backend, or when piping the resolved grid into a non-file consumer (e.g. an inline preview chunk in a Quarto notebook). ## Usage ``` r as_grid(.spec) ``` ## Arguments - .spec: *The `tabular_spec` to resolve.* `: required`. Built by the verb chain ([`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) -\> [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) -\> [`headers()`](https://vthanik.github.io/tabular/reference/headers.md) -\> [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md) -\> [`style()`](https://vthanik.github.io/tabular/reference/style.md) -\> [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md) -\> [`preset()`](https://vthanik.github.io/tabular/reference/preset.md)). ## Value *A `tabular_grid` S7 object.* Two slots: - `@pages` — a list of one entry per display page. Each entry is a named list with pagination fields (`page_index`, `panel_index`, `is_continuation`, `continuation`, `show_titles`, `repeat_headers`, `show_footnotes_here`), row + column slice indices (`row_indices`, `col_indices`, `col_names`), the sliced cell text (`cells_text` — character matrix), sliced inline ASTs (`cells_ast` — list-matrix of [`inline_ast`](https://vthanik.github.io/tabular/reference/tabular_classes.md)), sliced style nodes (`cells_style` — list-matrix of `style_node`), and the column-label ASTs for the visible columns (`col_labels_ast`). - `@metadata` — per-table information backends consume once per render: `format` (the resolved backend tag, `NA_character_` for `as_grid()` calls), `rows_per_page`, `total_pages`, `total_panels`, `nrow_data`, `ncol_data`, `col_names`, `cols` (the original [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) entries keyed by column name), `headers` (the flattened header band grid), `titles`, `footnotes`, `titles_ast`, `footnotes_ast`, `col_labels_ast`, `pagehead_ast` / `pagefoot_ast` (resolved page-band content — `NULL` when the active preset declares no band, otherwise `list(left, center, right)` of length-N lists of [`inline_ast`](https://vthanik.github.io/tabular/reference/tabular_classes.md) where N = row count and index 1 is the body-edge row). ## Details **Engine pipeline order is load-bearing.** Phases run in this fixed order; the order matters because each phase reads the post- previous-phase state of the spec: 1. `engine_sort()` — apply the sort spec. 2. `engine_headers()` — validate the header tree and flatten it to a band grid. 3. `engine_style()` — evaluate every style predicate against the post-sort data grid. A predicate may reference any column in `spec@data`. 4. `engine_format()` — apply per-column formats, substitute `na_text`, and parse every cell / title / footnote / label through `.parse_inline()` to its `inline_ast`. 5. `engine_decimal()` — column-wide decimal alignment for any column flagged `col_spec(align = "decimal")`. Operates on the formatted text; output is the same character matrix with NBSP padding inserted so the decimal marks line up. 6. `engine_paginate()` — split into pages (vertical row chunks + horizontal panel chunks). The plan drives the per-page slicing of cells / styles / ASTs below. **The grid is the backend contract.** Every backend (`backend_md`, future `backend_html`, etc.) consumes a `tabular_grid` — never a `tabular_spec`. New backends only need to walk `grid@pages` and `grid@metadata`; the engine pipeline is a fixed dependency they never re-implement. **No I/O.** `as_grid()` writes nothing to disk and touches no global state. It is safe to call repeatedly during interactive exploration; cost is roughly that of one [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) without the backend write step. ## See also **I/O sibling:** [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) writes the resolved grid to a file via a registered backend; `as_grid()` is the no-I/O entry into the same pipeline. **Build verbs the pipeline feeds from:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md), [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) / [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md), [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md), [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md), [`preset()`](https://vthanik.github.io/tabular/reference/preset.md). **Inline formatting helpers:** [`md()`](https://vthanik.github.io/tabular/reference/md.md), [`html()`](https://vthanik.github.io/tabular/reference/html.md). ## Examples ``` r # ---- Example 1: Demographics — inspect the resolved grid ---- # # Resolve the canonical safety-pop demographics pipeline into a # `tabular_grid` and inspect what `emit()` would hand a backend. # The first page's `cells_text` matrix is the decimal-aligned # output as the backend would render it; the metadata carries the # pagination plan + header / title / footnote ASTs. n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) demo <- tabular( cdisc_saf_demo, titles = c( "Table 14.1.1", "Demographics and Baseline Characteristics", "Safety Population" ), footnotes = "Source: ADSL." ) |> cols( variable = col_spec(label = "Characteristic"), stat_label = col_spec(label = "Statistic"), placebo = col_spec(label = "Placebo\nN={n['placebo']}", align = "decimal"), drug_50 = col_spec(label = "Drug 50\nN={n['drug_50']}", align = "decimal"), drug_100 = col_spec(label = "Drug 100\nN={n['drug_100']}", align = "decimal"), Total = col_spec(label = "Total\nN={n['Total']}", align = "decimal") ) |> group_rows(by = "variable") |> sort_rows(by = c("variable", "stat_label")) demo_grid <- as_grid(demo) demo_grid@metadata$total_pages #> [1] 1 demo_grid@pages[[1]]$cells_text[1:3, c("stat_label", "placebo")] #> stat_label placebo #> [1,] "Age (years)" "" #> [2,] " Mean (SD)" "75.2 (8.59)" #> [3,] " Median" "76.0       " # ---- Example 2: AE-by-SOC/PT paginated grid — verify the split ---- # # Same shape as Example 1 plus pagination protecting the SOC # grouping. With a tight font size the grid carries multiple page # entries; concatenating each page's `row_indices` reconstructs # the full data, and every page carries the full header band grid # at `grid@metadata$headers` so backends can re-render the header # on every continuation page. n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) ae_spec <- tabular( cdisc_saf_aesocpt, titles = c( "Table 14.3.1", "Adverse Events by SOC and Preferred Term", "Safety Population" ), footnotes = "Subjects counted once per SOC and once per PT." ) |> cols( label = col_spec(label = "SOC / PT", indent = "indent_level"), .hide = c("soc", "row_type", "soc_n", "n_total"), placebo = col_spec(label = "Placebo\nN={n['placebo']}", align = "decimal"), drug_50 = col_spec(label = "Drug 50\nN={n['drug_50']}", align = "decimal"), drug_100 = col_spec(label = "Drug 100\nN={n['drug_100']}", align = "decimal"), Total = col_spec(label = "Total\nN={n['Total']}", align = "decimal") ) |> sort_rows(by = c("soc_n", "n_total"), descending = c(TRUE, TRUE)) |> paginate(keep_together = "soc") ae_grid <- as_grid(ae_spec) length(ae_grid@pages) #> [1] 3 # ---- Example 3: Subgroup partition — one page set per group ---- # # When `subgroup()` is attached, `as_grid()` runs the resolve # pipeline once per group and concatenates the pages. `cdisc_saf_subgroup` # carries `sex` as a natural partition axis; inspect # `@pages[[i]]$subgroup_index` and `@pages[[i]]$subgroup_line_ast` # to confirm each page knows its group identity and banner text. # `sex` auto-hides as the partition `by` column; no explicit # `col_spec(visible = FALSE)` needed. sg_spec <- tabular(cdisc_saf_subgroup) |> cols( sex_n = col_spec(visible = FALSE), paramcd = col_spec(visible = FALSE), param = col_spec(label = "Parameter"), visit = col_spec(label = "Visit"), stat_label = col_spec(label = "Statistic") ) |> group_rows(by = c("param", "visit")) |> subgroup("sex") sg_grid <- as_grid(sg_spec) length(sg_grid@pages) #> [1] 2 vapply( sg_grid@pages, function(p) if (is.null(p$subgroup_index)) NA_integer_ else p$subgroup_index, integer(1) ) #> [1] 1 2 # ---- Example 4: Pre-flight inspection before emit() ---- # # Resolve a spec to its grid without writing anywhere. Useful in # tests, for snapshotting cell text under different presets, or # for spec-introspection inside higher-level wrappers that need # to know how many pages a render will produce. n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) demog_spec <- tabular( cdisc_saf_demo, titles = "Demographics" ) |> cols( variable = col_spec(label = "Characteristic"), stat_label = col_spec(label = "Statistic"), placebo = col_spec( label = "Placebo\nN={n['placebo']}", align = "decimal" ), drug_50 = col_spec( label = "Drug 50\nN={n['drug_50']}", align = "decimal" ), drug_100 = col_spec( label = "Drug 100\nN={n['drug_100']}", align = "decimal" ), Total = col_spec( label = "Total\nN={n['Total']}", align = "decimal" ) ) grid <- as_grid(demog_spec) length(grid@pages) #> [1] 1 dim(grid@pages[[1]]$cells_text) #> [1] 11 6 ``` # Convert a `tabular_spec` to an `htmltools` `tagList` Renders the spec to a self-contained HTML fragment and wraps it in an [`htmltools::tagList`](https://rstudio.github.io/htmltools/reference/tagList.html) suitable for inline embedding in Quarto / Rmd chunks, RStudio / Positron viewer panes, pkgdown reference pages, and Shiny UIs. ## Usage ``` r # S3 method for class 'tabular_spec' as.tags(x, ..., id = NULL) ``` ## Arguments - x: *The `tabular_spec` to convert.* `: required`. - ...: *Reserved.* Ignored. - id: *Wrapping div id.* `: default NULL (auto-generate)`. Pass an explicit id when you need to target the table from external CSS or JavaScript. ## Value *An [`htmltools::tagList`](https://rstudio.github.io/htmltools/reference/tagList.html)* containing a `
...table content...
The wrapping `
` gets a random unique `id` (so multiple tables on the same page have CSS-scopable hooks) and `overflow-x: auto` so wide tables get a horizontal scrollbar instead of overflowing their container. ## See also **Renders via:** [`print.tabular_spec`](https://vthanik.github.io/tabular/reference/print.tabular_spec.md), `knit_print()`. **Terminal verb:** [`emit()`](https://vthanik.github.io/tabular/reference/emit.md). ## Examples ``` r # `as.tags()` converts a spec into an htmltools tagList you can drop into # a custom HTML page, a Shiny UI, or a Quarto / Rmd chunk. `print()` and # `knit_print()` call it under the hood, so you seldom call it directly -- # but it is the seam for composing several tables into one container. s1 <- tabular(cdisc_saf_demo, titles = "Demographics") s2 <- tabular(cdisc_saf_ae, titles = "AE overall") # Compose two tables into one parent tagList. Autoprinting `tables` in a # Quarto / Rmd chunk renders both inline (via knit_print); embed it with # htmltools::save_html() or a Shiny renderUI(). tables <- htmltools::tagList( htmltools::as.tags(s1), htmltools::as.tags(s2) ) # The common path is autoprinting a spec: the viewer at an interactive # prompt, an inline live table under pkgdown / knitr, and HTML source # under R CMD check. This is the gt / flextable / tinytable convention -- # end on a bare table object and let the registered print method choose, # with no browsable() / if (interactive()) wrapper, so R CMD check never # launches a browser. s1 #tabular-763eb95427 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-763eb95427 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-763eb95427 p { line-height: inherit; } #tabular-763eb95427 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-763eb95427 .tabular-caption { margin: 0; padding: 0; } #tabular-763eb95427 .tabular-pad { margin: 0; line-height: 1; } #tabular-763eb95427 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-763eb95427 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-763eb95427 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-763eb95427 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-763eb95427 .tabular-table th, #tabular-763eb95427 .tabular-table td { padding: .18rem .6rem; } #tabular-763eb95427 .tabular-table td { text-align: left; vertical-align: top; } #tabular-763eb95427 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-763eb95427 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-763eb95427 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-763eb95427 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-763eb95427 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-763eb95427 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-763eb95427 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-763eb95427 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-763eb95427 .tabular-table tbody tr td { border-top: none; } #tabular-763eb95427 .tabular-band { text-align: center; } #tabular-763eb95427 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-763eb95427 .tabular-subgroup-label { font-weight: 600; } #tabular-763eb95427 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-763eb95427 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-763eb95427 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-763eb95427 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-763eb95427 .text-left { text-align: left; } #tabular-763eb95427 .text-center { text-align: center; } #tabular-763eb95427 .text-right { text-align: right; } #tabular-763eb95427 .tabular-table thead th.text-left { text-align: left; } #tabular-763eb95427 .tabular-table thead th.text-center { text-align: center; } #tabular-763eb95427 .tabular-table thead th.text-right { text-align: right; } #tabular-763eb95427 .tabular-table td.text-left { text-align: left; } #tabular-763eb95427 .tabular-table td.text-center { text-align: center; } #tabular-763eb95427 .tabular-table td.text-right { text-align: right; } #tabular-763eb95427 .valign-top { vertical-align: top; } #tabular-763eb95427 .valign-middle { vertical-align: middle; } #tabular-763eb95427 .valign-bottom { vertical-align: bottom; } #tabular-763eb95427 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-763eb95427 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-763eb95427 .tabular-page-break-row { display: none; } #tabular-763eb95427 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-763eb95427 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-763eb95427 .tabular-page-header, #tabular-763eb95427 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-763eb95427 .tabular-page-header { margin-bottom: 1rem; } #tabular-763eb95427 .tabular-page-footer { margin-top: 1rem; } #tabular-763eb95427 .tabular-page-header-left, #tabular-763eb95427 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-763eb95427 .tabular-page-header-center, #tabular-763eb95427 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-763eb95427 .tabular-page-header-right, #tabular-763eb95427 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-763eb95427 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-763eb95427 .tabular-table tr { page-break-inside: avoid; } #tabular-763eb95427 .tabular-page-header, #tabular-763eb95427 .tabular-page-footer { display: none; } #tabular-763eb95427 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-763eb95427 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-763eb95427 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Demographics   variable ``` # Border-line specification Build a small immutable record describing one border line — width, style, and colour. A `brdr()` value is the stroke you hand to the [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) `rules` knob (one entry per rule name, e.g. `rules = list(midrule = brdr(width = 0.75))`) or to [`style()`](https://vthanik.github.io/tabular/reference/style.md)'s border arguments (`style(border_top = brdr(...), .at = cells_table(side = "rows"))`). Successive [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) calls layer cleanly, so a one-off override composes onto a house-style template without disturbing the other rules. ## Usage ``` r brdr(width = "thin", style = "solid", color = "ink") is_brdr(x) ``` ## Arguments - width: *Stroke width.* `: default `"thin"`*. Either a numeric in points (>= 0) or one of the four named keywords (`"hairline"`, `"thin"`, `"medium"`, `"thick"\`). - style: *Line style.* `: default `"solid"`*. One of `"solid"`, `"dashed"`, `"dotted"`, `"double"`, `"dashdot"`, `"none"\`. - color: *Stroke colour.* `: default `"ink"“. The `"ink"` token (resolves to \`#212529\`), a hex (\`"#RRGGBB"\`), a CSS colour name, or \`"currentColor"\` to inherit the surrounding text colour. - x: *Any R object* — tested by `is_brdr()` for membership in the `tabular_brdr` S3 class. ## Value *A `tabular_brdr` S3 object* — a length-3 named list suitable for `preset(rules = list( = .))` or `style(border_* = .)`. ## Details **Surface.** A single `tabular_brdr` value is a length-3 named list with class `"tabular_brdr"`: `list(style, width, color)`. The shape is identical to the bare triple [`style()`](https://vthanik.github.io/tabular/reference/style.md)'s per-side scalars accept, so the resolver in `R/borders.R` can ingest either form transparently. Construct with `brdr()`; test with `is_brdr()`. **Width keywords.** `width` accepts either a numeric in points (typical clinical values: 0.25, 0.5, 1, 1.5) or one of the four named keywords: | | | |--------------|--------| | keyword | points | | `"hairline"` | 0.25 | | `"thin"` | 0.5 | | `"medium"` | 1 | | `"thick"` | 1.5 | Keywords resolve to numeric points immediately; the constructed value carries a numeric `width`. Numeric inputs pass through unchanged after a non-negative check. **Style enum.** `style` is one of `"solid"` (default), `"dashed"`, `"dotted"`, `"double"`, `"dashdot"`, `"none"`. `"none"` is the explicit clear-this-rule sentinel: setting a rule to `brdr(style = "none")` (or the bare string `"none"`) in [`preset()`](https://vthanik.github.io/tabular/reference/preset.md)`(rules = list(...))` suppresses the baseline rule that backend would otherwise draw. **Color.** Hex (`"#212529"`), CSS colour name (`"black"`, `"slategray"`), the `"ink"` token (default; resolves to the primary rule ink `#212529`, decoupled from the surrounding text colour so a recoloured header keeps a neutral rule), or `"currentColor"` (inherit the surrounding text colour per backend convention — `w:color="auto"` in DOCX, the document text colour in RTF, the CSS `currentColor` keyword in HTML). ## See also **Where to attach:** [`preset()`](https://vthanik.github.io/tabular/reference/preset.md)'s `rules` knob (one brdr() per rule name) and [`style()`](https://vthanik.github.io/tabular/reference/style.md)'s `border_*` arguments. **Per-cell predicates:** [`style()`](https://vthanik.github.io/tabular/reference/style.md) accepts the same per-side `border__{style,width,color}` triples without going through `brdr()`. **Resolver internals:** [`tabular_classes`](https://vthanik.github.io/tabular/reference/tabular_classes.md) (`style_node`'s 12 border scalars). ## Examples ``` r # ---- Example 1: A house-style rule set ---- # # The `rules` knob takes one brdr() value per rule name. Here a # thick column-label divider (midrule), a hairline dotted rule # between body rows (rowrule), and the muted spanner rule dropped. # Unlisted rules keep their booktabs defaults. demo_n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) tabular( cdisc_saf_ae, titles = c( "Table 14.3.1", "Overall Summary of Adverse Events", "Safety Population" ), footnotes = "Subjects counted once per category." ) |> cols( stat_label = col_spec(label = "Category"), placebo = col_spec(label = "Placebo\nN={demo_n['placebo']}"), drug_50 = col_spec(label = "Drug 50\nN={demo_n['drug_50']}"), drug_100 = col_spec(label = "Drug 100\nN={demo_n['drug_100']}"), Total = col_spec(label = "Total\nN={demo_n['Total']}") ) |> preset( rules = list( midrule = brdr(width = "thick"), rowrule = brdr(width = "hairline", style = "dotted"), spanrule = "none" ) ) #tabular-d7214c217f { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-d7214c217f .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-d7214c217f p { line-height: inherit; } #tabular-d7214c217f .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-d7214c217f .tabular-caption { margin: 0; padding: 0; } #tabular-d7214c217f .tabular-pad { margin: 0; line-height: 1; } #tabular-d7214c217f .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-d7214c217f .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-d7214c217f .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-d7214c217f .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-d7214c217f .tabular-table th, #tabular-d7214c217f .tabular-table td { padding: .18rem .6rem; } #tabular-d7214c217f .tabular-table td { text-align: left; vertical-align: top; } #tabular-d7214c217f .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-d7214c217f .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-d7214c217f .tabular-table thead tr:last-child th { border-bottom: 1.5pt solid #212529; } #tabular-d7214c217f .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-d7214c217f .tabular-table tbody tr td { border-top: none; } #tabular-d7214c217f .tabular-band { text-align: center; } #tabular-d7214c217f .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-d7214c217f .tabular-subgroup-label { font-weight: 600; } #tabular-d7214c217f .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-d7214c217f .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-d7214c217f .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-d7214c217f .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-d7214c217f .text-left { text-align: left; } #tabular-d7214c217f .text-center { text-align: center; } #tabular-d7214c217f .text-right { text-align: right; } #tabular-d7214c217f .tabular-table thead th.text-left { text-align: left; } #tabular-d7214c217f .tabular-table thead th.text-center { text-align: center; } #tabular-d7214c217f .tabular-table thead th.text-right { text-align: right; } #tabular-d7214c217f .tabular-table td.text-left { text-align: left; } #tabular-d7214c217f .tabular-table td.text-center { text-align: center; } #tabular-d7214c217f .tabular-table td.text-right { text-align: right; } #tabular-d7214c217f .valign-top { vertical-align: top; } #tabular-d7214c217f .valign-middle { vertical-align: middle; } #tabular-d7214c217f .valign-bottom { vertical-align: bottom; } #tabular-d7214c217f .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-d7214c217f .tabular-empty { font-style: italic; color: #6c757d; } #tabular-d7214c217f .tabular-page-break-row { display: none; } #tabular-d7214c217f { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-d7214c217f .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-d7214c217f .tabular-page-header, #tabular-d7214c217f .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-d7214c217f .tabular-page-header { margin-bottom: 1rem; } #tabular-d7214c217f .tabular-page-footer { margin-top: 1rem; } #tabular-d7214c217f .tabular-page-header-left, #tabular-d7214c217f .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-d7214c217f .tabular-page-header-center, #tabular-d7214c217f .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-d7214c217f .tabular-page-header-right, #tabular-d7214c217f .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-d7214c217f .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-d7214c217f .tabular-table tr { page-break-inside: avoid; } #tabular-d7214c217f .tabular-page-header, #tabular-d7214c217f .tabular-page-footer { display: none; } #tabular-d7214c217f .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-d7214c217f .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-d7214c217f .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.3.1 Overall Summary of Adverse Events Safety Population   Category ``` # Treatment-effect estimates by model Four competing efficacy models with their treatment-effect point estimate, 95% confidence-interval bounds, and nominal p-value. Shaped as a numeric-cell table (one row per model) rather than the usual pre-formatted character cells, so it exercises the `col_spec(format = ...)` + `col_spec(na_text = ...)` cascade. One row (`MMRM`) carries `NA` CI bounds to demonstrate `na_text`. ## Usage ``` r cdisc_eff_estimates ``` ## Format A data frame with 4 rows and 5 columns: - `model`: Model name (`"ANCOVA"`, `"MMRM"`, `"Cox PH"`, `"Bootstrap (1000 reps)"`). - `estimate`: Numeric point estimate. - `lower_ci`, `upper_ci`: Numeric 95% CI bounds. The MMRM row has `NA` bounds. - `p_value`: Nominal p-value (numeric). ## Source Synthetic estimates following the `_archive/.../arframe-examples/tables/tte-summary.qmd` and `efficacy-bor.qmd` shapes. Not derived from any patient-level data — illustrative values only. ## See also [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) for the formatting cascade these values exercise. ## Examples ``` r # Numeric-cell efficacy table — format = "%.2f" pins precision, # na_text = "--" renders the MMRM row's NA bounds as dashes. tabular(cdisc_eff_estimates, titles = "Treatment-effect estimates by model") |> cols( model = col_spec(label = "Model", valign = "top"), estimate = col_spec(label = "Estimate", align = "decimal", format = "%.2f"), lower_ci = col_spec(label = "Lower\n95% CI", align = "decimal", format = "%.2f", na_text = "--"), upper_ci = col_spec(label = "Upper\n95% CI", align = "decimal", format = "%.2f", na_text = "--"), p_value = col_spec(label = "p-value", align = "decimal", format = "%.4f") ) #tabular-3fcbfcfbba { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-3fcbfcfbba .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-3fcbfcfbba p { line-height: inherit; } #tabular-3fcbfcfbba .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-3fcbfcfbba .tabular-caption { margin: 0; padding: 0; } #tabular-3fcbfcfbba .tabular-pad { margin: 0; line-height: 1; } #tabular-3fcbfcfbba .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-3fcbfcfbba .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-3fcbfcfbba .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-3fcbfcfbba .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-3fcbfcfbba .tabular-table th, #tabular-3fcbfcfbba .tabular-table td { padding: .18rem .6rem; } #tabular-3fcbfcfbba .tabular-table td { text-align: left; vertical-align: top; } #tabular-3fcbfcfbba .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-3fcbfcfbba .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-3fcbfcfbba .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-3fcbfcfbba .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-3fcbfcfbba .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-3fcbfcfbba .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-3fcbfcfbba .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-3fcbfcfbba .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-3fcbfcfbba .tabular-table tbody tr td { border-top: none; } #tabular-3fcbfcfbba .tabular-band { text-align: center; } #tabular-3fcbfcfbba .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-3fcbfcfbba .tabular-subgroup-label { font-weight: 600; } #tabular-3fcbfcfbba .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-3fcbfcfbba .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-3fcbfcfbba .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-3fcbfcfbba .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-3fcbfcfbba .text-left { text-align: left; } #tabular-3fcbfcfbba .text-center { text-align: center; } #tabular-3fcbfcfbba .text-right { text-align: right; } #tabular-3fcbfcfbba .tabular-table thead th.text-left { text-align: left; } #tabular-3fcbfcfbba .tabular-table thead th.text-center { text-align: center; } #tabular-3fcbfcfbba .tabular-table thead th.text-right { text-align: right; } #tabular-3fcbfcfbba .tabular-table td.text-left { text-align: left; } #tabular-3fcbfcfbba .tabular-table td.text-center { text-align: center; } #tabular-3fcbfcfbba .tabular-table td.text-right { text-align: right; } #tabular-3fcbfcfbba .valign-top { vertical-align: top; } #tabular-3fcbfcfbba .valign-middle { vertical-align: middle; } #tabular-3fcbfcfbba .valign-bottom { vertical-align: bottom; } #tabular-3fcbfcfbba .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-3fcbfcfbba .tabular-empty { font-style: italic; color: #6c757d; } #tabular-3fcbfcfbba .tabular-page-break-row { display: none; } #tabular-3fcbfcfbba { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-3fcbfcfbba .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-3fcbfcfbba .tabular-page-header, #tabular-3fcbfcfbba .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-3fcbfcfbba .tabular-page-header { margin-bottom: 1rem; } #tabular-3fcbfcfbba .tabular-page-footer { margin-top: 1rem; } #tabular-3fcbfcfbba .tabular-page-header-left, #tabular-3fcbfcfbba .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-3fcbfcfbba .tabular-page-header-center, #tabular-3fcbfcfbba .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-3fcbfcfbba .tabular-page-header-right, #tabular-3fcbfcfbba .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-3fcbfcfbba .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-3fcbfcfbba .tabular-table tr { page-break-inside: avoid; } #tabular-3fcbfcfbba .tabular-page-header, #tabular-3fcbfcfbba .tabular-page-footer { display: none; } #tabular-3fcbfcfbba .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-3fcbfcfbba .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-3fcbfcfbba .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Treatment-effect estimates by model   Model ``` # Efficacy-population BigN per arm Per-arm subject counts (BigN) for the efficacy population used by `cdisc_eff_resp` / `eff_resp_card` — subjects with a `BOR` record in `pharmaverseadam::adrs_onco`. Same two-column naming convention as `cdisc_saf_n`; the totals differ from `cdisc_saf_n` because not every safety-pop subject contributes a best-overall-response record. ## Usage ``` r cdisc_eff_n ``` ## Format A data frame with 4 rows and 3 columns; same schema as [cdisc_saf_n](https://vthanik.github.io/tabular/reference/cdisc_saf_n.md) (`arm`, `arm_short`, `n`). ## Source Derived in `data-raw/bundle-demo.R` from the per-arm BOR denominator computed inside the `cdisc_eff_resp` pipeline. ## See also [cdisc_saf_n](https://vthanik.github.io/tabular/reference/cdisc_saf_n.md) for the safety-population counterpart. ## Examples ``` r # Efficacy BigN joined into column headers. ne <- stats::setNames(cdisc_eff_n$n, cdisc_eff_n$arm_short) col_spec(label = "Placebo\nN={ne['placebo']}")@label #> [1] "Placebo\nN=86" ``` # Best Overall Response and Response Rates Pre-summarised efficacy table. Per-arm counts of best overall response (BOR) per CDISC category, plus derived ORR, CBR, and DCR rate rows each followed by an exact (Clopper-Pearson) 95% CI row. Four sections (Best Overall Response, Objective Response Rate, Clinical Benefit Rate, Disease Control Rate) are encoded via the `groupid` + `group_label` pair so a single `group_rows(by = "group_label")` synthesises one bold section band per groupid block; the body rows render below each band, auto-indented one level by the `"section"` display itself (the stub needs no `indent` — the section supplies it). ## Usage ``` r cdisc_eff_resp ``` ## Format A data frame with 13 rows and 7 columns: - `stat_label`: Row label (`"CR"`, `"PR"`, `"SD"`, `"NON-CR/NON-PD"`, `"PD"`, `"NE"`, `"MISSING"`, `"ORR (CR + PR)"`, `"95% CI (Clopper-Pearson)"`, `"CBR (CR + PR + SD)"`, `"95% CI (Clopper-Pearson)"`, `"DCR (CR + PR + SD + NON-CR/NON-PD)"`, `"95% CI (Clopper-Pearson)"`). - `row_type`: `"category"` for BOR categorical rows, `"derived"` for ORR / CBR / DCR rate rows, `"ci"` for the paired confidence-interval rows. Hide via `col_spec(visible = FALSE)`. - `placebo`, `drug_50`, `drug_100`: Per-arm cell text (`"n (pct)"` on rate rows, `"(lower, upper)"` on CI rows). - `groupid`: Integer section id (1 = Best Overall Response, 2 = Objective Response Rate, 3 = Clinical Benefit Rate, 4 = Disease Control Rate). Hide via `col_spec(visible = FALSE)`; used as the section sort / partition key. - `group_label`: Character section label, repeating across every row of its groupid block ("Best Overall Response" x7, "Objective Response Rate" x2, ...). Drives the engine's [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) section-header synthesis. ## Source Derived in `data-raw/bundle-demo.R` from `pharmaverseadam::adrs_onco` filtered to `PARAMCD == "BOR"`. ## See also [cdisc_eff_n](https://vthanik.github.io/tabular/reference/cdisc_eff_n.md) for BigN denominators. ## Examples ``` r # 95% efficacy pattern: four bold section bands (Best Overall # Response / Objective Response Rate / Clinical Benefit Rate / # Disease Control Rate), each followed by indented stat rows. The # source already ships in the right display order, so no sort step # is needed; `group_label` repeats across every row of its section # so the engine's `section` mode emits exactly one band per # section. ne <- stats::setNames(cdisc_eff_n$n, cdisc_eff_n$arm_short) tabular( cdisc_eff_resp, titles = c( "Table 14.2.1", "Best Overall Response and Response Rates", "Efficacy Evaluable Population" ) ) |> cols( stat_label = col_spec(label = "Response"), groupid = col_spec(visible = FALSE), row_type = col_spec(visible = FALSE), placebo = col_spec( label = "Placebo\nN={ne['placebo']}", align = "decimal" ), drug_50 = col_spec( label = "Drug 50\nN={ne['drug_50']}", align = "decimal" ), drug_100 = col_spec( label = "Drug 100\nN={ne['drug_100']}", align = "decimal" ) ) |> group_rows(by = "group_label") #tabular-8024c4df67 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-8024c4df67 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-8024c4df67 p { line-height: inherit; } #tabular-8024c4df67 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-8024c4df67 .tabular-caption { margin: 0; padding: 0; } #tabular-8024c4df67 .tabular-pad { margin: 0; line-height: 1; } #tabular-8024c4df67 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-8024c4df67 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-8024c4df67 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-8024c4df67 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-8024c4df67 .tabular-table th, #tabular-8024c4df67 .tabular-table td { padding: .18rem .6rem; } #tabular-8024c4df67 .tabular-table td { text-align: left; vertical-align: top; } #tabular-8024c4df67 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-8024c4df67 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-8024c4df67 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-8024c4df67 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-8024c4df67 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-8024c4df67 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-8024c4df67 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-8024c4df67 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-8024c4df67 .tabular-table tbody tr td { border-top: none; } #tabular-8024c4df67 .tabular-band { text-align: center; } #tabular-8024c4df67 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-8024c4df67 .tabular-subgroup-label { font-weight: 600; } #tabular-8024c4df67 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-8024c4df67 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-8024c4df67 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-8024c4df67 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-8024c4df67 .text-left { text-align: left; } #tabular-8024c4df67 .text-center { text-align: center; } #tabular-8024c4df67 .text-right { text-align: right; } #tabular-8024c4df67 .tabular-table thead th.text-left { text-align: left; } #tabular-8024c4df67 .tabular-table thead th.text-center { text-align: center; } #tabular-8024c4df67 .tabular-table thead th.text-right { text-align: right; } #tabular-8024c4df67 .tabular-table td.text-left { text-align: left; } #tabular-8024c4df67 .tabular-table td.text-center { text-align: center; } #tabular-8024c4df67 .tabular-table td.text-right { text-align: right; } #tabular-8024c4df67 .valign-top { vertical-align: top; } #tabular-8024c4df67 .valign-middle { vertical-align: middle; } #tabular-8024c4df67 .valign-bottom { vertical-align: bottom; } #tabular-8024c4df67 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-8024c4df67 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-8024c4df67 .tabular-page-break-row { display: none; } #tabular-8024c4df67 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-8024c4df67 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-8024c4df67 .tabular-page-header, #tabular-8024c4df67 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-8024c4df67 .tabular-page-header { margin-bottom: 1rem; } #tabular-8024c4df67 .tabular-page-footer { margin-top: 1rem; } #tabular-8024c4df67 .tabular-page-header-left, #tabular-8024c4df67 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-8024c4df67 .tabular-page-header-center, #tabular-8024c4df67 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-8024c4df67 .tabular-page-header-right, #tabular-8024c4df67 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-8024c4df67 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-8024c4df67 .tabular-table tr { page-break-inside: avoid; } #tabular-8024c4df67 .tabular-page-header, #tabular-8024c4df67 .tabular-page-footer { display: none; } #tabular-8024c4df67 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-8024c4df67 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-8024c4df67 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.2.1 Best Overall Response and Response Rates Efficacy Evaluable Population   Response ``` # Overall adverse-event summary, Safety Population Pre-summarised wide-format AE overview. Two clinical blocks: high-level flag rows (any TEAE, any SAE, any treatment-related, any AE leading to death, any AE recovered / resolved) and maximum-severity rows (mild / moderate / severe). Severity rows are indented with two leading spaces in the data, so a plain `cols(stat_label = col_spec())` renders a flat overview with the severity rows nested under the flags, one row per category. ## Usage ``` r cdisc_saf_ae ``` ## Format A data frame with 8 rows and 5 columns: - `stat_label`: Row label (`"Any TEAE"`, `"Any Serious AE (SAE)"`, `"Any AE Related to Study Drug"`, `"Any AE Leading to Death"`, `"Any AE Recovered / Resolved"`, `" Maximum severity: Mild"`, `" Maximum severity: Moderate"`, `" Maximum severity: Severe"`). - `placebo`: Placebo arm cell text (`"n (pct)"`). - `drug_50`: Drug 50 arm cell text. - `drug_100`: Drug 100 arm cell text. - `Total`: Pooled-across-arms cell text. ## Source Derived in `data-raw/bundle-demo.R` from `pharmaverseadam::adae` filtered to `SAFFL == "Y"` and `TRTEMFL == "Y"`. ## See also [cdisc_saf_n](https://vthanik.github.io/tabular/reference/cdisc_saf_n.md) for BigN denominators; [cdisc_saf_aesocpt](https://vthanik.github.io/tabular/reference/cdisc_saf_aesocpt.md) for the SOC / PT detail companion. ## Examples ``` r n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) tabular( cdisc_saf_ae, titles = c( "Table 14.3.0", "Adverse Event Overview", "Safety Population" ) ) |> cols( stat_label = col_spec(label = ""), placebo = col_spec( label = "Placebo\nN={n['placebo']}", align = "decimal" ), drug_50 = col_spec( label = "Drug 50\nN={n['drug_50']}", align = "decimal" ), drug_100 = col_spec( label = "Drug 100\nN={n['drug_100']}", align = "decimal" ), Total = col_spec( label = "Total\nN={n['Total']}", align = "decimal" ) ) #tabular-77ba8233e9 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-77ba8233e9 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-77ba8233e9 p { line-height: inherit; } #tabular-77ba8233e9 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-77ba8233e9 .tabular-caption { margin: 0; padding: 0; } #tabular-77ba8233e9 .tabular-pad { margin: 0; line-height: 1; } #tabular-77ba8233e9 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-77ba8233e9 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-77ba8233e9 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-77ba8233e9 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-77ba8233e9 .tabular-table th, #tabular-77ba8233e9 .tabular-table td { padding: .18rem .6rem; } #tabular-77ba8233e9 .tabular-table td { text-align: left; vertical-align: top; } #tabular-77ba8233e9 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-77ba8233e9 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-77ba8233e9 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-77ba8233e9 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-77ba8233e9 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-77ba8233e9 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-77ba8233e9 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-77ba8233e9 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-77ba8233e9 .tabular-table tbody tr td { border-top: none; } #tabular-77ba8233e9 .tabular-band { text-align: center; } #tabular-77ba8233e9 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-77ba8233e9 .tabular-subgroup-label { font-weight: 600; } #tabular-77ba8233e9 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-77ba8233e9 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-77ba8233e9 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-77ba8233e9 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-77ba8233e9 .text-left { text-align: left; } #tabular-77ba8233e9 .text-center { text-align: center; } #tabular-77ba8233e9 .text-right { text-align: right; } #tabular-77ba8233e9 .tabular-table thead th.text-left { text-align: left; } #tabular-77ba8233e9 .tabular-table thead th.text-center { text-align: center; } #tabular-77ba8233e9 .tabular-table thead th.text-right { text-align: right; } #tabular-77ba8233e9 .tabular-table td.text-left { text-align: left; } #tabular-77ba8233e9 .tabular-table td.text-center { text-align: center; } #tabular-77ba8233e9 .tabular-table td.text-right { text-align: right; } #tabular-77ba8233e9 .valign-top { vertical-align: top; } #tabular-77ba8233e9 .valign-middle { vertical-align: middle; } #tabular-77ba8233e9 .valign-bottom { vertical-align: bottom; } #tabular-77ba8233e9 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-77ba8233e9 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-77ba8233e9 .tabular-page-break-row { display: none; } #tabular-77ba8233e9 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-77ba8233e9 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-77ba8233e9 .tabular-page-header, #tabular-77ba8233e9 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-77ba8233e9 .tabular-page-header { margin-bottom: 1rem; } #tabular-77ba8233e9 .tabular-page-footer { margin-top: 1rem; } #tabular-77ba8233e9 .tabular-page-header-left, #tabular-77ba8233e9 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-77ba8233e9 .tabular-page-header-center, #tabular-77ba8233e9 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-77ba8233e9 .tabular-page-header-right, #tabular-77ba8233e9 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-77ba8233e9 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-77ba8233e9 .tabular-table tr { page-break-inside: avoid; } #tabular-77ba8233e9 .tabular-page-header, #tabular-77ba8233e9 .tabular-page-footer { display: none; } #tabular-77ba8233e9 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-77ba8233e9 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-77ba8233e9 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.3.0 Adverse Event Overview Safety Population   ``` # Cards hierarchical ARD for AEs by SOC and PT Long-format companion to `cdisc_saf_aesocpt`. Produced by `cards::ard_stack_hierarchical()` over `(AEBODSYS, AEDECOD)` with adsl-level denominators, sorted by descending overall incidence via `cards::sort_ard_hierarchical()`. Limited to the same top-10 SOC, top-5 PT subset as `cdisc_saf_aesocpt` so the two datasets describe the same slice of the data. ## Usage ``` r cdisc_saf_aesocpt_ard ``` ## Format A `card`-classed tibble. Carries a hierarchical "overall" row (cards' internal `..ard_hierarchical_overall..` marker) that [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) relabels to `"Overall"` (overridable via its `label` argument) and emits as the table's top `row_type = "overall"` row. ## Source Derived in `data-raw/bundle-demo.R` via `cards::ard_stack_hierarchical()` over `pharmaverseadam::adae` filtered to the top SOC / PT subset. ## Details This is the package's canonical **hierarchical ARD** demo (two grouping variables nested SOC -\> PT). Its flat counterpart is [cdisc_saf_demo_ard](https://vthanik.github.io/tabular/reference/cdisc_saf_demo_ard.md); together they cover both shapes [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) must handle. ## See also [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) for the long-to-wide bridge; [cdisc_saf_aesocpt](https://vthanik.github.io/tabular/reference/cdisc_saf_aesocpt.md) for the wide companion. ## Examples ``` r # Hierarchical ARD pivot. pivot_across() recognises the # ard_stack_hierarchical shape and emits soc / label / row_type. n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) cdisc_saf_aesocpt_ard |> pivot_across(statistic = "{n} ({p}%)") |> tabular( titles = c( "Table 14.3.1", "Adverse Events by SOC and PT", "Safety Population" ) ) |> cols( label = col_spec(label = "SOC / PT", align = "left"), soc = col_spec(visible = FALSE), row_type = col_spec(visible = FALSE), `Placebo` = col_spec(align = "decimal"), `Xanomeline Low Dose` = col_spec(align = "decimal"), `Xanomeline High Dose` = col_spec(align = "decimal") ) #tabular-d914555dd7 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-d914555dd7 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-d914555dd7 p { line-height: inherit; } #tabular-d914555dd7 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-d914555dd7 .tabular-caption { margin: 0; padding: 0; } #tabular-d914555dd7 .tabular-pad { margin: 0; line-height: 1; } #tabular-d914555dd7 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-d914555dd7 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-d914555dd7 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-d914555dd7 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-d914555dd7 .tabular-table th, #tabular-d914555dd7 .tabular-table td { padding: .18rem .6rem; } #tabular-d914555dd7 .tabular-table td { text-align: left; vertical-align: top; } #tabular-d914555dd7 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-d914555dd7 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-d914555dd7 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-d914555dd7 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-d914555dd7 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-d914555dd7 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-d914555dd7 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-d914555dd7 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-d914555dd7 .tabular-table tbody tr td { border-top: none; } #tabular-d914555dd7 .tabular-band { text-align: center; } #tabular-d914555dd7 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-d914555dd7 .tabular-subgroup-label { font-weight: 600; } #tabular-d914555dd7 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-d914555dd7 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-d914555dd7 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-d914555dd7 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-d914555dd7 .text-left { text-align: left; } #tabular-d914555dd7 .text-center { text-align: center; } #tabular-d914555dd7 .text-right { text-align: right; } #tabular-d914555dd7 .tabular-table thead th.text-left { text-align: left; } #tabular-d914555dd7 .tabular-table thead th.text-center { text-align: center; } #tabular-d914555dd7 .tabular-table thead th.text-right { text-align: right; } #tabular-d914555dd7 .tabular-table td.text-left { text-align: left; } #tabular-d914555dd7 .tabular-table td.text-center { text-align: center; } #tabular-d914555dd7 .tabular-table td.text-right { text-align: right; } #tabular-d914555dd7 .valign-top { vertical-align: top; } #tabular-d914555dd7 .valign-middle { vertical-align: middle; } #tabular-d914555dd7 .valign-bottom { vertical-align: bottom; } #tabular-d914555dd7 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-d914555dd7 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-d914555dd7 .tabular-page-break-row { display: none; } #tabular-d914555dd7 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-d914555dd7 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-d914555dd7 .tabular-page-header, #tabular-d914555dd7 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-d914555dd7 .tabular-page-header { margin-bottom: 1rem; } #tabular-d914555dd7 .tabular-page-footer { margin-top: 1rem; } #tabular-d914555dd7 .tabular-page-header-left, #tabular-d914555dd7 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-d914555dd7 .tabular-page-header-center, #tabular-d914555dd7 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-d914555dd7 .tabular-page-header-right, #tabular-d914555dd7 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-d914555dd7 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-d914555dd7 .tabular-table tr { page-break-inside: avoid; } #tabular-d914555dd7 .tabular-page-header, #tabular-d914555dd7 .tabular-page-footer { display: none; } #tabular-d914555dd7 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-d914555dd7 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-d914555dd7 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.3.1 Adverse Events by SOC and PT Safety Population   SOC / PT ``` # Adverse events by System Organ Class and Preferred Term Pre-summarised AE-by-SOC/PT table. Interleaved row order: overall "any TEAE" row first, then per-SOC blocks where each SOC row is followed by its preferred-term detail rows. Top 10 SOCs and top 5 PTs per SOC are kept; `row_type` marks the role of each row and `indent_level` carries the canonical depth (0 for overall and SOC, 1 for PT) so the downstream pipeline drives the SOC -\> PT indent via `col_spec(indent = "indent_level")` without reconstructing it in every script. The richer SOC × PT slice exercises [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md) and the engine's horizontal-panel splitter end-to-end on a realistic submission shell. ## Usage ``` r cdisc_saf_aesocpt ``` ## Format A data frame with 61 rows and 10 columns: - `soc`: System Organ Class label. Repeats across the SOC's PT rows; hide via `col_spec(visible = FALSE)` once `label` carries the same SOC text on SOC rows. - `label`: The row's display label. Equal to `soc` on the overall and SOC-summary rows; equal to the preferred-term name on PT detail rows. Promoted to the primary display column — pair with `indent = "indent_level"` to drive the SOC -\> PT indent. - `row_type`: One of `"overall"`, `"soc"`, `"pt"`. Partition marker; hide via `col_spec(visible = FALSE)`. - `indent_level`: Integer depth (0 on overall and SOC rows, 1 on PT rows). Consumed by `col_spec(indent = "indent_level")` on the `label` column; the engine auto-hides this column at resolve time. - `n_total`: Integer. The row's own subject count — overall TEAE count on the overall row, the SOC's count on each SOC row, the PT's count on each PT row. Inner sort key. - `soc_n`: Integer. The parent SOC's count, broadcast to every row in that SOC's cluster (SOC row + its PT children) so a descending sort on `soc_n` keeps PTs grouped under their parent. On the overall row, equal to the overall TEAE count. Outer sort key. - `placebo`: Placebo arm cell text (`"n (pct)"`). - `drug_50`, `drug_100`: Drug arms cell text. - `Total`: Pooled-across-arms cell text. ## Source Derived in `data-raw/bundle-demo.R` from `pharmaverseadam::adae`. Filtered to the top 10 SOCs by total incidence and the top 5 PTs per SOC. Body rows are pre-sorted with the cards-style two-level rule (`arrange(desc(soc_n), soc, desc(n_total))`) so the canonical render order is already baked in; the render-time `sort_rows(by = c("soc_n", "n_total"), descending = c(TRUE, TRUE))` reproduces it via stable sort. ## See also [cdisc_saf_aesocpt_ard](https://vthanik.github.io/tabular/reference/cdisc_saf_aesocpt_ard.md) for the hierarchical long ARD; [cdisc_saf_n](https://vthanik.github.io/tabular/reference/cdisc_saf_n.md) for BigN denominators. ## Examples ``` r # 95% safety pattern: SOC/PT table where `label` carries SOC text # on SOC rows and PT text on PT rows, indented by `indent_level`. # `soc` / `row_type` / `n_total` / `soc_n` ride along as hidden # partition + sort keys. `sort_rows(soc_n, n_total)` clusters PTs # under their parent SOC and orders both levels by descending count. n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) tabular( cdisc_saf_aesocpt, titles = c( "Table 14.3.1", "Adverse Events by SOC and Preferred Term", "Safety Population" ) ) |> cols( label = col_spec( label = "SOC / PT", indent = "indent_level", align = "left" ), soc = col_spec(visible = FALSE), row_type = col_spec(visible = FALSE), n_total = col_spec(visible = FALSE), soc_n = col_spec(visible = FALSE), placebo = col_spec( label = "Placebo\nN={n['placebo']}", align = "decimal" ), drug_50 = col_spec( label = "Drug 50\nN={n['drug_50']}", align = "decimal" ), drug_100 = col_spec( label = "Drug 100\nN={n['drug_100']}", align = "decimal" ), Total = col_spec( label = "Total\nN={n['Total']}", align = "decimal" ) ) |> sort_rows( by = c("soc_n", "n_total"), descending = c(TRUE, TRUE) ) #tabular-ca84999b75 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-ca84999b75 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-ca84999b75 p { line-height: inherit; } #tabular-ca84999b75 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-ca84999b75 .tabular-caption { margin: 0; padding: 0; } #tabular-ca84999b75 .tabular-pad { margin: 0; line-height: 1; } #tabular-ca84999b75 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-ca84999b75 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-ca84999b75 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-ca84999b75 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-ca84999b75 .tabular-table th, #tabular-ca84999b75 .tabular-table td { padding: .18rem .6rem; } #tabular-ca84999b75 .tabular-table td { text-align: left; vertical-align: top; } #tabular-ca84999b75 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-ca84999b75 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-ca84999b75 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-ca84999b75 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-ca84999b75 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-ca84999b75 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-ca84999b75 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-ca84999b75 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-ca84999b75 .tabular-table tbody tr td { border-top: none; } #tabular-ca84999b75 .tabular-band { text-align: center; } #tabular-ca84999b75 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-ca84999b75 .tabular-subgroup-label { font-weight: 600; } #tabular-ca84999b75 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-ca84999b75 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-ca84999b75 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-ca84999b75 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-ca84999b75 .text-left { text-align: left; } #tabular-ca84999b75 .text-center { text-align: center; } #tabular-ca84999b75 .text-right { text-align: right; } #tabular-ca84999b75 .tabular-table thead th.text-left { text-align: left; } #tabular-ca84999b75 .tabular-table thead th.text-center { text-align: center; } #tabular-ca84999b75 .tabular-table thead th.text-right { text-align: right; } #tabular-ca84999b75 .tabular-table td.text-left { text-align: left; } #tabular-ca84999b75 .tabular-table td.text-center { text-align: center; } #tabular-ca84999b75 .tabular-table td.text-right { text-align: right; } #tabular-ca84999b75 .valign-top { vertical-align: top; } #tabular-ca84999b75 .valign-middle { vertical-align: middle; } #tabular-ca84999b75 .valign-bottom { vertical-align: bottom; } #tabular-ca84999b75 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-ca84999b75 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-ca84999b75 .tabular-page-break-row { display: none; } #tabular-ca84999b75 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-ca84999b75 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-ca84999b75 .tabular-page-header, #tabular-ca84999b75 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-ca84999b75 .tabular-page-header { margin-bottom: 1rem; } #tabular-ca84999b75 .tabular-page-footer { margin-top: 1rem; } #tabular-ca84999b75 .tabular-page-header-left, #tabular-ca84999b75 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-ca84999b75 .tabular-page-header-center, #tabular-ca84999b75 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-ca84999b75 .tabular-page-header-right, #tabular-ca84999b75 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-ca84999b75 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-ca84999b75 .tabular-table tr { page-break-inside: avoid; } #tabular-ca84999b75 .tabular-page-header, #tabular-ca84999b75 .tabular-page-footer { display: none; } #tabular-ca84999b75 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-ca84999b75 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-ca84999b75 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.3.1 Adverse Events by SOC and Preferred Term Safety Population   SOC / PT ``` # Cards ARD for demographics (flat ARD companion) The same demographics summary as `cdisc_saf_demo`, but in the long Analysis Results Data (ARD) format produced by `cards::ard_stack()`. One row per (treatment arm, variable, statistic). Shipped as a teaching dataset that shows the upstream shape users typically have when they start from `cards`. Convert it to the wide form [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) accepts via [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) — tabular itself does **not** consume the long ARD format, since pre-summarised wide data is the package boundary. ## Usage ``` r cdisc_saf_demo_ard ``` ## Format A `card`-classed tibble with columns `group1`, `group1_level`, `variable`, `variable_level`, `context`, `stat_name`, `stat_label`, `stat`. `group1 == "TRT01A"` and `group1_level` carries the original pharmaverseadam arm labels (`"Placebo"`, `"Xanomeline Low Dose"`, `"Xanomeline High Dose"`). `cards::ard_stack(.overall = TRUE)` adds overall rows with `group1_level = NA`; [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) renders those into a `Total` column. ## Source Derived in `data-raw/bundle-demo.R` via `cards::ard_stack(.by = "TRT01A", .overall = TRUE)` over `pharmaverseadam::adsl`. ## Details Continuous variables: `AGE`, `WEIGHT`, `HEIGHT`, `BMI` (each emitting `N`, `mean`, `sd`, `median`, `p25`, `p75`, `min`, `max`). Categorical variables: `AGEGR1`, `SEX`, `RACE`, `ETHNIC`, `BMI_CAT` (each emitting `n`, `N`, `p`). This is the package's canonical **flat ARD** demo. Its hierarchical counterpart is [cdisc_saf_aesocpt_ard](https://vthanik.github.io/tabular/reference/cdisc_saf_aesocpt_ard.md); together they cover both shapes [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) must handle. ## See also [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) for the long-to-wide bridge; [cdisc_saf_demo](https://vthanik.github.io/tabular/reference/cdisc_saf_demo.md) for the wide companion. ## Examples ``` r # 95% demographics pattern: cards ARD -> wide -> rendered table. n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) cdisc_saf_demo_ard |> pivot_across( statistic = list( continuous = "{mean} ({sd})", categorical = "{n} ({p}%)" ), label = c(AGE = "Age (years)", SEX = "Sex", RACE = "Race") ) |> tabular( titles = c( "Table 14.1.1", "Demographics", "Safety Population" ) ) #tabular-c9e79afd11 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-c9e79afd11 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-c9e79afd11 p { line-height: inherit; } #tabular-c9e79afd11 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-c9e79afd11 .tabular-caption { margin: 0; padding: 0; } #tabular-c9e79afd11 .tabular-pad { margin: 0; line-height: 1; } #tabular-c9e79afd11 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-c9e79afd11 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-c9e79afd11 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-c9e79afd11 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-c9e79afd11 .tabular-table th, #tabular-c9e79afd11 .tabular-table td { padding: .18rem .6rem; } #tabular-c9e79afd11 .tabular-table td { text-align: left; vertical-align: top; } #tabular-c9e79afd11 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-c9e79afd11 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-c9e79afd11 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-c9e79afd11 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-c9e79afd11 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-c9e79afd11 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-c9e79afd11 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-c9e79afd11 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-c9e79afd11 .tabular-table tbody tr td { border-top: none; } #tabular-c9e79afd11 .tabular-band { text-align: center; } #tabular-c9e79afd11 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-c9e79afd11 .tabular-subgroup-label { font-weight: 600; } #tabular-c9e79afd11 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-c9e79afd11 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-c9e79afd11 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-c9e79afd11 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-c9e79afd11 .text-left { text-align: left; } #tabular-c9e79afd11 .text-center { text-align: center; } #tabular-c9e79afd11 .text-right { text-align: right; } #tabular-c9e79afd11 .tabular-table thead th.text-left { text-align: left; } #tabular-c9e79afd11 .tabular-table thead th.text-center { text-align: center; } #tabular-c9e79afd11 .tabular-table thead th.text-right { text-align: right; } #tabular-c9e79afd11 .tabular-table td.text-left { text-align: left; } #tabular-c9e79afd11 .tabular-table td.text-center { text-align: center; } #tabular-c9e79afd11 .tabular-table td.text-right { text-align: right; } #tabular-c9e79afd11 .valign-top { vertical-align: top; } #tabular-c9e79afd11 .valign-middle { vertical-align: middle; } #tabular-c9e79afd11 .valign-bottom { vertical-align: bottom; } #tabular-c9e79afd11 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-c9e79afd11 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-c9e79afd11 .tabular-page-break-row { display: none; } #tabular-c9e79afd11 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-c9e79afd11 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-c9e79afd11 .tabular-page-header, #tabular-c9e79afd11 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-c9e79afd11 .tabular-page-header { margin-bottom: 1rem; } #tabular-c9e79afd11 .tabular-page-footer { margin-top: 1rem; } #tabular-c9e79afd11 .tabular-page-header-left, #tabular-c9e79afd11 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-c9e79afd11 .tabular-page-header-center, #tabular-c9e79afd11 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-c9e79afd11 .tabular-page-header-right, #tabular-c9e79afd11 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-c9e79afd11 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-c9e79afd11 .tabular-table tr { page-break-inside: avoid; } #tabular-c9e79afd11 .tabular-page-header, #tabular-c9e79afd11 .tabular-page-footer { display: none; } #tabular-c9e79afd11 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-c9e79afd11 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-c9e79afd11 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.1.1 Demographics Safety Population   variable ``` # Demographics summary, Safety Population Pre-summarised wide-format demographics suitable for direct passing into [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md). One row per displayed statistic. Three parameter blocks — a deliberately minimal set covering both summary shapes: ## Usage ``` r cdisc_saf_demo ``` ## Format A data frame with 11 rows and 6 columns: - `variable`: Display-block label (`"Age (years)"`, `"Sex, n (%)"`, `"Race, n (%)"`). Driven by [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) to collapse repeat values at render. - `stat_label`: Statistic or level label (`"n"`, `"Mean (SD)"`, `"Median"`, `"M"`, `"WHITE"`, ...). - `placebo`: Placebo arm cell text. - `drug_50`: Xanomeline Low Dose (50 mg) arm cell text. - `drug_100`: Xanomeline High Dose (100 mg) arm cell text. - `Total`: Pooled-across-arms cell text. ## Source Derived in `data-raw/bundle-demo.R` from `pharmaverseadam::adsl` filtered to `SAFFL == "Y"` and the three CDISCPILOT01 treatment arms. ## Details - continuous: `Age (years)` — emitted as `n`, `Mean (SD)`, `Median`, `Q1, Q3`, `Min, Max` - categorical: `Sex`, `Race` — each level rendered as `n (%)` Shaped for the display-only contract: every cell is the final string that will appear in the rendered table. ## See also [cdisc_saf_demo_ard](https://vthanik.github.io/tabular/reference/cdisc_saf_demo_ard.md) for the long-format ARD companion; [cdisc_saf_n](https://vthanik.github.io/tabular/reference/cdisc_saf_n.md) for the matching BigN denominators. ## Examples ``` r # 95% safety pattern: demographics table with BigN-embedded # column labels and CDISC-canonical statistic order. n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) tabular( cdisc_saf_demo, titles = c( "Table 14.1.1", "Demographics and Baseline Characteristics", "Safety Population" ) ) |> cols( variable = col_spec(label = "Parameter"), stat_label = col_spec(label = "Statistic"), placebo = col_spec( label = "Placebo\nN={n['placebo']}", align = "decimal" ), drug_50 = col_spec( label = "Drug 50\nN={n['drug_50']}", align = "decimal" ), drug_100 = col_spec( label = "Drug 100\nN={n['drug_100']}", align = "decimal" ), Total = col_spec( label = "Total\nN={n['Total']}", align = "decimal" ) ) #tabular-c73e2cc0e2 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-c73e2cc0e2 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-c73e2cc0e2 p { line-height: inherit; } #tabular-c73e2cc0e2 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-c73e2cc0e2 .tabular-caption { margin: 0; padding: 0; } #tabular-c73e2cc0e2 .tabular-pad { margin: 0; line-height: 1; } #tabular-c73e2cc0e2 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-c73e2cc0e2 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-c73e2cc0e2 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-c73e2cc0e2 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-c73e2cc0e2 .tabular-table th, #tabular-c73e2cc0e2 .tabular-table td { padding: .18rem .6rem; } #tabular-c73e2cc0e2 .tabular-table td { text-align: left; vertical-align: top; } #tabular-c73e2cc0e2 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-c73e2cc0e2 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-c73e2cc0e2 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-c73e2cc0e2 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-c73e2cc0e2 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-c73e2cc0e2 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-c73e2cc0e2 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-c73e2cc0e2 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-c73e2cc0e2 .tabular-table tbody tr td { border-top: none; } #tabular-c73e2cc0e2 .tabular-band { text-align: center; } #tabular-c73e2cc0e2 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-c73e2cc0e2 .tabular-subgroup-label { font-weight: 600; } #tabular-c73e2cc0e2 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-c73e2cc0e2 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-c73e2cc0e2 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-c73e2cc0e2 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-c73e2cc0e2 .text-left { text-align: left; } #tabular-c73e2cc0e2 .text-center { text-align: center; } #tabular-c73e2cc0e2 .text-right { text-align: right; } #tabular-c73e2cc0e2 .tabular-table thead th.text-left { text-align: left; } #tabular-c73e2cc0e2 .tabular-table thead th.text-center { text-align: center; } #tabular-c73e2cc0e2 .tabular-table thead th.text-right { text-align: right; } #tabular-c73e2cc0e2 .tabular-table td.text-left { text-align: left; } #tabular-c73e2cc0e2 .tabular-table td.text-center { text-align: center; } #tabular-c73e2cc0e2 .tabular-table td.text-right { text-align: right; } #tabular-c73e2cc0e2 .valign-top { vertical-align: top; } #tabular-c73e2cc0e2 .valign-middle { vertical-align: middle; } #tabular-c73e2cc0e2 .valign-bottom { vertical-align: bottom; } #tabular-c73e2cc0e2 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-c73e2cc0e2 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-c73e2cc0e2 .tabular-page-break-row { display: none; } #tabular-c73e2cc0e2 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-c73e2cc0e2 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-c73e2cc0e2 .tabular-page-header, #tabular-c73e2cc0e2 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-c73e2cc0e2 .tabular-page-header { margin-bottom: 1rem; } #tabular-c73e2cc0e2 .tabular-page-footer { margin-top: 1rem; } #tabular-c73e2cc0e2 .tabular-page-header-left, #tabular-c73e2cc0e2 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-c73e2cc0e2 .tabular-page-header-center, #tabular-c73e2cc0e2 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-c73e2cc0e2 .tabular-page-header-right, #tabular-c73e2cc0e2 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-c73e2cc0e2 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-c73e2cc0e2 .tabular-table tr { page-break-inside: avoid; } #tabular-c73e2cc0e2 .tabular-page-header, #tabular-c73e2cc0e2 .tabular-page-footer { display: none; } #tabular-c73e2cc0e2 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-c73e2cc0e2 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-c73e2cc0e2 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.1.1 Demographics and Baseline Characteristics Safety Population   Parameter ``` # Safety-population BigN per arm Per-arm subject counts (BigN) for the safety population, plus a `Total` row. Use this table to embed BigN inline in column headers with a glue-style `{expr}` template against `cols(col_spec(label = ...))`; there is no dedicated BigN field on `col_spec` because the denominator already lives here in a discoverable, joinable form. ## Usage ``` r cdisc_saf_n ``` ## Format A data frame with 4 rows and 3 columns: - `arm`: Raw pharmaverseadam arm label (`"Placebo"`, `"Xanomeline Low Dose"`, `"Xanomeline High Dose"`, `"Total"`). Matches `group1_level` in the `_card` ARDs (so the pivot output's column names match a `setNames(cdisc_saf_n$n, cdisc_saf_n$arm)` lookup). - `arm_short`: Renamed label (`"placebo"`, `"drug_50"`, `"drug_100"`, `"Total"`). Matches the column names of `cdisc_saf_demo`, `cdisc_saf_ae`, `cdisc_saf_aesocpt`, and `cdisc_saf_vital`. - `n`: Integer subject count. ## Source Derived in `data-raw/bundle-demo.R` from `pharmaverseadam::adsl` filtered to `SAFFL == "Y"` and the three CDISCPILOT01 arms. ## Details Two arm-naming columns are shipped side by side so the same table can serve both the `_card` ARDs (raw pharmaverseadam labels in `group1_level`) and the renamed wide datasets (snake-cased arm column names). ## See also [cdisc_eff_n](https://vthanik.github.io/tabular/reference/cdisc_eff_n.md) for the efficacy-population counterpart. ## Examples ``` r # Use cdisc_saf_n$arm_short when joining into the wide datasets # (cdisc_saf_demo, cdisc_saf_ae, cdisc_saf_aesocpt, cdisc_saf_vital). n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) col_spec(label = "Placebo\nN={n['placebo']}")@label #> [1] "Placebo\nN=86" # Use cdisc_saf_n$arm when joining into pivot_across() output # (column names match the raw pharmaverseadam arm labels). n_arm <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm) col_spec(label = "Placebo\nN={n_arm['Placebo']}")@label #> [1] "Placebo\nN=86" ``` # Vital-signs subgroup summary by Sex, by Visit Pre-summarised vital-signs stats partitioned by sex (`F` / `M`) across four visits (`Baseline`, `Week 8`, `Week 16`, `End of Treatment`). Two parameters (Systolic BP, Diastolic BP) emit four statistic rows each (`n`, `Mean (SD)`, `Median`, `Min, Max`). A partition-constant `sex_n` BigN column rides alongside so banners can inline the denominator via `subgroup(label = "Sex: {sex} (N = {sex_n})")` without reaching for a separate lookup. ## Usage ``` r cdisc_saf_subgroup ``` ## Format A data frame with 64 rows and 10 columns: - `sex`: Factor (`F` / `M`). - `sex_n`: Integer BigN — number of subjects in the partition row's sex (partition-constant; rides into the banner via `{sex_n}` template tokens). - `paramcd`: CDISC parameter code (`SYSBP` / `DIABP`). - `param`: Decoded parameter name (`"Systolic BP (mmHg)"`, `"Diastolic BP (mmHg)"`). - `visit`: Analysis visit (`Baseline`, `Week 8`, `Week 16`, `End of Treatment`). - `stat_label`: Statistic label (`n`, `Mean (SD)`, `Median`, `Min, Max`). - `placebo`, `drug_50`, `drug_100`, `Total`: Per-arm cell text. ## Source Derived in `data-raw/bundle-demo.R` from `pharmaverseadam::advs` filtered to `SAFFL == "Y"`, the three CDISCPILOT01 arms, the `SYSBP` / `DIABP` parameters, and the four scheduled visits. ## Details Designed for [`subgroup()`](https://vthanik.github.io/tabular/reference/subgroup.md) and [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md) examples: partition by sex (one page set per sex) and nest parameter then visit inside each page for the canonical by-visit CSR shape, or cross sex with visit for a multi-variable partition. ## See also [cdisc_saf_n](https://vthanik.github.io/tabular/reference/cdisc_saf_n.md) for BigN denominators; [`subgroup()`](https://vthanik.github.io/tabular/reference/subgroup.md) for the verb this dataset is designed for. ## Examples ``` r # 95% pattern: subgroup partition by sex with inline BigN, parameter # nesting visit inside each sex page. `sex` and `sex_n` auto-hide # from the body: `sex` because it is the partition `by` column; # `sex_n` because the banner template references it. No explicit # `col_spec(visible = FALSE)` needed. tabular(cdisc_saf_subgroup, titles = "Vital Signs by Visit") |> cols( paramcd = col_spec(visible = FALSE), param = col_spec(label = "Parameter"), visit = col_spec(label = "Visit"), stat_label = col_spec(label = "Statistic"), placebo = col_spec(label = "Placebo", align = "decimal"), drug_50 = col_spec(label = "Drug 50", align = "decimal"), drug_100 = col_spec(label = "Drug 100", align = "decimal"), Total = col_spec(label = "Total", align = "decimal") ) |> subgroup(by = "sex", label = "Sex: {sex} (N = {sex_n})") #tabular-bde4edb2c1 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-bde4edb2c1 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-bde4edb2c1 p { line-height: inherit; } #tabular-bde4edb2c1 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-bde4edb2c1 .tabular-caption { margin: 0; padding: 0; } #tabular-bde4edb2c1 .tabular-pad { margin: 0; line-height: 1; } #tabular-bde4edb2c1 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-bde4edb2c1 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-bde4edb2c1 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-bde4edb2c1 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-bde4edb2c1 .tabular-table th, #tabular-bde4edb2c1 .tabular-table td { padding: .18rem .6rem; } #tabular-bde4edb2c1 .tabular-table td { text-align: left; vertical-align: top; } #tabular-bde4edb2c1 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-bde4edb2c1 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-bde4edb2c1 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-bde4edb2c1 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-bde4edb2c1 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-bde4edb2c1 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-bde4edb2c1 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-bde4edb2c1 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-bde4edb2c1 .tabular-table tbody tr td { border-top: none; } #tabular-bde4edb2c1 .tabular-band { text-align: center; } #tabular-bde4edb2c1 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-bde4edb2c1 .tabular-subgroup-label { font-weight: 600; } #tabular-bde4edb2c1 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-bde4edb2c1 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-bde4edb2c1 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-bde4edb2c1 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-bde4edb2c1 .text-left { text-align: left; } #tabular-bde4edb2c1 .text-center { text-align: center; } #tabular-bde4edb2c1 .text-right { text-align: right; } #tabular-bde4edb2c1 .tabular-table thead th.text-left { text-align: left; } #tabular-bde4edb2c1 .tabular-table thead th.text-center { text-align: center; } #tabular-bde4edb2c1 .tabular-table thead th.text-right { text-align: right; } #tabular-bde4edb2c1 .tabular-table td.text-left { text-align: left; } #tabular-bde4edb2c1 .tabular-table td.text-center { text-align: center; } #tabular-bde4edb2c1 .tabular-table td.text-right { text-align: right; } #tabular-bde4edb2c1 .valign-top { vertical-align: top; } #tabular-bde4edb2c1 .valign-middle { vertical-align: middle; } #tabular-bde4edb2c1 .valign-bottom { vertical-align: bottom; } #tabular-bde4edb2c1 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-bde4edb2c1 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-bde4edb2c1 .tabular-page-break-row { display: none; } #tabular-bde4edb2c1 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-bde4edb2c1 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-bde4edb2c1 .tabular-page-header, #tabular-bde4edb2c1 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-bde4edb2c1 .tabular-page-header { margin-bottom: 1rem; } #tabular-bde4edb2c1 .tabular-page-footer { margin-top: 1rem; } #tabular-bde4edb2c1 .tabular-page-header-left, #tabular-bde4edb2c1 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-bde4edb2c1 .tabular-page-header-center, #tabular-bde4edb2c1 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-bde4edb2c1 .tabular-page-header-right, #tabular-bde4edb2c1 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-bde4edb2c1 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-bde4edb2c1 .tabular-table tr { page-break-inside: avoid; } #tabular-bde4edb2c1 .tabular-page-header, #tabular-bde4edb2c1 .tabular-page-footer { display: none; } #tabular-bde4edb2c1 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-bde4edb2c1 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-bde4edb2c1 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Vital Signs by Visit   Parameter ``` # Vital-signs summary Pre-summarised vital-signs stats. Four parameters (SYSBP, DIABP, PULSE, TEMP) at four visits (Baseline, Week 8, Week 16, End of Treatment), each producing four statistic rows (`n`, `Mean (SD)`, `Median`, `Min, Max`). The 4 x 4 x 4 grid makes this dataset a natural fit for [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md) examples — 64 rows comfortably exceed a single page under typical clinical row-per-page settings. ## Usage ``` r cdisc_saf_vital ``` ## Format A data frame with 64 rows and 7 columns: - `paramcd`: CDISC parameter code (`SYSBP` / `DIABP` / `PULSE` / `TEMP`). Repeats across visit and statistic; use [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) to collapse. - `param`: Decoded parameter name. - `visit`: Analysis visit label (`"Baseline"` / `"Week 8"` / `"Week 16"` / `"End of Treatment"`). - `stat_label`: Statistic label. - `placebo`, `drug_50`, `drug_100`: Per-arm cell text. ## Source Derived in `data-raw/bundle-demo.R` from `pharmaverseadam::advs`. ## See also [cdisc_saf_n](https://vthanik.github.io/tabular/reference/cdisc_saf_n.md) for BigN denominators. ## Examples ``` r n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) tabular( cdisc_saf_vital, titles = c( "Table 14.4.1", "Vital Signs Summary at Baseline and End of Treatment", "Safety Population" ) ) |> cols( paramcd = col_spec(visible = FALSE), param = col_spec(label = "Parameter"), visit = col_spec(label = "Visit"), stat_label = col_spec(label = "Statistic"), placebo = col_spec( label = "Placebo\nN={n['placebo']}", align = "decimal" ), drug_50 = col_spec( label = "Drug 50\nN={n['drug_50']}", align = "decimal" ), drug_100 = col_spec( label = "Drug 100\nN={n['drug_100']}", align = "decimal" ) ) #tabular-b13c054115 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-b13c054115 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-b13c054115 p { line-height: inherit; } #tabular-b13c054115 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-b13c054115 .tabular-caption { margin: 0; padding: 0; } #tabular-b13c054115 .tabular-pad { margin: 0; line-height: 1; } #tabular-b13c054115 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-b13c054115 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-b13c054115 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-b13c054115 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-b13c054115 .tabular-table th, #tabular-b13c054115 .tabular-table td { padding: .18rem .6rem; } #tabular-b13c054115 .tabular-table td { text-align: left; vertical-align: top; } #tabular-b13c054115 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-b13c054115 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-b13c054115 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-b13c054115 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-b13c054115 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-b13c054115 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-b13c054115 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-b13c054115 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-b13c054115 .tabular-table tbody tr td { border-top: none; } #tabular-b13c054115 .tabular-band { text-align: center; } #tabular-b13c054115 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-b13c054115 .tabular-subgroup-label { font-weight: 600; } #tabular-b13c054115 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-b13c054115 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-b13c054115 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-b13c054115 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-b13c054115 .text-left { text-align: left; } #tabular-b13c054115 .text-center { text-align: center; } #tabular-b13c054115 .text-right { text-align: right; } #tabular-b13c054115 .tabular-table thead th.text-left { text-align: left; } #tabular-b13c054115 .tabular-table thead th.text-center { text-align: center; } #tabular-b13c054115 .tabular-table thead th.text-right { text-align: right; } #tabular-b13c054115 .tabular-table td.text-left { text-align: left; } #tabular-b13c054115 .tabular-table td.text-center { text-align: center; } #tabular-b13c054115 .tabular-table td.text-right { text-align: right; } #tabular-b13c054115 .valign-top { vertical-align: top; } #tabular-b13c054115 .valign-middle { vertical-align: middle; } #tabular-b13c054115 .valign-bottom { vertical-align: bottom; } #tabular-b13c054115 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-b13c054115 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-b13c054115 .tabular-page-break-row { display: none; } #tabular-b13c054115 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-b13c054115 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-b13c054115 .tabular-page-header, #tabular-b13c054115 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-b13c054115 .tabular-page-header { margin-bottom: 1rem; } #tabular-b13c054115 .tabular-page-footer { margin-top: 1rem; } #tabular-b13c054115 .tabular-page-header-left, #tabular-b13c054115 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-b13c054115 .tabular-page-header-center, #tabular-b13c054115 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-b13c054115 .tabular-page-header-right, #tabular-b13c054115 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-b13c054115 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-b13c054115 .tabular-table tr { page-break-inside: avoid; } #tabular-b13c054115 .tabular-page-header, #tabular-b13c054115 .tabular-page-footer { display: none; } #tabular-b13c054115 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-b13c054115 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-b13c054115 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.4.1 Vital Signs Summary at Baseline and End of Treatment Safety Population   Parameter ``` # Cell-location constructors for `style()` Build a `tabular_location` value naming one region of the rendered table; pass the result to [`style()`](https://vthanik.github.io/tabular/reference/style.md)'s `.at` argument. Each constructor targets one surface (body, headers, footnotes, ...); optional `i` / `j` / `where` / `level` / `labels` filters narrow the target within that surface. ## Usage ``` r cells_body(i = NULL, j = NULL, where = NULL) cells_headers(level = NULL, labels = NULL, j = NULL) cells_group_headers(j = NULL, where = NULL) cells_title() cells_subgroup_labels() cells_footnotes() cells_pagehead(slot = NULL) cells_pagefoot(slot = NULL) cells_table(side = NULL, i = NULL, j = NULL) is_tabular_location(x) ``` ## Arguments - i: *Row index filter.* ``. Integer = 1-based row numbers; logical = length-`nrow` mask (broadcasts from scalar TRUE/FALSE); character = matches the visible row labels. `NULL` (default) = no filter (every row). - j: *Column index filter.* ``. Integer = 1-based column positions; character = matches column names in `spec@data`. `NULL` (default) = every column. - where: *Predicate.* An unquoted expression evaluating to a length-`nrow` logical vector when run against the data grid. Captured as an rlang quosure (so `pvalue < 0.05` works without needing to wrap in `vars()` or similar). Mutually exclusive with `i`. - level: *Header-band depth (for `cells_headers`).* ``. `1` = topmost spanner band; increasing integers walk toward the leaves. `-1` = the leaf band (per-column labels built from `col_spec@label`). `NULL` (default) = every band at every depth. - labels: *Header-band labels (for `cells_headers`).* ``. Targets `header_node`(s) whose `@label` matches, at any depth. Mutually exclusive with `level`. - slot: *Band slot (for `cells_pagehead` / `cells_pagefoot`).* ``. One of `"left"`, `"center"`, `"right"`, or `NULL` for every slot. - side: *Table edge / separator (for `cells_table`).* ``. One of `"outer"` (all four outer edges), `"outer_top"`, `"outer_bottom"`, `"outer_left"`, `"outer_right"`, `"rows"` (horizontal separator between body rows), `"cols"` (vertical separator between body columns), or `NULL` for whole-body (same as `cells_body()`). - x: *Any R object* — tested by `is_tabular_location()` for membership in the `tabular_location` S3 class. ## Value *A `tabular_location` S3 list* with slots `surface`, `i`, `j`, `where`, `labels`, `level`, `slot`, `side` (unused slots are `NULL`). Pass to [`style()`](https://vthanik.github.io/tabular/reference/style.md)'s `.at` argument. ## Details **One surface per location.** A `tabular_location` always names exactly one of: `body`, `headers`, `group_headers`, `title`, `subgroup_labels`, `footnotes`, `pagehead`, `pagefoot`, `table`. Cross-surface styling layers in via multiple chained [`style()`](https://vthanik.github.io/tabular/reference/style.md) calls (one per location). **Index vocabulary.** Where supported, the `i` (rows) and `j` (columns) arguments accept integer, logical, or character vectors — matching the convention established by **flextable** (`bold(ft, i, j)`) and **tinytable** (`style_tt(i, j)`). Character vectors match against the data frame's column names (`j`) or row labels (`i`); integers are 1-based positions; logicals broadcast to nrow / ncol. **Predicate vocabulary.** `cells_body(where = pvalue < 0.05)` is the canonical data-driven filter — `where` is captured as an rlang quosure and evaluated at engine time against the post-sort grid. Mutually exclusive with `i` (you target *either* by index *or* by predicate, not both). **Why `cells_headers` not `cells_column_spanners`.** The verb that builds the multi-level header tree is named [`headers()`](https://vthanik.github.io/tabular/reference/headers.md). The location follows the same vocabulary: one word ("headers") covers the entire column-header section — inner spanner bands AND the leaf band of per-column labels. Pass `level` or `labels` to narrow. ## Surface filters | | | |-----------------------------------|-----------------------------------| | constructor | filters | | `cells_body(i, j, where)` | row index / col index / predicate | | `cells_headers(level, labels, j)` | band depth / spanner label / cols | | `cells_group_headers(j, where)` | injected section rows | | `cells_title()` | (no filter — whole block) | | `cells_subgroup_labels()` | (no filter) | | `cells_footnotes()` | (no filter) | | `cells_pagehead(slot)` | `"left"` / `"center"` / `"right"` | | `cells_pagefoot(slot)` | `"left"` / `"center"` / `"right"` | | `cells_table(side, i, j)` | outer edge / row separator / etc. | ## See also **Verb that consumes locations:** [`style()`](https://vthanik.github.io/tabular/reference/style.md). **Border value type:** [`brdr()`](https://vthanik.github.io/tabular/reference/brdr.md). **Reusable house style:** [`style_template()`](https://vthanik.github.io/tabular/reference/style_template.md). ## Examples ``` r # Whole body cells (the default for style()) cells_body() #> # Row index 1:3, column "Total" cells_body(i = 1:3, j = "Total") #> # Data-driven subset cells_body(where = stat_label == "Mean (SD)") #> # Topmost spanner band only cells_headers(level = 1) #> # Leaf band (per-column labels) cells_headers(level = -1) #> # A specific spanner by label cells_headers(labels = "Treatment Group") #> # Section-header rows for group_rows(display = "section") cells_group_headers() #> # Title / footnotes blocks cells_title() #> cells_footnotes() #> # Page-header / page-footer slots cells_pagehead(slot = "left") #> cells_pagefoot(slot = "right") #> # Outer table frame cells_table(side = "outer") #> # Horizontal rules between body rows cells_table(side = "rows") #> ``` # Check font availability across backends Walks the resolved font fallback chain for each backend and reports which entries the local machine can find. Useful for answering "is the preview I'm seeing the same fonts the downstream reviewer will see?". ## Usage ``` r check_fonts(.spec) ``` ## Arguments - .spec: *A `tabular_spec` or `preset_spec`.* `: required`. The spec whose effective preset determines which font chain to walk. ## Value *Invisibly returns the resolved per-backend chains as a named list of character vectors.* Side effect: prints a cli tree showing the availability marker for every entry. ## Details The diagnostic does NOT change what [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) writes to the file. Tabular's backends emit font *names* (CSS strings, LaTeX `\setmainfont` commands, RTF font-table entries); the consuming application (browser, LaTeX engine, Word, Adobe Reader) on the opening machine resolves those names against its own installed fonts. `check_fonts()` is purely informational — it tells you which entries of the cross-platform fallback chain you can see on this machine, so you can predict drift. **Status markers:** - `v` — font is installed on this machine (via `systemfonts`). - `o` — font is a CSS / LaTeX generic; always resolvable by the consuming application. - `x` — font is not installed on this machine; the consuming app on a different machine may or may not have it. Every backend only **name-references** its fonts; the consuming application (browser, LaTeX engine, Word, Adobe Reader) resolves those names against its own installed fonts. An `x` therefore means the reader needs that face installed for the render to match exactly. The default chains lead with the ubiquitous Office cores (Courier New / Arial / Times New Roman), so a `v` on the default is the common case on Windows and macOS. Requires the `systemfonts` package (in `Suggests`); call `install.packages("systemfonts")` first if it isn't installed. ## See also **Builds the spec:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md), [`preset()`](https://vthanik.github.io/tabular/reference/preset.md). **Resolves the spec:** [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md), [`emit()`](https://vthanik.github.io/tabular/reference/emit.md). ## Examples ``` r # ---- Example 1: Inspect default font resolution ---- # # Build a spec with the default font_family ("mono") and ask # which entries in the cross-platform chain are findable # locally. Useful before sharing a render with downstream # reviewers who may be on a different OS. spec <- tabular( cdisc_saf_demo, titles = "Demographics" ) if (requireNamespace("systemfonts", quietly = TRUE)) { check_fonts(spec) } #> #> ── Font resolution for `font_family = mono` #> backend: html #> x Courier New (not on this machine) #> x Courier (not on this machine) #> v Nimbus Mono PS #> v Liberation Mono #> o monospace (generic, always available) #> backend: latex #> x Courier New (not on this machine) #> x Courier (not on this machine) #> v Nimbus Mono PS #> v Liberation Mono #> x TeX Gyre Cursor (not on this machine) #> x Latin Modern Mono (not on this machine) #> backend: rtf #> x Courier New (not on this machine) #> x Courier (not on this machine) #> v Nimbus Mono PS #> v Liberation Mono # ---- Example 2: Diagnose a Courier New request ---- # # A request for "Courier New" (a specific named font) renders # on macOS / Windows but may fall back to a serif on Linux. # `check_fonts()` flags this so the user knows to switch to # the "mono" generic for portable output. spec_mono <- tabular( cdisc_saf_demo, titles = "Mono request" ) |> preset(font_family = "Courier New") if (requireNamespace("systemfonts", quietly = TRUE)) { check_fonts(spec_mono) } #> #> ── Font resolution for `font_family = Courier New` #> backend: html #> x Courier New (not on this machine) #> x Courier (not on this machine) #> v Nimbus Mono PS #> v Liberation Mono #> o monospace (generic, always available) #> backend: latex #> x Courier New (not on this machine) #> x Courier (not on this machine) #> v Nimbus Mono PS #> v Liberation Mono #> x TeX Gyre Cursor (not on this machine) #> x Latin Modern Mono (not on this machine) #> backend: rtf #> x Courier New (not on this machine) #> x Courier (not on this machine) #> v Nimbus Mono PS #> v Liberation Mono # ---- Example 3: Explicit cross-platform stack ---- # # A length>1 input is treated as an explicit fallback chain and # emitted verbatim — no alias lookup, no fabrication. Use this # when the first choice is a sponsor / brand face that needs an # honest fallback for reviewers who don't have it installed. spec_brand <- tabular(cdisc_saf_demo) |> preset(font_family = c("Inter", "Liberation Sans", "Arial", "sans")) if (requireNamespace("systemfonts", quietly = TRUE)) { check_fonts(spec_brand) } #> #> ── Font resolution for `font_family = Inter , Liberation Sans, Arial , and sans ` #> backend: html #> x Inter (not on this machine) #> v Liberation Sans #> x Arial (not on this machine) #> o sans (generic, always available) #> backend: latex #> x Inter (not on this machine) #> v Liberation Sans #> x Arial (not on this machine) #> o sans (generic, always available) #> backend: rtf #> x Inter (not on this machine) #> v Liberation Sans #> x Arial (not on this machine) #> o sans (generic, always available) # ---- Example 4: Compare serif vs sans fallback chains ---- # # Side-by-side check of the two generic families. Useful when # deciding the house-style default: the serif chain leads with # Times New Roman, the sans chain with Arial, then each walks the # PostScript name and the metric-compatible Nimbus / Liberation # clones. Both close with the backend's native # fallback layer (CSS generic on HTML, Latin Modern on LaTeX). if (requireNamespace("systemfonts", quietly = TRUE)) { tabular(cdisc_saf_demo) |> preset(font_family = "serif") |> check_fonts() tabular(cdisc_saf_demo) |> preset(font_family = "sans") |> check_fonts() } #> #> ── Font resolution for `font_family = serif` #> backend: html #> x Times New Roman (not on this machine) #> x Times (not on this machine) #> v Nimbus Roman #> v Liberation Serif #> o serif (generic, always available) #> backend: latex #> x Times New Roman (not on this machine) #> x Times (not on this machine) #> v Nimbus Roman #> v Liberation Serif #> x TeX Gyre Termes (not on this machine) #> x Latin Modern Roman (not on this machine) #> backend: rtf #> x Times New Roman (not on this machine) #> x Times (not on this machine) #> v Nimbus Roman #> v Liberation Serif #> #> ── Font resolution for `font_family = sans` #> backend: html #> x Arial (not on this machine) #> x Helvetica (not on this machine) #> v Nimbus Sans #> v Liberation Sans #> o sans-serif (generic, always available) #> backend: latex #> x Arial (not on this machine) #> x Helvetica (not on this machine) #> v Nimbus Sans #> v Liberation Sans #> x TeX Gyre Heros (not on this machine) #> x Latin Modern Sans (not on this machine) #> backend: rtf #> x Arial (not on this machine) #> x Helvetica (not on this machine) #> v Nimbus Sans #> v Liberation Sans ``` # Check LaTeX-package availability for PDF output Reports, for every TeX package the LaTeX / PDF backend can emit, whether the local TeX installation can resolve it, and prints the exact [`tinytex::tlmgr_install()`](https://rdrr.io/pkg/tinytex/man/tlmgr.html) call that installs any that are genuinely missing. Run this before `emit(spec, "out.pdf")` on a fresh machine to turn a cryptic mid-compile `File 'tabularray.sty' not found` into an up-front, actionable checklist. ## Usage ``` r check_latex(quiet = FALSE) ``` ## Arguments - quiet: *Suppress the printed cli report.* `: default FALSE`. When `TRUE`, runs the checks and returns the result invisibly without printing. Use in scripts that branch on the return value. ## Value *Invisibly returns a data frame* with one row per required package and columns `package` (``), `installed` (``, `NA` when undeterminable), and `bundled` (``, `TRUE` for packages tabular ships a fallback copy of), plus a `texlive_year` attribute (``, the TeX Live release year of the active `xelatex`). Side effect: prints a cli report with a per-package status marker and, when anything is missing or the TeX Live release is older than 2023, the exact remedy. ## Details The required set is a superset of every `\\usepackage{}` / `\\UseTblrLibrary{}` directive the backend emits, across all conditional branches (running headers / footers pull `fancyhdr` + `lastpage`; `xelatex` pulls `fontspec`; `pdflatex` pulls the classic font bundles). The check is informational, it does not install anything. **Minimum TeX Live version.** Package availability alone is not sufficient: the bundled `tabularray` requires the 2022-11-01 LaTeX kernel, shipped from **TeX Live 2023** onward. The report therefore opens with the TeX Live year of the active `xelatex` and fails the check when the kernel predates it — the classic symptom is an OS-managed or containerised image (Domino, Posit Workbench) frozen on TeX Live 2018, where every package resolves but the compile dies at `\\ProvidesExplPackage`. The remedy is a newer TeX, not a package install: update the image, or install a user-space TinyTeX with [`tinytex::install_tinytex()`](https://rdrr.io/pkg/tinytex/man/install_tinytex.html)`(bundle = "TinyTeX")` or `quarto install tinytex` — the Quarto route downloads from GitHub, so it also works behind corporate proxies that block CTAN mirrors. Both land in the standard TinyTeX location, which the compile (and this check) prefer over the `PATH` automatically. MiKTeX is rolling-release (always current), so its version reports as undetermined (`?`) rather than failing. **How availability is probed.** The check first resolves TeX the way the compile does: [`tinytex::latexmk()`](https://rdrr.io/pkg/tinytex/man/latexmk.html) prefers a TinyTeX at the standard root (`~/.TinyTeX` on Linux, `~/Library/TinyTeX` on macOS, `%APPDATA%/TinyTeX` on Windows — the location used by both [`tinytex::install_tinytex()`](https://rdrr.io/pkg/tinytex/man/install_tinytex.html) and `quarto install tinytex`) over whatever is on the `PATH`, and the report probes that same tree. Each package is then resolved through `kpsewhich`, the same file resolver `xelatex` uses at compile time, so the report reflects what a compile will actually find. This works on every TeX layout — TinyTeX, a full TeX Live, or an OS-managed install (Debian/apt, RHEL/dnf) where the `tlmgr` package database is absent and database-backed checks report everything as missing. **Bundled fallback packages.** tabular ships verbatim copies of `tabularray` and `ninecolors` (the only requirements not included in any TinyTeX flavor) and stages them next to the generated `.tex` at compile time whenever the local TeX cannot resolve them. A bundled package therefore always passes the check — no `tlmgr_install()` is ever needed for those two. On the community TinyTeX bundle (`tinytex::install_tinytex(bundle = "TinyTeX")`) or any larger installation, everything else is already present, so PDF emission needs no package installs at all — including on restricted servers where `tlmgr` is locked. **OS-managed TeX Live gotcha.** On Linux distributions that ship TeX Live through the system package manager (RHEL / Fedora via `dnf`, Debian / Ubuntu via `apt`), `tlmgr` is locked against user installs and `tlmgr_install()` will fail. The fix is to install a user-space TinyTeX with [`tinytex::install_tinytex()`](https://rdrr.io/pkg/tinytex/man/install_tinytex.html)`(bundle = "TinyTeX")` and let that tree own the packages. Never force a locked `tlmgr` with `--ignore-warning`: it leaves the system tree half-written. Where no TeX install is possible at all, a missing single-file macro package can be sideloaded without `tlmgr`: download its `.sty` from CTAN into `~/texmf/tex/latex//` and set the `TEXMFHOME` environment variable to `~/texmf`. **Slow / stuck install (often Windows).** The default CTAN repository `mirror.ctan.org` redirects to a random mirror on every call, and a slow or stale one makes [`tinytex::tlmgr_install()`](https://rdrr.io/pkg/tinytex/man/tlmgr.html) appear to hang. Pin a concrete mirror once with [`tinytex::tlmgr_repo()`](https://rdrr.io/pkg/tinytex/man/tlmgr.html)`("auto")` (it follows the redirect a single time and remembers the result), then retry the install. **Status markers:** - `v` — package resolves in the local TeX tree, or is missing but covered by a bundled copy (marked `bundled copy used`). - `x` — package is missing; the `tlmgr_install()` line at the bottom of the report installs every missing package at once. - `?` — availability could not be determined (`kpsewhich` not on the `PATH`, i.e. no TeX installation); treated as missing for remediation. ## See also **Companion diagnostic:** [`check_fonts()`](https://vthanik.github.io/tabular/reference/check_fonts.md). **Consumes the result:** [`emit()`](https://vthanik.github.io/tabular/reference/emit.md). ## Examples ``` r # ---- Example 1: Audit the PDF toolchain before emitting ---- # # Run check_latex() on a fresh machine to confirm every LaTeX # package the PDF backend needs is present. The call prints a # status line per package and, if any are missing, the exact # tinytex::tlmgr_install() command to fix them in one shot. Where # no TeX is installed every row reports `?` and the remedy lines # print; the call never errors. check_latex() #> #> ── LaTeX packages for PDF output #> ? TeX Live version (xelatex missing, or a non-TeX-Live distribution #> such as MiKTeX) #> v tabularray (not found, bundled copy used) #> v ninecolors (not found, bundled copy used) #> ? xcolor #> ? graphics #> ? siunitx #> ? geometry #> ? hyperref #> ? iftex #> ? base #> ? fancyhdr #> ? lastpage #> ? fontspec #> ? tex-gyre #> ? psnfss #> ! Missing 12 LaTeX packages: "xcolor", "graphics", "siunitx", "geometry", "hyperref", "iftex", "base", "fancyhdr", "lastpage", "fontspec", "tex-gyre", and "psnfss". #> Install with `tinytex::tlmgr_install(c('xcolor', 'graphics', #> 'siunitx', 'geometry', 'hyperref', 'iftex', 'base', 'fancyhdr', #> 'lastpage', 'fontspec', 'tex-gyre', 'psnfss'))`. #> If the install stalls (commonly on Windows, where the default CTAN #> mirror redirects on every call), pin a concrete mirror once with #> `tinytex::tlmgr_repo("auto")` then retry. #> On an OS-managed TeX Live (RHEL/dnf, Debian/apt) or wherever tlmgr is #> locked: install a user-space TinyTeX with #> `tinytex::install_tinytex(bundle = "TinyTeX")` instead (the community #> bundle covers every package above). Never force a locked tlmgr with #> `--ignore-warning`. #> Where no TeX install is possible at all: download each missing `.sty` #> from CTAN into ~/texmf/tex/latex// and set `TEXMFHOME` to #> ~/texmf; xelatex resolves it from there without tlmgr. ``` # Check Typst availability for PDF output Reports whether a typst compiler is available (the standalone `typst` binary, or the copy bundled inside Quarto), whether its version meets tabular's floor, and which families of the default font chain the compiler can actually see. Run this before `emit(spec, "out.pdf", format = "typst")` on a fresh machine, and whenever a Typst-compiled PDF renders in an unexpected face. ## Usage ``` r check_typst(quiet = FALSE) ``` ## Arguments - quiet: *Suppress the printed cli report.* `: default FALSE`. When `TRUE`, runs the checks and returns the result invisibly without printing. Use in scripts that branch on the return value. ## Value *Invisibly returns a data frame* with one row per family in the resolved default font chain and columns `font` (``) and `available` (``, `NA` when the font list could not be read), plus attributes `typst_version` (``) and `typst_command` (``, the discovered compiler invocation). Side effect: prints a cli report with a status marker per check and, when anything is missing, the remedy. ## Details **Binary discovery.** A standalone `typst` on the `PATH` wins; otherwise the check falls back to `quarto typst` (Quarto \>= 1.4 bundles the typst compiler — so most machines with RStudio / Posit Workbench already have one). The Typst PDF path needs no TeX installation and no package downloads at all. **Fonts are the silent failure mode.** Where a missing LaTeX package stops a compile with an error, typst substitutes a missing font family silently and only notes it on the compiler's stderr. The check therefore lists every family in the resolved default chain with its availability. The chain is a *fallback* chain: typst renders in the first family it can see, so a missing later member is normal cross-OS variance, not a defect — the check reports ready as soon as any family resolves, and names the face PDFs will render in. [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) additionally warns after a Typst compile when a family the user explicitly named cannot be found (missing members of the built-in fallback chains stay silent, matching the other backends' silent font-substitution behaviour). **Status markers:** - `v` — found (binary; version at or above the floor; font family visible to typst). - `x` — missing (no binary; version below the floor; font family not visible). - `?` — could not be determined (e.g. the font list could not be read); treated as missing for remediation. ## See also **Companion diagnostics:** [`check_latex()`](https://vthanik.github.io/tabular/reference/check_latex.md), [`check_fonts()`](https://vthanik.github.io/tabular/reference/check_fonts.md). **Consumes the result:** [`emit()`](https://vthanik.github.io/tabular/reference/emit.md). ## Examples ``` r # ---- Example 1: Audit the Typst toolchain before emitting ---- # # Run check_typst() on a fresh machine to confirm a typst compiler # is present and to see which families of the default font chain it # resolves. Where no binary is found every row reports `?` and the # remedy lines print; the call never errors. check_typst() #> #> ── Typst toolchain for PDF output #> v quarto typst 0.14.2 #> x font Courier New #> x font Courier #> v font Nimbus Mono PS #> v font Liberation Mono #> v font DejaVu Sans Mono #> ✔ Typst is ready; PDFs render in "Nimbus Mono PS" (the first available family of the chain). ``` # Per-column display specification Build a single column's display attributes — label, format, visibility, width, alignment, NA text, indent. The result feeds [`cols()`](https://vthanik.github.io/tabular/reference/cols.md), which stamps the input column name onto the spec from its named-argument position and attaches it to the parent `tabular_spec`. Row structure (section headers, repeat suppression, blank spacers) is not a column attribute — declare it once with [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md). ## Usage ``` r col_spec( label = NA_character_, format = NULL, visible = NA, width = "auto", align = NULL, valign = NULL, na_text = NA_character_, indent = NA ) ``` ## Arguments - label: *Display label for the column header.* `: default NA_character_`. Embed `\n` for multi-line headers (arm name on row 1, BigN denominator on row 2 is the clinical convention). `NA_character_` means use the input column name verbatim. **Restriction:** Empty string and whitespace-only labels are accepted here, unlike [`headers()`](https://vthanik.github.io/tabular/reference/headers.md) band labels which are strict. Supports glue-style `{expr}` interpolation: braces are evaluated as R code in the calling environment at build time, so a BigN value folds inline, `label = "Placebo (N={n['placebo']})"`. Double a brace (`{{` or `}}`) for a literal one. An [`md()`](https://vthanik.github.io/tabular/reference/md.md) / [`html()`](https://vthanik.github.io/tabular/reference/html.md) label is passed through without interpolation. **Per-column token.** `{.name}` (alias `{.col}`) inside a `{expr}` is *deferred* and resolved to the matched column's name when the spec is stamped by [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) / [`cols_apply()`](https://vthanik.github.io/tabular/reference/cols_apply.md), so one spec can carry a variable-N arm header. See [`cols_apply()`](https://vthanik.github.io/tabular/reference/cols_apply.md) for the loop-free idiom. # Two-line header with arm name and BigN from cdisc_saf_n. n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) col_spec( label = "Placebo\nN={n['placebo']}", align = "decimal" ) - format: *Post-cell formatter.* `: default NULL`. A `sprintf` template applied per cell, OR a unary `function(x) -> character` of the same length, OR `NULL` for backend default. **Restriction:** Character templates are probed with `sprintf(format, 0)` at construction; malformed templates fail fast. **Tip:** Use a function for non-`sprintf` formatting (locale- aware numbers, thousand separators, conditional symbols). # sprintf template vs. function form. col_spec(format = "%.1f") col_spec(format = function(x) formatC(x, format = "f", digits = 1, big.mark = ",")) - visible: *Whether the column renders.* `: default NA`. `FALSE` hides the column from output but keeps it in `spec@data` so [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md) and [`style()`](https://vthanik.github.io/tabular/reference/style.md) predicates can still reference it. `NA` (default) is the merge "unset" sentinel — it resolves to visible at render and, crucially, is mergeable: a later [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) call with `visible = TRUE` can **re-show** a column an earlier call hid. **Interaction:** Hidden columns are the standard pattern for sort-key helpers (`row_type`, `n_total`) and for the numeric counts behind formatted-text percentage cells. **Auto-hide.** The depth column named by a character `indent` and every column named by [`subgroup(by = ...)`](https://vthanik.github.io/tabular/reference/subgroup.md) or referenced via a `{col}` placeholder in the subgroup banner template are flipped to `visible = FALSE` automatically at engine time — restating it here is redundant. **Break-only grouping key.** To drop a blank line wherever a hidden marker column changes (e.g. continuous stats vs. categorical groups inside one characteristic), set `visible = FALSE` here AND name the column in [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md)`(by = )`. A hidden grouping key is break-only: it renders nothing and contributes only its group transitions (the blank spacer and the decimal-section reset). - width: *Column width — auto-sized, pinned, or proportional.* `: default "auto"`. - **`"auto"`** *(default)* — engine measures the widest cell (header + body) using bundled Adobe AFM Core 13 glyph metrics and distributes against the available content width. The **header** is sized to its widest *word*, so a multi-word header (e.g. `"n, median"`) wraps at spaces; a non-breaking space (` `) keeps a run whole. The **body** is sized to its widest *line* and never wraps, so numeric values stay intact. Pin a numeric width to wrap the body too. - **``** — pinned in inches. Backends wrap content inside the pinned width (tabularray `Q[wd=...]`, HTML `style="width:..."`, RTF / DOCX after twips conversion). - **`"2.5in"` / `"60mm"` / `"4cm"` / `"30pt"` / `"5pc"`** — pinned dimension with an explicit TeX unit. Same behaviour as a bare numeric. - **`"30%"`** — proportional width, percent of available content width. Resolved at engine time against the printable area. **Tip:** Mix freely. Pinned and percent widths take priority; `"auto"` columns distribute whatever space remains. If pinned widths together exceed the available content width, the engine warns and leaves `"auto"` columns at their natural fit (layout may overflow). **Restriction:** Must be positive. Percent values must fall in `[0, 100]`. Font-relative units (`em`, `ex`, `rem`) are rejected (no font-size context at parse time). **Cross-format semantics (gt convention).** The width value is the user's source-of-truth. HTML emits it verbatim into `` (CSS accepts every unit: `%`, `in`, `px`, `pt`, `cm`, `mm`). Paper backends (LaTeX / RTF / PDF / DOCX) convert to their native unit via the AFM / distribute-widths pipeline. HTML is unconditionally responsive: when `width = "auto"` (default), the browser auto-sizes the column and cells wrap when the viewport narrows. **Note:** `NA` and `NULL` are rejected. In pre-v0.1.0 tabular `NA` deferred to backend auto-fit; that path was inconsistent across backends and is replaced by the `"auto"` default, which produces identical widths across RTF / LaTeX / HTML. **Merge sentinel.** For the field-merge across repeated [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) / [`cols_apply()`](https://vthanik.github.io/tabular/reference/cols_apply.md) calls, `"auto"` is treated as the default: a later call carrying `width = "auto"` leaves a previously pinned width intact, and only an explicit non-`"auto"` width overrides. - align: *Horizontal alignment within the column.* `: default NULL`. One of: - **`"left"`** — character columns; row labels. - **`"center"`** — column-header band; rarely on data cells. - **`"right"`** — numeric content without decimals. - **`"decimal"`** — numeric or mixed-format cells aligned on the decimal mark. Use for `"5 (3.2%)"` next to `"54 (32.1%)"`. - **`NULL`** (default) — falls through to `preset(alignment = list(body_halign = ...))` and then to the baked default `"left"`. **Tip:** `"decimal"` pads numerics with non-breaking spaces so the decimal mark falls on a single column-wide anchor. Pad counts follow the active preset's `decimal_metrics` knob (see [`preset()`](https://vthanik.github.io/tabular/reference/preset.md)): the default `"afm"` measures real glyph widths so the anchor holds in proportional fonts as well as monospace. **Default behaviour.** When `align` is unset (`NULL` / `NA`), every column emits with body left-aligned and header centred, regardless of the column's R data type. tabular's canonical input is pre-summarised wide data frames where numeric content is already formatted as character strings (e.g. `"52 (60.5)"`), so [`is.numeric()`](https://rdrr.io/r/base/numeric.html)-based auto-detection would mis-classify those columns as text and align them left — the opposite of intent. Use explicit `align = "decimal"` for NBSP-padded numeric columns (centred header over the padded centroid) or `align = "right"` for plain right-aligned numeric columns. The default cascade is body → `preset(alignment = list( body_halign = ...))` → CSS `text-align: left`; header → `preset(alignment = list(header_halign = ...))` → CSS `text-align: center`. - valign: *Vertical alignment within the cell.* `: default NULL`. One of `"top"`, `"middle"`, `"bottom"`. `NULL` falls through to `preset(alignment = list(body_valign = ...))` (baked default `"top"`). Per-cell overrides via `style(valign = ...)` still win over the column setting. **Tip:** Set `"middle"` on the row-label column of a banded- row table so the label stays centred against the multi-line stat-block in the adjacent cell. - na_text: *Text substituted for `NA` cells.* `: default NA`. Substituted BEFORE the `format` step, so `format` does not need to anticipate `NA`. `NA` (default) inherits the preset's table-wide `na_text`; any string overrides it for this column, including `""` to force blank cells even when the preset uses a non-empty token. **Tip:** Use a sentinel (`"-"`, `"NR"`, `"."`) when blank cells would be ambiguous, e.g. when "not applicable" and "not reported" both render blank. - indent: *Cosmetic indent depth on this column.* `: default NA`. Two modes by type: - **A non-negative whole number** — every body row of this column is indented that many levels (each level is `preset@indent_size` space-widths). `indent = 1` is the common "nudge this stub in one level" case; `indent = 0` is a real value that flattens children under a `"section"` header. - **A column name (character)** — per-row depth: the engine reads `spec@data[[indent]]`, coerces each row to a non-negative integer, and prefixes that row's text + AST with `strrep(" ", preset@indent_size * depth)`. The referenced depth column is auto-hidden — no need to set `visible = FALSE` on it. `NA` (default) means no indent. Backends with native padding-left (HTML / LaTeX / RTF / DOCX / PDF) emit the depth as cell padding so wrapped continuation lines align with the indented baseline; Markdown carries the literal space-prefix. Synthesised group-header rows are never indented — they are the parent at depth 0. **Interaction:** an explicit `indent` on the host column of a [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md)`(display = "section")` section **suppresses** that section's automatic one-level child indent (you take control of the depth) — so a stub under a section needs no `indent` at all, and adding `indent = 1` there yields a single, not double, indent. Per-row SOC / PT pattern (the bundled `cdisc_saf_aesocpt` ships the canonical depth column, so no upstream construction is needed): cols( label = col_spec(label = "Category", indent = "indent_level"), soc = col_spec(visible = FALSE), row_type = col_spec(visible = FALSE) ) Depth-column values `c(0L, 1L, 2L, …)` produce `0`, `1`, `2`, … levels. Negative values clamp to 0 (warn); fractional numerics floor (warn); NA → 0 (silent). Works in flat listings too — a character `indent` does not require any [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) keys. ## Value *A `col_spec` S7 object.* Pass it to [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) keyed by the input column name; the constructor itself does not stamp a name. ## Details **Constructor-only.** `col_spec()` does not know which input column it belongs to until [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) stamps the name. Build reusable specs as ordinary R objects (e.g. `arm_col <- col_spec(align = "decimal")`) and apply them to multiple inputs without restating the name. **Merge semantics across repeated [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) calls.** When [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) is called twice for the same column, the engine merges field-by-field: any field set to a non-default value on the new spec overrides; a field left at its "unset" sentinel (`NA` / `NULL` / `"auto"`) leaves the existing value intact. Because every mergeable field has a genuine unset sentinel, a later call can also *restore* a default — e.g. `visible = TRUE` re-shows a column an earlier call hid. Build a column's spec in stages without re-stating earlier attributes. **Validation timing.** Argument shapes are validated eagerly — a malformed `sprintf` template is probed at construction (`sprintf(format, 0)`) and fails fast at write time, not at render time. ## See also **Companion verb:** [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) attaches `col_spec` entries to a `tabular_spec` keyed by input column name. **Row structure:** [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) declares the grouping keys and section rendering at table level. **Sibling build verbs:** [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md), [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md), [`preset()`](https://vthanik.github.io/tabular/reference/preset.md). **Entry / terminal verbs:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md), [`emit()`](https://vthanik.github.io/tabular/reference/emit.md), [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md). **Inline label formatting:** [`md()`](https://vthanik.github.io/tabular/reference/md.md), [`html()`](https://vthanik.github.io/tabular/reference/html.md). ## Examples ``` r # ---- Example 1: Demographics with every col_spec field exercised ---- # # Demographics table where every `col_spec` field is in play: # the row-label columns are pinned to a fixed width and aligned # left, the four arm columns embed BigN inline in the header, # decimal-align numeric content, and render `NA` cells as "-". n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) tabular( cdisc_saf_demo, titles = c( "Table 14.1.1", "Demographics and Baseline Characteristics", "Safety Population" ), footnotes = "Percentages based on N per treatment group." ) |> cols( variable = col_spec( label = "Parameter", width = 2.0, align = "left" ), stat_label = col_spec(label = "Statistic", align = "left"), placebo = col_spec( label = "Placebo\nN={n['placebo']}", align = "decimal", na_text = "-" ), drug_50 = col_spec( label = "Drug 50\nN={n['drug_50']}", align = "decimal", na_text = "-" ), drug_100 = col_spec( label = "Drug 100\nN={n['drug_100']}", align = "decimal", na_text = "-" ), Total = col_spec( label = "Total\nN={n['Total']}", align = "decimal", na_text = "-" ) ) |> group_rows(by = "variable") |> sort_rows(by = c("variable", "stat_label")) #tabular-ba6debc427 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-ba6debc427 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-ba6debc427 p { line-height: inherit; } #tabular-ba6debc427 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-ba6debc427 .tabular-caption { margin: 0; padding: 0; } #tabular-ba6debc427 .tabular-pad { margin: 0; line-height: 1; } #tabular-ba6debc427 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-ba6debc427 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-ba6debc427 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-ba6debc427 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-ba6debc427 .tabular-table th, #tabular-ba6debc427 .tabular-table td { padding: .18rem .6rem; } #tabular-ba6debc427 .tabular-table td { text-align: left; vertical-align: top; } #tabular-ba6debc427 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-ba6debc427 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-ba6debc427 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-ba6debc427 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-ba6debc427 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-ba6debc427 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-ba6debc427 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-ba6debc427 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-ba6debc427 .tabular-table tbody tr td { border-top: none; } #tabular-ba6debc427 .tabular-band { text-align: center; } #tabular-ba6debc427 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-ba6debc427 .tabular-subgroup-label { font-weight: 600; } #tabular-ba6debc427 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-ba6debc427 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-ba6debc427 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-ba6debc427 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-ba6debc427 .text-left { text-align: left; } #tabular-ba6debc427 .text-center { text-align: center; } #tabular-ba6debc427 .text-right { text-align: right; } #tabular-ba6debc427 .tabular-table thead th.text-left { text-align: left; } #tabular-ba6debc427 .tabular-table thead th.text-center { text-align: center; } #tabular-ba6debc427 .tabular-table thead th.text-right { text-align: right; } #tabular-ba6debc427 .tabular-table td.text-left { text-align: left; } #tabular-ba6debc427 .tabular-table td.text-center { text-align: center; } #tabular-ba6debc427 .tabular-table td.text-right { text-align: right; } #tabular-ba6debc427 .valign-top { vertical-align: top; } #tabular-ba6debc427 .valign-middle { vertical-align: middle; } #tabular-ba6debc427 .valign-bottom { vertical-align: bottom; } #tabular-ba6debc427 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-ba6debc427 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-ba6debc427 .tabular-page-break-row { display: none; } #tabular-ba6debc427 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-ba6debc427 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-ba6debc427 .tabular-page-header, #tabular-ba6debc427 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-ba6debc427 .tabular-page-header { margin-bottom: 1rem; } #tabular-ba6debc427 .tabular-page-footer { margin-top: 1rem; } #tabular-ba6debc427 .tabular-page-header-left, #tabular-ba6debc427 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-ba6debc427 .tabular-page-header-center, #tabular-ba6debc427 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-ba6debc427 .tabular-page-header-right, #tabular-ba6debc427 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-ba6debc427 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-ba6debc427 .tabular-table tr { page-break-inside: avoid; } #tabular-ba6debc427 .tabular-page-header, #tabular-ba6debc427 .tabular-page-footer { display: none; } #tabular-ba6debc427 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-ba6debc427 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-ba6debc427 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.1.1 Demographics and Baseline Characteristics Safety Population   Statistic ``` # Apply one column spec to many columns Field-merge a single [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) onto every column matched by name or by a predicate. The vectorized companion to [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) for the common case of a variable number of treatment-arm columns that all share the same display rule (decimal alignment, a numeric format), so you avoid [`do.call()`](https://rdrr.io/r/base/do.call.html) / `!!!` splicing one named argument per arm. ## Usage ``` r cols_apply(.spec, .cols, .col_spec) ``` ## Arguments - .spec: *The `tabular_spec` to extend.* `: required`. Dot-prefixed so partial matching cannot bind a user name in another slot. - .cols: *Columns to match.* `: required`. Either a character vector of input column names in `.spec@data`, or a predicate `function(names) -> logical` evaluated against `names(.spec@data)` (one logical per column, same length). **Restriction:** Named columns must exist in `.spec@data`. A predicate must return a logical vector the length of `names(.spec@data)`. **Tip:** No tidyselect helpers ship; pass a base vector (`grep("^ARM", names(df), value = TRUE)`) or a predicate (`\(nm) startsWith(nm, "ARM")`). - .col_spec: *The spec to field-merge onto every match.* `: required`. Built with [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md). ## Value *The updated `tabular_spec`.* Continue chaining with [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md). ## Details **Field-merge, not replace.** `cols_apply()` reuses the same field-by-field merge as repeated [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) calls: a non-default field on `.col_spec` overrides; a default-valued field leaves any prior attribute on the matched column intact. Set the shared rule across arms first, then refine an individual arm with a later [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) call (or the reverse). **Per-column label token.** A `label` that references `{.name}` (or its alias `{.col}`) inside a `{expr}` is resolved *per matched column*, with `.name` and `.col` both bound to that column's name. This makes a variable-N arm header a single declarative call instead of a hand-written loop. The rest of the `{expr}` evaluates in the calling environment, so a per-arm BigN looked up from a named vector works directly: n <- c(placebo = 86, drug_50 = 84, drug_100 = 84) cols_apply( spec, c("placebo", "drug_50", "drug_100"), col_spec(label = "{.name}\n(N={n[.name]})", align = "decimal") ) # placebo -> "placebo\n(N=86)" ; drug_50 -> "drug_50\n(N=84)" ; ... The token is a plain-string feature; a label wrapped in [`md()`](https://vthanik.github.io/tabular/reference/md.md) / [`html()`](https://vthanik.github.io/tabular/reference/html.md) is parsed eagerly and does not interpolate. A failing token expression aborts naming the offending column. **`width` merge.** `width`'s default sentinel for the merge is `"auto"`: a later [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) / `cols_apply()` call carrying the default `width = "auto"` leaves a previously pinned width intact (only an explicit non-`"auto"` width overrides). Apply a shared width last to broadcast it across arms. ## See also **Companion verbs:** [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) attaches per-column specs by name; [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) builds the spec. **Sibling build verbs:** [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md), [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md), [`preset()`](https://vthanik.github.io/tabular/reference/preset.md). ## Examples ``` r # ---- Example 1: Decimal-align every arm column by name vector ---- # # Demographics table whose treatment-arm columns are selected by a # name vector (`grep()` against the data) and given one shared # decimal-alignment spec, while the two row-label columns keep # their own roles set with `cols()`. arm_cols <- grep("^placebo$|^drug_|^Total$", names(cdisc_saf_demo), value = TRUE) tabular( cdisc_saf_demo, titles = c( "Table 14.1.1", "Demographics and Baseline Characteristics", "Safety Population" ) ) |> cols( variable = "Parameter", stat_label = "Statistic" ) |> cols_apply(arm_cols, col_spec(align = "decimal")) |> group_rows(by = "variable") |> sort_rows(by = c("variable", "stat_label")) #tabular-d628277aa5 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-d628277aa5 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-d628277aa5 p { line-height: inherit; } #tabular-d628277aa5 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-d628277aa5 .tabular-caption { margin: 0; padding: 0; } #tabular-d628277aa5 .tabular-pad { margin: 0; line-height: 1; } #tabular-d628277aa5 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-d628277aa5 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-d628277aa5 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-d628277aa5 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-d628277aa5 .tabular-table th, #tabular-d628277aa5 .tabular-table td { padding: .18rem .6rem; } #tabular-d628277aa5 .tabular-table td { text-align: left; vertical-align: top; } #tabular-d628277aa5 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-d628277aa5 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-d628277aa5 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-d628277aa5 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-d628277aa5 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-d628277aa5 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-d628277aa5 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-d628277aa5 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-d628277aa5 .tabular-table tbody tr td { border-top: none; } #tabular-d628277aa5 .tabular-band { text-align: center; } #tabular-d628277aa5 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-d628277aa5 .tabular-subgroup-label { font-weight: 600; } #tabular-d628277aa5 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-d628277aa5 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-d628277aa5 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-d628277aa5 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-d628277aa5 .text-left { text-align: left; } #tabular-d628277aa5 .text-center { text-align: center; } #tabular-d628277aa5 .text-right { text-align: right; } #tabular-d628277aa5 .tabular-table thead th.text-left { text-align: left; } #tabular-d628277aa5 .tabular-table thead th.text-center { text-align: center; } #tabular-d628277aa5 .tabular-table thead th.text-right { text-align: right; } #tabular-d628277aa5 .tabular-table td.text-left { text-align: left; } #tabular-d628277aa5 .tabular-table td.text-center { text-align: center; } #tabular-d628277aa5 .tabular-table td.text-right { text-align: right; } #tabular-d628277aa5 .valign-top { vertical-align: top; } #tabular-d628277aa5 .valign-middle { vertical-align: middle; } #tabular-d628277aa5 .valign-bottom { vertical-align: bottom; } #tabular-d628277aa5 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-d628277aa5 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-d628277aa5 .tabular-page-break-row { display: none; } #tabular-d628277aa5 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-d628277aa5 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-d628277aa5 .tabular-page-header, #tabular-d628277aa5 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-d628277aa5 .tabular-page-header { margin-bottom: 1rem; } #tabular-d628277aa5 .tabular-page-footer { margin-top: 1rem; } #tabular-d628277aa5 .tabular-page-header-left, #tabular-d628277aa5 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-d628277aa5 .tabular-page-header-center, #tabular-d628277aa5 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-d628277aa5 .tabular-page-header-right, #tabular-d628277aa5 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-d628277aa5 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-d628277aa5 .tabular-table tr { page-break-inside: avoid; } #tabular-d628277aa5 .tabular-page-header, #tabular-d628277aa5 .tabular-page-footer { display: none; } #tabular-d628277aa5 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-d628277aa5 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-d628277aa5 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.1.1 Demographics and Baseline Characteristics Safety Population   Statistic ``` # Attach per-column specifications Add [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) entries to a `tabular_spec`. Each named argument is one column: the name is the input column in `.spec@data` and the value is either the `col_spec` carrying that column's display attributes (label, format, alignment, width, visibility, NA text) or a bare label string — `x = "Label"` is shorthand for `x = col_spec(label = "Label")`. Columns not mentioned get a default [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) at engine-validate time. ## Usage ``` r cols(.spec, ..., .default = NULL, .hide = character()) ``` ## Arguments - .spec: *The `tabular_spec` to extend.* `: required`. Dot-prefixed so R's partial argument matching cannot accidentally bind a short user-supplied name (e.g. `s`, `sp`) in `...` to the spec slot. Pipe input (`tabular(...) |> cols(...)`) works the normal way — the spec is supplied positionally. - ...: *Named `col_spec` objects or label strings, one per column.* Each name is the input column name in `.spec@data`. Names must match an existing column — pre-compute derived columns upstream with `dplyr::mutate()` (or equivalent) before [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md). A `character(1)` value is label shorthand: `soc = "SOC / PT"` is exactly `soc = col_spec(label = "SOC / PT")`, including glue-style `{expr}` interpolation and the deferred `{.name}` / `{.col}` token. **Restriction:** Names must be unique within a single `cols()` call (duplicates warn; "last value wins"). **Tip:** To override an attribute already declared, use a second `cols()` call downstream and let the merge rule apply. - .default: *Fallback `col_spec` for unmentioned columns.* `: default NULL`. When a `col_spec`, it is field-merged onto every data column that is NOT named in `...` and does not already carry a spec from an earlier `cols()` call. `NULL` (default) leaves unmentioned columns to the engine-time default. Use it to set one alignment / format across a variable number of arm columns in a single call. **Interaction:** Explicit `...` specs always win — `.default` only fills the gaps. A column carried over from a prior `cols()` call is treated as already specified and is left untouched. # Decimal-align every arm column without listing each by name. tabular(cdisc_saf_demo) |> cols( variable = "Parameter", stat_label = "Statistic", .default = col_spec(align = "decimal") ) - .hide: *Columns to hide, by name.* `: default character()`. Sugar for `nm = col_spec(visible = FALSE)` entries — one flat vector for the hidden sort keys and helper columns every clinical table carries. Field-merged like any other entry, so a later `cols(nm = col_spec(visible = TRUE))` can re-show the column. **Interaction:** A column named in both `...` and `.hide` ends up with its `...` attributes plus `visible = FALSE`. ## Value *The updated `tabular_spec`.* Continue chaining with [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md). ## Details **Sparse declaration.** Declare only the columns whose attributes differ from the default — a typical pipeline uses one `cols()` call with one entry per non-default column. **Layout order follows the data frame, not `cols()`.** The left-to-right column order in the rendered table is the column order of `.spec@data`; the order of the named `...` arguments here is irrelevant (they are a lookup keyed by name). To move a column, reorder the data frame upstream — a column derived with `df$new <- ...` is appended last and will render last unless you reorder. **Within-call duplicates warn.** A duplicate name inside one `cols()` call warns and "last value wins". To intentionally override an attribute, use a second `cols()` call downstream and let the merge rule below apply. ## Repeat-call merge semantics When `cols()` is called more than once for the same column, the engine merges the new `col_spec` into the existing one field-by- field. A field set to a non-default value on the new spec overrides; a field left at its "unset" sentinel leaves the existing value intact. Every mergeable field has a genuine unset sentinel, so a later call can also *restore* a default (e.g. `visible = TRUE` re-shows a hidden column). This lets you build a column's spec in stages — declare the label-and-alignment block up front, add the width once you know it fits, then attach a sort key, all without re-stating earlier attributes. Essential when generating specs programmatically (looping over arms, layering a house-style helper). Unset sentinels — a field left at this value does NOT override the existing field (every other value, including a default like `visible = TRUE`, overrides): | | | |-----------|----------------------------------| | field | unset sentinel | | `label` | `NA_character_` | | `format` | `NULL` | | `visible` | `NA` | | `width` | `"auto"` | | `align` | `NA_character_` | | `valign` | `NA_character_` | | `na_text` | `NA_character_` (inherit preset) | | `indent` | `NA` | # Three-stage build: label first, alignment second, width third. # Each stage leaves earlier fields intact. tabular(cdisc_saf_demo) |> cols(variable = "Parameter") |> cols(variable = col_spec(align = "left")) |> cols(variable = col_spec(width = 2.0)) # Result: variable has label="Parameter", align="left", # width=2.0 — all three fields set. ## See also **Companion constructor:** [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) builds the per-column DSL object that `cols()` attaches. **Sibling build verbs:** [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md), [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md), [`preset()`](https://vthanik.github.io/tabular/reference/preset.md). **Entry / terminal verbs:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md), [`emit()`](https://vthanik.github.io/tabular/reference/emit.md), [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md). ## Examples ``` r # ---- Example 1: Demographics with arm BigN inline in headers ---- # # Demographics table where the row-label columns sit on the left # and the four treatment-arm columns embed BigN in the header # label (drawn inline from the bundled `cdisc_saf_n` data frame). Every # arm column is decimal-aligned so mixed-format cells like # "5 (3.2%)" line up on the decimal mark. n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) tabular( cdisc_saf_demo, titles = c( "Table 14.1.1", "Demographics and Baseline Characteristics", "Safety Population" ), footnotes = "Percentages based on N per treatment group." ) |> cols( variable = "Parameter", stat_label = "Statistic", placebo = col_spec(label = "Placebo\nN={n['placebo']}", align = "decimal"), drug_50 = col_spec(label = "Drug 50\nN={n['drug_50']}", align = "decimal"), drug_100 = col_spec(label = "Drug 100\nN={n['drug_100']}", align = "decimal"), Total = col_spec(label = "Total\nN={n['Total']}", align = "decimal") ) |> group_rows(by = "variable") |> sort_rows(by = c("variable", "stat_label")) #tabular-69e6f53254 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-69e6f53254 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-69e6f53254 p { line-height: inherit; } #tabular-69e6f53254 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-69e6f53254 .tabular-caption { margin: 0; padding: 0; } #tabular-69e6f53254 .tabular-pad { margin: 0; line-height: 1; } #tabular-69e6f53254 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-69e6f53254 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-69e6f53254 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-69e6f53254 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-69e6f53254 .tabular-table th, #tabular-69e6f53254 .tabular-table td { padding: .18rem .6rem; } #tabular-69e6f53254 .tabular-table td { text-align: left; vertical-align: top; } #tabular-69e6f53254 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-69e6f53254 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-69e6f53254 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-69e6f53254 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-69e6f53254 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-69e6f53254 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-69e6f53254 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-69e6f53254 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-69e6f53254 .tabular-table tbody tr td { border-top: none; } #tabular-69e6f53254 .tabular-band { text-align: center; } #tabular-69e6f53254 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-69e6f53254 .tabular-subgroup-label { font-weight: 600; } #tabular-69e6f53254 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-69e6f53254 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-69e6f53254 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-69e6f53254 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-69e6f53254 .text-left { text-align: left; } #tabular-69e6f53254 .text-center { text-align: center; } #tabular-69e6f53254 .text-right { text-align: right; } #tabular-69e6f53254 .tabular-table thead th.text-left { text-align: left; } #tabular-69e6f53254 .tabular-table thead th.text-center { text-align: center; } #tabular-69e6f53254 .tabular-table thead th.text-right { text-align: right; } #tabular-69e6f53254 .tabular-table td.text-left { text-align: left; } #tabular-69e6f53254 .tabular-table td.text-center { text-align: center; } #tabular-69e6f53254 .tabular-table td.text-right { text-align: right; } #tabular-69e6f53254 .valign-top { vertical-align: top; } #tabular-69e6f53254 .valign-middle { vertical-align: middle; } #tabular-69e6f53254 .valign-bottom { vertical-align: bottom; } #tabular-69e6f53254 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-69e6f53254 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-69e6f53254 .tabular-page-break-row { display: none; } #tabular-69e6f53254 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-69e6f53254 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-69e6f53254 .tabular-page-header, #tabular-69e6f53254 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-69e6f53254 .tabular-page-header { margin-bottom: 1rem; } #tabular-69e6f53254 .tabular-page-footer { margin-top: 1rem; } #tabular-69e6f53254 .tabular-page-header-left, #tabular-69e6f53254 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-69e6f53254 .tabular-page-header-center, #tabular-69e6f53254 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-69e6f53254 .tabular-page-header-right, #tabular-69e6f53254 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-69e6f53254 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-69e6f53254 .tabular-table tr { page-break-inside: avoid; } #tabular-69e6f53254 .tabular-page-header, #tabular-69e6f53254 .tabular-page-footer { display: none; } #tabular-69e6f53254 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-69e6f53254 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-69e6f53254 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.1.1 Demographics and Baseline Characteristics Safety Population   Statistic ``` # Render a `tabular_spec` to a file Resolve `spec` through the engine pipeline, dispatch to the backend registered for the chosen format, and (optionally) write a QC data file and a CDISC ARS audit manifest alongside the rendered artefact. `emit()` is the package's terminal verb — it returns `file` invisibly so the call can sit at the bottom of a pipe without losing the path. ## Usage ``` r emit( .spec, file, format = NULL, data_file = NULL, manifest = FALSE, create_dir = FALSE ) ``` ## Arguments - .spec: *The `tabular_spec` to render.* `: required`. The full verb chain ([`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) -\> [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) -\> [`headers()`](https://vthanik.github.io/tabular/reference/headers.md) -\> [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md) -\> [`style()`](https://vthanik.github.io/tabular/reference/style.md) -\> [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md) -\> [`preset()`](https://vthanik.github.io/tabular/reference/preset.md)) feeds into `emit()`'s first argument by pipe. - file: *Destination path for the rendered artefact.* `: required`. Extension drives the backend (see the dispatch table in the Details section). The parent directory must already exist; `emit()` does not auto-create directories. **Tip:** Use `tempfile(fileext = ".md")` inside vignettes and examples so the example runs in `R CMD check` without polluting the package directory. - format: *Explicit backend override.* `: default NULL`. When set, wins over the file extension. Useful for writing `.txt` files that should contain RTF, for round-trip testing, or when the user has a custom backend registered under a non-standard name. **Interaction:** On a `.pdf` target, `format` names the compile ENGINE: `"latex"` compiles via TeX and `"typst"` via the typst binary (see the *PDF engines* section). On every other extension the generic override semantics apply unchanged. - data_file: *QC artefact writer.* ` character(1) | NULL>:` `default NULL`. When set, writes the resolved wide data frame alongside the render. A character path writes there directly; a lambda receives the render path and returns the data file path (typical for sponsor-flexible naming). **Restriction:** Returned-path extension must be `.csv`, `.tsv` / `.txt`, or `.rds`. **Tip:** The data frame the lambda governs is pre-backend — the same CSV is emitted regardless of whether `file` is RTF, PDF, or DOCX. # Three canonical sponsor patterns for the lambda. data_file = \(f) paste0(tools::file_path_sans_ext(f), "_qc.csv") data_file = \(f) file.path( "validation", paste0("val_", basename(tools::file_path_sans_ext(f)), ".csv") ) data_file = \(f) file.path( "rd", paste0("rd_", basename(tools::file_path_sans_ext(f)), ".rds") ) - manifest: *Emit the CDISC ARS audit manifest sidecar.* `: default FALSE`. `TRUE` writes `.audit.yml` with verbatim CDISC ARS LDM v1.0 Output keys; see the **`manifest = TRUE`** invariant in the Details section for what the file contains and the determinism contract it satisfies. - create_dir: *Create the destination directory if it is missing.* `: default FALSE`. When `TRUE`, the parent directory of `file` (and any missing ancestors) is created recursively before rendering, instead of aborting. The default `FALSE` keeps the safe behaviour of erroring on a missing parent. ## Value *The `file` path, invisibly.* Use this when chaining `emit()` into a downstream consumer that needs the resolved path (e.g. printing the link in a Quarto chunk, copying the sidecar manifest into an archive, attaching the render to a submission folder builder). ## Details **Validation before I/O.** Every argument is validated and the backend is resolved BEFORE the engine runs. An unsupported extension, a malformed `data_file` path, or a missing backend raises `tabular_error_input` without writing any file. A spec that resolves cleanly but whose backend errors mid-write may leave a partial file behind; this is the only failure mode that touches disk. **Backend dispatch.** The effective backend is resolved from the file extension via the table below; the `format` argument always wins when both are supplied. Each backend lives in its own `R/backend_.R` file and self-registers at package load time. | | | | |--------------------|----------|----------------------------------| | extension(s) | format | backend | | `.md`, `.markdown` | `md` | GFM pipe table | | `.html`, `.htm` | `html` | self-contained Bootstrap 5 | | `.tex`, `.latex` | `latex` | tabularray | | `.typ` | `typst` | Typst native `#table` | | `.pdf` | (probed) | LaTeX (tinytex) or Typst compile | | `.rtf` | `rtf` | RTF 1.9.1, native | | `.docx` | `docx` | OOXML native, no JVM | Unknown extensions, missing extensions, and formats with no registered backend all raise `tabular_error_input`. The error message lists the currently registered formats so the failure is actionable. **PDF engines.** A `.pdf` target compiles through one of two engines: **LaTeX** (via [`tinytex::latexmk()`](https://rdrr.io/pkg/tinytex/man/latexmk.html); needs a TeX installation) or **Typst** (via the standalone `typst` binary or the copy bundled inside Quarto \>= 1.4; needs no TeX at all). Pass `format = "latex"` or `format = "typst"` to pick one explicitly. With no `format`, `emit()` probes the machine LaTeX-first: a usable TeX (found the way the compile finds it, preferring a standard-root TinyTeX, and not frozen on a pre-2023 TeX Live kernel) keeps the historical LaTeX path; otherwise a discoverable typst binary takes over; with neither, `emit()` aborts up front naming both remedies. Audit the toolchains with [`check_latex()`](https://vthanik.github.io/tabular/reference/check_latex.md) and [`check_typst()`](https://vthanik.github.io/tabular/reference/check_typst.md). **Typst capability notes.** The Typst output matches the LaTeX layout contract, including the engine's keep-with-next mask ([`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md)'s `keep_together` / orphan control): Typst has no per-row no-break primitive (LaTeX `\\\\*`, RTF `\\keepn`, DOCX `keepNext`), so the backend enforces the mask through a hidden zero-width column whose unbreakable rowspans pin each keep run to one page. Two documented deviations remain: (1) the `paginate(continuation =)` marker appears on continuation panels only (the repeating page header is identical on every page), matching the RTF tier rather than LaTeX's every-page marker; (2) the spanner underline is trimmed by the cell inset at both ends (the HTML tier), where LaTeX keeps the table's outer edges flush. Conversely, Typst renders per-cell body borders that the LaTeX backend cannot (see [`style()`](https://vthanik.github.io/tabular/reference/style.md)). **`data_file` is sponsor-neutral.** Pass an explicit path (`"out/qc.csv"`) for a fixed location, or a lambda (`function(file) -> path`) for sponsor-flexible naming. The lambda receives the resolved render path so it can derive the QC file from it (suffix, sibling folder, separate sponsor-styled name). Recognised extensions on the returned path are `.csv`, `.tsv` (alias: `.txt`), and `.rds`; anything else raises `tabular_error_input`. The written data frame is the post- [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md) / post-`engine_decimal()` wide grid — exactly the cell text the backend wrote. **`manifest = TRUE` writes a sidecar.** The audit manifest is written to `.audit.yml` next to the render (e.g. `out.md` -\> `out.audit.yml`). Keys are CDISC ARS LDM v1.0 Output verbatim: `id`, `name`, `programmingCode` (best-effort git + R + platform - timestamp), `fileSpecifications` (sha256 of every emitted artefact including `data_file`), `displays/displaySections` (Title / Header / Body / Footnote), `referencedAnalyses` (empty in v0.1; reserved for the mintverse handoff), `x-tabular` (rendering geometry, pagination, style trace, input provenance). Determinism contract: two consecutive `emit()` calls are byte- identical except for the `rendered_at` parameter timestamp; the YAML round-trips through [`yaml::read_yaml()`](https://yaml.r-lib.org/reference/read_yaml.html) + [`yaml::write_yaml()`](https://yaml.r-lib.org/reference/write_yaml.html). **Pure dispatcher.** `emit()` does not do any rendering itself; it composes [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md) with a backend writer. To inspect the resolved grid without writing a file (during development, or to build a custom downstream consumer), call [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md) directly. ## See also **No-I/O sibling:** [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md) returns the resolved grid without writing a file — use during development to inspect what `emit()` would hand a backend. **Build verbs the pipeline feeds from:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md), [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) / [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md), [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md), [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md), [`preset()`](https://vthanik.github.io/tabular/reference/preset.md). **Inline formatting helpers:** [`md()`](https://vthanik.github.io/tabular/reference/md.md), [`html()`](https://vthanik.github.io/tabular/reference/html.md) (titles, footnotes, labels, cell text). ## Examples ``` r # ---- Example 1: Render demographics to Markdown ---- # # Smallest possible emit: spec in, .md out. The backend is chosen # from the file extension; the engine pipeline runs internally, # then the registered md backend writes a GFM pipe table you can # preview in any Markdown renderer. tempfile() keeps the example # clean for `R CMD check`. n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) demo <- tabular( cdisc_saf_demo, titles = c( "Table 14.1.1", "Demographics and Baseline Characteristics", "Safety Population" ), footnotes = "Source: ADSL." ) |> cols( variable = col_spec(label = "Characteristic"), stat_label = col_spec(label = "Statistic"), placebo = col_spec(label = "Placebo\nN={n['placebo']}", align = "decimal"), drug_50 = col_spec(label = "Drug 50\nN={n['drug_50']}", align = "decimal"), drug_100 = col_spec(label = "Drug 100\nN={n['drug_100']}", align = "decimal"), Total = col_spec(label = "Total\nN={n['Total']}", align = "decimal") ) |> group_rows(by = "variable") |> sort_rows(by = c("variable", "stat_label")) demo_md <- tempfile(fileext = ".md") emit(demo, demo_md) # ---- Example 2: Render + QC data + CDISC audit manifest ---- # # The clinical double-programming pattern: render the table, # write a QC CSV alongside it for an independent programmer to # verify cell-for-cell, and emit the CDISC ARS audit manifest # for submission packaging. The lambda derives the QC path from # the render path so the sponsor's naming convention lives in one # place. ae_spec <- tabular( cdisc_saf_aesocpt, titles = c( "Table 14.3.1", "Adverse Events by SOC and Preferred Term", "Safety Population" ), footnotes = "Subjects counted once per SOC and once per PT." ) |> cols( label = col_spec(label = "SOC / PT", indent = "indent_level"), soc = col_spec(visible = FALSE), row_type = col_spec(visible = FALSE), soc_n = col_spec(visible = FALSE), n_total = col_spec(visible = FALSE), placebo = col_spec(label = "Placebo\nN={n['placebo']}", align = "decimal"), drug_50 = col_spec(label = "Drug 50\nN={n['drug_50']}", align = "decimal"), drug_100 = col_spec(label = "Drug 100\nN={n['drug_100']}", align = "decimal"), Total = col_spec(label = "Total\nN={n['Total']}", align = "decimal") ) |> sort_rows(by = c("soc_n", "n_total"), descending = c(TRUE, TRUE)) ae_md <- tempfile(fileext = ".md") emit( ae_spec, ae_md, data_file = \(f) paste0(tools::file_path_sans_ext(f), "_qc.csv"), manifest = TRUE ) # ---- Example 3: Same spec, every text backend — one-loop fan-out ---- # # `emit()` dispatches by file extension, so the same spec can # render to every backend in one loop. Useful for visual diffs # across formats during development and for shipping a build # artefact set (RTF for submission, HTML for review, PDF for the # CSR appendix). eff_spec <- tabular(cdisc_eff_resp, titles = "Best Overall Response") |> cols( stat_label = col_spec(label = "Response"), row_type = col_spec(visible = FALSE), groupid = col_spec(visible = FALSE), group_label = col_spec(visible = FALSE), placebo = col_spec(label = "Placebo", align = "decimal"), drug_50 = col_spec(label = "Drug 50", align = "decimal"), drug_100 = col_spec(label = "Drug 100", align = "decimal") ) out_dir <- tempfile() dir.create(out_dir) for (ext in c(".html", ".rtf", ".tex", ".typ", ".docx", ".md")) { emit(eff_spec, file.path(out_dir, paste0("eff", ext))) } list.files(out_dir) #> [1] "eff.docx" "eff.html" "eff.md" "eff.rtf" "eff.tex" "eff.typ" # ---- Example 4: QC artefact via data_file alongside the render ---- # # `emit(data_file = ...)` writes the resolved post-engine wide # data frame alongside the rendered table. The sponsor's QC # programmer picks up the side-car .csv (or .rds) and validates # cell values without parsing the rendered RTF. rtf_out <- tempfile(fileext = ".rtf") data_out <- tempfile(fileext = ".csv") emit(eff_spec, rtf_out, data_file = data_out) file.exists(rtf_out) #> [1] TRUE file.exists(data_out) #> [1] TRUE # ---- Example 5: Render into a not-yet-existing output folder ---- # # `create_dir = TRUE` builds the destination directory tree on the # fly, so a submission-folder layout can be written in one pass # without a separate `dir.create()` step. nested <- file.path(tempfile(), "tables", "safety", "eff.md") emit(eff_spec, nested, create_dir = TRUE) file.exists(nested) #> [1] TRUE ``` # Wrap a plot or image in submission chrome Builds a figure display, the "F" in TFL. `figure()` takes a ggplot, a recorded base-R plot, a zero-argument drawing function, or a path to a PNG / JPG file, and surrounds it with the same canonical submission chrome as a table: up to four centred title lines, footnotes, and the per-page header / footer drawn from the active [`preset()`](https://vthanik.github.io/tabular/reference/preset.md). Pass a list to emit one figure per page in a single file. ## Usage ``` r figure( plot, titles = NULL, footnotes = NULL, width = NULL, height = NULL, halign = "center", valign = "middle", dpi = 300, meta = NULL ) ``` ## Arguments - plot: *The figure to display.* One of: a `ggplot` object; a recorded base plot from [`grDevices::recordPlot()`](https://rdrr.io/r/grDevices/recordplot.html); a zero-argument function that draws to the active device when called; a length-1 path to a `.png`, `.jpg`, or `.jpeg` file; or a `list` of any of these for a multi-page figure. **Tip:** a list may mix kinds freely — a ggplot, a recorded plot, and a PNG path can share one multi-page figure. - titles: *Title lines above the figure.* ` | NULL`. One element per line, up to four; same `{glue}` interpolation and [`md()`](https://vthanik.github.io/tabular/reference/md.md) / [`html()`](https://vthanik.github.io/tabular/reference/html.md) inline formatting as [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md). `NULL` draws no titles. - footnotes: *Footnote lines below the figure.* ` | NULL`. One element per line; same interpolation and inline formatting as `titles`. `NULL` draws no footnotes. - width: *Drawn image width in inches.* ` | NULL`. `NULL` fills the full printable width. - height: *Drawn image height in inches.* ` | NULL`. `NULL` fills the body box height (the printable height minus the title and footnote chrome). Set a smaller value to leave vertical slack for `valign` to place the image within. - halign: *Horizontal placement in the content box.* ``. One of: - `"left"` - `"center"` (default) - `"right"` - valign: *Vertical placement in the content box.* ``. One of: - `"top"` - `"middle"` (default) - `"bottom"` **Note:** continuous backends (HTML / Markdown) render the figure contained to the viewport with no fixed page height, so `valign` is a no-op there; the paged backends honour it exactly. - dpi: *Raster resolution for plot inputs.* ``. Resolution in dots per inch for PNG rasterisation. Ignored for file inputs (passed through unchanged) and for vector PDF targets. - meta: *Per-page token data frame.* ` | NULL`. Multi-page only: one row per plot, whose columns become `{token}` values in that page's `titles` / `footnotes`. Ignored (with a warning) for a single-plot figure. ## Value *A `figure_spec`.* Pass it to [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to write a file, or print it to preview the figure inline. ## Details **Two-axis placement.** By default the image FILLS the body content box — the full printable width by the box height (the printable height minus the title / footnote chrome). Pass an explicit `width` / `height` smaller than the box and `halign` / `valign` place the image within the resulting slack, independently — horizontally (`left` / `center` / `right`) and vertically (`top` / `middle` / `bottom`), both defaulting to centred. Paged backends (RTF / PDF / DOCX) honour `valign` exactly against the content-box height; with the box-filling default there is no vertical slack, so `valign` only bites once you set a shorter `height`. The continuous backends (HTML / Markdown) render the figure responsively, contained to the viewport, so `halign` still applies but `valign` is a no-op there. **Format-aware rasterisation.** Plot inputs render to vector PDF for `.pdf` / `.tex` targets and to PNG at `dpi` for every other backend; file inputs pass through byte-for-byte. No raster work happens until [`emit()`](https://vthanik.github.io/tabular/reference/emit.md). **Styling the chrome.** A figure carries the same chrome surfaces as a table, so [`style()`](https://vthanik.github.io/tabular/reference/style.md) and the [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) cosmetic knobs reach its titles, footnotes, and page header / footer — e.g. `style(fig, font_size = 14, .at = cells_title())` or `preset(fig, colors = list(footnotes = c(text = "grey40")))`. A figure has no body, column headers, or subgroup banner, so styling those surfaces is an error. Inter-section spacing follows the preset `spacing` knob (`title`, `footnote`), exactly like a table. ## See also **Terminal verb:** [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) (write the figure to a file). **Shared chrome:** [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) / [`set_preset()`](https://vthanik.github.io/tabular/reference/set_preset.md) (page geometry, fonts, header / footer), [`style()`](https://vthanik.github.io/tabular/reference/style.md) (per-figure title / footnote / page-chrome styling), [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) (the table sibling). **Class predicate:** [`is_figure_spec()`](https://vthanik.github.io/tabular/reference/tabular_predicates.md). ## Examples ``` r # ---- Example 1: a single base-R figure with submission chrome ---- # # A zero-argument drawing function is the simplest portable input: it # draws to whatever device the backend opens. Here, subjects enrolled # per treatment arm from the bundled BigN frame, wrapped in the # canonical title block and a population footnote. arms <- cdisc_saf_n[cdisc_saf_n$arm_short != "Total", ] draw_enrollment <- function() { barplot( arms$n, names.arg = arms$arm_short, ylab = "Subjects enrolled", col = "grey70" ) } fig <- figure( draw_enrollment, titles = c( "Figure 14.1.1", "Subjects Enrolled by Treatment Arm", "Safety Population" ), footnotes = "Total enrolled: N = 254." ) fig #tabular-cd0522e723 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-cd0522e723 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-cd0522e723 p { line-height: inherit; } #tabular-cd0522e723 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-cd0522e723 .tabular-caption { margin: 0; padding: 0; } #tabular-cd0522e723 .tabular-pad { margin: 0; line-height: 1; } #tabular-cd0522e723 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-cd0522e723 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-cd0522e723 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-cd0522e723 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-cd0522e723 .tabular-table th, #tabular-cd0522e723 .tabular-table td { padding: .18rem .6rem; } #tabular-cd0522e723 .tabular-table td { text-align: left; vertical-align: top; } #tabular-cd0522e723 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-cd0522e723 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-cd0522e723 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-cd0522e723 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-cd0522e723 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-cd0522e723 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-cd0522e723 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-cd0522e723 .tabular-table tbody tr td { border-top: none; } #tabular-cd0522e723 .tabular-band { text-align: center; } #tabular-cd0522e723 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-cd0522e723 .tabular-subgroup-label { font-weight: 600; } #tabular-cd0522e723 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-cd0522e723 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-cd0522e723 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-cd0522e723 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-cd0522e723 .text-left { text-align: left; } #tabular-cd0522e723 .text-center { text-align: center; } #tabular-cd0522e723 .text-right { text-align: right; } #tabular-cd0522e723 .tabular-table thead th.text-left { text-align: left; } #tabular-cd0522e723 .tabular-table thead th.text-center { text-align: center; } #tabular-cd0522e723 .tabular-table thead th.text-right { text-align: right; } #tabular-cd0522e723 .tabular-table td.text-left { text-align: left; } #tabular-cd0522e723 .tabular-table td.text-center { text-align: center; } #tabular-cd0522e723 .tabular-table td.text-right { text-align: right; } #tabular-cd0522e723 .valign-top { vertical-align: top; } #tabular-cd0522e723 .valign-middle { vertical-align: middle; } #tabular-cd0522e723 .valign-bottom { vertical-align: bottom; } #tabular-cd0522e723 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-cd0522e723 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-cd0522e723 .tabular-page-break-row { display: none; } #tabular-cd0522e723 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-cd0522e723 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-cd0522e723 .tabular-page-header, #tabular-cd0522e723 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-cd0522e723 .tabular-page-header { margin-bottom: 1rem; } #tabular-cd0522e723 .tabular-page-footer { margin-top: 1rem; } #tabular-cd0522e723 .tabular-page-header-left, #tabular-cd0522e723 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-cd0522e723 .tabular-page-header-center, #tabular-cd0522e723 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-cd0522e723 .tabular-page-header-right, #tabular-cd0522e723 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-cd0522e723 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-cd0522e723 .tabular-table tr { page-break-inside: avoid; } #tabular-cd0522e723 .tabular-page-header, #tabular-cd0522e723 .tabular-page-footer { display: none; } #tabular-cd0522e723 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-cd0522e723 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-cd0522e723 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Figure 14.1.1 Subjects Enrolled by Treatment Arm Safety Population   Total enrolled: N = 254. # ---- Example 2: one figure per page from a list ---- # # A list input emits one figure per page in a single file. Each arm # gets its own page; the kinds may mix (a ggplot, a recorded plot, or # a PNG path could share the list). Bottom-anchored here to show the # two-axis placement. draw_arm <- function(i) { force(i) function() { barplot(arms$n[i], names.arg = arms$arm_short[i], col = "grey70") } } per_arm <- figure( lapply(seq_len(nrow(arms)), draw_arm), titles = c("Figure 14.1.2", "Enrollment by Arm, One Page per Arm"), valign = "bottom" ) per_arm #tabular-e184540ca8 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-e184540ca8 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-e184540ca8 p { line-height: inherit; } #tabular-e184540ca8 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-e184540ca8 .tabular-caption { margin: 0; padding: 0; } #tabular-e184540ca8 .tabular-pad { margin: 0; line-height: 1; } #tabular-e184540ca8 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-e184540ca8 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-e184540ca8 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-e184540ca8 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-e184540ca8 .tabular-table th, #tabular-e184540ca8 .tabular-table td { padding: .18rem .6rem; } #tabular-e184540ca8 .tabular-table td { text-align: left; vertical-align: top; } #tabular-e184540ca8 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-e184540ca8 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-e184540ca8 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-e184540ca8 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-e184540ca8 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-e184540ca8 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-e184540ca8 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-e184540ca8 .tabular-table tbody tr td { border-top: none; } #tabular-e184540ca8 .tabular-band { text-align: center; } #tabular-e184540ca8 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-e184540ca8 .tabular-subgroup-label { font-weight: 600; } #tabular-e184540ca8 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-e184540ca8 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-e184540ca8 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-e184540ca8 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-e184540ca8 .text-left { text-align: left; } #tabular-e184540ca8 .text-center { text-align: center; } #tabular-e184540ca8 .text-right { text-align: right; } #tabular-e184540ca8 .tabular-table thead th.text-left { text-align: left; } #tabular-e184540ca8 .tabular-table thead th.text-center { text-align: center; } #tabular-e184540ca8 .tabular-table thead th.text-right { text-align: right; } #tabular-e184540ca8 .tabular-table td.text-left { text-align: left; } #tabular-e184540ca8 .tabular-table td.text-center { text-align: center; } #tabular-e184540ca8 .tabular-table td.text-right { text-align: right; } #tabular-e184540ca8 .valign-top { vertical-align: top; } #tabular-e184540ca8 .valign-middle { vertical-align: middle; } #tabular-e184540ca8 .valign-bottom { vertical-align: bottom; } #tabular-e184540ca8 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-e184540ca8 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-e184540ca8 .tabular-page-break-row { display: none; } #tabular-e184540ca8 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-e184540ca8 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-e184540ca8 .tabular-page-header, #tabular-e184540ca8 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-e184540ca8 .tabular-page-header { margin-bottom: 1rem; } #tabular-e184540ca8 .tabular-page-footer { margin-top: 1rem; } #tabular-e184540ca8 .tabular-page-header-left, #tabular-e184540ca8 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-e184540ca8 .tabular-page-header-center, #tabular-e184540ca8 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-e184540ca8 .tabular-page-header-right, #tabular-e184540ca8 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-e184540ca8 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-e184540ca8 .tabular-table tr { page-break-inside: avoid; } #tabular-e184540ca8 .tabular-page-header, #tabular-e184540ca8 .tabular-page-footer { display: none; } #tabular-e184540ca8 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-e184540ca8 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-e184540ca8 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Figure 14.1.2 Enrollment by Arm, One Page per Arm   ``` # Attach an auto-numbered footnote to a table location Anchor a footnote to a cell, column header, title line, or any other `cells_*()` location. The engine assigns the marker, places a superscript at every matching anchor, and emits the marked-footnote line at the foot of the table. Markers are assigned **once**, in reading order, deduped by `id`, and are byte-identical across every backend (RTF / LaTeX / PDF / HTML / DOCX) and every page, so the marker at the anchor can never desynchronise from its note. ## Usage ``` r footnote(.spec, text, .at = cells_body(), id = NULL, symbol = NULL) ``` ## Arguments - .spec: *The `tabular_spec` to annotate.* `: required`. - text: *The footnote text.* ` | md() | html()`. Wrap in [`md()`](https://vthanik.github.io/tabular/reference/md.md) / [`html()`](https://vthanik.github.io/tabular/reference/html.md) for inline markup; plain strings are shown verbatim. A plain string supports glue-style `{expr}` interpolation, evaluated as R code in the calling environment at build time (double a brace for a literal one); an [`md()`](https://vthanik.github.io/tabular/reference/md.md) / [`html()`](https://vthanik.github.io/tabular/reference/html.md) value is passed through without interpolation. - .at: *Where the marker is placed.* `: default [`cells_body()`]`. Any `cells_*()` location: a body-cell predicate (`cells_body(where = ...)`), a column header ([`cells_headers()`](https://vthanik.github.io/tabular/reference/cells.md)), a title line ([`cells_title()`](https://vthanik.github.io/tabular/reference/cells.md)), and so on. # data-driven body anchor: mark every high-frequency preferred term footnote(spec, "Includes events of any severity.", .at = cells_body(where = n_total >= 50, j = "label")) # column-header anchor: mark the analysis-population denominator footnote(spec, "Safety population.", .at = cells_headers(j = "Total")) **Note:** the styling argument is `.at`, never `at`. - id: *Stable identifier for sharing one marker across anchors.* ` | NULL`. Two `footnote()` calls with the same `id` share a single marker and a single note line. `NULL` (default) makes each call its own note. - symbol: *Pin an explicit marker glyph.* ` | NULL`. Overrides the auto-allocated marker for this note (e.g. `"*"`). A pinned symbol is reserved and skipped by the auto-allocator, so it never collides. `NULL` (default) auto-allocates from the preset scheme. ## Value *A `tabular_spec`.* Pipe it onward to more verbs or to [`emit()`](https://vthanik.github.io/tabular/reference/emit.md). ## Details **Engine-assigned, never hand-typed.** Unlike a literal `^a^` typed into both a cell and the `footnotes` argument, a `footnote()` marker is allocated by the resolve engine after decimal alignment, so it never disturbs column alignment and never drifts out of sync. The scheme (`letters` / `numbers` / `symbols`) and the block-line format come from the active preset (`footnote_markers`, `footnote_label`). **Dedup by id.** Give two anchors the same `id` to share one marker and one note line. Without an `id`, each `footnote()` call is its own note. **Coexists with `footnotes`.** Manual `footnotes` lines render first; the auto-numbered block follows. The two systems do not cross-dedup, so do not mix a hand-typed marker with an engine one for the same note. ## See also **Manual footnote lines:** the `footnotes` argument to [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md). **Location helpers:** [`cells_body()`](https://vthanik.github.io/tabular/reference/cells.md), [`cells_headers()`](https://vthanik.github.io/tabular/reference/cells.md), [`cells_title()`](https://vthanik.github.io/tabular/reference/cells.md). **Inline markup:** [`md()`](https://vthanik.github.io/tabular/reference/md.md), [`html()`](https://vthanik.github.io/tabular/reference/html.md). ## Examples ``` r # ---- Example 1: a denominator note on a column header ---- # # AE-by-SOC/PT table whose Total column header carries the analysis- # population note. The engine drops a superscript "a" on the header # and prints "a " beneath the table. n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) tabular(cdisc_saf_aesocpt) |> cols( label = col_spec(label = "SOC / PT", indent = "indent_level"), soc = col_spec(visible = FALSE), row_type = col_spec(visible = FALSE), soc_n = col_spec(visible = FALSE), n_total = col_spec(visible = FALSE), placebo = col_spec(label = "Placebo\nN={n['placebo']}"), drug_50 = col_spec(label = "Drug 50\nN={n['drug_50']}"), drug_100 = col_spec(label = "Drug 100\nN={n['drug_100']}"), Total = col_spec(label = "Total\nN={n['Total']}") ) |> footnote( "Safety population: all randomised subjects who took study drug.", .at = cells_headers(j = "Total") ) #tabular-755de0cc12 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-755de0cc12 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-755de0cc12 p { line-height: inherit; } #tabular-755de0cc12 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-755de0cc12 .tabular-caption { margin: 0; padding: 0; } #tabular-755de0cc12 .tabular-pad { margin: 0; line-height: 1; } #tabular-755de0cc12 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-755de0cc12 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-755de0cc12 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-755de0cc12 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-755de0cc12 .tabular-table th, #tabular-755de0cc12 .tabular-table td { padding: .18rem .6rem; } #tabular-755de0cc12 .tabular-table td { text-align: left; vertical-align: top; } #tabular-755de0cc12 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-755de0cc12 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-755de0cc12 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-755de0cc12 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-755de0cc12 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-755de0cc12 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-755de0cc12 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-755de0cc12 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-755de0cc12 .tabular-table tbody tr td { border-top: none; } #tabular-755de0cc12 .tabular-band { text-align: center; } #tabular-755de0cc12 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-755de0cc12 .tabular-subgroup-label { font-weight: 600; } #tabular-755de0cc12 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-755de0cc12 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-755de0cc12 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-755de0cc12 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-755de0cc12 .text-left { text-align: left; } #tabular-755de0cc12 .text-center { text-align: center; } #tabular-755de0cc12 .text-right { text-align: right; } #tabular-755de0cc12 .tabular-table thead th.text-left { text-align: left; } #tabular-755de0cc12 .tabular-table thead th.text-center { text-align: center; } #tabular-755de0cc12 .tabular-table thead th.text-right { text-align: right; } #tabular-755de0cc12 .tabular-table td.text-left { text-align: left; } #tabular-755de0cc12 .tabular-table td.text-center { text-align: center; } #tabular-755de0cc12 .tabular-table td.text-right { text-align: right; } #tabular-755de0cc12 .valign-top { vertical-align: top; } #tabular-755de0cc12 .valign-middle { vertical-align: middle; } #tabular-755de0cc12 .valign-bottom { vertical-align: bottom; } #tabular-755de0cc12 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-755de0cc12 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-755de0cc12 .tabular-page-break-row { display: none; } #tabular-755de0cc12 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-755de0cc12 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-755de0cc12 .tabular-page-header, #tabular-755de0cc12 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-755de0cc12 .tabular-page-header { margin-bottom: 1rem; } #tabular-755de0cc12 .tabular-page-footer { margin-top: 1rem; } #tabular-755de0cc12 .tabular-page-header-left, #tabular-755de0cc12 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-755de0cc12 .tabular-page-header-center, #tabular-755de0cc12 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-755de0cc12 .tabular-page-header-right, #tabular-755de0cc12 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-755de0cc12 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-755de0cc12 .tabular-table tr { page-break-inside: avoid; } #tabular-755de0cc12 .tabular-page-header, #tabular-755de0cc12 .tabular-page-footer { display: none; } #tabular-755de0cc12 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-755de0cc12 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-755de0cc12 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } } SOC / PT ``` # Get the active session-default preset Return the `preset_spec` last attached via [`set_preset()`](https://vthanik.github.io/tabular/reference/set_preset.md), or `NULL` when no session default has been set. The cascade resolver calls this internally; users call it for diagnostics ("what is my session inheriting?") or to copy the active default into a per-spec override via [`preset()`](https://vthanik.github.io/tabular/reference/preset.md). ## Usage ``` r get_preset() ``` ## Value *A `preset_spec`*, or `NULL` when no session default is active. ## See also **Session-scope setter:** [`set_preset()`](https://vthanik.github.io/tabular/reference/set_preset.md). **Per-spec partner:** [`preset()`](https://vthanik.github.io/tabular/reference/preset.md). **Entry / terminal verbs:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md), [`emit()`](https://vthanik.github.io/tabular/reference/emit.md), [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md). ## Examples ``` r # ---- Example 1: Inspect after setting a session default ---- # # `get_preset()` returns NULL before any session default has been # attached, then returns the `preset_spec` after `set_preset()`. get_preset() # NULL #> NULL set_preset(font_size = 8, orientation = "landscape") active <- get_preset() is_preset_spec(active) # TRUE #> [1] TRUE active@font_size # 8 #> [1] 8 active@orientation # "landscape" #> [1] "landscape" # ---- Example 2: Copy the session default into a per-spec override ---- # # Read the session preset, tweak one knob for a single table, and # attach as a per-spec override without disturbing the session. set_preset(font_size = 9, paper_size = "letter") # Read-tweak-attach without mutating the session default. base_knobs <- get_preset() tabular(cdisc_saf_n) |> preset( font_size = base_knobs@font_size, paper_size = base_knobs@paper_size, orientation = "landscape" ) #tabular-01893db7f4 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 9pt; line-height: 1.3; } #tabular-01893db7f4 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-01893db7f4 p { line-height: inherit; } #tabular-01893db7f4 .tabular-title { font-size: 9pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-01893db7f4 .tabular-caption { margin: 0; padding: 0; } #tabular-01893db7f4 .tabular-pad { margin: 0; line-height: 1; } #tabular-01893db7f4 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-01893db7f4 .tabular-table { border-collapse: collapse; font-size: 9pt; margin: 0 auto; } #tabular-01893db7f4 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-01893db7f4 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-01893db7f4 .tabular-table th, #tabular-01893db7f4 .tabular-table td { padding: .18rem .6rem; } #tabular-01893db7f4 .tabular-table td { text-align: left; vertical-align: top; } #tabular-01893db7f4 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-01893db7f4 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-01893db7f4 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-01893db7f4 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-01893db7f4 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-01893db7f4 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-01893db7f4 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-01893db7f4 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-01893db7f4 .tabular-table tbody tr td { border-top: none; } #tabular-01893db7f4 .tabular-band { text-align: center; } #tabular-01893db7f4 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-01893db7f4 .tabular-subgroup-label { font-weight: 600; } #tabular-01893db7f4 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-01893db7f4 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-01893db7f4 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-01893db7f4 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-01893db7f4 .text-left { text-align: left; } #tabular-01893db7f4 .text-center { text-align: center; } #tabular-01893db7f4 .text-right { text-align: right; } #tabular-01893db7f4 .tabular-table thead th.text-left { text-align: left; } #tabular-01893db7f4 .tabular-table thead th.text-center { text-align: center; } #tabular-01893db7f4 .tabular-table thead th.text-right { text-align: right; } #tabular-01893db7f4 .tabular-table td.text-left { text-align: left; } #tabular-01893db7f4 .tabular-table td.text-center { text-align: center; } #tabular-01893db7f4 .tabular-table td.text-right { text-align: right; } #tabular-01893db7f4 .valign-top { vertical-align: top; } #tabular-01893db7f4 .valign-middle { vertical-align: middle; } #tabular-01893db7f4 .valign-bottom { vertical-align: bottom; } #tabular-01893db7f4 .tabular-footnote { font-size: 9pt; color: #495057; margin: .25rem 0; } #tabular-01893db7f4 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-01893db7f4 .tabular-page-break-row { display: none; } #tabular-01893db7f4 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-01893db7f4 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-01893db7f4 .tabular-page-header, #tabular-01893db7f4 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 8pt; color: var(--tabular-chrome-color); } #tabular-01893db7f4 .tabular-page-header { margin-bottom: 1rem; } #tabular-01893db7f4 .tabular-page-footer { margin-top: 1rem; } #tabular-01893db7f4 .tabular-page-header-left, #tabular-01893db7f4 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-01893db7f4 .tabular-page-header-center, #tabular-01893db7f4 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-01893db7f4 .tabular-page-header-right, #tabular-01893db7f4 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-01893db7f4 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-01893db7f4 .tabular-table tr { page-break-inside: avoid; } #tabular-01893db7f4 .tabular-page-header, #tabular-01893db7f4 .tabular-page-footer { display: none; } #tabular-01893db7f4 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-01893db7f4 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-01893db7f4 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } } arm ``` # Declare the row-grouping structure of the table `group_rows()` names the **structural** columns whose runs of identical values define the table's row hierarchy, ordered outer to inner. List only the keys that drive the structure — the section headers and any hidden break keys; the visible row-label column (e.g. the statistic stub) stays an ordinary [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) column and is indented automatically. It is the row-structure counterpart of [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md): one declaration per table, replaced wholesale on a repeat call. ## Usage ``` r group_rows(.spec, by, display = "section", skip = TRUE) ``` ## Arguments - .spec: *The `tabular_spec` to attach the grouping plan to.* `: required`. - by: *Structural grouping key columns, ordered outer to inner.* `: required`. Names at least one column of `data`; duplicates are rejected. List only the section-header and break-only keys, not the visible label column. **Interaction:** A [`subgroup()`](https://vthanik.github.io/tabular/reference/subgroup.md)`(by = )` partition column may also be a grouping key; within each partition the key is constant and auto-hidden, so the combination composes. - display: *How the keys' values render in the body.* `: default "section"`. One value, applied to every key: - `"section"` (default) — each unique value emits a section header row spanning the visible columns; the key column is hidden from the body. The canonical submission shape. - `"collapse"` — the key column stays visible; repeated values are suppressed so only the first row of each run shows the label. The classic listing shape. - `"repeat"` — the key column stays visible and every row repeats the value. The export / QC shape, where every row must be self-describing. **Tip:** for a hidden break-only key, set `col_spec(visible = FALSE)` on it rather than a display mode. - skip: *Which keys get a blank spacer row between their groups.* `: default TRUE`. A logical flag or an explicit character set (the `readr::read_csv(col_names = )` pattern): - `TRUE` (default) — derive: a `"section"` key or a break-only (`visible = FALSE`) key breaks with a blank line; a visible `"collapse"` / `"repeat"` key runs continuous. - `FALSE` — no spacer rows anywhere. - `` — exactly these `by` keys break, e.g. `skip = "param"` (blank line between params, none between visits). Every name must be in `by`; `character(0)` is equivalent to `FALSE`. ## Value *``.* A new spec with `@row_groups` replaced; pipe into the remaining build verbs or [`emit()`](https://vthanik.github.io/tabular/reference/emit.md). ## Details **One plan per table.** A second `group_rows()` call replaces the first (the [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md) contract); levels never accumulate across calls. **Structural keys only.** Nesting is just listing the header keys: `by = c("param", "visit")` renders `param` as the outer section header and `visit` as the indented sub-header, and the first visible column beneath (the label stub) is auto-indented one level per header. You do not put the label column in `by`. **Break-only keys use `visible = FALSE`.** A key you mark `col_spec(visible = FALSE)` renders nothing and contributes only group transitions — the blank spacer between blocks (`skip`) and the decimal-alignment reset — exactly what a hidden sort/break key needs. There is no separate display mode for it. ## See also **Column display:** [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) / [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) for labels, alignment, and visibility of the key columns. **Row order:** [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md) — sort so each key's runs are contiguous before grouping. **Pagination:** [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md) — the grouping keys form the default panel stub; `keep_together` protects runs across page breaks independently of grouping. ## Examples ``` r # ---- Example 1: Demographics with section headers and a stat column ---- # # The canonical demographics shape: `variable` is the one structural # key. The defaults do all the work -- `display = "section"` renders # one section header row per parameter (Age, Sex, ...) and hides the # key column; `skip = TRUE` derives a blank spacer between sections. # `stat_label` is NOT a grouping key -- it stays an ordinary column # and is auto-indented one level under each section header. n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) tabular( cdisc_saf_demo, titles = c("Table 14.1.1", "Demographics", "Safety Population") ) |> cols( variable = "Parameter", stat_label = "Statistic", placebo = "Placebo\nN={n['placebo']}", drug_50 = "Drug 50\nN={n['drug_50']}", drug_100 = "Drug 100\nN={n['drug_100']}", Total = "Total\nN={n['Total']}" ) |> cols_apply( c("placebo", "drug_50", "drug_100", "Total"), col_spec(align = "decimal") ) |> group_rows(by = "variable") #tabular-70f56d538c { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-70f56d538c .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-70f56d538c p { line-height: inherit; } #tabular-70f56d538c .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-70f56d538c .tabular-caption { margin: 0; padding: 0; } #tabular-70f56d538c .tabular-pad { margin: 0; line-height: 1; } #tabular-70f56d538c .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-70f56d538c .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-70f56d538c .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-70f56d538c .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-70f56d538c .tabular-table th, #tabular-70f56d538c .tabular-table td { padding: .18rem .6rem; } #tabular-70f56d538c .tabular-table td { text-align: left; vertical-align: top; } #tabular-70f56d538c .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-70f56d538c .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-70f56d538c .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-70f56d538c .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-70f56d538c .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-70f56d538c .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-70f56d538c .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-70f56d538c .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-70f56d538c .tabular-table tbody tr td { border-top: none; } #tabular-70f56d538c .tabular-band { text-align: center; } #tabular-70f56d538c .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-70f56d538c .tabular-subgroup-label { font-weight: 600; } #tabular-70f56d538c .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-70f56d538c .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-70f56d538c .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-70f56d538c .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-70f56d538c .text-left { text-align: left; } #tabular-70f56d538c .text-center { text-align: center; } #tabular-70f56d538c .text-right { text-align: right; } #tabular-70f56d538c .tabular-table thead th.text-left { text-align: left; } #tabular-70f56d538c .tabular-table thead th.text-center { text-align: center; } #tabular-70f56d538c .tabular-table thead th.text-right { text-align: right; } #tabular-70f56d538c .tabular-table td.text-left { text-align: left; } #tabular-70f56d538c .tabular-table td.text-center { text-align: center; } #tabular-70f56d538c .tabular-table td.text-right { text-align: right; } #tabular-70f56d538c .valign-top { vertical-align: top; } #tabular-70f56d538c .valign-middle { vertical-align: middle; } #tabular-70f56d538c .valign-bottom { vertical-align: bottom; } #tabular-70f56d538c .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-70f56d538c .tabular-empty { font-style: italic; color: #6c757d; } #tabular-70f56d538c .tabular-page-break-row { display: none; } #tabular-70f56d538c { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-70f56d538c .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-70f56d538c .tabular-page-header, #tabular-70f56d538c .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-70f56d538c .tabular-page-header { margin-bottom: 1rem; } #tabular-70f56d538c .tabular-page-footer { margin-top: 1rem; } #tabular-70f56d538c .tabular-page-header-left, #tabular-70f56d538c .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-70f56d538c .tabular-page-header-center, #tabular-70f56d538c .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-70f56d538c .tabular-page-header-right, #tabular-70f56d538c .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-70f56d538c .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-70f56d538c .tabular-table tr { page-break-inside: avoid; } #tabular-70f56d538c .tabular-page-header, #tabular-70f56d538c .tabular-page-footer { display: none; } #tabular-70f56d538c .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-70f56d538c .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-70f56d538c .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.1.1 Demographics Safety Population   Statistic ``` # Attach multi-level column headers Build the column-header band(s) above the rendered table. Each named argument is one band; the value is either a character vector of column names (leaf band) or a named list of further bands (inner band). Nesting depth is arbitrary — the engine renders one band row per depth level, with each cell spanning the columns of its leaves. ## Usage ``` r headers(.spec, ...) ``` ## Arguments - .spec: *The `tabular_spec` to attach the header tree to.* `: required`. Dot-prefixed so R's partial argument matching cannot accidentally bind a short user-supplied band label in `...` to the spec slot. - ...: *Named header bands.* Each name is the band label (must be non-blank); each value is either: - a **character vector** of data-column names — leaf band, or - a **named list** whose entries follow the same recursive pattern — inner band. Inside a nested-list value, an unnamed character-vector entry declares a passthrough leaf (see the Passthrough section below). **Restriction:** Every column referenced must exist in `.spec@data`. A column may appear under at most one leaf. Names must be unique within one `headers()` call. **Tip:** Pass `headers()` with no arguments to clear the tree. **Interaction:** Band labels support glue-style `{expr}` interpolation, evaluated as R code in the calling environment at build time (double a brace for a literal one). The non-blank and uniqueness checks apply to the raw author-typed name, before interpolation. ## Value *The updated `tabular_spec`.* Continue chaining with [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md). ## Details **Replace, not stack.** A second `headers()` call REPLACES the prior tree — header structure is a single spec, not a stackable list. Call with no arguments to clear the tree. **Strict label rule.** Every declared band label must carry visible text — empty strings, NA, and whitespace-only labels are rejected at every nesting level. This is stricter than [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md), which DOES accept empty labels (a row-label column with no header text is a legitimate clinical case). A silently-blank band would be a layout artefact. **Uncovered columns render naked.** Columns not referenced under any band render with their `col_spec.label` only — no extra band row above them. This is the canonical pattern for row-label columns (`variable`, `soc`, `stat_label`). **Multi-line band labels.** Embed `\n` in a band label for a two-line band cell (arm name on row 1, BigN on row 2). **Spanner underline trim (backend limitation).** Each spanner's underline is trimmed at both ends, booktabs `\cmidrule(lr)` style, so adjacent spanners are separated by a visible gap rather than merging into one continuous line. PDF / LaTeX (tabularray `leftpos`/`rightpos`) and HTML (an inset rule) render the trim natively. RTF and DOCX cannot inset a cell border horizontally, so there the spanner underline spans the full band width (adjacent spanner rules abut). This is a known, documented limitation of the OOXML / RTF cell-border model, not a bug. ## Passthrough leaves inside a nested band Inside a nested-list value, a child entry may be **unnamed** — the entry is then a character vector of column names that sit directly under the parent with no intermediate band at this depth. Use this when one column under a band has no sub-grouping while its siblings do. The strict-label rule still applies to every declared band; an unnamed passthrough is NOT a band with a missing label — it is "no band declared at this depth for this column." ## See also **Companion verb:** [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) / [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) sets per-column labels — the leaf-row header text that sits below the band rows this verb builds. **Sibling build verbs:** [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md), [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md), [`preset()`](https://vthanik.github.io/tabular/reference/preset.md). **Entry / terminal verbs:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md), [`emit()`](https://vthanik.github.io/tabular/reference/emit.md), [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md). **Inline label formatting:** [`md()`](https://vthanik.github.io/tabular/reference/md.md), [`html()`](https://vthanik.github.io/tabular/reference/html.md). ## Examples ``` r # ---- Example 1: Single "Treatment Group" band over four arms ---- # # AE-by-SOC/PT table with one flat band labelled "Treatment Group" # spanning the four arm columns and the Total column. The # row-label column (`soc`) sits to the left of the band with no # header covering it — the canonical clinical layout. n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) tabular( cdisc_saf_aesocpt, titles = c( "Table 14.3.1", "Adverse Events by System Organ Class and Preferred Term", "Safety Population" ), footnotes = "Subjects are counted once per SOC and once per PT." ) |> cols( label = col_spec(label = "SOC / PT", indent = "indent_level"), soc = col_spec(visible = FALSE), row_type = col_spec(visible = FALSE), soc_n = col_spec(visible = FALSE), n_total = col_spec(visible = FALSE), placebo = col_spec(label = "Placebo\nN={n['placebo']}"), drug_50 = col_spec(label = "Drug 50\nN={n['drug_50']}"), drug_100 = col_spec(label = "Drug 100\nN={n['drug_100']}"), Total = col_spec(label = "Total\nN={n['Total']}") ) |> headers( "Treatment Group" = c("placebo", "drug_50", "drug_100", "Total") ) |> sort_rows(by = c("soc_n", "n_total"), descending = c(TRUE, TRUE)) #tabular-b46407910e { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-b46407910e .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-b46407910e p { line-height: inherit; } #tabular-b46407910e .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-b46407910e .tabular-caption { margin: 0; padding: 0; } #tabular-b46407910e .tabular-pad { margin: 0; line-height: 1; } #tabular-b46407910e .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-b46407910e .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-b46407910e .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-b46407910e .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-b46407910e .tabular-table th, #tabular-b46407910e .tabular-table td { padding: .18rem .6rem; } #tabular-b46407910e .tabular-table td { text-align: left; vertical-align: top; } #tabular-b46407910e .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-b46407910e .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-b46407910e .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-b46407910e .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-b46407910e .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-b46407910e .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-b46407910e .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-b46407910e .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-b46407910e .tabular-table tbody tr td { border-top: none; } #tabular-b46407910e .tabular-band { text-align: center; } #tabular-b46407910e .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-b46407910e .tabular-subgroup-label { font-weight: 600; } #tabular-b46407910e .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-b46407910e .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-b46407910e .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-b46407910e .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-b46407910e .text-left { text-align: left; } #tabular-b46407910e .text-center { text-align: center; } #tabular-b46407910e .text-right { text-align: right; } #tabular-b46407910e .tabular-table thead th.text-left { text-align: left; } #tabular-b46407910e .tabular-table thead th.text-center { text-align: center; } #tabular-b46407910e .tabular-table thead th.text-right { text-align: right; } #tabular-b46407910e .tabular-table td.text-left { text-align: left; } #tabular-b46407910e .tabular-table td.text-center { text-align: center; } #tabular-b46407910e .tabular-table td.text-right { text-align: right; } #tabular-b46407910e .valign-top { vertical-align: top; } #tabular-b46407910e .valign-middle { vertical-align: middle; } #tabular-b46407910e .valign-bottom { vertical-align: bottom; } #tabular-b46407910e .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-b46407910e .tabular-empty { font-style: italic; color: #6c757d; } #tabular-b46407910e .tabular-page-break-row { display: none; } #tabular-b46407910e { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-b46407910e .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-b46407910e .tabular-page-header, #tabular-b46407910e .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-b46407910e .tabular-page-header { margin-bottom: 1rem; } #tabular-b46407910e .tabular-page-footer { margin-top: 1rem; } #tabular-b46407910e .tabular-page-header-left, #tabular-b46407910e .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-b46407910e .tabular-page-header-center, #tabular-b46407910e .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-b46407910e .tabular-page-header-right, #tabular-b46407910e .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-b46407910e .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-b46407910e .tabular-table tr { page-break-inside: avoid; } #tabular-b46407910e .tabular-page-header, #tabular-b46407910e .tabular-page-footer { display: none; } #tabular-b46407910e .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-b46407910e .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-b46407910e .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.3.1 Adverse Events by System Organ Class and Preferred Term Safety Population   ``` # Mark a string as HTML for inline formatting Wrap a length-1 character vector so [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md), [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md), and similar string slots interpret it as a constrained HTML subset at render time. Use when CommonMark cannot express the formatting (custom CSS via ``, raw destination codes via ``). ## Usage ``` r html(text) ``` ## Arguments - text: *The HTML fragment.* `: required`. Length-1 character vector. `NA` is rejected. ## Value *A length-1 character vector classed `c("from_html", "character")`.* Pass it directly into any string-bearing slot ([`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) titles / footnotes, [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) label, [`style()`](https://vthanik.github.io/tabular/reference/style.md) pretext / posttext); the resolve engine calls `.parse_inline()` internally and backends walk the resulting `inline_ast`. ## Details **Recognised tag whitelist.** `

`, `
` / `
`, ``, ``, ``, ``, ``, ``, ``, ``, ``. Tags outside this set drop their wrapper and keep their text content (no arbitrary HTML attack surface). **Span styles.** `x` parses the style attribute into a named character vector (`c(color = "red", "font-weight" = "bold")`). Backends translate CSS keys to destination-specific markup (RTF `\cf`, LaTeX `\textcolor`, DOCX ``, HTML inline style). **Backend-specific raw codes.** A span with `data-rtf`, `data-latex`, `data-html`, or `data-docx` attributes carries per-backend raw markup. The matching backend emits its data value verbatim and ignores the others; non-matching backends render the span's text content as plain. Use for cases the AST cannot express portably. ## See also **Sibling helper:** [`md()`](https://vthanik.github.io/tabular/reference/md.md) — Markdown wrapper for the common case. **String slots that consume the wrapper:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) (`titles`, `footnotes`), [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) (`label`), [`style()`](https://vthanik.github.io/tabular/reference/style.md) (`pretext`, `posttext`). **Entry / terminal verbs:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md), [`emit()`](https://vthanik.github.io/tabular/reference/emit.md), [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md). ## Examples ``` r # ---- Example 1: Colour-styled span in a title ---- # # Demographics table title with the population subset shaded # red. The HTML wrapper carries an inline CSS style; backends # translate (RTF: \cf, LaTeX: \textcolor, HTML: inline style). n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) tabular( cdisc_saf_demo, titles = c( "Table 14.1.1", "Demographics", html(sprintf("Safety Pop (N=%d)", n["Total"])) ) ) #tabular-d9e90739e2 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-d9e90739e2 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-d9e90739e2 p { line-height: inherit; } #tabular-d9e90739e2 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-d9e90739e2 .tabular-caption { margin: 0; padding: 0; } #tabular-d9e90739e2 .tabular-pad { margin: 0; line-height: 1; } #tabular-d9e90739e2 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-d9e90739e2 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-d9e90739e2 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-d9e90739e2 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-d9e90739e2 .tabular-table th, #tabular-d9e90739e2 .tabular-table td { padding: .18rem .6rem; } #tabular-d9e90739e2 .tabular-table td { text-align: left; vertical-align: top; } #tabular-d9e90739e2 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-d9e90739e2 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-d9e90739e2 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-d9e90739e2 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-d9e90739e2 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-d9e90739e2 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-d9e90739e2 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-d9e90739e2 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-d9e90739e2 .tabular-table tbody tr td { border-top: none; } #tabular-d9e90739e2 .tabular-band { text-align: center; } #tabular-d9e90739e2 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-d9e90739e2 .tabular-subgroup-label { font-weight: 600; } #tabular-d9e90739e2 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-d9e90739e2 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-d9e90739e2 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-d9e90739e2 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-d9e90739e2 .text-left { text-align: left; } #tabular-d9e90739e2 .text-center { text-align: center; } #tabular-d9e90739e2 .text-right { text-align: right; } #tabular-d9e90739e2 .tabular-table thead th.text-left { text-align: left; } #tabular-d9e90739e2 .tabular-table thead th.text-center { text-align: center; } #tabular-d9e90739e2 .tabular-table thead th.text-right { text-align: right; } #tabular-d9e90739e2 .tabular-table td.text-left { text-align: left; } #tabular-d9e90739e2 .tabular-table td.text-center { text-align: center; } #tabular-d9e90739e2 .tabular-table td.text-right { text-align: right; } #tabular-d9e90739e2 .valign-top { vertical-align: top; } #tabular-d9e90739e2 .valign-middle { vertical-align: middle; } #tabular-d9e90739e2 .valign-bottom { vertical-align: bottom; } #tabular-d9e90739e2 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-d9e90739e2 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-d9e90739e2 .tabular-page-break-row { display: none; } #tabular-d9e90739e2 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-d9e90739e2 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-d9e90739e2 .tabular-page-header, #tabular-d9e90739e2 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-d9e90739e2 .tabular-page-header { margin-bottom: 1rem; } #tabular-d9e90739e2 .tabular-page-footer { margin-top: 1rem; } #tabular-d9e90739e2 .tabular-page-header-left, #tabular-d9e90739e2 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-d9e90739e2 .tabular-page-header-center, #tabular-d9e90739e2 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-d9e90739e2 .tabular-page-header-right, #tabular-d9e90739e2 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-d9e90739e2 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-d9e90739e2 .tabular-table tr { page-break-inside: avoid; } #tabular-d9e90739e2 .tabular-page-header, #tabular-d9e90739e2 .tabular-page-footer { display: none; } #tabular-d9e90739e2 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-d9e90739e2 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-d9e90739e2 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.1.1 Demographics Safety Pop (N=254)   variable ``` # Package index ## Entry verbs Wrap a pre-summarised wide data frame into a `tabular_spec`. - [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) : Start a tabular display - [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) : Convert a cards ARD to a wide display data.frame ## Figures Wrap a ggplot, base-R plot, drawing function, or image file into a `figure_spec`, rendered with the same submission chrome as a table. A list input emits one figure per page. - [`figure()`](https://vthanik.github.io/tabular/reference/figure.md) : Wrap a plot or image in submission chrome ## Spec building Configure per-column display, row grouping, header bands, sort order, and subgrouping. Each verb attaches one slot onto the spec and returns the updated spec for chaining. - [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) : Attach per-column specifications - [`cols_apply()`](https://vthanik.github.io/tabular/reference/cols_apply.md) : Apply one column spec to many columns - [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) : Per-column display specification - [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) : Declare the row-grouping structure of the table - [`headers()`](https://vthanik.github.io/tabular/reference/headers.md) : Attach multi-level column headers - [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md) : Sort the display rows - [`subgroup()`](https://vthanik.github.io/tabular/reference/subgroup.md) : Partition the report by a variable ## Styling A single [`style()`](https://vthanik.github.io/tabular/reference/style.md) verb, paired with one of the `cells_*()` location helpers, drives every visual rule — body cells, headers, footnotes, page chrome, table edges. Build a reusable house style with [`style_template()`](https://vthanik.github.io/tabular/reference/style_template.md) and attach it to [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) so every downstream table inherits the look. - [`style()`](https://vthanik.github.io/tabular/reference/style.md) : Attach a style layer to a `tabular_spec` or `style_template` - [`cells_body()`](https://vthanik.github.io/tabular/reference/cells.md) [`cells_headers()`](https://vthanik.github.io/tabular/reference/cells.md) [`cells_group_headers()`](https://vthanik.github.io/tabular/reference/cells.md) [`cells_title()`](https://vthanik.github.io/tabular/reference/cells.md) [`cells_subgroup_labels()`](https://vthanik.github.io/tabular/reference/cells.md) [`cells_footnotes()`](https://vthanik.github.io/tabular/reference/cells.md) [`cells_pagehead()`](https://vthanik.github.io/tabular/reference/cells.md) [`cells_pagefoot()`](https://vthanik.github.io/tabular/reference/cells.md) [`cells_table()`](https://vthanik.github.io/tabular/reference/cells.md) [`is_tabular_location()`](https://vthanik.github.io/tabular/reference/cells.md) : Cell-location constructors for [`style()`](https://vthanik.github.io/tabular/reference/style.md) - [`style_template()`](https://vthanik.github.io/tabular/reference/style_template.md) [`is_style_template()`](https://vthanik.github.io/tabular/reference/style_template.md) : Reusable style template (for house-style presets) - [`brdr()`](https://vthanik.github.io/tabular/reference/brdr.md) [`is_brdr()`](https://vthanik.github.io/tabular/reference/brdr.md) : Border-line specification ## Presets and theming Page geometry and cosmetic defaults. [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) overrides per spec in the pipe; [`set_preset()`](https://vthanik.github.io/tabular/reference/set_preset.md) sets a session default; [`preset_minimal()`](https://vthanik.github.io/tabular/reference/preset_minimal.md) applies a stripped-down look. - [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) : Override the render preset on a spec - [`set_preset()`](https://vthanik.github.io/tabular/reference/set_preset.md) : Set or clear the session default preset - [`get_preset()`](https://vthanik.github.io/tabular/reference/get_preset.md) : Get the active session-default preset - [`preset_minimal()`](https://vthanik.github.io/tabular/reference/preset_minimal.md) : Minimal theme: one header rule, normal weight throughout ## Inline markup Mark label and cell text as Markdown or HTML. - [`md()`](https://vthanik.github.io/tabular/reference/md.md) : Mark a string as Markdown for inline formatting - [`html()`](https://vthanik.github.io/tabular/reference/html.md) : Mark a string as HTML for inline formatting ## Footnotes Attach an auto-numbered footnote to any `cells_*()` location. The engine assigns the marker once, in reading order, deduped by id, and byte-identical across every backend and page. - [`footnote()`](https://vthanik.github.io/tabular/reference/footnote.md) : Attach an auto-numbered footnote to a table location ## Pagination Configure page splits, group-run protection, and horizontal panel layout for wide tables. Row budget per page is computed by the engine from the active preset and the spec’s chrome. - [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md) : Configure pagination ## Rendering and inspection Terminal verbs. [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) writes a file; [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md) resolves the spec without I/O; [`check_fonts()`](https://vthanik.github.io/tabular/reference/check_fonts.md), [`check_latex()`](https://vthanik.github.io/tabular/reference/check_latex.md), and [`check_typst()`](https://vthanik.github.io/tabular/reference/check_typst.md) audit font and PDF-toolchain availability; the print and `as.tags()` methods drive the live HTML preview. - [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) : Render a `tabular_spec` to a file - [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md) : Resolve a `tabular_spec` into a `tabular_grid` - [`check_fonts()`](https://vthanik.github.io/tabular/reference/check_fonts.md) : Check font availability across backends - [`check_latex()`](https://vthanik.github.io/tabular/reference/check_latex.md) : Check LaTeX-package availability for PDF output - [`check_typst()`](https://vthanik.github.io/tabular/reference/check_typst.md) : Check Typst availability for PDF output - [`print.tabular_spec`](https://vthanik.github.io/tabular/reference/print.tabular_spec.md) : Print a `tabular_spec` - [`as.tags(`*``*`)`](https://vthanik.github.io/tabular/reference/as.tags.tabular_spec.md) : Convert a `tabular_spec` to an `htmltools` `tagList` ## Predicates Class predicates for tabular’s S7 objects. - [`tabular-package`](https://vthanik.github.io/tabular/reference/tabular-package.md) : tabular: Render Tables, Listings, and Figures for Clinical Submissions - [`tabular_classes`](https://vthanik.github.io/tabular/reference/tabular_classes.md) [`.col_spec_class`](https://vthanik.github.io/tabular/reference/tabular_classes.md) [`header_node`](https://vthanik.github.io/tabular/reference/tabular_classes.md) [`sort_spec`](https://vthanik.github.io/tabular/reference/tabular_classes.md) [`row_group_spec`](https://vthanik.github.io/tabular/reference/tabular_classes.md) [`subgroup_spec`](https://vthanik.github.io/tabular/reference/tabular_classes.md) [`style_node`](https://vthanik.github.io/tabular/reference/tabular_classes.md) [`style_layer`](https://vthanik.github.io/tabular/reference/tabular_classes.md) [`style_spec`](https://vthanik.github.io/tabular/reference/tabular_classes.md) [`.repeat_content_values`](https://vthanik.github.io/tabular/reference/tabular_classes.md) [`preset_spec`](https://vthanik.github.io/tabular/reference/tabular_classes.md) [`tabular_spec`](https://vthanik.github.io/tabular/reference/tabular_classes.md) [`figure_spec`](https://vthanik.github.io/tabular/reference/tabular_classes.md) [`inline_ast`](https://vthanik.github.io/tabular/reference/tabular_classes.md) [`tabular_grid`](https://vthanik.github.io/tabular/reference/tabular_classes.md) : tabular S7 classes - [`is_tabular_spec()`](https://vthanik.github.io/tabular/reference/tabular_predicates.md) [`is_figure_spec()`](https://vthanik.github.io/tabular/reference/tabular_predicates.md) [`is_tabular_grid()`](https://vthanik.github.io/tabular/reference/tabular_predicates.md) [`is_col_spec()`](https://vthanik.github.io/tabular/reference/tabular_predicates.md) [`is_header_node()`](https://vthanik.github.io/tabular/reference/tabular_predicates.md) [`is_sort_spec()`](https://vthanik.github.io/tabular/reference/tabular_predicates.md) [`is_row_group_spec()`](https://vthanik.github.io/tabular/reference/tabular_predicates.md) [`is_style_node()`](https://vthanik.github.io/tabular/reference/tabular_predicates.md) [`is_style_layer()`](https://vthanik.github.io/tabular/reference/tabular_predicates.md) [`is_style_spec()`](https://vthanik.github.io/tabular/reference/tabular_predicates.md) [`is_pagination_spec()`](https://vthanik.github.io/tabular/reference/tabular_predicates.md) [`is_preset_spec()`](https://vthanik.github.io/tabular/reference/tabular_predicates.md) [`is_subgroup_spec()`](https://vthanik.github.io/tabular/reference/tabular_predicates.md) [`is_inline_ast()`](https://vthanik.github.io/tabular/reference/tabular_predicates.md) : Test for tabular S7 class instances ## Demo datasets Pre-summarised wide-format tables and their upstream `cards`-format counterparts. Power every `@examples` block, every vignette, and every smoke test. - [`cdisc_eff_estimates`](https://vthanik.github.io/tabular/reference/cdisc_eff_estimates.md) : Treatment-effect estimates by model - [`cdisc_eff_n`](https://vthanik.github.io/tabular/reference/cdisc_eff_n.md) : Efficacy-population BigN per arm - [`cdisc_eff_resp`](https://vthanik.github.io/tabular/reference/cdisc_eff_resp.md) : Best Overall Response and Response Rates - [`cdisc_saf_ae`](https://vthanik.github.io/tabular/reference/cdisc_saf_ae.md) : Overall adverse-event summary, Safety Population - [`cdisc_saf_aesocpt`](https://vthanik.github.io/tabular/reference/cdisc_saf_aesocpt.md) : Adverse events by System Organ Class and Preferred Term - [`cdisc_saf_aesocpt_ard`](https://vthanik.github.io/tabular/reference/cdisc_saf_aesocpt_ard.md) : Cards hierarchical ARD for AEs by SOC and PT - [`cdisc_saf_demo`](https://vthanik.github.io/tabular/reference/cdisc_saf_demo.md) : Demographics summary, Safety Population - [`cdisc_saf_demo_ard`](https://vthanik.github.io/tabular/reference/cdisc_saf_demo_ard.md) : Cards ARD for demographics (flat ARD companion) - [`cdisc_saf_n`](https://vthanik.github.io/tabular/reference/cdisc_saf_n.md) : Safety-population BigN per arm - [`cdisc_saf_subgroup`](https://vthanik.github.io/tabular/reference/cdisc_saf_subgroup.md) : Vital-signs subgroup summary by Sex, by Visit - [`cdisc_saf_vital`](https://vthanik.github.io/tabular/reference/cdisc_saf_vital.md) : Vital-signs summary # Mark a string as Markdown for inline formatting Wrap a length-1 character vector so [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md), [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md) pretext / posttext, and similar string slots interpret it as CommonMark Markdown at render time. Supports the GitHub-flavoured plus Pandoc-style superscript (`^sup^`) and subscript (`~sub~`) extensions; raw HTML inside Markdown passes through to the constrained tag set documented under [`html()`](https://vthanik.github.io/tabular/reference/html.md). ## Usage ``` r md(text) ``` ## Arguments - text: *The Markdown string.* `: required`. Length-1 character vector. `NA` is rejected; the empty string `""` renders as no content. ## Value *A length-1 character vector classed `c("from_markdown", "character")`.* Pass it directly into any string-bearing slot ([`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) titles / footnotes, [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) label, [`style()`](https://vthanik.github.io/tabular/reference/style.md) pretext / posttext); the resolve engine calls `.parse_inline()` internally and backends walk the resulting `inline_ast`. ## Details **Convention adopted from gt.** Marking strings with `md()` and [`html()`](https://vthanik.github.io/tabular/reference/html.md) mirrors the well-tested gt convention. Plain (unwrapped) strings render as plain text — a stray `**` will NOT silently bold the surrounding span. Wrap explicitly to opt in. **Recognised Markdown.** `**bold**`, `*italic*`, `` `code` ``, `[link text](url)`, hard line break (two trailing spaces + `\n` or `\\` + `\n`), Pandoc `^sup^` and `~sub~`. Single embedded `\n` (a "soft break" in CommonMark) renders as a space in HTML; tabular preserves it as a line break for clinical-table use where multi-line cells / titles are routine. **HTML pass-through.** Raw HTML in Markdown (e.g. `md("Drug A warning")`) is parsed as HTML using the same tag whitelist as [`html()`](https://vthanik.github.io/tabular/reference/html.md). Tags outside the whitelist drop their wrapper and keep their text content. **Composition with plain strings.** `md()` and [`html()`](https://vthanik.github.io/tabular/reference/html.md) wrap the input with an internal control-character prefix that survives [`c()`](https://rdrr.io/r/base/c.html) concatenation, so you can freely mix plain and marked strings in a single character vector: `c("Table 14.3.1", md("**Drug A**"), "third")`. Backends strip the marker before rendering; users never see it. ## See also **Sibling helper:** [`html()`](https://vthanik.github.io/tabular/reference/html.md) — same wrapper pattern for raw HTML when Markdown cannot express the formatting. **String slots that consume the wrapper:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) (`titles`, `footnotes`), [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) (`label`), [`style()`](https://vthanik.github.io/tabular/reference/style.md) (`pretext`, `posttext`). **Entry / terminal verbs:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md), [`emit()`](https://vthanik.github.io/tabular/reference/emit.md), [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md). ## Examples ``` r # ---- Example 1: Italic title qualifier with Pandoc footnote marker ---- # # AE-by-SOC/PT table. Title lines are bold by default, so the third # line italicises "Safety Population" via `md("*...*")` for a visible # contrast; the first footnote carries a Pandoc-style superscript # marker `^a^` that the backends render as a true superscript. n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) tabular( cdisc_saf_aesocpt, titles = c( "Table 14.3.1", "Adverse Events by System Organ Class and Preferred Term", md("*Safety Population*") ), footnotes = c( md("^a^ Subjects counted once per SOC and once per PT.") ) ) |> cols( label = col_spec(label = "SOC / PT", indent = "indent_level"), soc = col_spec(visible = FALSE), row_type = col_spec(visible = FALSE), soc_n = col_spec(visible = FALSE), n_total = col_spec(visible = FALSE), placebo = col_spec(label = "Placebo\nN={n['placebo']}", align = "decimal"), drug_50 = col_spec(label = "Drug 50\nN={n['drug_50']}", align = "decimal"), drug_100 = col_spec(label = "Drug 100\nN={n['drug_100']}", align = "decimal"), Total = col_spec(label = "Total\nN={n['Total']}", align = "decimal") ) #tabular-3a410ec737 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-3a410ec737 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-3a410ec737 p { line-height: inherit; } #tabular-3a410ec737 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-3a410ec737 .tabular-caption { margin: 0; padding: 0; } #tabular-3a410ec737 .tabular-pad { margin: 0; line-height: 1; } #tabular-3a410ec737 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-3a410ec737 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-3a410ec737 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-3a410ec737 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-3a410ec737 .tabular-table th, #tabular-3a410ec737 .tabular-table td { padding: .18rem .6rem; } #tabular-3a410ec737 .tabular-table td { text-align: left; vertical-align: top; } #tabular-3a410ec737 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-3a410ec737 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-3a410ec737 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-3a410ec737 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-3a410ec737 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-3a410ec737 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-3a410ec737 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-3a410ec737 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-3a410ec737 .tabular-table tbody tr td { border-top: none; } #tabular-3a410ec737 .tabular-band { text-align: center; } #tabular-3a410ec737 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-3a410ec737 .tabular-subgroup-label { font-weight: 600; } #tabular-3a410ec737 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-3a410ec737 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-3a410ec737 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-3a410ec737 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-3a410ec737 .text-left { text-align: left; } #tabular-3a410ec737 .text-center { text-align: center; } #tabular-3a410ec737 .text-right { text-align: right; } #tabular-3a410ec737 .tabular-table thead th.text-left { text-align: left; } #tabular-3a410ec737 .tabular-table thead th.text-center { text-align: center; } #tabular-3a410ec737 .tabular-table thead th.text-right { text-align: right; } #tabular-3a410ec737 .tabular-table td.text-left { text-align: left; } #tabular-3a410ec737 .tabular-table td.text-center { text-align: center; } #tabular-3a410ec737 .tabular-table td.text-right { text-align: right; } #tabular-3a410ec737 .valign-top { vertical-align: top; } #tabular-3a410ec737 .valign-middle { vertical-align: middle; } #tabular-3a410ec737 .valign-bottom { vertical-align: bottom; } #tabular-3a410ec737 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-3a410ec737 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-3a410ec737 .tabular-page-break-row { display: none; } #tabular-3a410ec737 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-3a410ec737 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-3a410ec737 .tabular-page-header, #tabular-3a410ec737 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-3a410ec737 .tabular-page-header { margin-bottom: 1rem; } #tabular-3a410ec737 .tabular-page-footer { margin-top: 1rem; } #tabular-3a410ec737 .tabular-page-header-left, #tabular-3a410ec737 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-3a410ec737 .tabular-page-header-center, #tabular-3a410ec737 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-3a410ec737 .tabular-page-header-right, #tabular-3a410ec737 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-3a410ec737 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-3a410ec737 .tabular-table tr { page-break-inside: avoid; } #tabular-3a410ec737 .tabular-page-header, #tabular-3a410ec737 .tabular-page-footer { display: none; } #tabular-3a410ec737 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-3a410ec737 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-3a410ec737 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.3.1 Adverse Events by System Organ Class and Preferred Term Safety Population   SOC / PT ``` # Configure pagination Attach a `pagination_spec` to a `tabular_spec`. The engine uses the spec at render time to decide where page breaks fall, how wide tables split into horizontal panels, and what continuation marker (if any) prints on continued pages. The row budget per page is computed by the engine from the active preset (paper, orientation, margins, font size) and the chrome rows consumed by titles, column headers, and footnotes — you do not set rows-per-page directly. ## Usage ``` r paginate( .spec, keep_together = character(), panels = 1, repeat_cols = NULL, orphan_floor = 3, widow_floor = 2, repeat_content = c("titles", "headers", "footnotes"), continuation = NULL ) ``` ## Arguments - .spec: *The `tabular_spec` to attach pagination to.* `: required`. - keep_together: *Columns whose runs of identical values must not be split across a page break.* `: default character()`. Every entry must be a column of `data` — typically a [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) key, or a hidden block-key column (`.hide` in [`cols()`](https://vthanik.github.io/tabular/reference/cols.md)) when the block structure lives in the row text rather than a grouping key (the AE SOC/PT idiom). **Interaction:** A run too tall to fit in the computed row budget less `orphan_floor` is split anyway; pagination is best-effort, not a hard contract. # Protect the SOC-level grouping in an AE-by-SOC/PT table. paginate(keep_together = "soc") - panels: *Number of horizontal panels for wide tables.* `: default 1`. With `1`, every column is on every page (single vertical scroll). With `N > 1`, the engine splits non-stub columns into `N` chunks and repeats the stub on every panel. - repeat_cols: *Stub columns repeated on every horizontal panel.* `: default NULL`. `NULL` derives the stub from the [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) keys, excluding break-only `col_spec(visible = FALSE)` keys (hidden columns never repeat). An explicit character vector REPLACES that default — name every column the stub should carry (e.g. the grouping key plus a per-row statistic label). [`character()`](https://rdrr.io/r/base/character.html) repeats nothing. **Interaction:** Only meaningful with `panels > 1` (or the column-fit horizontal split); a single-panel table renders every column anyway. - orphan_floor: *Minimum rows on a continued-from page.* `: default 3`. When `keep_together` would move a page break back so far that fewer than `orphan_floor` rows would ride on the current page, the engine splits the protected run anyway. Acts as the escape valve for groups too tall to fit. - widow_floor: *Minimum rows on the final page.* `: default 2`. If the last page would carry fewer than `widow_floor` rows, the engine merges those rows back onto the previous page (page overflow accepted). Avoids the "one-row-orphaned-on-page-N" look without complicating the primary split rule. - repeat_content: *Which page chrome repeats on every page.* `: default c("titles", "headers", "footnotes")`. A subset of those three values; each is governed independently: - **`"titles"`** — title block on every page (else page 1 only). - **`"headers"`** — column-header band on every page (else page 1 only). - **`"footnotes"`** — footnote block on every page (else last page only). The default repeats all three so each page is self-contained per the submission layout contract. Pass a subset to drop one (e.g. `c("headers", "footnotes")` keeps the title on page 1 only), or [`character()`](https://rdrr.io/r/base/character.html) to repeat nothing. **Note:** Footnotes are always anchored to the page foot when present; membership only chooses every-page vs last-page-only, never table-body placement. **HTML / MD:** ignored. HTML renders one continuous `` and browsers natively repeat `` on print; MD has no print model. Effective only for the page-oriented backends (RTF, PDF, LaTeX, DOCX). - continuation: *Marker text appended after a continuing table's title block.* `: default NULL`. `NULL` (the default) renders no marker — pick the wording your submission style guide expects (e.g. `"(continued)"`, `"(Cont'd)"`, `"Page %d of %d"`) and pass it explicitly. **Backend support is uneven** — verify against your render target: - **PDF / LaTeX** — full: the marker prints on every continuation page (both vertical page overflow and horizontal panels). - **RTF** — horizontal continuation *panels* only (`paginate(panels = N)`); the marker does NOT appear on vertical page-overflow continuations. - **DOCX** — not marked. DOCX paginates natively but emits no continuation marker. - **HTML / MD** — ignored. With one continuous document on screen there is no continuing-page boundary to mark. ## Value *The updated `tabular_spec`.* Continue chaining with [`style()`](https://vthanik.github.io/tabular/reference/style.md), [`preset()`](https://vthanik.github.io/tabular/reference/preset.md), then render via [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) (or resolve without I/O via [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md)). ## Details **Replace, not stack.** A second `paginate()` call REPLACES the prior spec — pagination is a single configuration block, not a stackable list. Call with all defaults to clear back to the engine's auto behaviour. **Rows per page are computed, not configured.** The engine takes the paper height for the active orientation (`letter`, `a4`) and subtracts the top + bottom margins, the title block height (number of title lines + a blank separator), the column-header band height (max embedded `\n` line count across visible column labels, plus any spanning header levels), and the footnote block height (number of footnote lines + a blank separator). The remainder, divided by the row height for the active font size, gives the body-row budget per page. Landscape pages naturally carry fewer rows than portrait at the same paper size; smaller fonts carry more. **`keep_together` protects block runs.** When a page break would fall in the middle of a contiguous run of identical values in a column listed in `keep_together`, the engine moves the break BACK to the start of the run so the whole run rides on the next page. Single rule of escape: if moving the break back would leave fewer than `orphan_floor` rows on the current page, the engine splits the run anyway (a single group too tall to fit on one page cannot be kept together). On the natively-paginating backends (RTF, DOCX) the consumer (Word) picks the break against the space remaining on its current page, which the engine cannot see — so protection is emitted as row-glue hints encoding the floor contract instead: a break inside a run leaves at least `orphan_floor` rows behind and carries at least `widow_floor` rows forward; runs short enough for the two edges to meet ride as one block. **`panels` and the stub.** With `panels > 1`, the engine splits the non-stub columns into approximately equal slices and repeats the stub — `repeat_cols` when set, otherwise the visible [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) keys — on every panel for row context. ## See also **Render-geometry partner:** [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) / [`set_preset()`](https://vthanik.github.io/tabular/reference/set_preset.md) — the preset's paper, orientation, margins, and font size feed the per-page row budget this verb depends on. **Sibling build verbs:** [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) / [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md), [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md). **Entry / terminal verbs:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md), [`emit()`](https://vthanik.github.io/tabular/reference/emit.md), [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md). ## Examples ``` r # ---- Example 1: AE table paginated by SOC ---- # # AE-by-SOC/PT table that may run several pages. The SOC column is # protected by `keep_together` so a page break never lands in the # middle of one SOC's PT rows. The engine derives the row budget # from the preset's orientation + font_size + paper size and from # the title / footnote / header line counts on the spec — no # manual rows-per-page knob to keep in sync. n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) tabular( cdisc_saf_aesocpt, titles = c( "Table 14.3.1", "Adverse Events by System Organ Class and Preferred Term", "Safety Population" ), footnotes = "Subjects are counted once per SOC and once per PT." ) |> cols( label = col_spec(label = "SOC / PT", indent = "indent_level"), placebo = "Placebo\nN={n['placebo']}", drug_50 = "Drug 50\nN={n['drug_50']}", drug_100 = "Drug 100\nN={n['drug_100']}", Total = "Total\nN={n['Total']}", .hide = c("soc", "row_type", "soc_n", "n_total") ) |> headers("Treatment Group" = c("placebo", "drug_50", "drug_100", "Total")) |> sort_rows(by = c("soc_n", "n_total"), descending = c(TRUE, TRUE)) |> paginate( keep_together = "soc", repeat_content = c("titles", "headers", "footnotes"), continuation = "(continued)" ) #tabular-8ae01bbdb5 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-8ae01bbdb5 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-8ae01bbdb5 p { line-height: inherit; } #tabular-8ae01bbdb5 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-8ae01bbdb5 .tabular-caption { margin: 0; padding: 0; } #tabular-8ae01bbdb5 .tabular-pad { margin: 0; line-height: 1; } #tabular-8ae01bbdb5 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-8ae01bbdb5 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-8ae01bbdb5 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-8ae01bbdb5 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-8ae01bbdb5 .tabular-table th, #tabular-8ae01bbdb5 .tabular-table td { padding: .18rem .6rem; } #tabular-8ae01bbdb5 .tabular-table td { text-align: left; vertical-align: top; } #tabular-8ae01bbdb5 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-8ae01bbdb5 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-8ae01bbdb5 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-8ae01bbdb5 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-8ae01bbdb5 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-8ae01bbdb5 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-8ae01bbdb5 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-8ae01bbdb5 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-8ae01bbdb5 .tabular-table tbody tr td { border-top: none; } #tabular-8ae01bbdb5 .tabular-band { text-align: center; } #tabular-8ae01bbdb5 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-8ae01bbdb5 .tabular-subgroup-label { font-weight: 600; } #tabular-8ae01bbdb5 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-8ae01bbdb5 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-8ae01bbdb5 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-8ae01bbdb5 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-8ae01bbdb5 .text-left { text-align: left; } #tabular-8ae01bbdb5 .text-center { text-align: center; } #tabular-8ae01bbdb5 .text-right { text-align: right; } #tabular-8ae01bbdb5 .tabular-table thead th.text-left { text-align: left; } #tabular-8ae01bbdb5 .tabular-table thead th.text-center { text-align: center; } #tabular-8ae01bbdb5 .tabular-table thead th.text-right { text-align: right; } #tabular-8ae01bbdb5 .tabular-table td.text-left { text-align: left; } #tabular-8ae01bbdb5 .tabular-table td.text-center { text-align: center; } #tabular-8ae01bbdb5 .tabular-table td.text-right { text-align: right; } #tabular-8ae01bbdb5 .valign-top { vertical-align: top; } #tabular-8ae01bbdb5 .valign-middle { vertical-align: middle; } #tabular-8ae01bbdb5 .valign-bottom { vertical-align: bottom; } #tabular-8ae01bbdb5 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-8ae01bbdb5 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-8ae01bbdb5 .tabular-page-break-row { display: none; } #tabular-8ae01bbdb5 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-8ae01bbdb5 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-8ae01bbdb5 .tabular-page-header, #tabular-8ae01bbdb5 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-8ae01bbdb5 .tabular-page-header { margin-bottom: 1rem; } #tabular-8ae01bbdb5 .tabular-page-footer { margin-top: 1rem; } #tabular-8ae01bbdb5 .tabular-page-header-left, #tabular-8ae01bbdb5 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-8ae01bbdb5 .tabular-page-header-center, #tabular-8ae01bbdb5 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-8ae01bbdb5 .tabular-page-header-right, #tabular-8ae01bbdb5 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-8ae01bbdb5 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-8ae01bbdb5 .tabular-table tr { page-break-inside: avoid; } #tabular-8ae01bbdb5 .tabular-page-header, #tabular-8ae01bbdb5 .tabular-page-footer { display: none; } #tabular-8ae01bbdb5 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-8ae01bbdb5 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-8ae01bbdb5 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.3.1 Adverse Events by System Organ Class and Preferred Term Safety Population   ``` # Convert a cards ARD to a wide display data.frame `pivot_across()` is tabular's input-side helper: it consumes a long Analysis Results Data (ARD) data frame (typically produced by `cards::ard_stack()` or `cards::ard_stack_hierarchical()`) and returns a wide display data.frame ready to pass to [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md). ## Usage ``` r pivot_across( data, statistic = list(continuous = "{mean} ({sd})", categorical = "{n} ({p}%)"), column = NULL, row_group = NULL, label = NULL, overall = "Total", decimals = NULL, fmt = NULL, aux = NULL ) ``` ## Arguments - data: *Long ARD input data.* `: required`. At minimum needs `stat_name` and `stat`. Cards-style group columns (`group1`, `group1_level`, ...) and `variable` / `variable_level` are auto-detected. Tibbles / `card` objects / arrow tables are coerced via [`as.data.frame()`](https://rdrr.io/r/base/as.data.frame.html). - statistic: *Format spec for cell composition.* `: required`. Combines one or more ARD stats into one display cell. Three accepted forms — each illustrated below. Inside a format string, `{stat_name}` substitutes that stat's value from the ARD (for example, `"{n} ({p}%)"` interpolates the `n` and `p` stats into a `"53 (62%)"` cell). The lookup order when a value is needed for a variable is: per-variable -\> per-context -\> `default` -\> the literal `"{n}"`. ### Form 1: single string One format string applied to every variable regardless of context. Use when your ARD is homogeneous (e.g. all categorical). # Every variable rendered as "n (p%)" — categorical-only slice. cat_only <- cdisc_saf_demo_ard[cdisc_saf_demo_ard$context == "categorical", ] pivot_across( cat_only, statistic = "{n} ({p}%)" ) ### Form 2: named list by context Different formats per context. This is the typical clinical-table form because demographics mix continuous and categorical variables. **The list names must match the values in the ARD's `context` column verbatim.** Which strings appear there depends on how the ARD was built: - `cards::ard_continuous()` / `ard_categorical()` emit `"continuous"` / `"categorical"`. - `cards::ard_summary()` / `ard_tabulate()` emit `"summary"` / `"tabulate"`. So an ARD assembled with `ard_stack(ard_summary(...), ard_tabulate(...))` is keyed `summary` / `tabulate`, not `continuous` / `categorical`. Inspect `unique(ard$context)` when unsure. # AGE (continuous) -> "75.2 (8.59)"; SEX (categorical) -> "53 (62%)" pivot_across( cdisc_saf_demo_ard, statistic = list( continuous = "{mean} ({sd})", categorical = "{n} ({p}%)" ) ) ### Form 3: named list by variable Override on a per-variable basis; fall back to `default` or context. Use when one variable needs a custom format. # AGE shows just the mean; SEX / RACE keep the categorical default. pivot_across( cdisc_saf_demo_ard, statistic = list( AGE = "{mean}", categorical = "{n} ({p}%)", default = "{mean} ({sd})" ) ) ### Multi-row continuous spec Any single entry can itself be a **named character vector** — each element becomes one display row, with the name as the row label. Use for `N / Mean (SD) / Median / Min, Max`-style blocks. pivot_across( cdisc_saf_demo_ard, statistic = list( continuous = c( N = "{N}", "Mean (SD)" = "{mean} ({sd})", Median = "{median}", "Min, Max" = "{min}, {max}" ), categorical = "{n} ({p}%)" ) ) - column: *What runs across the top of the table.* `: default NULL`. A single grouping variable whose unique values become arm columns (`NULL` auto-detects from `group1`, or picks the single non-standard column of renamed input). Two reserved tokens turn the analysis variable into a **column band**: - `c(".variable", "")` — each variable becomes a band of arm columns; the statistic entries stack as rows. The cells are combined strings (e.g. `"323.9 (106)"`). Emitted columns are named `".."`. - `c(".variable", ".stat")` — each variable becomes a band whose statistic entries become their own columns (the landscape "value and change" shell); the arm drops to a leading row stub. Emitted columns are named `".."`. Anything present in the ARD but not named in `column` (and not in `row_group`) stacks as rows. Per-variable `statistic` / `decimals` resolve inside each band, so bands may carry different (even different-length) stat lists; ragged bands pad with `NA`. **Tip:** you reference the emitted column names verbatim in a manual [`headers()`](https://vthanik.github.io/tabular/reference/headers.md) call to build the band spanners; pivot_across does not build spanners itself. - row_group: *Second, non-column grouping dimension.* `: default NULL`. Names the non-arm group variable of a two-variable `.by` (e.g. `SEX` in `ard_stack(.by = c(ARM, SEX))`). It widens into a leading row column (not a pivoted arm column), so the result composes with [`subgroup(by = ...)`](https://vthanik.github.io/tabular/reference/subgroup.md) or [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) downstream. **Why it is required.** cards encodes a crossing factor and a SOC/PT hierarchy identically (the second group variable appears in `variable` on its by-marginal rows), so the two cannot be told apart automatically. Naming `row_group` declares "this is a crossing factor": the by-marginal rows are dropped and the flat path is used. Leave it `NULL` for a genuine hierarchy. **Restriction:** Must name a second grouping variable present in the ARD and must differ from `column`. - label: *Variable-name to display-label map.* ` | NULL: default NULL`. Named character vector mapping variable names to display labels (e.g. `c(AGE = "Age (years)", SEX = "Sex")`). Applies to `variable`, `soc`, and `label` columns of the output. `NULL` leaves the upstream variable names verbatim. **Renaming the hierarchical "overall" row.** A `cards::ard_stack_hierarchical(overall = TRUE)` ARD carries an internal `..ard_hierarchical_overall..` sentinel for the grand-total ("any event") row. It is relabelled to `"Overall"` by default; map the sentinel key to override, e.g. `label = c("..ard_hierarchical_overall.." = "TOTAL SUBJECTS WITH AN EVENT")`. The raw sentinel never reaches the output at any hierarchy depth. - overall: *Column name for `NA`-arm (overall / total) rows.* `: default "Total"`. Pass `NULL` to drop overall rows entirely (per-arm only output). **Requirement:** this relabels pooled rows the ARD already carries — the `NA`-arm rows cards emits from `cards::ard_stack_hierarchical(overall = TRUE)` or an `ard_*(.overall = TRUE)`. It does not synthesize a total: cards re-runs the calculation with the `by` variable removed, so the pooled `n` / `N` / `p` stay internally consistent. With no such rows in the input there is no overall column to label. **Note:** if a study arm is literally named the same as `overall` (default `"Total"`), that arm and the pooled rows collide under one label and the pivot warns. Pass a distinct `overall =` or rename the arm upstream. - decimals: *Per-stat decimal precision.* `: default `c()“. Accepts three forms: - **named integer vector** — global per-stat overrides (`c(mean = 1, sd = 2, p = 0)`). - **named list keyed by variable** — per-variable plus `.default` (`list(AGE = c(mean = 2), .default = c(p = 1))`). - **named list keyed by `row_group` value** — per-group precision in one call (`list(SYSBP = c(mean = 0, sd = 1), WEIGHT = c(mean = 1), .default = c(mean = 1, sd = 2))`). Each entry is a per-token spec (a named numeric vector, or a bare scalar applied to every token). Built-in defaults apply when none sets a stat. **Interaction:** a list `decimals` is read as per-`row_group` only when `row_group` is set and every key (apart from `.default`) is one of its levels; otherwise it stays per-variable. Within the matched group the token falls back group token, then the per-group `.default` token, then the built-in default. A group present in the data but absent from the list (and NA / ungrouped rows) uses `.default`. If `row_group` is `NULL` but the keys match no variable, `pivot_across()` errors and asks for a `row_group`. - fmt: *Per-stat custom formatter functions.* `: default `list()“. Each function takes a numeric value and returns a character string; overrides built-ins and `decimals` for that stat. Useful for p-value styling and other domain-specific formatting. - aux: *Auxiliary comparison columns from a second ARD.* `: default NULL`. Each entry is a between-arm statistic (difference, hazard ratio, p-value, ...) computed in its own ARD and bound on as a trailing column, aligned 1:1 on the `row_group` key. The entry name is the column name; reference it in a manual [`headers()`](https://vthanik.github.io/tabular/reference/headers.md) call. Each entry is a list: - `ard` — the auxiliary ARD (required), one row per `row_group`. - `statistic` — its format string (e.g. `"{estimate} ({conf.low}, {conf.high})"`); defaults to `"{n}"`. - `decimals` / `fmt` — optional, as for the main pivot. Entries append left to right. One entry is one column; for several comparison columns (estimate then p-value) pass several entries. **Requirement:** needs a `row_group`; the auxiliary rows align to the main table on it, which must be unique 1:1 on both sides (a many-to-many key would silently fabricate rows, so it aborts). # p-value formatter: render below-threshold values as "<0.001". fmt = list( p.value = function(x) { ifelse(x < 0.001, "<0.001", sprintf("%.3f", x)) } ) ## Value *A wide `data.frame` ready for [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md).* Schema: - `variable` — variable name (or label after `label = ...`). - `stat_label` — display-row label. - One column per arm level (named after the `group1_level` values or the renamed arm column). - `Total` (or whatever `overall` is set to) when applicable. - A leading column named after `row_group` when set (the second grouping dimension). - Hierarchical ARD adds `soc`, `label`, `row_type` instead of `variable`. Pass the result straight into [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) to start the render pipeline. ## Details tabular's package boundary is **display-only**: pre-summarised data in, rendered file out. `pivot_across()` is the canonical bridge between the cards aggregation backend and that boundary. It does not aggregate — it pivots arms to columns, interpolates per-cell display strings from the stat values, and applies decimal precision. Filtering, weighting, and aggregation happen upstream in cards or your own data-prep step. ### Key `statistic` by the ARD `context` `statistic` (and `fmt`) are matched against the ARD's `context` column verbatim, and that value differs per generating function. Keying by the wrong name silently drops the format. Inspect `unique(ard$context)` first and key to match (or pass a single format string / `default =` to cover everything). When an explicitly-supplied `statistic` matches no context at all, `pivot_across()` warns rather than silently emitting `{n}`. | | | |-----------------------------------|-----------------------------| | Generating function | `context` to key on | | `cards::ard_summary()` | `summary` | | `cards::ard_tabulate()` | `tabulate` | | `cards::ard_continuous()` | `continuous` | | `cards::ard_categorical()` | `categorical` | | `cards::ard_stack_hierarchical()` | `tabulate` + `hierarchical` | | `cardx::ard_categorical_ci()` | `proportion_ci` | | `cardx::ard_continuous_ci()` | `continuous_ci` | ### Zero-suppression (always-on default) A row whose `n` value equals zero renders the whole cell as the bare `n` value instead of fully interpolating the format string. For a categorical level with `n = 0`, the cell shows `"0"`, not `"0 (0.0%)"`. This is clinical convention — empty cells should read as a single zero, not advertise a meaningless rate. **How the default fires (chain of events).** During cell assembly, before format-string interpolation, the engine checks the row's `n` stat. If it is zero, the engine short-circuits and returns the formatted `n` value (`"0"`) as the entire cell — `{p}` is never substituted, so the `(0.0%)` half of the format string is dropped. **How to opt out: supply a custom `fmt$n`.** Setting any function under `fmt$n` is the engine's signal that the user owns the `n` rendering. The short-circuit is disabled for the whole table; for every row the full format string interpolates, so `{n}` becomes your formatter's output and `{p}` becomes the standard percentage. For `n = 0`, that's `"0 (0.0%)"`. # Force "0 (0.0%)" for n = 0 rows by attaching a custom n formatter. # The body of fmt$n can be the default integer rendering — its # presence alone is what disables the zero-suppression branch. pivot_across( cdisc_saf_demo_ard, statistic = list( continuous = "{mean} ({sd})", categorical = "{n} ({p}%)" ), fmt = list(n = function(x) sprintf("%d", as.integer(x))) ) ### Pharma rounding (always-on default) A percentage that would otherwise round to `0` (when the value is positive but smaller than the chosen precision) renders as `<0.1`; one that would round to `100` (positive but smaller than 100) renders as `>99.9`. The threshold is precision-aware: `decimals = c(p = 2)` produces `<0.01` / `>99.99`. This matches the pharma convention of never claiming exactly `0%` or `100%` when at least one subject contributed. Override per-stat via `fmt`: # Show exact rounded percentages even at the extremes pivot_across( data, statistic = "{n} ({p}%)", decimals = c(p = 1), fmt = list(p = function(x) sprintf("%.1f", x * 100)) ) Your `fmt$p` receives the raw stat value (a proportion between 0 and 1) and returns the displayed string. The pharma-threshold branch only fires inside the built-in `p` formatter and the `decimals`-driven path, so any custom `fmt$p` bypasses it. ## See also **Pipeline entry consumer:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) — wraps the wide data frame this helper returns. **Downstream spec-build verbs:** [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) / [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md), [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md), [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md), [`preset()`](https://vthanik.github.io/tabular/reference/preset.md). **Terminal verbs:** [`emit()`](https://vthanik.github.io/tabular/reference/emit.md), [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md). ## Examples ``` r # ---- Example 1: Demographics — long ARD to rendered spec ---- # # Full pipeline from a `cards::ard_stack()`-style long ARD to a # sorted `tabular_spec`. The multi-row continuous block (N / # Mean (SD) / Median / Min, Max) sits above each categorical # block; decimals are set per-stat (mean 1, sd 2, p 1) to match # the CDISC convention. n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) cdisc_saf_demo_ard |> pivot_across( statistic = list( continuous = c( N = "{N}", "Mean (SD)" = "{mean} ({sd})", Median = "{median}", "Min, Max" = "{min}, {max}" ), categorical = "{n} ({p}%)" ), decimals = c(mean = 1, sd = 2, p = 1, median = 1, min = 0, max = 0), label = c(AGE = "Age (years)", SEX = "Sex", RACE = "Race") ) |> tabular( titles = c( "Table 14.1.1", "Demographics and Baseline Characteristics", "Safety Population" ), footnotes = "Percentages based on N per treatment group." ) |> cols( variable = col_spec(label = "Parameter"), stat_label = col_spec(label = "Statistic"), Placebo = col_spec( label = "Placebo\nN={n['placebo']}", align = "decimal" ), `Xanomeline Low Dose` = col_spec( label = "Drug 50\nN={n['drug_50']}", align = "decimal" ), `Xanomeline High Dose` = col_spec( label = "Drug 100\nN={n['drug_100']}", align = "decimal" ), Total = col_spec( label = "Total\nN={n['Total']}", align = "decimal" ) ) #tabular-0eb6858e8f { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-0eb6858e8f .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-0eb6858e8f p { line-height: inherit; } #tabular-0eb6858e8f .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-0eb6858e8f .tabular-caption { margin: 0; padding: 0; } #tabular-0eb6858e8f .tabular-pad { margin: 0; line-height: 1; } #tabular-0eb6858e8f .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-0eb6858e8f .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-0eb6858e8f .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-0eb6858e8f .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-0eb6858e8f .tabular-table th, #tabular-0eb6858e8f .tabular-table td { padding: .18rem .6rem; } #tabular-0eb6858e8f .tabular-table td { text-align: left; vertical-align: top; } #tabular-0eb6858e8f .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-0eb6858e8f .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-0eb6858e8f .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-0eb6858e8f .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-0eb6858e8f .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-0eb6858e8f .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-0eb6858e8f .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-0eb6858e8f .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-0eb6858e8f .tabular-table tbody tr td { border-top: none; } #tabular-0eb6858e8f .tabular-band { text-align: center; } #tabular-0eb6858e8f .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-0eb6858e8f .tabular-subgroup-label { font-weight: 600; } #tabular-0eb6858e8f .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-0eb6858e8f .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-0eb6858e8f .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-0eb6858e8f .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-0eb6858e8f .text-left { text-align: left; } #tabular-0eb6858e8f .text-center { text-align: center; } #tabular-0eb6858e8f .text-right { text-align: right; } #tabular-0eb6858e8f .tabular-table thead th.text-left { text-align: left; } #tabular-0eb6858e8f .tabular-table thead th.text-center { text-align: center; } #tabular-0eb6858e8f .tabular-table thead th.text-right { text-align: right; } #tabular-0eb6858e8f .tabular-table td.text-left { text-align: left; } #tabular-0eb6858e8f .tabular-table td.text-center { text-align: center; } #tabular-0eb6858e8f .tabular-table td.text-right { text-align: right; } #tabular-0eb6858e8f .valign-top { vertical-align: top; } #tabular-0eb6858e8f .valign-middle { vertical-align: middle; } #tabular-0eb6858e8f .valign-bottom { vertical-align: bottom; } #tabular-0eb6858e8f .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-0eb6858e8f .tabular-empty { font-style: italic; color: #6c757d; } #tabular-0eb6858e8f .tabular-page-break-row { display: none; } #tabular-0eb6858e8f { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-0eb6858e8f .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-0eb6858e8f .tabular-page-header, #tabular-0eb6858e8f .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-0eb6858e8f .tabular-page-header { margin-bottom: 1rem; } #tabular-0eb6858e8f .tabular-page-footer { margin-top: 1rem; } #tabular-0eb6858e8f .tabular-page-header-left, #tabular-0eb6858e8f .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-0eb6858e8f .tabular-page-header-center, #tabular-0eb6858e8f .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-0eb6858e8f .tabular-page-header-right, #tabular-0eb6858e8f .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-0eb6858e8f .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-0eb6858e8f .tabular-table tr { page-break-inside: avoid; } #tabular-0eb6858e8f .tabular-page-header, #tabular-0eb6858e8f .tabular-page-footer { display: none; } #tabular-0eb6858e8f .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-0eb6858e8f .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-0eb6858e8f .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.1.1 Demographics and Baseline Characteristics Safety Population   Parameter ``` # Minimal theme: one header rule, normal weight throughout Apply the stripped-down table look in one verb. The column-label divider (`midrule`) becomes the only rule drawn, and every bold-by-default surface renders in normal weight: the title block, the column-header band, the subgroup banner, and the section-header rows synthesized for [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) keys. The analogue of ggplot2's `theme_minimal()`, composable on the pipe between the build verbs and the terminal [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) / [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md). ## Usage ``` r preset_minimal(.spec, ...) ``` ## Arguments - .spec: *The `tabular_spec` to apply the minimal theme to.* `: required`. Dot-prefixed so partial matching cannot bind a `...` knob to the spec slot. - ...: *Named preset knobs.* Forwarded verbatim to [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) (e.g. `font_size`, `font_family`, `orientation`, `paper_size`, `margins`), so a single call sets both the minimal look and the page geometry. **Restriction:** the `rules` (and legacy `borders`) knob is owned by this helper and may not be passed here; call [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) directly for a custom rule set. ## Value *The updated `tabular_spec`.* Continue chaining with [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md) / [`style()`](https://vthanik.github.io/tabular/reference/style.md), then render via [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) (or resolve without I/O via [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md)). ## Details **What it sets**, both at theme (lowest) precedence so an explicit later [`style()`](https://vthanik.github.io/tabular/reference/style.md) wins: 1. **Rules.** Drops the booktabs `toprule` and `bottomrule` (the outer frame), keeping the `midrule` under the column labels and the muted column-spanner `spanrule`. Equivalent to `preset(rules = list(toprule = "none", bottomrule = "none"))`. 2. **Weight.** Sets `bold = FALSE` on the title, column-header, subgroup-label, and group-header surfaces. The HTML backend overrides its `font-weight: 600` class default with an inline `font-weight: normal`; the paginated backends (RTF / LaTeX / PDF / DOCX) suppress the surface's bold run. **Last verb wins.** Because the weight layers ride the theme tier, a later explicit `style(bold = TRUE, .at = cells_title())` (or any surface) re-bolds it. Treat `preset_minimal()` as the theme baseline and override individual surfaces afterwards. **Markdown.** GFM cannot represent colour / background / font on a surface; rendering a styled surface to `.md` emits a one-time `tabular_warning_fidelity` and degrades gracefully. Weight (bold) and italic carry through. ## See also **Underlying verbs:** [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) (the rule presets `"booktabs"` / `"grid"` / `"frame"` / `"none"` live there as `rules` string sugar), [`style()`](https://vthanik.github.io/tabular/reference/style.md). **Target the surfaces it touches:** [`cells_title()`](https://vthanik.github.io/tabular/reference/cells.md), [`cells_headers()`](https://vthanik.github.io/tabular/reference/cells.md), [`cells_subgroup_labels()`](https://vthanik.github.io/tabular/reference/cells.md), [`cells_group_headers()`](https://vthanik.github.io/tabular/reference/cells.md). **Entry / terminal verbs:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md), [`emit()`](https://vthanik.github.io/tabular/reference/emit.md), [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md). ## Examples ``` r # ---- Example 1: Minimal AE overall summary ---- # # The overall adverse-event summary with a single rule under the # column labels and no bold anywhere. `preset_minimal()` is the theme # baseline; the page stays at the session default geometry. demo_n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) tabular( cdisc_saf_ae, titles = c( "Table 14.3.1", "Overall Summary of Adverse Events", "Safety Population" ), footnotes = "Subjects counted once per category." ) |> cols( stat_label = col_spec(label = "Category"), placebo = col_spec(label = "Placebo\nN={demo_n['placebo']}"), drug_50 = col_spec(label = "Drug 50\nN={demo_n['drug_50']}"), drug_100 = col_spec(label = "Drug 100\nN={demo_n['drug_100']}"), Total = col_spec(label = "Total\nN={demo_n['Total']}") ) |> preset_minimal() #tabular-8e8c2851ff { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-8e8c2851ff .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-8e8c2851ff p { line-height: inherit; } #tabular-8e8c2851ff .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-8e8c2851ff .tabular-caption { margin: 0; padding: 0; } #tabular-8e8c2851ff .tabular-pad { margin: 0; line-height: 1; } #tabular-8e8c2851ff .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-8e8c2851ff .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-8e8c2851ff .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-8e8c2851ff .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-8e8c2851ff .tabular-table th, #tabular-8e8c2851ff .tabular-table td { padding: .18rem .6rem; } #tabular-8e8c2851ff .tabular-table td { text-align: left; vertical-align: top; } #tabular-8e8c2851ff .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-8e8c2851ff .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-8e8c2851ff .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-8e8c2851ff .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-8e8c2851ff .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-8e8c2851ff .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-8e8c2851ff .tabular-table tbody tr td { border-top: none; } #tabular-8e8c2851ff .tabular-band { text-align: center; } #tabular-8e8c2851ff .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-8e8c2851ff .tabular-subgroup-label { font-weight: 600; } #tabular-8e8c2851ff .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-8e8c2851ff .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-8e8c2851ff .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-8e8c2851ff .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-8e8c2851ff .text-left { text-align: left; } #tabular-8e8c2851ff .text-center { text-align: center; } #tabular-8e8c2851ff .text-right { text-align: right; } #tabular-8e8c2851ff .tabular-table thead th.text-left { text-align: left; } #tabular-8e8c2851ff .tabular-table thead th.text-center { text-align: center; } #tabular-8e8c2851ff .tabular-table thead th.text-right { text-align: right; } #tabular-8e8c2851ff .tabular-table td.text-left { text-align: left; } #tabular-8e8c2851ff .tabular-table td.text-center { text-align: center; } #tabular-8e8c2851ff .tabular-table td.text-right { text-align: right; } #tabular-8e8c2851ff .valign-top { vertical-align: top; } #tabular-8e8c2851ff .valign-middle { vertical-align: middle; } #tabular-8e8c2851ff .valign-bottom { vertical-align: bottom; } #tabular-8e8c2851ff .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-8e8c2851ff .tabular-empty { font-style: italic; color: #6c757d; } #tabular-8e8c2851ff .tabular-page-break-row { display: none; } #tabular-8e8c2851ff { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-8e8c2851ff .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-8e8c2851ff .tabular-page-header, #tabular-8e8c2851ff .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-8e8c2851ff .tabular-page-header { margin-bottom: 1rem; } #tabular-8e8c2851ff .tabular-page-footer { margin-top: 1rem; } #tabular-8e8c2851ff .tabular-page-header-left, #tabular-8e8c2851ff .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-8e8c2851ff .tabular-page-header-center, #tabular-8e8c2851ff .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-8e8c2851ff .tabular-page-header-right, #tabular-8e8c2851ff .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-8e8c2851ff .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-8e8c2851ff .tabular-table tr { page-break-inside: avoid; } #tabular-8e8c2851ff .tabular-page-header, #tabular-8e8c2851ff .tabular-page-footer { display: none; } #tabular-8e8c2851ff .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-8e8c2851ff .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-8e8c2851ff .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.3.1 Overall Summary of Adverse Events Safety Population   Category ``` # Override the render preset on a spec Attach a `preset_spec` to a `tabular_spec`, carrying page-geometry knobs (paper, orientation, margins, body font_size + family, h-rule policy, decimal metric, typography defaults). The engine consults the per-spec preset first when computing the per-page row budget, decimal-aligned column widths, and the chrome that the backend renders around the body grid. ## Usage ``` r preset(.spec, ..., .template = NULL, .style = NULL, .reset = FALSE) ``` ## Arguments - .spec: *The spec to attach the preset to.* `: required`. Dot-prefixed so R's partial argument matching cannot accidentally bind a knob name in `...` to the spec slot. **Note:** a [`figure()`](https://vthanik.github.io/tabular/reference/figure.md) spec accepts the page-geometry knobs (`paper_size`, `orientation`, `margins`, `font_size`, `font_family`, `pagehead`, `pagefoot`, ...) plus the cosmetic surface knobs (`alignment` / `fonts` / `colors` / `padding`) that target its chrome surfaces, the titles and footnotes, e.g. `fonts = list(titles = c(size = 14))`. A cosmetic knob that targets a table-only surface (`body` / `header` / `subgroup`), a `rules` knob (the rules sit on the header band a figure lacks), and the `.template` / `.style` style templates are rejected, since a figure has no such surfaces. - ...: *Named preset knobs.* Any subset of the preset knobs the `preset_spec` class carries. Knob values are validated against the class's enum / length / type rules; bad values raise `tabular_error_input`. Unknown knob names raise `tabular_error_input` with the recognised set listed. Recognised knobs: - **`font_size`** — body point size. ``. - **`font_family`** — body font family. ``. Default `"mono"`. Four accepted shapes: 1. **Generic family** — `"mono"` (default), `"serif"`, `"sans"` (CSS aliases `"monospace"` / `"sans-serif"` also recognised). The resolver expands to a per-backend chain that leads with the Microsoft Office face (Courier New / Times New Roman / Arial) — installed on every Windows and macOS machine, where documents are reviewed — then the PostScript legacy name, then the two metric-compatible Linux-server fallbacks: the **URW / Nimbus** clone (Nimbus Mono PS / Nimbus Roman / Nimbus Sans, ghostscript's Core-35 set shipped on virtually every Linux distro) and the **Liberation** face (Posit Workbench / Domino / Citrix / RStudio Server), then TeX Gyre for LaTeX compile / the CSS generic for HTML. Every link is metric-compatible with Courier New / TNR / Arial, so layout, line breaks, and decimal alignment hold across every render context regardless of which end of the chain resolves. The mono default matches the dominant submission-TFL convention where deterministic glyph widths drive `n (%)` cell alignment. 2. **Named alias** — `"Times"`, `"Times New Roman"`, `"Arial"`, `"Helvetica"`, `"Courier"`, `"Courier New"`. These PostScript-era names alias to the appropriate generic family (Times -\> serif, Arial / Helvetica -\> sans, Courier -\> mono) and emit the same expanded chain. Honours the user's intent ("I want Times-like rendering") on every OS instead of hard-erroring on a Linux server with no TNR installed. 3. **Arbitrary named font** — `"Inter"`, `"JetBrains Mono"`, `"IBM Plex Mono"`, `"Source Code Pro"`, sponsor-specific face, etc. Emitted verbatim with no fallback fabricated. The consuming app (browser, xelatex, Word, LibreOffice) resolves the name against its own font matcher: RTF and DOCX substitute when the name is missing; **xelatex hard-errors at compile time** if the face is not installed; HTML browsers fall through to the browser's default font (not necessarily class-matched). For a portable result, prefer a generic family (shape 1) or an explicit stack (shape 4). 4. **Explicit stack** — `c("Inter", "Helvetica", "sans")`. User owns the chain. Returned verbatim — alias lookup is **bypassed**, so `c("Times", "Times")` honours the exact name with no chain expansion (escape hatch for users who genuinely want exact-name semantics). **Note:** tabular bundles no fonts. Because the default chain leads with the Office face, Word's font dropdown shows a face the reader actually has installed on Windows / macOS (e.g. Courier New for `"mono"`), not a phantom name; the metric-compatible Nimbus / Liberation faces only appear as the fallback for a headless Linux box. - **`orientation`** — page orientation. ``. One of `"landscape"` (default), `"portrait"`. - **`paper_size`** — paper key. ``. One of `"letter"` (default), `"a4"`. - **`margins`** — page margins in inches. ``. Length 1 = all four sides; length 4 = top, right, bottom, left. - **`pagehead`**, **`pagefoot`** — per-page header / footer band content. ``. Each band is a named list with slots from `left` / `center` / `right`; every other slot name is rejected. Each slot accepts `NULL` (omit), a character scalar, a character vector (multi-row content), or an [`inline_ast`](https://vthanik.github.io/tabular/reference/tabular_classes.md). Empty [`list()`](https://rdrr.io/r/base/list.html) (the default) -\> no band emitted. **Single-row form** (scalar slots): pagehead = list( left = "Protocol: ABC-123", center = "Draft", right = "Page {page} of {npages}" ) **Multi-row form** (vector slots, index-aligned): pagehead = list( left = c("Protocol: ABC-123", "Analysis Set: Safety"), right = "Page {page} of {npages}" # scalar -> body-edge row ) **Growth direction.** Vector index 1 = body edge; index N = far from body. `pagehead` rows stack **upward** away from the table (the row closest to the table is index 1). `pagefoot` rows stack **downward** away from the table (the row closest to the table is index 1). Shorter slots pad with `""` at the FAR end (high index), so a scalar slot naturally lands on the body-edge row. **Token vocabulary** — substituted into slot text: | | | | |------------------|---------|----------------------------------------| | Token | Phase | Expansion | | `{page}` | backend | current page number (field code) | | `{npages}` | backend | total page count (field code) | | `{program}` | engine | calling script's base name | | `{program_path}` | engine | calling script's full path | | `{datetime}` | engine | `DDMMMYYYY HH:MM:SS` UTC (render time) | `{program}`, `{program_path}`, and `{datetime}` resolve once per render (at [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md) / [`emit()`](https://vthanik.github.io/tabular/reference/emit.md)); `{page}` and `{npages}` resolve per page (filled in by Word / xelatex / the browser's print engine at view time). The program tokens walk a 5-mode detection chain — RStudio API, [`source()`](https://rdrr.io/r/base/source.html) frame, Rscript / R CMD BATCH commandArgs (covers Domino + Linux batch + CI), knitr current_input, fallback `""`. - **`rules`** — the single border vocabulary (replaces the old `borders` knob). String sugar `"booktabs"` (default, the clinical baseline), `"grid"`, `"frame"`, `"none"`; a single [`brdr()`](https://vthanik.github.io/tabular/reference/brdr.md) broadcast to every active rule; or a named list keyed by the nine rule names (`toprule`, `midrule`, `bottomrule`, `spanrule`, `rowrule`, `footnoterule`, `leftrule`, `rightrule`, `colrule`) — unlisted rules keep their default, and the bare string `"none"` drops one. `rules = list(rowrule = brdr())` reproduces the old `hlines = "all"`. **`bottomrule` vs `footnoterule`.** These are mutually exclusive: exactly one rule sits at the data -\> footnote boundary. The default is `bottomrule` (the table's bottom edge); `footnoterule` (a table-width rule opening the footnote section) is OFF by default. As a distinct footnote-section rule, `footnoterule` is drawn only by the paginated backends — **RTF, LaTeX / PDF, and DOCX**. The **HTML** backend is continuous (non-paginated) and has no separate footnote section, so it folds both into one rule: whichever of `bottomrule` / `footnoterule` is active becomes the table's bottom edge (`bottomrule` wins when both are set). Setting `footnoterule` therefore still draws a closing rule on HTML — rendered as the `bottomrule`. - **`spacing`** — region-keyed blank-line control. A named list keyed by `title` / `body` / `subgroup` / `footnote`, each a named numeric `c(above = , below = )` (footnote: `above` only). Default is the one blank line above and below the title block. Two adjoining region-sides that target the same physical gap resolve to the MAX (never the sum), so a gap is never accidentally doubled. - **`stripe`** — zebra body-row fills. A single colour (applied to even rows) or a named `c(odd = , even = )`; `NULL` (default) is off. - **`indent_size`** — row-label indent width, in monospace- space units. ``. Default `2L`. Each indent level adds this many space-widths of left padding to the cell. `0L` disables the indent prefix entirely. Backends with native padding-left semantics (HTML / LaTeX / RTF / DOCX / PDF) emit this as cell padding so wrapped continuation lines align with the indented baseline; Markdown carries the literal space-prefix. Block alignment for the title / footnote / header / subgroup / body surfaces is set via the `alignment` named-list knob (`alignment = list(title_halign = "left", ...)`), not a scalar knob; blank-line spacing is set via `spacing` (above). - **`na_text`** — global NA fallback. ``. - **`decimal_metrics`** — decimal-padding metric. ``. `"afm"` (default) measures glyphs with the bundled Core font metrics, so decimal columns align width-exact in proportional fonts (to within one padding space of rounding; exact in Courier). A `font_family` with no bundled metric table (e.g. a system-installed face such as Courier 10 Pitch) is measured through a temporary graphics device instead, so alignment stays exact whenever the host can resolve the font; only when that also fails does the engine fall back to Times metrics with a fidelity warning. `"chars"` pads by character count — exact in monospaced faces only. Markdown output always pads by character count, the correct geometry for a text medium. - **`decimal_markers`** — missing-value tokens recognised by `col_spec(align = "decimal")`. ``. Default `c("NR", "NE", "NC", "ND", "BLQ")`. A cell whose trimmed value is one of these is treated as a non-numeric *marker*: it is shown and right-aligned in the column rather than parsed as a number, and a marker appearing inside a compound (e.g. the upper bound of `14.3 (11.2, NR)`) is preserved and slot-aligned. Excludes `"-"`, `"NA"`, and `"INF"`/`"-INF"` by default: `"-"` collides with range separators, `"NA"` is handled by `na_text`, and infinities are real values. Set to `character(0)` to disable marker handling. - **`width_mode`** — table-level column-sizing policy. Mirrors Word's Table Layout menu. ``. One of: - **`"content"`** *(default)* — Each column auto-sized to `max(body, header)`. The table doesn't fill the page. Word's "Auto-fit Contents". - **`"window"`** — Auto-sized columns are scaled proportionally to their natural width to fill the residual page width. Pinned and percent columns keep their pins. Word's "Auto-fit Window". - **`"fixed"`** — Only explicit per-column widths drive the layout. Auto-sized columns collapse to a minimum sliver. Word's "Fixed Column Width". **Interaction:** Pair with `col_spec(width = ...)` pins to drive the layout under `"window"` / `"fixed"`. Under `"content"`, pins still take priority over auto columns. **HTML backend.** `width_mode` drives paper backends (LaTeX / RTF / PDF / DOCX) only. HTML is unconditionally responsive — the table always fills its parent and columns wrap when the viewport narrows, regardless of `width_mode`. Per-column widths (`col_spec(width)`) emit verbatim into the HTML colgroup per the gt convention. - **`empty_text`** — house-style *wording* for the empty-state message shown when a spec resolves to zero data rows. ``. The resolution is spec arg -\> preset knob -\> built-in default: a per-table `tabular(empty_text = ...)` wins, else this preset knob (set once via [`set_preset()`](https://vthanik.github.io/tabular/reference/set_preset.md) for a whole house style), else the built-in `"No data available to report"`. Glue [`{}`](https://rdrr.io/r/base/Paren.html) and [`md()`](https://vthanik.github.io/tabular/reference/md.md) / [`html()`](https://vthanik.github.io/tabular/reference/html.md) inline formatting are honoured, exactly like a title line. - **`whitespace`** — how significant ASCII spaces in labels and cells render. ``. One of: - **`"preserve"`** *(default)* — leading, trailing, and interior runs of 2+ spaces become the backend non-breaking token (` ` / `~` / `\~`; DOCX preserves via `xml:space`), so a hand-built indent like `col_spec(label = " Placebo")` renders verbatim across every backend. A single interior space stays breakable, so cells still wrap. - **`"collapse"`** — leave the backend's native run-folding in place (HTML / md / LaTeX collapse runs to one space). **Note:** never affects `col_spec(align = "decimal")` padding, which uses U+00A0 and is preserved unconditionally. - **`chrome_onscreen`** — whether the on-screen running header / footer bands render in HTML output. ``. One of: - **`"auto"`** *(default)* — the `pagehead` / `pagefoot` content renders as on-screen `
` / `
` bands. - **`"off"`** — suppress the on-screen bands; the print-time `@page` chrome still renders, so print-to-PDF output is unchanged. Useful when the HTML is consumed only via print. HTML-only; the paged backends (RTF / PDF / DOCX) always emit per-page chrome regardless of this knob. - **`footnote_markers`** — the glyph scheme for [`footnote()`](https://vthanik.github.io/tabular/reference/footnote.md) markers, which the engine allocates once in reading order. ``. One of: - **`"letters"`** *(default)* — `a`, `b`, …, `z`, `aa`, `ab`, … (bijective base-26). - **`"numbers"`** — `1`, `2`, `3`, … - **`"symbols"`** — Lamport's sequence `*`, `†`, `‡`, `§`, `¶`, `‖`, then doubled (`**`, `††`, …) once it spills past the sixth. **Interaction:** a note's *anchor* is fixed by [`footnote()`](https://vthanik.github.io/tabular/reference/footnote.md); its *scheme* (this knob) and *label* (`footnote_label`) are resolved from the active preset at render, so flipping either re-letters every marker at once. - **`footnote_label`** — block-line template for a [`footnote()`](https://vthanik.github.io/tabular/reference/footnote.md) marker. ``. Default `"{m}"`; the `{m}` token is replaced by the allocated marker, so `"[{m}]"` prints `[a]` ahead of the note text on the footnote line. - **`cell_padding`** — cell padding in points, CSS shorthand of length 1 / 2 / 4 (`all` \| `vertical horizontal` \| `top right bottom left`), parsed by the same length rule as `margins`. `: default c(0, 5.4)` (vertical 0, horizontal 5.4pt). The single source of truth for both auto column-width measurement (left + right) and every backend's cell margin, so measured and rendered widths agree. **Interaction:** A body per-side padding override (`preset(padding = list(body = ...))` or `style(.at = cells_body(), padding = ...)`) takes precedence at both measurement and render. **Note:** DOCX and LaTeX render left / right exactly; RTF (`\\trgaph` is one symmetric gap) renders the average, so the total width still matches but the two sides look equal. # Landscape A4, 8pt body, slim margins for one wide table. preset( orientation = "landscape", paper_size = "a4", font_size = 8, margins = c(0.75, 0.5, 0.75, 0.5) ) - .template: *A `preset_spec` to bulk-apply before `...`.* `: default NULL`. When supplied, every knob the template has set away from its factory default feeds in as the base layer; user-supplied `...` knobs then merge on top. List-valued knobs (`rules`, `fonts`, `colors`, `padding`, `alignment`) shallow-merge per key; scalars replace. Use this to layer a house-style `preset_spec` onto a chain without restating its knobs. - .style: *A [`style_template()`](https://vthanik.github.io/tabular/reference/style_template.md) to layer onto the cascade.* `: default NULL`. When supplied, every layer the template has accumulated via [`style()`](https://vthanik.github.io/tabular/reference/style.md) is replayed in order at engine time, after the per-spec [`style()`](https://vthanik.github.io/tabular/reference/style.md) layers on `.spec`. Use this to attach a sponsor's reusable house style to a chain without restating every per-region rule. - .reset: *Discard the spec's existing preset before applying `...`.* `: default FALSE`. When `TRUE`, the spec's prior `preset_spec` (if any) is dropped and `...` knobs are merged onto fresh [`preset_spec()`](https://vthanik.github.io/tabular/reference/tabular_classes.md) defaults. With no knobs, the per-spec preset is cleared back to NULL (the spec falls through to [`set_preset()`](https://vthanik.github.io/tabular/reference/set_preset.md) or [`preset_spec()`](https://vthanik.github.io/tabular/reference/tabular_classes.md) defaults). ## Value *The updated `tabular_spec`.* Continue chaining with [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md), then render via [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) (or resolve without I/O via [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md)). ## Details **Per-spec, chained.** `preset()` is the per-spec override — a verb that returns a modified spec, composable on the pipe alongside [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) / [`headers()`](https://vthanik.github.io/tabular/reference/headers.md) / [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md). Use it when a single table needs a one-off geometry (e.g. landscape A4 for one wide efficacy summary inside a portfolio of portrait letter tables). **Merge, not replace.** A second `preset()` call merges its scalar knobs onto the spec's existing preset; unspecified knobs keep their prior value. The five named-list knobs (`alignment` / `rules` / `fonts` / `colors` / `padding`) lower to `style_layer` records on `preset@style` via `.preset_args_to_layers()` (internal) and append in call order; layer order is precedence within the engine cascade, so a later `preset()` call's lowered attribute wins over an earlier one at the cell. Pass `.reset = TRUE` to discard the existing knobs and start from [`preset_spec()`](https://vthanik.github.io/tabular/reference/tabular_classes.md) defaults. `preset(.spec, .reset = TRUE)` with no knobs clears the per-spec override entirely (the spec then falls through to [`set_preset()`](https://vthanik.github.io/tabular/reference/set_preset.md) or [`preset_spec()`](https://vthanik.github.io/tabular/reference/tabular_classes.md) defaults at render time). **Direct [`preset_spec()`](https://vthanik.github.io/tabular/reference/tabular_classes.md) calls bypass lowering.** The five named-list knobs are no longer slots on the `preset_spec` S7 class — they exist only as `preset()` / [`set_preset()`](https://vthanik.github.io/tabular/reference/set_preset.md) arguments that lower into `@style`. `preset_spec(rules = list(...))` (and analogous direct calls) raise "unused argument". Wrap such calls in `tabular(...) |> preset(...)` so the lowering helper fires and the layers land on `@style`. **Cascade with [`set_preset()`](https://vthanik.github.io/tabular/reference/set_preset.md).** The engine resolves the active preset in this order: (1) the spec's per-call preset (this verb), (2) the session default attached via [`set_preset()`](https://vthanik.github.io/tabular/reference/set_preset.md), (3) [`preset_spec()`](https://vthanik.github.io/tabular/reference/tabular_classes.md) factory defaults. The first non-NULL layer wins; layers are not field-merged across the cascade. ## See also **Session-scope partners:** [`set_preset()`](https://vthanik.github.io/tabular/reference/set_preset.md), [`get_preset()`](https://vthanik.github.io/tabular/reference/get_preset.md). **Render-geometry consumer:** [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md) derives the per-page row budget from the active preset's paper, orientation, margins, and font size. **Sibling build verbs:** [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) / [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md), [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md). **Entry / terminal verbs:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md), [`emit()`](https://vthanik.github.io/tabular/reference/emit.md), [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md). ## Examples ``` r # ---- Example 1: Landscape A4 for a wide efficacy table ---- # # BOR table where the four-arm column block fits portrait letter # with a smaller body font, but the sponsor wants A4 landscape at # 8pt for visual breathing room. `preset()` attaches the geometry; # `paginate()` reads it later to size the per-page row budget. bor_levels <- c( "CR", "PR", "SD", "NON-CR/NON-PD", "PD", "NE", "MISSING", "ORR (CR + PR)", "CBR (CR + PR + SD)", "DCR (CR + PR + SD + NON-CR/NON-PD)", "95% CI (Clopper-Pearson)" ) eff <- cdisc_eff_resp eff$stat_label <- factor(eff$stat_label, levels = bor_levels) ne <- stats::setNames(cdisc_eff_n$n, cdisc_eff_n$arm_short) tabular( eff, titles = c( "Table 14.2.1", "Best Overall Response and Response Rates", "Efficacy Evaluable Population" ), footnotes = "Response per RECIST 1.1, investigator assessment." ) |> cols( stat_label = col_spec(label = "Response"), row_type = col_spec(visible = FALSE), groupid = col_spec(visible = FALSE), group_label = col_spec(visible = FALSE), placebo = col_spec(label = "Placebo\nN={ne['placebo']}"), drug_50 = col_spec(label = "Drug 50\nN={ne['drug_50']}"), drug_100 = col_spec(label = "Drug 100\nN={ne['drug_100']}") ) |> sort_rows(by = c("groupid", "stat_label")) |> preset( orientation = "landscape", paper_size = "a4", font_size = 8 ) |> paginate() #tabular-da34745d33 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 8pt; line-height: 1.3; } #tabular-da34745d33 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-da34745d33 p { line-height: inherit; } #tabular-da34745d33 .tabular-title { font-size: 8pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-da34745d33 .tabular-caption { margin: 0; padding: 0; } #tabular-da34745d33 .tabular-pad { margin: 0; line-height: 1; } #tabular-da34745d33 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-da34745d33 .tabular-table { border-collapse: collapse; font-size: 8pt; margin: 0 auto; } #tabular-da34745d33 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-da34745d33 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-da34745d33 .tabular-table th, #tabular-da34745d33 .tabular-table td { padding: .18rem .6rem; } #tabular-da34745d33 .tabular-table td { text-align: left; vertical-align: top; } #tabular-da34745d33 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-da34745d33 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-da34745d33 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-da34745d33 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-da34745d33 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-da34745d33 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-da34745d33 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-da34745d33 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-da34745d33 .tabular-table tbody tr td { border-top: none; } #tabular-da34745d33 .tabular-band { text-align: center; } #tabular-da34745d33 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-da34745d33 .tabular-subgroup-label { font-weight: 600; } #tabular-da34745d33 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-da34745d33 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-da34745d33 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-da34745d33 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-da34745d33 .text-left { text-align: left; } #tabular-da34745d33 .text-center { text-align: center; } #tabular-da34745d33 .text-right { text-align: right; } #tabular-da34745d33 .tabular-table thead th.text-left { text-align: left; } #tabular-da34745d33 .tabular-table thead th.text-center { text-align: center; } #tabular-da34745d33 .tabular-table thead th.text-right { text-align: right; } #tabular-da34745d33 .tabular-table td.text-left { text-align: left; } #tabular-da34745d33 .tabular-table td.text-center { text-align: center; } #tabular-da34745d33 .tabular-table td.text-right { text-align: right; } #tabular-da34745d33 .valign-top { vertical-align: top; } #tabular-da34745d33 .valign-middle { vertical-align: middle; } #tabular-da34745d33 .valign-bottom { vertical-align: bottom; } #tabular-da34745d33 .tabular-footnote { font-size: 8pt; color: #495057; margin: .25rem 0; } #tabular-da34745d33 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-da34745d33 .tabular-page-break-row { display: none; } #tabular-da34745d33 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-da34745d33 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-da34745d33 .tabular-page-header, #tabular-da34745d33 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 7pt; color: var(--tabular-chrome-color); } #tabular-da34745d33 .tabular-page-header { margin-bottom: 1rem; } #tabular-da34745d33 .tabular-page-footer { margin-top: 1rem; } #tabular-da34745d33 .tabular-page-header-left, #tabular-da34745d33 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-da34745d33 .tabular-page-header-center, #tabular-da34745d33 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-da34745d33 .tabular-page-header-right, #tabular-da34745d33 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-da34745d33 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-da34745d33 .tabular-table tr { page-break-inside: avoid; } #tabular-da34745d33 .tabular-page-header, #tabular-da34745d33 .tabular-page-footer { display: none; } #tabular-da34745d33 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-da34745d33 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-da34745d33 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.2.1 Best Overall Response and Response Rates Efficacy Evaluable Population   Response ``` # Print a `tabular_spec` Renders a `tabular_spec` interactively. The default behaviour mirrors `gt::gt()`: convert the spec to an `htmltools` tag list and let htmltools dispatch — RStudio + Positron viewer panes, Quarto / Rmd notebook inline, Databricks `displayHTML`, and plain-console [`cat()`](https://rdrr.io/r/base/cat.html) are all handled without any IDE- specific branching. ## Value *Invisibly returns `x`.* Side effect: opens the viewer, inlines under a chunk, or [`cat()`](https://rdrr.io/r/base/cat.html)s output. ## Details **Dispatch.** [`print()`](https://rdrr.io/r/base/print.html) delegates to [`as.tags.tabular_spec()`](https://vthanik.github.io/tabular/reference/as.tags.tabular_spec.md) which returns an [`htmltools::tagList`](https://rstudio.github.io/htmltools/reference/tagList.html). That tag list is handed to `htmltools`'s own print method with `browse = view`: htmltools opens the IDE viewer when one is registered, inlines under a Quarto / Rmd chunk when running inside one, or [`cat()`](https://rdrr.io/r/base/cat.html)s the HTML when neither applies. No `is_rstudio()` / `is_positron()` / `is_notebook()` heuristics — htmltools already knows. **`view` argument.** Defaults to [`interactive()`](https://rdrr.io/r/base/interactive.html), the same universal off-switch `gt::gt()` uses. Non-interactive contexts (`Rscript`, `R CMD check`, CI, devtools::test) bypass the viewer automatically. Pass `view = FALSE` explicitly at an interactive prompt to suppress the viewer for a single call. **`output` argument.** Forces a specific preview format instead of the default HTML-via-htmltools path. One of: - `"html"` — same as the default, but explicit. - `"md"` / `"markdown"` — [`cat()`](https://rdrr.io/r/base/cat.html) the markdown source to the console (round-trips through `backend_md`). - `"latex"` — [`cat()`](https://rdrr.io/r/base/cat.html) the markdown source as a temporary placeholder (real LaTeX preview lands with `backend_latex`). - `"rtf"` / `"docx"` / `"pdf"` — render an HTML preview and emit a cli note pointing at [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) for the real artefact. The viewer pane cannot render RTF / OOXML, and we deliberately do *not* compile through tinytex on every autoprint. - `"cli"` — print the structural cli-tree summary (props, headers, sort, pagination, preset). Useful for debugging spec composition without paying the HTML render cost. **Robustness.** The HTML render is wrapped in `tryCatch`; if rendering fails for any reason the printer falls back to the cli-tree summary and a [`cli::cli_warn()`](https://cli.r-lib.org/reference/cli_abort.html) describing the failure, so a broken spec never crashes the REPL. **Tempdir.** Preview HTML files live under `getOption("tabular_preview_dir", default = tempdir())`. Override the option to keep them in a stable location (handy on Linux distros where browsers don't have read access to `/tmp/`). ## Arguments [`print()`](https://rdrr.io/r/base/print.html) dispatches on a `tabular_spec` via an S7 method on the base generic, so its arguments are documented here rather than in a formal usage table: - `x` — *the `tabular_spec` to render.* Required. The same object you'd hand to [`emit()`](https://vthanik.github.io/tabular/reference/emit.md). - `...` — *forwarded to `htmltools::print` / `as.tags()`.* Pass `id`, `style`, `class` overrides for the wrapping `
`. - `view` — *open the viewer?* `logical(1)`, default [`interactive()`](https://rdrr.io/r/base/interactive.html). Same role as `gt::gt`'s `view` argument: passes through to htmltools as `browse = view`. Set `view = FALSE` to suppress the viewer for one call (e.g. to capture the HTML string without launching a window). - `output` — *force a specific preview format.* `character(1)` or `NULL`, default `NULL` (auto). See the **`output` argument** section below for the full list. The session default can be set via `options(tabular_print_output = "cli")` for users who prefer the structural summary over the HTML preview. ## See also **Tag conversion:** [`as.tags.tabular_spec()`](https://vthanik.github.io/tabular/reference/as.tags.tabular_spec.md) — the htmltools tag list that [`print()`](https://rdrr.io/r/base/print.html) delegates to. Call it directly to embed the table in a custom [`htmltools::tagList`](https://rstudio.github.io/htmltools/reference/tagList.html) or Shiny UI. **Terminal verb:** [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) writes the resolved artefact to disk; [`print()`](https://rdrr.io/r/base/print.html) is for in-session preview only. **Pipeline shape:** [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md) resolves the engine pipeline to a `tabular_grid` without I/O. ## Examples ``` r # ---- Example 1: Build + autoprint (HTML preview) ---- # # Build a spec and let autoprint render it. Inside RStudio / # Positron the HTML lands in the viewer pane; inside a # Quarto / Rmd chunk it inlines under the chunk; at a plain # console the HTML source is `cat()`-ed. tabular( cdisc_saf_demo, titles = c("Table 14.1.1", "Demographics"), footnotes = "Safety Population." ) #tabular-dc6b2f85cd { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-dc6b2f85cd .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-dc6b2f85cd p { line-height: inherit; } #tabular-dc6b2f85cd .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-dc6b2f85cd .tabular-caption { margin: 0; padding: 0; } #tabular-dc6b2f85cd .tabular-pad { margin: 0; line-height: 1; } #tabular-dc6b2f85cd .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-dc6b2f85cd .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-dc6b2f85cd .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-dc6b2f85cd .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-dc6b2f85cd .tabular-table th, #tabular-dc6b2f85cd .tabular-table td { padding: .18rem .6rem; } #tabular-dc6b2f85cd .tabular-table td { text-align: left; vertical-align: top; } #tabular-dc6b2f85cd .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-dc6b2f85cd .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-dc6b2f85cd .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-dc6b2f85cd .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-dc6b2f85cd .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-dc6b2f85cd .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-dc6b2f85cd .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-dc6b2f85cd .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-dc6b2f85cd .tabular-table tbody tr td { border-top: none; } #tabular-dc6b2f85cd .tabular-band { text-align: center; } #tabular-dc6b2f85cd .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-dc6b2f85cd .tabular-subgroup-label { font-weight: 600; } #tabular-dc6b2f85cd .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-dc6b2f85cd .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-dc6b2f85cd .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-dc6b2f85cd .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-dc6b2f85cd .text-left { text-align: left; } #tabular-dc6b2f85cd .text-center { text-align: center; } #tabular-dc6b2f85cd .text-right { text-align: right; } #tabular-dc6b2f85cd .tabular-table thead th.text-left { text-align: left; } #tabular-dc6b2f85cd .tabular-table thead th.text-center { text-align: center; } #tabular-dc6b2f85cd .tabular-table thead th.text-right { text-align: right; } #tabular-dc6b2f85cd .tabular-table td.text-left { text-align: left; } #tabular-dc6b2f85cd .tabular-table td.text-center { text-align: center; } #tabular-dc6b2f85cd .tabular-table td.text-right { text-align: right; } #tabular-dc6b2f85cd .valign-top { vertical-align: top; } #tabular-dc6b2f85cd .valign-middle { vertical-align: middle; } #tabular-dc6b2f85cd .valign-bottom { vertical-align: bottom; } #tabular-dc6b2f85cd .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-dc6b2f85cd .tabular-empty { font-style: italic; color: #6c757d; } #tabular-dc6b2f85cd .tabular-page-break-row { display: none; } #tabular-dc6b2f85cd { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-dc6b2f85cd .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-dc6b2f85cd .tabular-page-header, #tabular-dc6b2f85cd .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-dc6b2f85cd .tabular-page-header { margin-bottom: 1rem; } #tabular-dc6b2f85cd .tabular-page-footer { margin-top: 1rem; } #tabular-dc6b2f85cd .tabular-page-header-left, #tabular-dc6b2f85cd .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-dc6b2f85cd .tabular-page-header-center, #tabular-dc6b2f85cd .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-dc6b2f85cd .tabular-page-header-right, #tabular-dc6b2f85cd .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-dc6b2f85cd .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-dc6b2f85cd .tabular-table tr { page-break-inside: avoid; } #tabular-dc6b2f85cd .tabular-page-header, #tabular-dc6b2f85cd .tabular-page-footer { display: none; } #tabular-dc6b2f85cd .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-dc6b2f85cd .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-dc6b2f85cd .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.1.1 Demographics   variable ``` # Set or clear the session default preset Stash a `preset_spec` in the package-internal session environment. Every subsequent [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) chain that does not attach its own [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) inherits these knobs at render time. Mirrors ggplot2's [[`ggplot2::theme_set()`](https://ggplot2.tidyverse.org/reference/get_theme.html)](https://ggplot2.tidyverse.org/reference/get_theme.html): one call up front, many tables downstream. ## Usage ``` r set_preset(new = NULL, ..., .template = NULL, .style = NULL, .reset = FALSE) ``` ## Arguments - new: *A `preset_spec` to install wholesale.* `: default NULL`. When non-`NULL`, replaces the session preset in one call without touching knobs. The primary use is the save/restore round-trip (`old <- set_preset(...); set_preset(old)`) — `new` accepts any `preset_spec` previously returned by `set_preset()` or [`get_preset()`](https://vthanik.github.io/tabular/reference/get_preset.md). Mutually exclusive with `...`, `.template`, `.style`, `.reset`: passing any of those alongside a non-`NULL` `new` raises `tabular_error_input`. - ...: *Named preset knobs.* Same shape as [`preset()`](https://vthanik.github.io/tabular/reference/preset.md); see that verb for the full list of recognised knobs. Unknown names raise `tabular_error_input`. Mutually exclusive with a non-`NULL` `new`. - .template: *A `preset_spec` to bulk-apply before `...`.* `: default NULL`. Same semantics as [`preset()`](https://vthanik.github.io/tabular/reference/preset.md)'s `.template`: every knob set away from its factory default feeds in as the base layer; user-supplied `...` knobs then merge on top with shallow-merge per list-valued knob. - .style: *A [`style_template()`](https://vthanik.github.io/tabular/reference/style_template.md) to layer into the session default.* `: default NULL`. Same semantics as [`preset()`](https://vthanik.github.io/tabular/reference/preset.md)'s `.style`: the template's accumulated layers feed in as session-default style, layered before any per-spec [`style()`](https://vthanik.github.io/tabular/reference/style.md) calls. - .reset: *Discard the existing session preset before applying `...`.* `: default FALSE`. With no knobs, clears the session default back to NULL. ## Value *The previous session `preset_spec` (invisible).* Returns `NULL` when no session preset was attached prior to the call. Capture it to round-trip a temporary override: `old <- set_preset(...); set_preset(old)`. Mirrors [[`ggplot2::theme_set()`](https://ggplot2.tidyverse.org/reference/get_theme.html)](https://ggplot2.tidyverse.org/reference/get_theme.html) and [`base::options()`](https://rdrr.io/r/base/options.html) — the canonical tidyverse save/restore primitive. ## Details **Persistence.** The session preset lives in a package-internal environment populated when `tabular` is loaded and emptied when the namespace unloads. There is no on-disk persistence; set the default at the top of each analysis script (or in a project-level `.Rprofile`) when a sticky house style is needed. **Merge, not replace.** A second `set_preset()` call merges its knobs onto the existing session preset; unspecified knobs keep their prior value. Pass `.reset = TRUE` to discard the existing session preset and start from [`preset_spec()`](https://vthanik.github.io/tabular/reference/tabular_classes.md) defaults. `set_preset(.reset = TRUE)` with no knobs clears the session default back to NULL. **Save and restore.** Every call returns the *previous* session preset invisibly, the same primitive ggplot2's [[`ggplot2::theme_set()`](https://ggplot2.tidyverse.org/reference/get_theme.html)](https://ggplot2.tidyverse.org/reference/get_theme.html) ships. Capture it once, render, and restore by passing the saved value back as the positional `new` argument: old <- set_preset(font_size = 10, paper_size = "a4") # ... one renegade render at 10pt A4 ... set_preset(old) # restore When the prior was `NULL` (no session preset ever attached), the restore is `set_preset(.reset = TRUE)` instead — `set_preset(NULL)` is the same shape as `set_preset()` and falls through to factory defaults rather than clearing the session. **Cascade with [`preset()`](https://vthanik.github.io/tabular/reference/preset.md).** A per-spec [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) always wins over the session default. The session default fills in only when the spec carries no preset of its own. ## See also **Per-spec partner:** [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) — overrides the session default on one chain. **Inspect:** [`get_preset()`](https://vthanik.github.io/tabular/reference/get_preset.md). **Entry / terminal verbs:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md), [`emit()`](https://vthanik.github.io/tabular/reference/emit.md), [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md). ## Examples ``` r # ---- Example 1: Sticky session default for an analysis script ---- # # The submission's safety tables all use portrait letter, 9pt # Times New Roman with 1-inch margins. Set once at the top of the # analysis script and every `tabular()` chain inherits it — no # per-table `preset()` call needed unless one table deviates. set_preset( font_size = 9, font_family = "Times New Roman", orientation = "portrait", paper_size = "letter", margins = 1 ) # Subsequent tabular() chains pick up the session preset at render. demo_n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) tabular( cdisc_saf_ae, titles = c( "Table 14.3.1", "Overall Summary of Adverse Events", "Safety Population" ), footnotes = "Subjects counted once per category." ) |> cols( stat_label = col_spec(label = "Category"), placebo = col_spec(label = "Placebo\nN={demo_n['placebo']}"), drug_50 = col_spec(label = "Drug 50\nN={demo_n['drug_50']}"), drug_100 = col_spec(label = "Drug 100\nN={demo_n['drug_100']}"), Total = col_spec(label = "Total\nN={demo_n['Total']}") ) #tabular-b73983854c { font-family: "Times New Roman", Times, "Nimbus Roman", "Liberation Serif", serif; color: #212529; margin: 1.5rem; font-size: 9pt; line-height: 1.3; } #tabular-b73983854c .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-b73983854c p { line-height: inherit; } #tabular-b73983854c .tabular-title { font-size: 9pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-b73983854c .tabular-caption { margin: 0; padding: 0; } #tabular-b73983854c .tabular-pad { margin: 0; line-height: 1; } #tabular-b73983854c .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-b73983854c .tabular-table { border-collapse: collapse; font-size: 9pt; margin: 0 auto; } #tabular-b73983854c .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-b73983854c .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-b73983854c .tabular-table th, #tabular-b73983854c .tabular-table td { padding: .18rem .6rem; } #tabular-b73983854c .tabular-table td { text-align: left; vertical-align: top; } #tabular-b73983854c .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-b73983854c .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-b73983854c .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-b73983854c .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-b73983854c .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-b73983854c .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-b73983854c .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-b73983854c .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-b73983854c .tabular-table tbody tr td { border-top: none; } #tabular-b73983854c .tabular-band { text-align: center; } #tabular-b73983854c .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-b73983854c .tabular-subgroup-label { font-weight: 600; } #tabular-b73983854c .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-b73983854c .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-b73983854c .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-b73983854c .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-b73983854c .text-left { text-align: left; } #tabular-b73983854c .text-center { text-align: center; } #tabular-b73983854c .text-right { text-align: right; } #tabular-b73983854c .tabular-table thead th.text-left { text-align: left; } #tabular-b73983854c .tabular-table thead th.text-center { text-align: center; } #tabular-b73983854c .tabular-table thead th.text-right { text-align: right; } #tabular-b73983854c .tabular-table td.text-left { text-align: left; } #tabular-b73983854c .tabular-table td.text-center { text-align: center; } #tabular-b73983854c .tabular-table td.text-right { text-align: right; } #tabular-b73983854c .valign-top { vertical-align: top; } #tabular-b73983854c .valign-middle { vertical-align: middle; } #tabular-b73983854c .valign-bottom { vertical-align: bottom; } #tabular-b73983854c .tabular-footnote { font-size: 9pt; color: #495057; margin: .25rem 0; } #tabular-b73983854c .tabular-empty { font-style: italic; color: #6c757d; } #tabular-b73983854c .tabular-page-break-row { display: none; } #tabular-b73983854c { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-b73983854c .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-b73983854c .tabular-page-header, #tabular-b73983854c .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 8pt; color: var(--tabular-chrome-color); } #tabular-b73983854c .tabular-page-header { margin-bottom: 1rem; } #tabular-b73983854c .tabular-page-footer { margin-top: 1rem; } #tabular-b73983854c .tabular-page-header-left, #tabular-b73983854c .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-b73983854c .tabular-page-header-center, #tabular-b73983854c .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-b73983854c .tabular-page-header-right, #tabular-b73983854c .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-b73983854c .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-b73983854c .tabular-table tr { page-break-inside: avoid; } #tabular-b73983854c .tabular-page-header, #tabular-b73983854c .tabular-page-footer { display: none; } #tabular-b73983854c .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-b73983854c .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-b73983854c .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.3.1 Overall Summary of Adverse Events Safety Population   Category ``` # Sort the display rows Attach a `sort_spec` to a `tabular_spec`. The engine applies the sort before pagination, so `by` may reference any column in `spec@data` whether or not the column is declared in [`cols()`](https://vthanik.github.io/tabular/reference/cols.md). ## Usage ``` r sort_rows(.spec, by = character(), descending = FALSE) ``` ## Arguments - .spec: *The `tabular_spec` to attach the sort to.* `: required`. - by: *Ordered column names to sort by, in precedence order.* `: default character()`. Length 0 is accepted (no-op sort). May reference columns not declared in [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) — sort-only helper columns ride along through the engine. **Restriction:** Every entry must be a column in `spec@data`. Cannot reference arm columns produced by [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md); pivot upstream of the sort instead. Arm cells hold rendered stat strings (e.g. `"75.2 (8.3)"`) that do not order meaningfully. # Two-key hierarchical sort: SOC clusters by descending count, # each PT nested under its SOC. sort_rows(by = c("soc_n", "n_total"), descending = c(TRUE, TRUE)) - descending: *Per-key sort direction.* `: default FALSE`. `TRUE` sorts the corresponding key descending; length 1 recycles to every key. **Restriction:** No NAs. Length must be 1 or `length(by)`. **Tip:** For mixed-direction multi-key sorts, pass `length(by)` values; the engine inverts the `xtfrm` rank of each descending key and calls [`order()`](https://rdrr.io/r/base/order.html) once on all keys. ## Value *The updated `tabular_spec`.* Continue chaining with [`style()`](https://vthanik.github.io/tabular/reference/style.md), [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md), [`preset()`](https://vthanik.github.io/tabular/reference/preset.md), then render via [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) (or resolve without I/O via [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md)). ## Details **Replace, not stack.** A second `sort_rows()` call REPLACES the prior sort — sort is a single spec, not a stackable list. Call with no arguments to clear. **NA last, regardless of direction.** NA values in a sort key are placed at the end whether the key is ascending or descending (matching `order(..., na.last = TRUE)`). **Factor levels drive the order.** Factor columns sort by factor levels, not by the character label. The CDISC BOR ordering (`CR < PR < SD < NON-CR/NON-PD < PD < NE < MISSING`) survives a tabular pipeline without an explicit `mutate()` — coerce `stat_label` to a factor with the levels in clinical order upstream, then `sort_rows(by = "stat_label")` does the rest. ## See also **Sibling build verbs:** [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) / [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md), [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md), [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md), [`preset()`](https://vthanik.github.io/tabular/reference/preset.md). **Entry / terminal verbs:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md), [`emit()`](https://vthanik.github.io/tabular/reference/emit.md), [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md). ## Examples ``` r # ---- Example 1: AE table clustered by SOC, PTs nested by count ---- # # AE-by-SOC/PT table sorted so each SOC is followed immediately by # its own preferred terms, SOC clusters in descending subject-count # order. The sort runs on the bundled numeric helpers `soc_n` and # `n_total`, not the formatted `Total` text, which would sort # lexically ("14" < "171" < "29"). n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) tabular( cdisc_saf_aesocpt, titles = c( "Table 14.3.1", "Adverse Events by System Organ Class and Preferred Term", "Safety Population" ), footnotes = "Subjects are counted once per SOC and once per PT." ) |> cols( label = col_spec(label = "SOC / PT", indent = "indent_level"), soc = col_spec(visible = FALSE), row_type = col_spec(visible = FALSE), soc_n = col_spec(visible = FALSE), n_total = col_spec(visible = FALSE), placebo = col_spec(label = "Placebo\nN={n['placebo']}"), drug_50 = col_spec(label = "Drug 50\nN={n['drug_50']}"), drug_100 = col_spec(label = "Drug 100\nN={n['drug_100']}"), Total = col_spec(label = "Total\nN={n['Total']}") ) |> sort_rows(by = c("soc_n", "n_total"), descending = c(TRUE, TRUE)) #tabular-04d130afcc { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-04d130afcc .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-04d130afcc p { line-height: inherit; } #tabular-04d130afcc .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-04d130afcc .tabular-caption { margin: 0; padding: 0; } #tabular-04d130afcc .tabular-pad { margin: 0; line-height: 1; } #tabular-04d130afcc .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-04d130afcc .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-04d130afcc .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-04d130afcc .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-04d130afcc .tabular-table th, #tabular-04d130afcc .tabular-table td { padding: .18rem .6rem; } #tabular-04d130afcc .tabular-table td { text-align: left; vertical-align: top; } #tabular-04d130afcc .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-04d130afcc .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-04d130afcc .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-04d130afcc .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-04d130afcc .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-04d130afcc .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-04d130afcc .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-04d130afcc .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-04d130afcc .tabular-table tbody tr td { border-top: none; } #tabular-04d130afcc .tabular-band { text-align: center; } #tabular-04d130afcc .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-04d130afcc .tabular-subgroup-label { font-weight: 600; } #tabular-04d130afcc .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-04d130afcc .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-04d130afcc .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-04d130afcc .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-04d130afcc .text-left { text-align: left; } #tabular-04d130afcc .text-center { text-align: center; } #tabular-04d130afcc .text-right { text-align: right; } #tabular-04d130afcc .tabular-table thead th.text-left { text-align: left; } #tabular-04d130afcc .tabular-table thead th.text-center { text-align: center; } #tabular-04d130afcc .tabular-table thead th.text-right { text-align: right; } #tabular-04d130afcc .tabular-table td.text-left { text-align: left; } #tabular-04d130afcc .tabular-table td.text-center { text-align: center; } #tabular-04d130afcc .tabular-table td.text-right { text-align: right; } #tabular-04d130afcc .valign-top { vertical-align: top; } #tabular-04d130afcc .valign-middle { vertical-align: middle; } #tabular-04d130afcc .valign-bottom { vertical-align: bottom; } #tabular-04d130afcc .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-04d130afcc .tabular-empty { font-style: italic; color: #6c757d; } #tabular-04d130afcc .tabular-page-break-row { display: none; } #tabular-04d130afcc { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-04d130afcc .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-04d130afcc .tabular-page-header, #tabular-04d130afcc .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-04d130afcc .tabular-page-header { margin-bottom: 1rem; } #tabular-04d130afcc .tabular-page-footer { margin-top: 1rem; } #tabular-04d130afcc .tabular-page-header-left, #tabular-04d130afcc .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-04d130afcc .tabular-page-header-center, #tabular-04d130afcc .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-04d130afcc .tabular-page-header-right, #tabular-04d130afcc .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-04d130afcc .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-04d130afcc .tabular-table tr { page-break-inside: avoid; } #tabular-04d130afcc .tabular-page-header, #tabular-04d130afcc .tabular-page-footer { display: none; } #tabular-04d130afcc .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-04d130afcc .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-04d130afcc .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.3.1 Adverse Events by System Organ Class and Preferred Term Safety Population   SOC / PT ``` # Reusable style template (for house-style presets) Build a reusable, composable style template by chaining [`style()`](https://vthanik.github.io/tabular/reference/style.md) calls against a `tabular_style_template`. The template carries an ordered list of [`style_layer`](https://vthanik.github.io/tabular/reference/tabular_classes.md) records and can be attached to [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) / [`set_preset()`](https://vthanik.github.io/tabular/reference/set_preset.md) as the `.style` argument — every downstream [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) chain then inherits the template's layers via the engine cascade. ## Usage ``` r style_template() is_style_template(x) ``` ## Arguments - x: *Any R object.* The predicate inspects the class via [`inherits()`](https://rdrr.io/r/base/class.html); no other introspection is performed. ## Value *A `tabular_style_template`* — a small S3 list with a `layers` slot. Pipe through [`style()`](https://vthanik.github.io/tabular/reference/style.md) to add layers. ## Details **One verb, two surfaces.** The same `style(.spec_or_template, ..., .at = ...)` call that attaches a layer to a per-table spec also accumulates layers onto a template. Symmetric API — no need to learn a second function for the multi-table use case. **Submission workflow.** A submission typically renders 100–200 tables with one visual identity. Build the template once at the top of the submission script, pass it to `set_preset(.style = template)`, and every subsequent [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) produces output that inherits the same column-header rules, group-header bolding, title spacing, and outer-frame borders without a single per-table [`style()`](https://vthanik.github.io/tabular/reference/style.md) call. **Cascade order.** Engines apply layers low-to-high priority: backend defaults → session preset's `@style` → spec preset's `@style` → per-spec [`style()`](https://vthanik.github.io/tabular/reference/style.md) layers. Later layers override prior ones per attribute; NA fields leave the prior layer's value in place. ## See also **Style verb:** [`style()`](https://vthanik.github.io/tabular/reference/style.md) — the same verb chains onto a spec or a template. **Locations:** [`cells_body`](https://vthanik.github.io/tabular/reference/cells.md) — locations that name the *where* half of every layer. ## Examples ``` r # ---- Sponsor "house style" composed once ---- # # The result becomes the default look for every table rendered # against this preset. No per-table style() boilerplate. house <- style_template() |> style(background = "#DBE4F0", .at = cells_headers(level = -1)) |> style(color = "#1F3B5C", .at = cells_group_headers()) |> style( border_top = brdr("thick", "double"), border_bottom = brdr("thick", "double"), .at = cells_headers() ) |> style(blank_above = 1, blank_below = 1, .at = cells_title()) length(house$layers) #> [1] 4 # ---- Verify class ---- is_style_template(house) #> [1] TRUE ``` # Attach a style layer to a `tabular_spec` or `style_template` One verb, one cascade. Each `style()` call appends a single `style_layer` (location + style attributes) to the spec or template. Layers accumulate in declaration order; the engine merges them at render time so later layers win per attribute, NA-valued fields leave the prior layer intact. ## Usage ``` r style(.spec, ..., .at = cells_body()) ``` ## Arguments - .spec: *A `tabular_spec` OR a `tabular_style_template`.* `: required`. Dot-prefixed so R's partial argument matching cannot accidentally bind a short attribute name in `...` to the spec slot. When piping through `style_template() |> style(...)` layers accumulate onto the template instead of a spec. - ...: *Named style attributes.* At least one required. See the *Style attributes* section for the recognised names. - .at: *Location object selecting which surface the layer targets.* `: default cells_body()`. Build with one of the `cells_*()` constructors; see [`cells_body()`](https://vthanik.github.io/tabular/reference/cells.md) and siblings. Dot-prefixed (tidyverse convention) because it comes AFTER `...` — that way a user-passed style attribute can never collide with this arg's name. ## Value The updated `tabular_spec` (or `tabular_style_template`, when called against one). ## Locations The `.at` argument selects which surface the layer targets. Every region of the rendered page has a `cells_*()` constructor: - [`cells_body()`](https://vthanik.github.io/tabular/reference/cells.md) — body cells (default) - [`cells_headers()`](https://vthanik.github.io/tabular/reference/cells.md) — column header band - [`cells_group_headers()`](https://vthanik.github.io/tabular/reference/cells.md) — synthetic group-header rows - [`cells_title()`](https://vthanik.github.io/tabular/reference/cells.md) — title block - [`cells_subgroup_labels()`](https://vthanik.github.io/tabular/reference/cells.md) — subgroup banner row - [`cells_footnotes()`](https://vthanik.github.io/tabular/reference/cells.md) — footnote block - [`cells_pagehead()`](https://vthanik.github.io/tabular/reference/cells.md) — page-header band - [`cells_pagefoot()`](https://vthanik.github.io/tabular/reference/cells.md) — page-footer band - [`cells_table()`](https://vthanik.github.io/tabular/reference/cells.md) — table-wide regions (outer borders, body-row separators) Body filters live on [`cells_body()`](https://vthanik.github.io/tabular/reference/cells.md): `i = 1:3` for integer-index rows, `j = "Total"` for column-name targeting, `where = ` for a quosure-captured predicate evaluated against `spec@data`. A [`figure()`](https://vthanik.github.io/tabular/reference/figure.md) spec shares the chrome surfaces, so `style()` accepts a figure at [`cells_title()`](https://vthanik.github.io/tabular/reference/cells.md), [`cells_footnotes()`](https://vthanik.github.io/tabular/reference/cells.md), [`cells_pagehead()`](https://vthanik.github.io/tabular/reference/cells.md), and [`cells_pagefoot()`](https://vthanik.github.io/tabular/reference/cells.md) only; a figure has no body, column headers, or subgroup banner, so those locations raise an error. ## Style attributes Each layer carries a `style_node` built from `...`. Recognised attribute names: - Text — `bold`, `italic`, `underline`, `color`, `background`, `font_family`, `font_size` - Alignment — `halign` (`"left" / "center" / "right"`), `valign` (`"top" / "middle" / "bottom"`) - Borders — `border` (umbrella), `border_top`, `border_bottom`, `border_left`, `border_right` (each takes a [`brdr()`](https://vthanik.github.io/tabular/reference/brdr.md) value or the literal `"none"`); per-side scalars `border__{style,width,color}` for finer control - Padding — `padding` (a scalar applies to all four sides; a named vector `c(top = , right = , bottom = , left = )` sets each side); or the per-side scalars `padding_` directly - Spacing — `blank_above`, `blank_below` (integer blank lines above / below the block — for [`cells_title()`](https://vthanik.github.io/tabular/reference/cells.md) / [`cells_footnotes()`](https://vthanik.github.io/tabular/reference/cells.md) / [`cells_subgroup_labels()`](https://vthanik.github.io/tabular/reference/cells.md)) - Inline — `pretext`, `posttext` (literal text prepended / appended around the cell value) Unknown attribute names emit a [`cli::cli_warn`](https://cli.r-lib.org/reference/cli_abort.html) and drop from the constructed node; the engine never sees a foreign property. ## See also **Companion verbs:** [`cols()`](https://vthanik.github.io/tabular/reference/cols.md), [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), [`preset()`](https://vthanik.github.io/tabular/reference/preset.md), [`set_preset()`](https://vthanik.github.io/tabular/reference/set_preset.md). **Location constructors:** [`cells_body()`](https://vthanik.github.io/tabular/reference/cells.md), [`cells_headers()`](https://vthanik.github.io/tabular/reference/cells.md), [`cells_group_headers()`](https://vthanik.github.io/tabular/reference/cells.md), [`cells_title()`](https://vthanik.github.io/tabular/reference/cells.md), [`cells_subgroup_labels()`](https://vthanik.github.io/tabular/reference/cells.md), [`cells_footnotes()`](https://vthanik.github.io/tabular/reference/cells.md), [`cells_pagehead()`](https://vthanik.github.io/tabular/reference/cells.md), [`cells_pagefoot()`](https://vthanik.github.io/tabular/reference/cells.md), [`cells_table()`](https://vthanik.github.io/tabular/reference/cells.md). **Style values:** [`brdr()`](https://vthanik.github.io/tabular/reference/brdr.md), [`style_template()`](https://vthanik.github.io/tabular/reference/style_template.md). ## Examples ``` r # ---- AE table by SOC and PT with per-row indent + styled hierarchy ---- # `cdisc_saf_aesocpt` ships with `indent_level` (0 on overall/SOC rows, # 1 on PT rows); `col_spec(indent = "indent_level")` drives the # PT indent on the `label` column. tabular(cdisc_saf_aesocpt, titles = "Adverse Events by SOC / PT", footnotes = "") |> cols( label = col_spec(label = "Category", align = "left", indent = "indent_level"), soc = col_spec(visible = FALSE), row_type = col_spec(visible = FALSE), soc_n = col_spec(visible = FALSE), n_total = col_spec(visible = FALSE), placebo = col_spec(label = "Placebo", align = "decimal"), drug_50 = col_spec(label = "Drug 50", align = "decimal"), drug_100 = col_spec(label = "Drug 100", align = "decimal"), Total = col_spec(label = "Total", align = "decimal") ) |> # SOC summary rows bolded (depth 0 — flush) style(bold = TRUE, .at = cells_body(where = row_type == "soc")) |> # Overall row gets a light background style(background = "#f0f0f0", .at = cells_body(where = row_type == "overall")) #tabular-7434ee2d40 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-7434ee2d40 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-7434ee2d40 p { line-height: inherit; } #tabular-7434ee2d40 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-7434ee2d40 .tabular-caption { margin: 0; padding: 0; } #tabular-7434ee2d40 .tabular-pad { margin: 0; line-height: 1; } #tabular-7434ee2d40 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-7434ee2d40 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-7434ee2d40 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-7434ee2d40 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-7434ee2d40 .tabular-table th, #tabular-7434ee2d40 .tabular-table td { padding: .18rem .6rem; } #tabular-7434ee2d40 .tabular-table td { text-align: left; vertical-align: top; } #tabular-7434ee2d40 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-7434ee2d40 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-7434ee2d40 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-7434ee2d40 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-7434ee2d40 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-7434ee2d40 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-7434ee2d40 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-7434ee2d40 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-7434ee2d40 .tabular-table tbody tr td { border-top: none; } #tabular-7434ee2d40 .tabular-band { text-align: center; } #tabular-7434ee2d40 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-7434ee2d40 .tabular-subgroup-label { font-weight: 600; } #tabular-7434ee2d40 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-7434ee2d40 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-7434ee2d40 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-7434ee2d40 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-7434ee2d40 .text-left { text-align: left; } #tabular-7434ee2d40 .text-center { text-align: center; } #tabular-7434ee2d40 .text-right { text-align: right; } #tabular-7434ee2d40 .tabular-table thead th.text-left { text-align: left; } #tabular-7434ee2d40 .tabular-table thead th.text-center { text-align: center; } #tabular-7434ee2d40 .tabular-table thead th.text-right { text-align: right; } #tabular-7434ee2d40 .tabular-table td.text-left { text-align: left; } #tabular-7434ee2d40 .tabular-table td.text-center { text-align: center; } #tabular-7434ee2d40 .tabular-table td.text-right { text-align: right; } #tabular-7434ee2d40 .valign-top { vertical-align: top; } #tabular-7434ee2d40 .valign-middle { vertical-align: middle; } #tabular-7434ee2d40 .valign-bottom { vertical-align: bottom; } #tabular-7434ee2d40 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-7434ee2d40 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-7434ee2d40 .tabular-page-break-row { display: none; } #tabular-7434ee2d40 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-7434ee2d40 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-7434ee2d40 .tabular-page-header, #tabular-7434ee2d40 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-7434ee2d40 .tabular-page-header { margin-bottom: 1rem; } #tabular-7434ee2d40 .tabular-page-footer { margin-top: 1rem; } #tabular-7434ee2d40 .tabular-page-header-left, #tabular-7434ee2d40 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-7434ee2d40 .tabular-page-header-center, #tabular-7434ee2d40 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-7434ee2d40 .tabular-page-header-right, #tabular-7434ee2d40 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-7434ee2d40 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-7434ee2d40 .tabular-table tr { page-break-inside: avoid; } #tabular-7434ee2d40 .tabular-page-header, #tabular-7434ee2d40 .tabular-page-footer { display: none; } #tabular-7434ee2d40 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-7434ee2d40 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-7434ee2d40 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Adverse Events by SOC / PT   Category ``` # Partition the report by a variable Attach a `subgroup_spec` to a `tabular_spec`. At render time the engine partitions `spec@data` by the unique values of `by`, runs the full resolve pipeline per group, and concatenates the results. **A hard page break is inserted between groups** — every subgroup value starts on its own page. A centred banner line appears above the column-header rule on every page of the group (including continuation pages), matching the canonical submission page-layout convention. ## Usage ``` r subgroup( .spec, by, label = NULL, big_n = NULL, big_n_fmt = "\n(N={n})", keep_empty = FALSE ) ``` ## Arguments - .spec: *The `tabular_spec` to partition.* `: required`. - by: *Column name(s) to partition by.* `: required`. Must reference a column in `spec@data`. Length-0 (or `character(0)`) clears the partition. Matches the `by =` arg convention of [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md). **Multi-variable.** Pass `c("var1", "var2")` to cross on every combination present in the data. Multi-var partitions require an explicit `label` template (the single-var auto-default does not generalise). - label: *Banner template.* `: default NULL`. Glue-style template with `{column_name}` placeholders. `NULL` derives a default from the partition variable's `attr(data[[by]], "label")` (falling back to the column name). **Tip:** reference auxiliary columns to inline the BigN or any qualifier that is constant within group — e.g. `"Cohort: {cohort} (N = {n})"`. **Restriction:** Every `{col}` reference must be a column in `spec@data`. Unknown columns raise `tabular_error_subgroup_template_unknown_col`. - big_n: *Per-page BigN denominators.* ` | NULL: default NULL`. A table giving the `(N=x)` denominator each arm's header should show on each subgroup page. Each arm is named as it appears in the header — either a data column (the N rides that column's leaf label) **or** a [`headers()`](https://vthanik.github.io/tabular/reference/headers.md) band label (the N rides that spanner band). Ns are non-negative whole numbers; provide one per `by` combination present in the data. Accepts **either** shape: - **Wide** — the `by` column(s) plus one numeric column per arm (cells are the Ns). - **Long** — the `by` column(s) plus one arm-name column and one numeric N column, i.e. `dplyr::count()` / `summarise()` output used directly with no reshaping. # Wide: one column per arm. wide <- tibble::tribble( ~sex, ~placebo, ~drug_50, ~Total, "F", 24L, 9L, 42L, "M", 18L, 15L, 47L ) # Long: count()-style, pivoted internally. Equivalent to `wide`. long <- tibble::tribble( ~sex, ~arm, ~n, "F", "placebo", 24L, "F", "drug_50", 9L, "F", "Total", 42L, "M", "placebo", 18L, "M", "drug_50", 15L, "M", "Total", 47L ) spec |> subgroup(by = "sex", big_n = long) **Requirement:** band keying needs [`headers()`](https://vthanik.github.io/tabular/reference/headers.md) **before** `subgroup()` in the pipeline; each arm name must resolve to exactly one leaf XOR one band. Every missing per-page N is a call-time error, never a silently wrong denominator. **Note:** the per-arm N renders in every backend. The paged backends (RTF, PDF / LaTeX, DOCX) carry it on the column header that repeats on every page of the subgroup. HTML and Markdown are continuous (one stacked table, one header), so they instead emit a per-arm N row directly under each subgroup banner, the `(N=x)` aligned beneath its arm column. - big_n_fmt: *Per-page BigN template.* `: default "\n(N={n})"`. Appended to each arm's header label, with `{n}` substituted by that page/column's integer N. Only the `{n}` token is allowed; the default puts the N on its own line under the arm name. - keep_empty: *Retain zero-N crossings.* `: default FALSE`. When `FALSE` (the default), a `by` crossing combination with no data rows is dropped. When `TRUE`, it is retained and rendered as an empty-state page carrying its banner, so the report shows every combination explicitly. Only multi-variable crossings can produce empty combinations; a single-variable partition never does. **Note:** an empty group has no data row to read constant-within-group banner values from, so a `label` template that references a non-`by` column (e.g. an auxiliary BigN column) resolves that token to `NA` for the empty group; the `by`-column tokens always resolve. ## Value *The updated `tabular_spec`.* Continue chaining or resolve via [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md) / [`emit()`](https://vthanik.github.io/tabular/reference/emit.md). ## Details **Label is a glue-style template.** When `label` carries `{col}` placeholders, the engine substitutes each placeholder against the FIRST ROW of the group's filtered data — so any column whose value is constant within group (BigN, cohort descriptor, qualifier text) can ride into the banner. Columns that vary within group also resolve, but always to the first row's value; pre-compute aggregates upstream. **Default label** (when `label = NULL`, single var): the engine generates `": {}"`, so `subgroup(by = "cohort")` renders banners like `"Cohort: A"` and `"Cohort: B"` without further configuration. **Replace, not stack.** A second `subgroup()` call REPLACES the prior partition — subgroup is a single spec, not a stackable list. Passing `by = character(0)` clears the slot, though typical clinical pipelines set the partition once up front. **Display-side only.** `subgroup()` partitions a pre-summarised wide data frame; it does not aggregate, filter, or weight. The user supplies one summary row per displayed row per group; tabular's job is solely to lay them out with the per-group banner and page break. **Multi-variable crossing.** `by = c("SEX", "AGEGR1")` partitions on every combination present in the data (first variable varies slowest, matching [`expand.grid()`](https://rdrr.io/r/base/expand.grid.html) convention). An explicit `label` template is required for multi-var partitions since the single-var default `": {}"` does not generalise; raise `tabular_error_subgroup_label_required` otherwise. **Auto-hide of partition + template columns.** Every column named in `by`, plus every column referenced via a `{col}` placeholder in `label`, automatically flips to `visible = FALSE` at engine time. Users do not restate `col_spec(visible = FALSE)` inside [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) for these columns — mirroring the [`col_spec(indent = ...)`](https://vthanik.github.io/tabular/reference/col_spec.md) auto-hide ergonomic. ## See also **Pipeline siblings:** [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md), [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md). **Resolve / render:** [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md), [`emit()`](https://vthanik.github.io/tabular/reference/emit.md). ## Examples ``` r # ---- Example 1: Vital signs split into one page set per sex ---- # # The simplest partition: a single clinical variable. Each `sex` # value gets its own page set with a centred `Sex: ` banner # above the column-header rule on every page, separated by hard page # breaks. With no `label` template the banner uses the variable's # `label` attribute when present (set here), falling back to the # column name. Within each page, parameter nests visit nests the # statistic rows. vs <- cdisc_saf_subgroup attr(vs$sex, "label") <- "Sex" tabular( vs, titles = c( "Table 14.2.1", "Vital Signs by Visit", "Safety Population" ), footnotes = "Descriptive statistics by treatment arm." ) |> cols( sex_n = col_spec(visible = FALSE), paramcd = col_spec(visible = FALSE), param = col_spec(label = "Parameter"), visit = col_spec(label = "Visit"), stat_label = col_spec(label = "Statistic"), placebo = col_spec(label = "Placebo", align = "decimal"), drug_50 = col_spec(label = "Drug 50", align = "decimal"), drug_100 = col_spec(label = "Drug 100", align = "decimal"), Total = col_spec(label = "Total", align = "decimal") ) |> group_rows(by = c("param", "visit")) |> subgroup(by = "sex") #tabular-12edd6302c { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-12edd6302c .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-12edd6302c p { line-height: inherit; } #tabular-12edd6302c .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-12edd6302c .tabular-caption { margin: 0; padding: 0; } #tabular-12edd6302c .tabular-pad { margin: 0; line-height: 1; } #tabular-12edd6302c .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-12edd6302c .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-12edd6302c .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-12edd6302c .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-12edd6302c .tabular-table th, #tabular-12edd6302c .tabular-table td { padding: .18rem .6rem; } #tabular-12edd6302c .tabular-table td { text-align: left; vertical-align: top; } #tabular-12edd6302c .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-12edd6302c .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-12edd6302c .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-12edd6302c .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-12edd6302c .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-12edd6302c .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-12edd6302c .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-12edd6302c .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-12edd6302c .tabular-table tbody tr td { border-top: none; } #tabular-12edd6302c .tabular-band { text-align: center; } #tabular-12edd6302c .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-12edd6302c .tabular-subgroup-label { font-weight: 600; } #tabular-12edd6302c .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-12edd6302c .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-12edd6302c .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-12edd6302c .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-12edd6302c .text-left { text-align: left; } #tabular-12edd6302c .text-center { text-align: center; } #tabular-12edd6302c .text-right { text-align: right; } #tabular-12edd6302c .tabular-table thead th.text-left { text-align: left; } #tabular-12edd6302c .tabular-table thead th.text-center { text-align: center; } #tabular-12edd6302c .tabular-table thead th.text-right { text-align: right; } #tabular-12edd6302c .tabular-table td.text-left { text-align: left; } #tabular-12edd6302c .tabular-table td.text-center { text-align: center; } #tabular-12edd6302c .tabular-table td.text-right { text-align: right; } #tabular-12edd6302c .valign-top { vertical-align: top; } #tabular-12edd6302c .valign-middle { vertical-align: middle; } #tabular-12edd6302c .valign-bottom { vertical-align: bottom; } #tabular-12edd6302c .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-12edd6302c .tabular-empty { font-style: italic; color: #6c757d; } #tabular-12edd6302c .tabular-page-break-row { display: none; } #tabular-12edd6302c { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-12edd6302c .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-12edd6302c .tabular-page-header, #tabular-12edd6302c .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-12edd6302c .tabular-page-header { margin-bottom: 1rem; } #tabular-12edd6302c .tabular-page-footer { margin-top: 1rem; } #tabular-12edd6302c .tabular-page-header-left, #tabular-12edd6302c .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-12edd6302c .tabular-page-header-center, #tabular-12edd6302c .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-12edd6302c .tabular-page-header-right, #tabular-12edd6302c .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-12edd6302c .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-12edd6302c .tabular-table tr { page-break-inside: avoid; } #tabular-12edd6302c .tabular-page-header, #tabular-12edd6302c .tabular-page-footer { display: none; } #tabular-12edd6302c .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-12edd6302c .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-12edd6302c .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.2.1 Vital Signs by Visit Safety Population   Statistic ``` # tabular S7 classes S7 class definitions backing tabular's display-side IR. Users do not construct these directly except for [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md); every other class is built and chained by the verb pipeline ([`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) -\> [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) -\> [`headers()`](https://vthanik.github.io/tabular/reference/headers.md) -\> [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md) -\> [`style()`](https://vthanik.github.io/tabular/reference/style.md) -\> [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md) -\> [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) -\> [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md) / [`emit()`](https://vthanik.github.io/tabular/reference/emit.md)). ## Details The class set is intentionally small (~11 concepts) so the IR fits in one mental model: | | | | |----|----|----| | class | role | constructor | | `tabular_spec` | root container; carries data + every other spec slot | [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) | | `col_spec` | per-column DSL (label, format, align, width, ...) | [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) | | `header_node` | one node in the multi-level header tree | internal — built by [`headers()`](https://vthanik.github.io/tabular/reference/headers.md) | | `sort_spec` | sort keys + per-key direction | internal — built by [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md) | | `row_group_spec` | row-grouping plan (keys + per-key display / skip) | internal — built by [`group_rows()`](https://vthanik.github.io/tabular/reference/group_rows.md) | | `style_node` | one resolved style attribute set (per-cell) | internal — built by [`style()`](https://vthanik.github.io/tabular/reference/style.md) | | `style_layer` | one `tabular_location` + style_node | internal — built by [`style()`](https://vthanik.github.io/tabular/reference/style.md) | | `style_spec` | the cascade root (defaults + cols + headers + layers) | internal — built by [`style()`](https://vthanik.github.io/tabular/reference/style.md) | | `pagination_spec` | page-split policy (keep_together, panels, floors) | internal — built by [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md) | | `preset_spec` | render geometry (paper, orientation, font, margins) | internal — built by [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) | | `inline_ast` | parsed inline-formatting AST (runs of bold / sup / …) | internal — built by `.parse_inline()` | | `tabular_grid` | resolved per-page cells + ASTs + styles + headers | [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md) | Every spec slot is typed: a verb that would mutate a slot to an invalid value fails at construction time (the S7 validator runs as a last-line defense behind the cli-friendly verb-level validators). **Class predicates.** Each class has a matching `is_()` predicate; see [`tabular_predicates`](https://vthanik.github.io/tabular/reference/tabular_predicates.md) for the full list. ## See also **Class predicates:** [`tabular_predicates`](https://vthanik.github.io/tabular/reference/tabular_predicates.md). **Pipeline entry verbs:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md), [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md), [`emit()`](https://vthanik.github.io/tabular/reference/emit.md). # Test for tabular S7 class instances Class predicates returning a single logical indicating whether `x` inherits from the corresponding tabular S7 class. Use them to gate user-side code that branches on what a verb has returned, to write defensive helpers that wrap tabular pipelines, or to assert intermediate shapes during pipeline debugging. ## Usage ``` r is_tabular_spec(x) is_figure_spec(x) is_tabular_grid(x) is_col_spec(x) is_header_node(x) is_sort_spec(x) is_row_group_spec(x) is_style_node(x) is_style_layer(x) is_style_spec(x) is_pagination_spec(x) is_preset_spec(x) is_subgroup_spec(x) is_inline_ast(x) ``` ## Arguments - x: *Object to test.* Any R value. Each predicate returns `TRUE` if `x` inherits from the named class, `FALSE` otherwise. ## Value *A single `TRUE` / `FALSE`.* Use in `if` / `stopifnot` guards, or chain into validation helpers. *A length-1 `logical`* — `TRUE` or `FALSE`. Never `NA`. ## Details Twelve predicates cover the full S7 surface: | | | | |----|----|----| | predicate | tests for | produced by | | `is_tabular_spec()` | `tabular_spec` | [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md) and every build verb | | `is_tabular_grid()` | `tabular_grid` | [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md) | | `is_col_spec()` | `col_spec` | [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md) | | `is_header_node()` | `header_node` | [`headers()`](https://vthanik.github.io/tabular/reference/headers.md) (internal nodes) | | `is_sort_spec()` | `sort_spec` | [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md) | | `is_style_node()` | `style_node` | [`style()`](https://vthanik.github.io/tabular/reference/style.md) (per-cell style) | | `is_style_layer()` | `style_layer` | [`style()`](https://vthanik.github.io/tabular/reference/style.md) (one per call) | | `is_style_spec()` | `style_spec` | [`style()`](https://vthanik.github.io/tabular/reference/style.md) (the cascade root) | | `is_pagination_spec()` | `pagination_spec` | [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md) | | `is_preset_spec()` | `preset_spec` | [`preset()`](https://vthanik.github.io/tabular/reference/preset.md), [`set_preset()`](https://vthanik.github.io/tabular/reference/set_preset.md) | | `is_subgroup_spec()` | `subgroup_spec` | [`subgroup()`](https://vthanik.github.io/tabular/reference/subgroup.md) | | `is_inline_ast()` | `inline_ast` | `.parse_inline()` (post-format) | Predicates never error — they return `FALSE` for `NULL`, vectors, objects of any other class, and S7 objects from other packages. Use them at any layer of a user's pipeline without a defensive [`tryCatch()`](https://rdrr.io/r/base/conditions.html). ## See also **Class definitions:** [`tabular_classes`](https://vthanik.github.io/tabular/reference/tabular_classes.md). **Verbs producing each class:** [`tabular()`](https://vthanik.github.io/tabular/reference/tabular.md), [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md), [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md), [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md), [`preset()`](https://vthanik.github.io/tabular/reference/preset.md), [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md). ## Examples ``` r # ---- Example 1: Gate user-side code on the spec class ---- # # A user-side helper that pre-validates its input before piping # into a downstream tabular chain. The predicate returns FALSE # for any non-spec input without raising, so the helper can emit # a friendlier error than tabular's own S7 validator would. add_safety_footnote <- function(spec) { if (!is_tabular_spec(spec)) { stop("`spec` must be a tabular_spec; build one with tabular().") } spec } demo <- tabular(cdisc_saf_demo, titles = "Demographics") is_tabular_spec(demo) # TRUE #> [1] TRUE is_tabular_spec("not a spec") # FALSE — does not raise #> [1] FALSE add_safety_footnote(demo) #tabular-763eb95427 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-763eb95427 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-763eb95427 p { line-height: inherit; } #tabular-763eb95427 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-763eb95427 .tabular-caption { margin: 0; padding: 0; } #tabular-763eb95427 .tabular-pad { margin: 0; line-height: 1; } #tabular-763eb95427 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-763eb95427 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-763eb95427 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-763eb95427 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-763eb95427 .tabular-table th, #tabular-763eb95427 .tabular-table td { padding: .18rem .6rem; } #tabular-763eb95427 .tabular-table td { text-align: left; vertical-align: top; } #tabular-763eb95427 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-763eb95427 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-763eb95427 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-763eb95427 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-763eb95427 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-763eb95427 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-763eb95427 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-763eb95427 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-763eb95427 .tabular-table tbody tr td { border-top: none; } #tabular-763eb95427 .tabular-band { text-align: center; } #tabular-763eb95427 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-763eb95427 .tabular-subgroup-label { font-weight: 600; } #tabular-763eb95427 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-763eb95427 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-763eb95427 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-763eb95427 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-763eb95427 .text-left { text-align: left; } #tabular-763eb95427 .text-center { text-align: center; } #tabular-763eb95427 .text-right { text-align: right; } #tabular-763eb95427 .tabular-table thead th.text-left { text-align: left; } #tabular-763eb95427 .tabular-table thead th.text-center { text-align: center; } #tabular-763eb95427 .tabular-table thead th.text-right { text-align: right; } #tabular-763eb95427 .tabular-table td.text-left { text-align: left; } #tabular-763eb95427 .tabular-table td.text-center { text-align: center; } #tabular-763eb95427 .tabular-table td.text-right { text-align: right; } #tabular-763eb95427 .valign-top { vertical-align: top; } #tabular-763eb95427 .valign-middle { vertical-align: middle; } #tabular-763eb95427 .valign-bottom { vertical-align: bottom; } #tabular-763eb95427 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-763eb95427 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-763eb95427 .tabular-page-break-row { display: none; } #tabular-763eb95427 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-763eb95427 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-763eb95427 .tabular-page-header, #tabular-763eb95427 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-763eb95427 .tabular-page-header { margin-bottom: 1rem; } #tabular-763eb95427 .tabular-page-footer { margin-top: 1rem; } #tabular-763eb95427 .tabular-page-header-left, #tabular-763eb95427 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-763eb95427 .tabular-page-header-center, #tabular-763eb95427 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-763eb95427 .tabular-page-header-right, #tabular-763eb95427 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-763eb95427 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-763eb95427 .tabular-table tr { page-break-inside: avoid; } #tabular-763eb95427 .tabular-page-header, #tabular-763eb95427 .tabular-page-footer { display: none; } #tabular-763eb95427 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-763eb95427 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-763eb95427 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Demographics   variable ``` # tabular: Render Tables, Listings, and Figures for Clinical Submissions Render clinical submission tables, listings, and figures to 'RTF', 'LaTeX', 'Typst', 'HTML', 'PDF', and 'DOCX' from pre-summarised data frames, with no external 'Java' or 'SAS' dependency. Features include decimal alignment via font metrics, multi-level column headers with passthrough leaves, predicate-targeted cell styling, footnotes, group-aware pagination, and figures that wrap a plot or image in the same page chrome as a table. Built for Clinical Data Interchange Standards Consortium (CDISC) Analysis Data Model (ADaM) workflows and regulatory submissions to agencies such as the Food and Drug Administration (FDA), European Medicines Agency (EMA), and Pharmaceuticals and Medical Devices Agency (PMDA). ## See also Useful links: - - - Report bugs at ## Author **Maintainer**: Vignesh Thanikachalam # Start a tabular display Wrap a pre-summarised data frame into a `tabular_spec` ready for the verb chain. `tabular()` is the entry verb — it owns the `data`, `titles`, and `footnotes` slots; every downstream verb ([`cols()`](https://vthanik.github.io/tabular/reference/cols.md), [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md), [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md), [`preset()`](https://vthanik.github.io/tabular/reference/preset.md)) returns an updated spec for further chaining, terminating in [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) (write to file) or [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md) (resolve without writing). ## Usage ``` r tabular(data, titles = NULL, footnotes = NULL, empty_text = NULL) ``` ## Arguments - data: *The display rows.* `: required`. Pre-summarised wide-format data; tibbles, data.tables, and arrow tables are coerced via [`as.data.frame()`](https://rdrr.io/r/base/as.data.frame.html). Factor columns are preserved (their levels drive [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md)). **Restriction:** At least one column; column names must be unique. Zero rows is accepted (engine renders a "No data" stub). **Interaction:** The `cards`-format counterparts (`cdisc_saf_demo_ard`, `cdisc_saf_aesocpt_ard`) are NOT accepted directly; pipe through [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) first. - titles: *Page-title block, one element per row.* ` | NULL: default NULL`. Each element renders on its own centred line; embedded `\n` wraps within that row. The backend collapses unused rows so the column-header band sits flush against the lowest used title. **Restriction:** No NAs. Each element supports glue-style `{expr}` interpolation: braces are evaluated as R code in the calling environment at build time, e.g. `"N total = {sum(n)}"`. Double a brace (`{{` or `}}`) for a literal one. An [`md()`](https://vthanik.github.io/tabular/reference/md.md) / [`html()`](https://vthanik.github.io/tabular/reference/html.md) element is passed through without interpolation. # Canonical 3-line title block with BigN-qualified population. n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) titles = c( "Table 14.3.1", "Adverse Events by System Organ Class and Preferred Term", "Safety Population" ) - footnotes: *Page-footnote block, one element per row.* ` | NULL: default NULL`. User-supplied prose rows only; the backend appends its own program-path / program-name / timestamp band below them at render time. **Restriction:** No NAs. Each element supports glue-style `{expr}` interpolation (see `titles`). # Canonical 3-line footnote block. footnotes = c( "Subjects are counted once per SOC and once per PT.", "Percentages based on N per treatment group.", "TEAE = treatment-emergent adverse event." ) - empty_text: *Placeholder shown when `data` has zero rows.* `: default NULL`. When the display resolves to no data rows, the backends still emit the full page chrome and — when a column structure is present — the column headers, then place this message in the body where the rows would sit. `NULL` (the default) inherits the house-style wording from `preset(empty_text = ...)` when set, falling back to the built-in `"No data available to report"`. Pass any sponsor or study wording (a localized string, "No subjects met the criteria for this table.", a protocol-qualified line) to override per table; glue `{expr}` interpolation and [`md()`](https://vthanik.github.io/tabular/reference/md.md) / [`html()`](https://vthanik.github.io/tabular/reference/html.md) are honoured, exactly like a title line. The message renders as a single horizontally centred row in the table body, where the first data row would otherwise sit. ## Value *A `tabular_spec` S7 object.* Pipe it into [`cols()`](https://vthanik.github.io/tabular/reference/cols.md), [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md), [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md), and [`preset()`](https://vthanik.github.io/tabular/reference/preset.md) to build the display, then into [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) to render or [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md) to resolve without writing. ## Details **Pre-summarised input contract.** `data` is one row per displayed row of the final table. `tabular()` does not aggregate, filter, weight, or generate subtotal rows — those happen upstream in `cards`, `dplyr`, or SAS. If the upstream is a long `cards::ard_stack()` ARD, pipe through [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) first to land in the wide shape `tabular()` accepts. **Multi-line titles and footnotes by contract.** Clinical tables routinely carry 2-4 title rows and 1-4 user footnote rows. Pass each row as one element of the character vector; the backend renders each element on its own line, collapsing unused rows so the column-header band sits flush against the lowest used title. ## See also **Downstream build verbs:** [`cols()`](https://vthanik.github.io/tabular/reference/cols.md) / [`col_spec()`](https://vthanik.github.io/tabular/reference/col_spec.md), [`headers()`](https://vthanik.github.io/tabular/reference/headers.md), [`sort_rows()`](https://vthanik.github.io/tabular/reference/sort_rows.md), [`style()`](https://vthanik.github.io/tabular/reference/style.md), [`paginate()`](https://vthanik.github.io/tabular/reference/paginate.md), [`preset()`](https://vthanik.github.io/tabular/reference/preset.md). **Terminal verbs:** [`emit()`](https://vthanik.github.io/tabular/reference/emit.md) (write), [`as_grid()`](https://vthanik.github.io/tabular/reference/as_grid.md) (resolve without I/O). **Input helper:** [`pivot_across()`](https://vthanik.github.io/tabular/reference/pivot_across.md) (cards ARD -\> wide). **Demo data:** `cdisc_saf_demo`, `cdisc_saf_aesocpt`, `cdisc_eff_resp`, `cdisc_saf_n`, `cdisc_eff_n`. ## Examples ``` r # ---- Example 1: Adverse-event table by SOC and Preferred Term ---- # # The regulatory work-horse layout: AE-by-SOC/PT with the # canonical 3-line title block (table number, description, # population qualifier with BigN drawn inline from `cdisc_saf_n`) and a # two-line footnote block explaining the denominator. The # downstream pipeline hides the hierarchy markers (`row_type`, # `soc_n`, `n_total`) but keeps them in the data so `sort_rows()` # can arrange SOCs and PTs in descending order of subject count. # The dataset already ships `n_total` and `soc_n`; here we slice to # the overall row plus the two highest-incidence SOCs to keep the # preview compact. ae <- cdisc_saf_aesocpt keep_soc <- head(unique(ae$soc[ae$row_type == "soc"]), 2L) ae <- ae[ae$row_type == "overall" | ae$soc %in% keep_soc, ] n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short) tabular( ae, titles = c( "Table 14.3.1", "Adverse Events by System Organ Class and Preferred Term", "Safety Population" ), footnotes = c( "Subjects are counted once per SOC and once per PT.", "Percentages based on N per treatment group." ) ) |> cols( label = col_spec(label = "SOC / PT", indent = "indent_level"), soc = col_spec(visible = FALSE), soc_n = col_spec(visible = FALSE), row_type = col_spec(visible = FALSE), n_total = col_spec(visible = FALSE), placebo = col_spec(label = "Placebo\nN={n['placebo']}"), drug_50 = col_spec(label = "Drug 50\nN={n['drug_50']}"), drug_100 = col_spec(label = "Drug 100\nN={n['drug_100']}"), Total = col_spec(label = "Total\nN={n['Total']}") ) |> sort_rows(by = c("soc_n", "n_total"), descending = c(TRUE, TRUE)) #tabular-44ce677a75 { font-family: "Courier New", Courier, "Nimbus Mono PS", "Liberation Mono", monospace; color: #212529; margin: 1.5rem; font-size: 10pt; line-height: 1.3; } #tabular-44ce677a75 .tabular-content { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-44ce677a75 p { line-height: inherit; } #tabular-44ce677a75 .tabular-title { font-size: 10pt; font-weight: 600; text-align: center; margin: .2rem 0; } #tabular-44ce677a75 .tabular-caption { margin: 0; padding: 0; } #tabular-44ce677a75 .tabular-pad { margin: 0; line-height: 1; } #tabular-44ce677a75 .tabular-table-wrap { overflow-x: auto; margin: .2rem 0; } #tabular-44ce677a75 .tabular-table { border-collapse: collapse; font-size: 10pt; margin: 0 auto; } #tabular-44ce677a75 .tabular-table { --bs-table-bg: transparent; --bs-table-accent-bg: transparent; --bs-table-border-color: transparent; width: auto; } #tabular-44ce677a75 .tabular-table > :not(caption) > * > * { border-bottom-width: 0; box-shadow: none; } #tabular-44ce677a75 .tabular-table th, #tabular-44ce677a75 .tabular-table td { padding: .18rem .6rem; } #tabular-44ce677a75 .tabular-table td { text-align: left; vertical-align: top; } #tabular-44ce677a75 .tabular-table thead th { font-weight: 600; text-align: center; vertical-align: bottom; } #tabular-44ce677a75 .tabular-table thead tr:first-child th { border-top: 0.5pt solid #212529; } #tabular-44ce677a75 .tabular-table thead tr:last-child th { border-bottom: 0.5pt solid #212529; } #tabular-44ce677a75 .tabular-table thead .tabular-band { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-44ce677a75 .tabular-table thead .tabular-band.tabular-band-flush-left { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0.5em), transparent calc(100% - 0.5em)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-44ce677a75 .tabular-table thead .tabular-band.tabular-band-flush-right { background-image: linear-gradient(to right, transparent 0.5em, #adb5bd 0.5em, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-44ce677a75 .tabular-table thead .tabular-band.tabular-band-flush-both { background-image: linear-gradient(to right, transparent 0px, #adb5bd 0px, #adb5bd calc(100% - 0px), transparent calc(100% - 0px)); background-repeat: no-repeat; background-position: left bottom; background-size: 100% 0.5pt; } #tabular-44ce677a75 .tabular-table tbody tr:last-child td { border-bottom: 0.5pt solid #212529; } #tabular-44ce677a75 .tabular-table tbody tr td { border-top: none; } #tabular-44ce677a75 .tabular-band { text-align: center; } #tabular-44ce677a75 .tabular-subgroup td { text-align: center; vertical-align: middle; padding: .15rem .6rem; } #tabular-44ce677a75 .tabular-subgroup-label { font-weight: 600; } #tabular-44ce677a75 .tabular-subgroup-bign td { text-align: center; border-bottom: 1px solid #adb5bd; } #tabular-44ce677a75 .tabular-subgroup-closed td { border-bottom: 1px solid #adb5bd; } #tabular-44ce677a75 .tabular-group-header td { font-weight: 600; text-align: left; padding-top: .55rem; } #tabular-44ce677a75 .tabular-blank-row td { padding: 0; border: none; height: 1em; line-height: 1em; } #tabular-44ce677a75 .text-left { text-align: left; } #tabular-44ce677a75 .text-center { text-align: center; } #tabular-44ce677a75 .text-right { text-align: right; } #tabular-44ce677a75 .tabular-table thead th.text-left { text-align: left; } #tabular-44ce677a75 .tabular-table thead th.text-center { text-align: center; } #tabular-44ce677a75 .tabular-table thead th.text-right { text-align: right; } #tabular-44ce677a75 .tabular-table td.text-left { text-align: left; } #tabular-44ce677a75 .tabular-table td.text-center { text-align: center; } #tabular-44ce677a75 .tabular-table td.text-right { text-align: right; } #tabular-44ce677a75 .valign-top { vertical-align: top; } #tabular-44ce677a75 .valign-middle { vertical-align: middle; } #tabular-44ce677a75 .valign-bottom { vertical-align: bottom; } #tabular-44ce677a75 .tabular-footnote { font-size: 10pt; color: #495057; margin: .25rem 0; } #tabular-44ce677a75 .tabular-empty { font-style: italic; color: #6c757d; } #tabular-44ce677a75 .tabular-page-break-row { display: none; } #tabular-44ce677a75 { --tabular-border-color: #212529; --tabular-border-color-muted: #adb5bd; --tabular-chrome-color: #495057; } #tabular-44ce677a75 .tabular-chrome-wrap { width: fit-content; max-width: 100%; margin: 0 auto; } #tabular-44ce677a75 .tabular-page-header, #tabular-44ce677a75 .tabular-page-footer { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: .5rem 0; font-size: 9pt; color: var(--tabular-chrome-color); } #tabular-44ce677a75 .tabular-page-header { margin-bottom: 1rem; } #tabular-44ce677a75 .tabular-page-footer { margin-top: 1rem; } #tabular-44ce677a75 .tabular-page-header-left, #tabular-44ce677a75 .tabular-page-footer-left { flex: 1; text-align: left; } #tabular-44ce677a75 .tabular-page-header-center, #tabular-44ce677a75 .tabular-page-footer-center { flex: 1; text-align: center; } #tabular-44ce677a75 .tabular-page-header-right, #tabular-44ce677a75 .tabular-page-footer-right { flex: 1; text-align: right; } @media print { #tabular-44ce677a75 .tabular-table-wrap { overflow-x: visible; margin: 0; } #tabular-44ce677a75 .tabular-table tr { page-break-inside: avoid; } #tabular-44ce677a75 .tabular-page-header, #tabular-44ce677a75 .tabular-page-footer { display: none; } #tabular-44ce677a75 .tabular-page-break-row { display: table-row; page-break-before: always; break-before: page; } #tabular-44ce677a75 .tabular-page-break-row td { border: none; padding: 0; height: 0; line-height: 0; font-size: 0; } #tabular-44ce677a75 .tabular-table + .tabular-table { page-break-before: always; break-before: page; } }   Table 14.3.1 Adverse Events by System Organ Class and Preferred Term Safety Population   SOC / PT ``` --- name: tabular description: > Render clinical submission tables, listings, and figures to RTF, HTML, DOCX, PDF (LaTeX or Typst engine), LaTeX, Typst, and Markdown from R. Use when writing R code that uses the tabular package. license: MIT compatibility: Requires R >=4.3. --- # tabular Render tables, listings, and figures for clinical submissions, natively to RTF, HTML, DOCX, PDF, LaTeX, Typst, and Markdown from a single immutable spec, with no Java, SAS, or Office dependency. PDF compiles through LaTeX when a TeX is installed, or through the typst engine (bundled with Quarto ≥ 1.4) on TeX-less machines. ## Installation ```r install.packages("tabular") # development version: # pak::pak("vthanik/tabular") ``` ## Mental model tabular is **display-only**: it never aggregates, filters, weights, or computes statistics. You bring a **pre-summarised, wide data frame** (one input row = one display row) and pipe a `tabular()` object through verbs; each verb returns a new immutable spec. Nothing renders until `emit()`, which picks the backend from the file extension (`.rtf` `.html` `.docx` `.tex` `.typ` `.pdf` `.md`) or an explicit `format=`. A `.pdf` target probes LaTeX first and falls back to the typst engine; force one with `format = "latex"` or `format = "typst"`. ```r library(tabular) data(cdisc_saf_demo, package = "tabular") tabular(cdisc_saf_demo, titles = c("Table 14-2.01", "Demographics", "ITT")) |> cols(variable = "", stat_label = "") |> group_rows(by = "variable") |> emit("table.rtf") ``` ## API overview ### Table creation Wrap a pre-summarised wide data frame, a cards ARD, a plot, or an image into a spec. - `tabular`: Wrap a wide data frame into a `tabular_spec` - `pivot_across`: Pivot a long ARD / tidy frame into the wide display shape - `figure`: Wrap a ggplot, base plot, drawing function, or image into a `figure_spec` ### Column specification Describe each column's role, label, width, alignment, and visibility. - `cols`: Assign a `col_spec` to one or more columns (a bare string is label shorthand; `.hide` hides columns) - `col_spec`: Build a per-column specification (`label`, `width`, `align`, `visible`, `indent`) - `cols_apply`: Apply one `col_spec` across many columns by predicate - `group_rows`: Declare the table-level row grouping (`by` keys outer to inner; scalar `display` = `"section"` / `"collapse"` / `"repeat"`; `skip` = TRUE / FALSE / a subset of `by`) ### Column headers Build multi-level column spanners above the data columns. - `headers`: Add multi-level column header bands / spanners ### Row ordering and grouping Order rows on a (usually hidden) key and split the body into banner sections. - `sort_rows`: Order display rows by one or more columns - `subgroup`: Split the body into banner-led subgroup sections ### Pagination Split a long table across pages for the paged backends (RTF, DOCX, PDF). - `paginate`: Configure page splitting, repeated chrome, and continuation markers ### Styling and themes Cosmetic control. `preset()` is pipe-scoped; `set_preset()` is session-scoped (the ggplot2 `theme()` / `theme_set()` split). - `style`: Apply styling to predicate-targeted locations (via `.at = cells_*()`) - `style_template`: Build a reusable named style template - `preset`: Set cosmetic defaults on a spec (`alignment`, `rules`, `fonts`, `colors`, `padding`, ...) - `preset_minimal`: The one bundled minimal theme helper - `set_preset`: Set session-wide cosmetic defaults - `get_preset`: Read the active preset - `brdr`: Build a border / rule line spec ### Location targeting Select precise table regions for `style(.at = ...)`. - `cells_body` - `cells_headers` - `cells_title` - `cells_footnotes` - `cells_group_headers` - `cells_subgroup_labels` - `cells_pagehead` - `cells_pagefoot` - `cells_table` ### Inline text and footnotes - `md`: Interpret label text as Markdown - `html`: Interpret label text as HTML - `footnote`: Attach a footnote (with an optional reference marker) to a location ### Rendering and export - `emit`: Render the spec to a file (backend chosen by extension or `format=`) - `as_grid`: Resolve a spec to its finalized `tabular_grid` (the pre-backend IR) ### Toolchain and font diagnostics - `check_fonts`: Verify the fonts a spec needs are available for decimal alignment - `check_latex`: Verify the LaTeX toolchain for `.pdf` (LaTeX engine) / `.tex` output - `check_typst`: Verify the Typst toolchain for `.pdf` (typst engine) / `.typ` output — binary, version floor, and the font chain PDFs render in (no TeX needed) ### Predicates Class checks for the spec types. - `is_tabular_spec`, `is_figure_spec`, `is_col_spec`, `is_header_node` - `is_row_group_spec`, `is_sort_spec`, `is_subgroup_spec`, `is_pagination_spec` - `is_preset_spec`, `is_style_spec`, `is_style_layer`, `is_style_node`, `is_style_template` - `is_brdr`, `is_inline_ast`, `is_tabular_grid`, `is_tabular_location` ### Built-in datasets Pre-summarised CDISC demo frames used throughout the examples. Use these instead of inventing toy data. - `cdisc_saf_demo`, `cdisc_saf_n`: demographics summary + BigN counts - `cdisc_saf_ae`, `cdisc_saf_aesocpt`: adverse events overall / by SOC and PT - `cdisc_saf_vital`, `cdisc_saf_subgroup`: vitals by visit, subgroup split - `cdisc_eff_resp`, `cdisc_eff_n`, `cdisc_eff_estimates`: efficacy response, BigN, estimates - `cdisc_saf_demo_ard`, `cdisc_saf_aesocpt_ard`: cards ARD variants for `pivot_across()` ## Conventions (don't fight these) - **Sort on a hidden numeric key, never display text** — `"217 (85.4)"` sorts lexically; derive an integer key, hide it with `col_spec(visible = FALSE)`, then `sort_rows(by = key)`. - **BigN goes inline in the label string**, not a field. - **`group_rows()` sections auto-indent their child rows** — don't also add `col_spec(indent = )` on the stub (double indent). - **Titles and footnotes are multi-line** — pass a `character()` of any length. - Cosmetic knobs are named lists keyed by surface; per-surface specs are flat `c(...)` vectors, validated strictly at call time. ## Resources - [Full documentation](https://vthanik.github.io/tabular/) - [llms.txt](https://vthanik.github.io/tabular/llms.txt) — Indexed reference for LLMs - [llms-full.txt](https://vthanik.github.io/tabular/llms-full.txt) — Full documentation for LLMs