Package {tplyr2}


Title: A Grammar of Clinical Summary Tables
Version: 0.2.0
Description: Implements a grammar of summary data for clinical reports. Clinical summary tables are decomposed into modular layers, each representing an independent summary block. Supports count, descriptive statistics, and shift layer types with a declarative spec-based API built on data.table for performance.
License: MIT + file LICENSE
URL: https://github.com/atorus-research/tplyr2, https://atorus-research.github.io/tplyr2/
BugReports: https://github.com/atorus-research/tplyr2/issues
Encoding: UTF-8
Depends: R (≥ 4.1.0)
Imports: data.table, jsonlite, purrr, rlang, stringr
Suggests: testthat (≥ 3.0.0), withr, yaml, knitr, rmarkdown
VignetteBuilder: knitr
Config/testthat/edition: 3
LazyData: true
Config/roxygen2/version: 8.0.0
NeedsCompilation: no
Packaged: 2026-08-02 14:12:57 UTC; mstackhouse
Author: Mike Stackhouse [aut, cre]
Maintainer: Mike Stackhouse <mike.stackhouse@atorusresearch.com>
Repository: CRAN
Date/Publication: 2026-08-08 12:00:02 UTC

tplyr2: A Grammar of Clinical Summary Tables

Description

Implements a grammar of summary data for clinical reports. Clinical summary tables are decomposed into modular layers, each representing an independent summary block. Supports count, descriptive statistics, and shift layer types with a declarative spec-based API built on data.table for performance.

Author(s)

Maintainer: Mike Stackhouse mike.stackhouse@atorusresearch.com

Authors:

See Also

Useful links:


Attach single-proportion CI columns to a long count table

Description

Adds ci_lower/ci_upper (from n/total) and, when the distinct columns are present, distinct_ci_lower/distinct_ci_upper (from distinct_n/distinct_total). Bounds are stored on the percentage scale (proportion times 100) to match the pct/distinct_pct statistics.

Usage

add_count_ci(dt, settings)

Arguments

dt

A long count data.table (or NULL, a no-op)

settings

A tplyr_layer_settings object supplying ci_method/ci_level

Value

dt, modified in place


Conditional reformatting of a pre-populated string of numbers

Description

This function allows you to conditionally re-format a string of numbers based on a numeric value within the string itself. By selecting a "format group", which is targeting a specific number within the string, a user can establish a condition upon which a provided replacement string can be used. Either the entire replacement can be used to replace the entire string, or the replacement text can refill the "format group" while preserving the original width and alignment of the target string.

Usage

apply_conditional_format(
  string,
  format_group,
  condition,
  replacement,
  full_string = FALSE
)

Arguments

string

Target character vector where text may be replaced

format_group

An integer representing the targeted numeric field within the string, numbered from left to right

condition

An expression, using the variable name x as the target variable within the condition

replacement

A string to use as the replacement value

full_string

TRUE if the full string should be replaced, FALSE if the replacement should be done within the format group

Value

A character vector

Examples

string <- c(" 0  (0.0%)", " 8  (9.3%)", "78 (90.7%)")

apply_conditional_format(string, 2, x == 0, " 0        ", full_string = TRUE)

apply_conditional_format(string, 2, x < 1, "(<1%)")


Apply count format(s) to a long counts table

Description

Single-format mode (unnamed) writes a single formatted column. Stat-columns mode (named formats) writes one ⁠formatted_<i>⁠ column per format; cast_to_wide() spreads these into separate res columns per column group. All count statistics are already present on dt (including the special total and missing row tables), so every format can be applied to every row.

Usage

apply_count_formats(
  dt,
  fmts,
  pct_lt = NULL,
  pct_gt = NULL,
  zero_count_display = "full"
)

Arguments

dt

data.table with computed count statistics (or NULL, a no-op)

fmts

List of f_str objects from get_count_formats()

pct_lt

Optional numeric less-than threshold for percents (see f_str())

pct_gt

Optional numeric greater-than threshold for percents

zero_count_display

One of "full" (default, unchanged), "count_only" (zero cells show just the count field, e.g. " 0"), or "blank" (zero cells render as "")

Details

The pct_lt/pct_gt and zero_count_display arguments implement the regulatory display conventions from issue #14. pct_lt/pct_gt retarget the percent statistic (the pct/distinct_pct format group) to the "<1"/">99" tokens. zero_count_display rewrites cells whose count is zero.


Apply custom column groups to data

Description

Duplicates rows matching source levels with the column variable set to the custom group name.

Usage

apply_custom_groups(dt, custom_groups)

Arguments

dt

data.table

custom_groups

List of tplyr_custom_group objects (or NULL)

Value

Modified data.table


Drop missing-counted rows from the denominator source

Description

Implements missing_count$denom_exclude: the rows folded into the Missing row leave the denominator, so the layer's percentages are of the non-missing population rather than of everyone.

Usage

apply_denom_exclude(denom_dt, tv, missing_count, layer_index = NULL)

Arguments

denom_dt

data.table used as the denominator source

tv

Character string, target variable name

missing_count

The layer's missing_count setting

layer_index

Integer layer index, used in the warning message

Value

denom_dt, filtered when denom_exclude is TRUE


Apply format strings to numeric values

Description

Vectorized formatting function. Takes an f_str object and numeric vectors, returns a character vector of formatted strings.

Usage

apply_formats(
  fmt,
  ...,
  precision = NULL,
  lt = NULL,
  gt = NULL,
  lt_gt_group = NULL,
  na = NULL,
  width = NULL,
  pad = c("right", "left")
)

Arguments

fmt

An f_str() object. A bare character format string is rejected, since the variable names are what bind ... to the format groups.

...

Numeric vectors, one per variable in the f_str (positional matching)

precision

Optional list of resolved precision per group (for auto-precision)

lt

Optional numeric less-than threshold applied to the group named by lt_gt_group: values in ⁠(0, lt)⁠ render as ⁠"<" lt⁠ (see format_number_vec()).

gt

Optional numeric greater-than threshold applied to the group named by lt_gt_group: values in ⁠(gt, 100)⁠ render as ⁠">" gt⁠.

lt_gt_group

Optional integer index of the format group to which lt/gt apply (used by count layers to target the percent statistic). NULL disables.

na

Optional string substituted for cells whose format-group inputs are all NA, used instead of the default blank-width fill. na = "" produces a truly empty cell (nchar 0); na = "NE" renders "NE". The default NULL preserves the blank-width fill. This lets apply_formats() replace hand-rolled fixed-width formatters for externally row-bound statistics.

width

Optional integer total width to pad each formatted token to, using stringr::str_pad(). When the na substitution applies to a cell, na wins and that cell is not padded. The default NULL leaves tokens at their natural format width.

pad

Side to pad on when width is set: "right" (default, trailing spaces) or "left" (leading spaces).

Value

Character vector of formatted values

See Also

f_str() for the format-string grammar.

Examples

# Vectorized: one formatted string per element
apply_formats(f_str("xx (xx.x%)", "n", "pct"),
              n = c(5, 12, 103), pct = c(4.5, 33.333, 99.9))

# `na` replaces the default blank-width fill
apply_formats(f_str("xx.x", "mean"), mean = c(1.2, NA))
apply_formats(f_str("xx.x", "mean"), mean = c(1.2, NA), na = "NE")
apply_formats(f_str("xx.x", "mean"), mean = c(1.2, NA), na = "")

# lt/gt thresholds, targeting the percent group (index 2)
apply_formats(f_str("xx (xx.x%)", "n", "pct"), n = c(1, 199), pct = c(0.4, 99.7),
              lt = 1, gt = 99, lt_gt_group = 2)

# Pad to a fixed width for row-binding against other output
apply_formats(f_str("xx.x", "mean"), mean = c(1.2, 10.75), width = 10)
apply_formats(f_str("xx.x", "mean"), mean = c(1.2, 10.75), width = 10, pad = "left")


Apply build-time overrides to a spec

Description

Merges override parameters into a copy of the spec. Handles special cases:

Usage

apply_overrides(spec, overrides)

Arguments

spec

A tplyr_spec object

overrides

Named list of override values

Value

Modified spec (shallow copy)


Apply precision caps

Description

Applies layer-level cap first, falls back to global option.

Usage

apply_precision_cap(prec, precision_cap = NULL)

Arguments

prec

data.table with max_int and max_dec columns

precision_cap

Named numeric vector c(int=, dec=) or NULL

Value

Modified data.table


Apply row masks to blank repeated row labels

Description

Walks each rowlabel* column top-to-bottom and blanks values that are identical to the previous row, respecting layer boundaries (ord_layer_index).

Usage

apply_row_masks(result, row_breaks = FALSE)

Arguments

result

A data.frame produced by tplyr_build()

row_breaks

Logical. If TRUE, insert a blank row between layers.

Value

A data.frame with repeated labels blanked

Examples

spec <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(group_count("AGEGR1", by = "SEX"))
)
built <- tplyr_build(spec, tplyr_adsl)

# SEX repeats on every age-group row
built[, c("rowlabel1", "rowlabel2")]

# Masked: each value prints once, at the top of its block
apply_row_masks(built)[, c("rowlabel1", "rowlabel2")]

# row_breaks inserts a blank row between layers
two <- tplyr_build(
  tplyr_spec(cols = "TRT01P",
             layers = tplyr_layers(group_count("SEX"), group_count("AGEGR1"))),
  tplyr_adsl
)
apply_row_masks(two, row_breaks = TRUE)[, c("rowlabel1", "res1")]


Apply total groups to data

Description

Duplicates all rows with the column variable set to the total group label, creating a synthetic "Total" column level.

Usage

apply_total_groups(dt, total_groups)

Arguments

dt

data.table

total_groups

List of tplyr_total_group objects (or NULL)

Value

Modified data.table


Extract a display-ready frame from a build result

Description

Returns just the display content of a tplyr_build result, dropping the internal ordering helpers (ord_layer_index, ord_layer_*) and the row_id metadata column, and giving a frame ready to hand to a table-rendering package (clinify, flextable, gt, ...). The build output is already ordered, so no re-sorting is performed.

Usage

as_display(x, labels = FALSE)

Arguments

x

A data.frame produced by tplyr_build.

labels

Logical. When TRUE, the res* / rdiff* / pval* columns are renamed to their header labels (their label attribute, as returned by get_data_labels); the row-label columns keep their names. Defaults to FALSE.

Details

Everything that is not an internal helper is kept. That is normally the rowlabel*, res*, rdiff*, and pval* columns, but a stats_as_columns desc layer with no by variable names its result columns after the statistics themselves, and those are retained too.

Value

A data.frame of display columns.

Examples

spec <- tplyr_spec(cols = "TRT", layers = tplyr_layers(group_count("SEX")))
b <- tplyr_build(spec, data.frame(TRT = rep(c("A", "B"), 3),
                                  SEX = rep(c("F", "M"), 3)))
as_display(b)

Association-test column(s) for count, shift, and desc layers

Description

Configures an association test and lands its formatted result beside the n(\ comparisons is supplied:

Usage

assoc_test(
  fn,
  format = f_str("x.xxx", "p"),
  label = NULL,
  reference = NULL,
  comparisons = NULL,
  total_row = TRUE
)

Arguments

fn

A function of one argument. In omnibus mode it is called with the source-data subset (a data.frame) for a single by group; in pairwise mode it is called with a 2x2 numeric matrix (see Details). Its return is rendered into the cell one of two ways: a numeric value (or a numeric vector matching the number of variables in format) is formatted with format – a scalar p-value, or several statistics such as an odds ratio with its confidence interval mapped positionally onto a multi-variable f_str; or a character string is passed through verbatim, letting the function that computes an arbitrary test also supply the finished display (a significance flag "0.031*", a ceiling/floor ">.99"/"<.0001", a sentinel "NE"). Return NA (numeric or character) to render a blank.

format

An f_str object formatting a numeric return; it is ignored when fn returns a character string. Its variable count sets how many values fn must return: one variable for a scalar (e.g. f_str("x.xxx", "p"), the default), or several for a tuple (e.g. f_str("xx.xx (xx.xx, xx.xx)", "or", "lo", "hi")). The returned values are passed positionally, so the variable names are free.

label

Character string used as the result column's header label. In pairwise mode it may be a vector with one entry per comparison (or a single value recycled across comparisons); NULL generates a default "<reference> vs <comparison>" label per comparison. In omnibus mode defaults to "p-value".

reference

Pairwise mode only. Character(1) naming the reference arm level of the first cols variable. NULL (default) uses that variable's first level at build time.

comparisons

Pairwise mode only. A character vector (or list of single levels) of arm levels, each compared to reference (e.g. c("Low", "High")). Supplying this switches on pairwise/per-level mode; NULL (default) keeps omnibus mode.

total_row

Pairwise mode only. Logical(1); when the layer also emits a total row (layer_settings(total_row = TRUE)), TRUE (default) computes the pairwise p-value on that row too – for a nested AE layer the grand-total ("any event anywhere") 2x2 – while FALSE leaves it blank. Missing rows are always left blank.

Details

Omnibus mode (comparisons = NULL, the default). Runs fn once per by group, across the treatment columns, and lands its result as a single trailing column. The supplied function receives the raw source-data subset for the by group (all cols levels and all target/row levels), so a caller can tabulate and test naturally (e.g. fisher.test(table(.data$TRT, .data$RESP)) or coin::cmh_test(...)). When the layer has no by variable the test runs once over the whole layer; otherwise once per by group, with the value placed on that group's first output row. This mode works on count, shift, and desc layers – on a desc layer it is the natural home for a continuous-variable comparison across arms (ANOVA / Kruskal-Wallis / t-test), e.g. fn = function(.data) anova(lm(AGE ~ TRT, .data))[["Pr(>F)"]][1], with one p-value per by group on that group's first statistic row.

Pairwise / per-level mode (comparisons non-NULL). Count layers only. Emits one pval column per comparison, each comparing an arm level of the first cols variable to reference, with a value on every target-level row (like risk_diff's rdiff columns). On a nested count layer it emits a value on every row of every level – each inner (e.g. preferred-term) row and each outer (e.g. system-organ-class subtotal) row, each row's 2x2 built from that row's own counts – and, when the layer has a total row, on the grand-total row too (see total_row). Here fn receives, for one (row, comparison) pair, a 2x2 contingency matrix matrix(c(n_ref, n_cmp, N_ref - n_ref, N_cmp - n_cmp), nrow = 2) – rows are (reference, comparison) arm, columns are (event, no event) – where n is the cell count and N the population denominator for that arm. When the layer sets distinct_by, the distinct counts/denominators are used. fn returns either a numeric value (a scalar, or a vector of several statistics matching a multi-variable format) or a verbatim character display string (NA renders a blank).

Attach it to a layer via layer_settings(assoc_test = assoc_test(...)).

Value

A tplyr_assoc_test object.

Examples

# Omnibus
at <- assoc_test(
  fn = function(.data) fisher.test(table(.data$TRT, .data$RESP))$p.value,
  format = f_str("x.xxx", "p"),
  label = "p-value [1]"
)

# Pairwise per-level (count layer): Fisher on an incidence 2x2
at2 <- assoc_test(
  fn = function(m) fisher.test(m)$p.value,
  reference = "Placebo",
  comparisons = c("Low", "High"),
  format = f_str("x.xxx", "p")
)

# Omnibus on a desc layer: continuous comparison across arms (ANOVA)
at3 <- assoc_test(
  fn = function(.data) anova(lm(AGE ~ TRT, .data))[["Pr(>F)"]][1],
  format = f_str("x.xxx", "p")
)

# Multiple statistics in one cell: odds ratio with a confidence interval
at4 <- assoc_test(
  fn = function(m) {
    ft <- fisher.test(m)
    c(ft$estimate, ft$conf.int[1], ft$conf.int[2])
  },
  reference = "Placebo",
  comparisons = c("Low", "High"),
  format = f_str("xx.xx (xx.xx, xx.xx)", "or", "lo", "hi"),
  label = "OR (95% CI)"
)

Process a custom analysis layer

Description

Calls the user-provided analyze_fn for each group combination and formats results using either format_strings or a pre-formatted column.

Usage

build_analyze_layer(dt, layer, cols, layer_index, col_n = NULL, pop_dt = NULL)

Arguments

dt

data.table with the (filtered) input data

layer

A tplyr_analyze_layer object

cols

Character vector of column variable names from the spec

layer_index

Integer index of this layer

col_n

data.table with column counts (or NULL)

pop_dt

data.table with population data (or NULL)

Value

A data.table with rowlabel*, res*, and ord* columns


Build cell-level metadata for the full output table

Description

For each output row x result column combination, constructs filter expressions that describe the source data subset for that cell. The expressions can be evaluated at query time against the original data.

Usage

build_cell_metadata(output, spec, col_names, pop_col_map = NULL)

Arguments

output

data.frame output from tplyr_build (with rowlabel/res/ord cols)

spec

tplyr_spec object

col_names

Character vector of original data column names

Value

Named list of tplyr_meta objects, keyed by "row_id||column"


Build column labels with header N suffix

Description

Takes raw dcast column names and a col_n data.table, returns labels with "(N=<n>)" suffix. For shift layers where the label includes both spec-level cols and the shift column variable, only the spec-level portion is used for the N lookup.

Usage

build_col_labels(raw_labels, col_n)

Arguments

raw_labels

Character vector of raw column labels from dcast

col_n

data.table with spec-level column variables and .n column, or NULL (in which case labels are returned unchanged)

Value

Character vector of labels with N suffix


Process a count layer

Description

Process a count layer

Usage

build_count_layer(
  dt,
  layer,
  cols,
  layer_index,
  col_n = NULL,
  pop_dt = NULL,
  col_levels = NULL
)

Arguments

dt

data.table with the (filtered) input data

layer

A tplyr_count_layer object

cols

Character vector of column variable names from the spec

layer_index

Integer index of this layer

Value

A data.table with rowlabel*, res*, and ord* columns


Process a nested (multi-variable) count layer

Description

Process a nested (multi-variable) count layer

Usage

build_count_layer_nested(
  dt,
  target_vars,
  cols,
  by_data_vars,
  by_labels,
  settings,
  layer_index,
  col_n = NULL,
  pop_dt = NULL,
  col_levels = NULL
)

Process a single-variable count layer

Description

Process a single-variable count layer

Usage

build_count_layer_single(
  dt,
  tv,
  cols,
  by_data_vars,
  by_labels,
  settings,
  layer_index,
  col_n = NULL,
  pop_dt = NULL,
  col_levels = NULL
)

Process a descriptive statistics layer

Description

Process a descriptive statistics layer

Usage

build_desc_layer(
  dt,
  layer,
  cols,
  layer_index,
  col_n = NULL,
  pop_dt = NULL,
  col_levels = NULL
)

Arguments

dt

data.table with the (filtered) input data

layer

A tplyr_desc_layer object

cols

Character vector of column variable names from the spec

layer_index

Integer index of this layer

Value

A data.table with rowlabel*, res*, and ord* columns


Build a multi-target desc layer

Description

Build a multi-target desc layer

Usage

build_desc_multi(
  dt,
  target_vars,
  cols,
  by_data_vars,
  by_labels,
  settings,
  layer_index,
  col_n,
  pop_dt = NULL,
  col_levels = NULL
)

Build a single-target desc layer

Description

Build a single-target desc layer

Usage

build_desc_single(
  dt,
  tv,
  cols,
  by_data_vars,
  by_labels,
  settings,
  layer_index,
  col_n,
  var_label = NULL,
  var_index = NULL,
  pop_dt = NULL,
  col_levels = NULL
)

Build row labels for a nested count level

Description

Build row labels for a nested count level

Usage

build_nested_row_labels(
  counts,
  by_labels,
  by_data_vars,
  target_vars,
  level,
  n_levels
)

Build row labels for special rows (total/missing) in nested context

Description

Build row labels for special rows (total/missing) in nested context

Usage

build_nested_row_labels_special(
  dt,
  by_labels,
  by_data_vars,
  target_vars,
  tv,
  n_label_cols
)

Write rowlabel columns onto a long-format layer table

Description

Writes one ⁠rowlabel<n>⁠ column per by label constant, then one per by data variable (as character), then the value variable (as character).

Usage

build_row_labels_long(dt, by_labels, by_data_vars, value_var)

Arguments

dt

data.table to modify by reference

by_labels

Character vector of constant by labels

by_data_vars

Character vector of by data variable names

value_var

Name of the variable supplying the final rowlabel column. ARD reconstruction can encounter a target variable absent from the stats table; the column is skipped (but still named) in that case.

Value

Character vector of the rowlabel column names


Build row labels for special rows (missing, total) in single-variable context

Description

Build row labels for special rows (missing, total) in single-variable context

Usage

build_row_labels_special(dt, by_labels, by_data_vars, tv, existing_label_cols)

Process a shift layer

Description

Builds a cross-tabulation (row variable × column variable) within each treatment arm. The shift column variable becomes an additional column dimension, producing result columns like "Placebo_H", "Placebo_N", etc.

Usage

build_shift_layer(
  dt,
  layer,
  cols,
  layer_index,
  col_n = NULL,
  pop_dt = NULL,
  col_levels = NULL
)

Arguments

dt

data.table with the (filtered) input data

layer

A tplyr_shift_layer object

cols

Character vector of column variable names from the spec

layer_index

Integer index of this layer

Value

A data.table with rowlabel*, res*, and ord* columns


Map data variable names to their rowlabel columns

Description

Map data variable names to their rowlabel columns

Usage

build_var_to_rowlabel_map(layer, by_data_vars, by_labels)

Arguments

layer

A tplyr_layer object

by_data_vars

Character vector of by-variable data column names

by_labels

Character vector of by-variable label strings

Value

Named list where names are data variables and values are rowlabel column names (e.g., list(SEX = "rowlabel1"))


Call analyze_fn for each group combination

Description

Call analyze_fn for each group combination

Usage

call_analyze_fn_by_group(dt, analyze_fn, target_var, group_vars)

Cast long data to wide output format

Description

When stat_labels is provided (stat_columns mode), the long data carries one ⁠formatted_<i>⁠ column per statistic and each column group spreads into one res column per statistic, interleaved column-group-major. Column labels follow the pattern "<column group> (N=n) | <stat label>" so renderers can span the column group over its stat sub-columns.

Usage

cast_to_wide(
  dt,
  row_label_cols,
  cols,
  layer_index,
  col_n = NULL,
  stat_labels = NULL,
  col_levels = NULL,
  row_order_col = NULL
)

Arguments

stat_labels

Character vector of stat column labels (the names of the stat_columns setting), or NULL for the standard single-format cast

col_levels

Named list mapping factor column variables to their level order (from get_col_levels()); orders the resulting ⁠res*⁠ columns by factor levels instead of alphabetically. NULL leaves dcast's default alphabetical column order.

row_order_col

Name of a numeric column in dt giving the intended row order. dcast sorts its LHS alphabetically, so a caller whose row labels are not alphabetical (e.g. format-string names) must carry the order through the cast; the column joins the LHS, sorts the result, and is then dropped.


Warn when a nonzero count has a missing or zero denominator

Description

Denominators are attached with a left join, so a group present in the analysis data but absent from the denominator source comes back with total = NA and renders a blank-width percent (" 5 ( )") — and total == 0 with n > 0 used to display an affirmatively wrong 0.0%. Both mean the denominator setup is wrong, so say so.

Usage

check_denominator_integrity(counts, n_col, total_col, group_cols, layer_index)

Arguments

counts

data.table holding the counts and their denominators

n_col

Name of the count column ("n" or "distinct_n")

total_col

Name of the denominator column

group_cols

Columns identifying a row, used to name offending groups

layer_index

Integer layer index

Value

Invisible TRUE


Classify by values into data variables and labels

Description

Classify by values into data variables and labels

Usage

classify_by(by, col_names)

Collapse row labels into a single column

Description

This is a generalized post processing function that allows you to take groups of by variables and collapse them into a single column. Repeating values are split into separate rows, and for each level of nesting, a specified indentation level can be applied.

Usage

collapse_row_labels(
  x,
  ...,
  indent = "  ",
  target_col = "row_label",
  nest = FALSE
)

Arguments

x

Input data frame

...

Column names (as character strings) to be collapsed, must be 2 or more

indent

Indentation string to be used, which is multiplied at each indentation level

target_col

Character string naming the output column containing collapsed row labels

nest

Logical. If TRUE, collapse row labels in-place without inserting stub rows for repeating values. Allows a single column to be passed. Default is FALSE.

Value

data.frame with row labels collapsed into a single column

Examples

x <- data.frame(
  row_label1 = c("A", "A", "A", "B", "B"),
  row_label2 = c("C", "C", "D", "E", "F"),
  var1 = 1:5,
  stringsAsFactors = FALSE
)

collapse_row_labels(x, "row_label1", "row_label2")

collapse_row_labels(x, "row_label1", "row_label2", indent = "    ",
                    target_col = "rl")


Collect precision from data

Description

Scans a numeric variable to determine the maximum integer width and maximum decimal precision present in the data, optionally grouped.

Usage

collect_precision(
  dt,
  precision_on,
  precision_by = character(0),
  precision_data = NULL,
  precision_cap = NULL
)

Arguments

dt

data.table with the data

precision_on

Character string naming the variable to scan

precision_by

Character vector of grouping variables (can be empty)

precision_data

Optional external data.frame with pre-computed precision

precision_cap

Named numeric vector c(int=, dec=) for capping

Value

data.table with precision_by columns + "max_int" and "max_dec" columns


Compute max integer width and max decimal precision from a numeric vector

Description

Compute max integer width and max decimal precision from a numeric vector

Usage

collect_precision_values(vals)

Arguments

vals

Numeric vector (should already have NA/Inf removed)

Value

list(max_int, max_dec)


Evaluate a build, reporting any user-code failures as one warning

Description

Evaluate a build, reporting any user-code failures as one warning

Usage

collect_user_fn_errors(expr)

Arguments

expr

Expression to evaluate

Value

The value of expr


Complete count data to ensure all combinations exist

Description

Complete count data to ensure all combinations exist

Usage

complete_counts(
  counts,
  dt,
  cols,
  by_data_vars,
  tv,
  limit_data_by = NULL,
  denom_group = NULL,
  col_levels = NULL
)

Complete counts for a nested level

Description

Complete counts for a nested level

Usage

complete_nested_level(
  counts,
  dt,
  cols,
  by_data_vars,
  level_tvs,
  limit_data_by = NULL,
  denom_group = NULL,
  col_levels = NULL
)

Complete shift count data

Description

Ensures all row_var × col_var × cols combinations exist, filling missing combinations with zero counts.

Usage

complete_shift_counts(
  counts,
  dt,
  all_cols,
  by_data_vars,
  row_var,
  denom_group = NULL,
  col_levels = NULL
)

Compute the association-test result per by-group

Description

Runs config$fn once per by group over the source-data subset for that group, and returns the display string keyed by the by variables.

Usage

compute_assoc_test(source_dt, by_data_vars, config)

Arguments

source_dt

data.table of source rows for the layer (after any layer where), holding the cols, by, and target/row variables.

by_data_vars

Character vector of by data-variable names (may be empty).

config

A tplyr_assoc_test object.

Value

A data.table with the by_data_vars columns (as character) plus a formatted character column .assoc_p. When by_data_vars is empty, a single-row table with only .assoc_p.


Compute sort keys for count layer rows

Description

Computes ordering columns for a count layer's rows, based on the by-variable and target variable values.

Usage

compute_count_sort_keys(counts, dt, cols, by_data_vars, tv, settings)

Arguments

counts

data.table with count data (long format, before cast)

dt

data.table with the original input data (for VARN lookup)

cols

Character vector of spec column variables

by_data_vars

Character vector of by data variable names

tv

Character string, target variable name

settings

Layer settings object

Value

The counts data.table with ⁠.ord_by_*⁠ and .ord_tv columns added


Compute missing count row

Description

Compute missing count row

Usage

compute_missing_counts(
  dt,
  counts,
  cols,
  by_data_vars,
  tv,
  group_vars,
  denom_group,
  denom_dt,
  distinct_by,
  missing_count
)

Compute missing subjects row

Description

Counts subjects present in pop_data but absent from target data. Uses distinct_by to identify subjects; if NULL, uses row-level counts.

Usage

compute_missing_subjects(
  dt,
  pop_dt,
  cols,
  by_data_vars,
  tv,
  distinct_by,
  missing_label,
  denom_group,
  denom_dt,
  fmt
)

Arguments

dt

data.table with target data (after layer where filter)

pop_dt

data.table with population data

cols

Character vector of spec column variable names

by_data_vars

Character vector of by-variable names from data

tv

Character string, target variable name

distinct_by

Character string naming the subject identifier (or NULL)

missing_label

Character string for the row label

denom_group

Character vector of denominator grouping variables

denom_dt

data.table for denominator computation

fmt

f_str object for formatting

Value

A data.table for the missing subjects row, or NULL


Compute pairwise per-level association-test p-values from a counts table

Description

For each comparison arm and each target-variable level, builds a 2x2 contingency matrix from the assembled cell counts and population denominators and calls config$fn to obtain a scalar p-value. This mirrors compute_risk_diff() in placement (a value per target level per comparison) but delegates the test to the caller-supplied function.

Usage

compute_pairwise_assoc(
  counts_long,
  cols,
  tv,
  by_data_vars,
  distinct_by,
  config,
  reference
)

Arguments

counts_long

data.table (pre-formatting) with the column variable, any by variables, the target variable, and n/total (plus distinct_n/distinct_total when distinct counting).

cols

Character vector of column variable names from the spec.

tv

Character string naming the target variable.

by_data_vars

Character vector of by-variable names.

distinct_by

Distinct-by variable name (or NULL); selects the distinct counts/denominators when non-NULL.

config

A tplyr_assoc_test object (pairwise mode).

reference

Character(1) resolved reference arm level.

Value

A data.table with one row per target level per comparison, holding the row variables, .comp_idx, and the formatted display string .disp. Numeric fn returns are formatted with config$format; a character fn return is passed through verbatim (issue #47); NA and a zero denominator render a blank.


Compute pairwise per-level association-test p-values for a nested layer

Description

Like compute_pairwise_assoc() but keyed directly by the assembled rowlabel* columns rather than a single target variable, so it works at every nesting level at once: each inner (e.g. preferred-term) row and each outer (e.g. system-organ-class subtotal) row is one rowlabel tuple, and its 2x2 is built from that row's own reference/comparison counts and population denominators. The same helper computes the grand-total row's p-value when passed the total-row table (a single rowlabel tuple).

Usage

compute_pairwise_assoc_nested(
  long,
  cols,
  row_label_cols,
  distinct_by,
  config,
  reference,
  arm_n = NULL
)

Arguments

long

data.table holding the column variable, the assembled rowlabel* columns, and the raw n/total (or distinct_n/distinct_total) statistics – the nested combined table (category rows) or a total-row table.

cols

Character vector of column variable names from the spec.

row_label_cols

Character vector of the rowlabel* column names that jointly identify an output row.

distinct_by

Distinct-by variable name (or NULL); selects the distinct counts/denominators when non-NULL.

config

A tplyr_assoc_test object (pairwise mode).

reference

Character(1) resolved reference arm level.

arm_n

Named numeric of population arm sizes (arm level -> N), used to back-fill the 2x2 denominator for an arm that has no events on a row (or no events at all). Without it, a zero-event reference or comparison arm would have a missing denominator and blank the test; with it, an empty arm still yields a valid 0-vs-k test (issue #49, sparse-table fix).

Value

A data.table with the row_label_cols (as character), .comp_idx, and the display string .disp; one row per output row per comparison.


Compute risk differences for count layer data

Description

For each comparison pair and each target variable level, computes the difference in proportions with a confidence interval using stats::prop.test().

Usage

compute_risk_diff(counts_long, cols, tv, by_data_vars, risk_diff_config)

Arguments

counts_long

data.table in long format with n, total columns

cols

Character vector of column variable names from the spec

tv

Character string naming the target variable

by_data_vars

Character vector of by-variable names

risk_diff_config

List with comparisons, ci, and format

Value

A data.table with one row per target_var level per comparison, containing rdiff, lower, upper, p_value columns


Compute total row

Description

Compute total row

Usage

compute_total_row(
  counts,
  dt,
  cols,
  by_data_vars,
  tv,
  total_label,
  total_missings,
  distinct_by,
  missing_count,
  denom_group,
  denom_dt
)

Compute sort key for a variable

Description

Returns an integer or numeric vector of sort keys for the values of a variable. Priority: factor levels > VARN companion column > alphabetical. The method parameter can override this auto-detection.

Usage

compute_var_order(
  values,
  var_name = NULL,
  data_dt = NULL,
  method = NULL,
  count_values = NULL
)

Arguments

values

Character or factor vector of values to sort

var_name

Character string naming the variable (for VARN lookup)

data_dt

data.table with the raw data (for VARN lookup)

method

Character: NULL (auto), "byfactor", "byvarn", "bycount", "alphabetical"

count_values

Numeric vector of counts per row (for bycount method)

Value

Numeric vector of sort keys (lower = earlier)


Create a custom column group configuration

Description

Combines existing column levels into a custom group. Rows matching any of the source levels are duplicated with the column variable set to the group name.

Usage

custom_group(col_var, ...)

Arguments

col_var

Character string naming the column variable

...

Named arguments where names are group labels and values are character vectors of source levels to combine. Example: "High Dose" = c("Dose 1", "Dose 2")

Value

A tplyr_custom_group object

Examples

# Pool the two dose arms into one "Xanomeline (All)" column, kept alongside
# the arms it is built from
spec <- tplyr_spec(
  cols = "TRT01P",
  custom_groups = list(custom_group(
    "TRT01P",
    "Xanomeline (All)" = c("Xanomeline High Dose", "Xanomeline Low Dose")
  )),
  layers = tplyr_layers(group_count("AGEGR1"))
)
tplyr_build(spec, tplyr_adsl)

# Several groups at once
custom_group(
  "TRT01P",
  "Active"  = c("Xanomeline High Dose", "Xanomeline Low Dose"),
  "Control" = "Placebo"
)


Deserialize by parameter

Description

Deserialize by parameter

Usage

deserialize_by(raw)

Deserialize expression

Description

Deserialize expression

Usage

deserialize_expr(raw)

Deserialize f_str from raw list

Description

Deserialize f_str from raw list

Usage

deserialize_f_str(raw)

Deserialize a function

Description

Deserialize a function

Usage

deserialize_function(raw)

Deserialize a layer from raw list

Description

Deserialize a layer from raw list

Usage

deserialize_layer(raw_layer, layer_id = NULL)

Arguments

raw_layer

Named list of parsed layer fields

layer_id

Human-readable layer identifier used in warning messages


Deserialize layer settings

Description

Deserialize layer settings

Usage

deserialize_settings(raw, layer_id = NULL)

Arguments

raw

Named list of parsed settings

layer_id

Human-readable layer identifier used in warning messages


Drop target-variable levels that were folded into the Missing row

Description

Values named in missing_count$missing_values are counted in the Missing row. Without removing them here they would also keep their own category row, counting the same records twice and pushing the column past 100%.

Usage

drop_missing_value_levels(counts, tv, missing_count)

Arguments

counts

data.table of category counts

tv

Character string, target variable name

missing_count

The layer's missing_count setting

Value

counts with the folded-in levels removed


Create a format string object

Description

Create a format string object

Usage

f_str(format_string, ..., empty = NULL)

Arguments

format_string

Character string defining the display template

...

Character strings naming the variables that populate the template

empty

Value to display when data is NA/missing. Supplied as c(.overall = "..."), it replaces the entire cell, but only once every format group in the string is NA. Supplied unnamed (e.g. empty = "NA"), it instead fills each NA format group in place, right-justified to the width that group would have occupied, so a partially missing cell keeps its alignment – f_str("xx (xxx)", "n", "pct", empty = "NA") renders "NA ( NA)". The default (NULL) leaves NA groups as blanks of the field width.

Details

Each run of x characters is one format group, and each group is filled by the correspondingly-positioned variable in .... The count of xs sets the field width, so "xx.x" renders two integer digits and one decimal. Literal text between groups is preserved verbatim. a (and A) request auto-precision, where the decimal count comes from the data.

Value

A tplyr_f_str object

See Also

apply_formats() to render values outside a build.

Examples

# Two format groups filled by n and pct
fmt <- f_str("xx (xx.x%)", "n", "pct")
fmt
apply_formats(fmt, n = c(5, 12), pct = c(4.5, 33.33))

# Width is set by the number of x's
apply_formats(f_str("xxx", "n"), n = 7)
apply_formats(f_str("x", "n"), n = 7)

# `empty` fills each NA group in place, preserving alignment
apply_formats(f_str("xx (xxx)", "n", "pct", empty = "NA"),
              n = NA, pct = NA)

# `.overall` replaces the whole cell, but only when every group is NA
both_na <- f_str("xx (xxx)", "n", "pct", empty = c(.overall = "Not est."))
apply_formats(both_na, n = NA, pct = NA)

# Used in a layer
spec <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(
    group_count("AGEGR1", settings = layer_settings(
      format_strings = list(n_counts = f_str("xx (xx.x%)", "n", "pct"))))
  )
)
tplyr_build(spec, tplyr_adsl)


Zero-fill synthetic markers after a bind

Description

rbindlist(fill = TRUE) sets a marker absent from one side to NA; those rows are originals for that variable.

Usage

fill_synth_markers(dt)

Arguments

dt

data.table

Value

dt


Format analyze results using format_strings

Description

For each group combination, takes the first row of numeric values from the analyze_fn output and creates one formatted row per format_string entry.

Usage

format_analyze_results(fn_combined, format_strings, group_vars)

Arguments

fn_combined

data.table of raw analyze_fn results

format_strings

Named list of f_str objects

group_vars

Character vector of grouping column names

Value

data.table with row_label and formatted columns


Render an assoc_test fn return value for display

Description

Turns the value returned by a caller-supplied fn into the string shown in the pval cell:

Usage

format_assoc_return(raw, format, label = "assoc_test fn", group = NULL)

Arguments

raw

The raw value returned by fn (already wrapped so errors arrive as NA).

format

An f_str object; its variable count determines how many values a numeric return must supply.

label

What produced raw, used when reporting a shape mismatch.

group

Optional group identifier used when reporting a shape mismatch.

Value

A length-1 character display string.


Render a data.table .BY group as a human-readable label

Description

Render a data.table .BY group as a human-readable label

Usage

format_group_label(by_values)

Arguments

by_values

Named list of group values (data.table's .BY)

Value

Single string, or NULL when there is no grouping


Format a numeric vector to a fixed-width field

Description

Format a numeric vector to a fixed-width field

Usage

format_number_vec(values, group, precision = NULL, lt = NULL, gt = NULL)

Arguments

values

Numeric vector to format

group

A parsed format group (from parse_format_group())

precision

Optional resolved precision (int_width/dec_width) overriding the group's static widths

lt

Optional numeric less-than threshold. Values strictly greater than 0 whose rounded display would fall below lt render as ⁠"<" lt⁠ (e.g. a percent of 0.4 renders as ⁠<1⁠), right-justified to the field width. Used for the regulatory "<1%" convention on count-layer percents.

gt

Optional numeric greater-than threshold. Values strictly less than 100 whose rounded display would exceed gt render as ⁠">" gt⁠ (e.g. 99.6 renders as ⁠>99⁠).


Format risk difference values

Description

Applies an f_str format to the computed risk difference data.

Usage

format_risk_diff(rd_data, fmt)

Arguments

rd_data

data.table with rdiff, lower, upper, p_value columns

fmt

An f_str object for formatting

Value

Character vector of formatted risk difference strings


Format values with auto-precision

Description

Handles the split-apply-combine when precision_by creates multiple precision groups. For a single precision group (no precision_by), resolves precision once and formats all rows.

Usage

format_with_precision(
  fmt,
  var_names,
  stats,
  group_vars,
  precision_table,
  precision_by
)

Arguments

fmt

An f_str object

var_names

Character vector of variable names to format

stats

data.table with computed statistics

group_vars

Character vector of grouping column names

precision_table

data.table from collect_precision()

precision_by

Character vector of precision grouping variables (or NULL)

Value

Character vector of formatted values


Generate unique row IDs for output rows

Description

Creates a character ID for each row by combining the layer index and row label values. These IDs can be used with tplyr_meta_result() and tplyr_meta_subset() to look up cell metadata.

Usage

generate_row_ids(result)

Arguments

result

A data.frame produced by tplyr_build()

Value

Character vector of row IDs (same length as nrow(result))

Examples

spec <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(group_count("AGEGR1"))
)
built <- tplyr_build(spec, tplyr_adsl)
generate_row_ids(built)

# IDs are derived from the row labels, so generate them from an unmodified
# build. tplyr_build(metadata = TRUE) attaches a row_id column that survives
# post-processing, which is the safer route.
with_meta <- tplyr_build(spec, tplyr_adsl, metadata = TRUE)
with_meta$row_id


Ordered factor levels for the column variable(s)

Description

Returns a named list mapping each cols variable that is a factor in source_dt to its level order. Non-factor column variables are omitted. Used to preserve the column variable's factor-level order through the dcast() in cast_to_wide() (issue #13), so count/shift/desc layers all order their ⁠res*⁠ columns by factor levels rather than alphabetically.

Usage

get_col_levels(source_dt, cols, complete = FALSE)

Arguments

source_dt

data.table with the original (factor-typed) input data

cols

Character vector of column variable names


Get the count format string, falling back to defaults

Description

Get the count format string, falling back to defaults

Usage

get_count_format(settings)

Resolve the list of count formats for a layer

Description

Returns the stat_columns list when set (one result column per format per column group); otherwise a single-element unnamed list wrapping the single default format so callers can treat both modes uniformly. The presence of names on the result signals stat-columns mode downstream.

Usage

get_count_formats(settings)

Extract variable labels from a data.frame

Description

Returns a named character vector of variable labels. Labels are extracted from the "label" attribute of each column (standard for Haven-imported CDISC data).

Usage

get_data_labels(data)

Arguments

data

A data.frame

Value

Named character vector where names are column names and values are labels. Columns without labels return NA_character_.

Examples

# CDISC data imported via haven carries a "label" attribute per column
labs <- get_data_labels(tplyr_adsl)
head(labs)

# Columns with no label attribute come back NA
get_data_labels(data.frame(a = 1, b = 2))


Get descriptive format strings, falling back to defaults

Description

Get descriptive format strings, falling back to defaults

Usage

get_desc_formats(settings)

Resolve denominator group for a nesting level

Description

Resolve denominator group for a nesting level

Usage

get_nested_denom_group(denoms_by, level, cols)

Create a custom analysis layer

Description

Allows a user-defined function to compute summary statistics. The function receives a data subset and the target variable name for each group combination, and returns a data.frame of results.

Usage

group_analyze(
  target_var,
  by = NULL,
  where = NULL,
  analyze_fn,
  settings = layer_settings()
)

Arguments

target_var

Character string naming the target variable(s)

by

Character string or vector for row grouping

where

Expression for filtering data for this layer

analyze_fn

A function with signature function(.data, .target_var) that returns a data.frame. See Details.

settings

A layer_settings object

Details

The analyze_fn is called once per group combination (defined by cols and by data variables). It receives:

If format_strings are provided in settings, analyze_fn should return a single-row data.frame of named numeric values. Each format string entry becomes one output row, with its name used as the row label.

If no format_strings are provided, analyze_fn must return a data.frame with row_label and formatted columns.

Note that analyze_fn is called once per cols x by combination, so it only ever sees a single treatment column at a time — it cannot compute a statistic across the treatment columns. For an omnibus association test that spans the columns (e.g. Fisher's exact or CMH on a count/shift layer), see assoc_test.

Value

A tplyr_analyze_layer object

See Also

assoc_test for cross-column association tests.

Examples

# format_strings mode: the function returns one row of named numbers, and
# each format string becomes an output row.
spec <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(
    group_analyze("AGE",
      analyze_fn = function(.data, .target_var) {
        v <- .data[[.target_var]]
        data.frame(gmean = exp(mean(log(v))), rng = diff(range(v)))
      },
      settings = layer_settings(format_strings = list(
        "Geometric mean" = f_str("xx.xx", "gmean"),
        "Range"          = f_str("xx", "rng")
      )))
  )
)
tplyr_build(spec, tplyr_adsl)

# Pre-formatted mode: the function supplies row_label and formatted itself.
pre <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(
    group_analyze("AGE",
      analyze_fn = function(.data, .target_var) {
        v <- .data[[.target_var]]
        data.frame(
          row_label = "Median [IQR]",
          formatted = sprintf("%.1f [%.1f]", median(v), IQR(v))
        )
      })
  )
)
tplyr_build(pre, tplyr_adsl)


Create a count layer

Description

Create a count layer

Usage

group_count(target_var, by = NULL, where = NULL, settings = layer_settings())

Arguments

target_var

Character string or vector naming the target variable(s). Multiple variables create nested/hierarchical counts.

by

Character string or vector for row grouping. Strings that don't match column names are treated as text labels. Use label() for explicit disambiguation.

where

Expression for filtering data for this layer

settings

A layer_settings object

Value

A tplyr_count_layer object

See Also

layer_settings() for denominators, sorting, and special rows.

Examples

# Counts of a categorical variable within each column group
spec <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(group_count("AGEGR1"))
)
tplyr_build(spec, tplyr_adsl)

# Distinct subject counts with a total row, filtered to serious events
ae <- tplyr_spec(
  cols = "TRTA",
  layers = tplyr_layers(
    group_count("AEBODSYS",
      where = AESER == "Y",
      settings = layer_settings(distinct_by = "USUBJID", total_row = TRUE))
  )
)
head(tplyr_build(ae, tplyr_adae))

# Two target variables nest: preferred term within body system
nested <- tplyr_spec(
  cols = "TRTA",
  layers = tplyr_layers(group_count(c("AEBODSYS", "AEDECOD")))
)
head(tplyr_build(nested, tplyr_adae))


Create a descriptive statistics layer

Description

Create a descriptive statistics layer

Usage

group_desc(target_var, by = NULL, where = NULL, settings = layer_settings())

Arguments

target_var

Character string or vector naming the target variable(s)

by

Character string or vector for row grouping

where

Expression for filtering data for this layer

settings

A layer_settings object

Value

A tplyr_desc_layer object

See Also

layer_settings() for auto-precision and custom summaries.

Examples

# Default summary: n, Mean (SD), Median, Q1/Q3, Min/Max, Missing
spec <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(group_desc("AGE"))
)
tplyr_build(spec, tplyr_adsl)

# Choose the statistics and their formats
custom <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(
    group_desc("AGE", settings = layer_settings(
      format_strings = list(
        "n"         = f_str("xx", "n"),
        "Mean (SD)" = f_str("xx.x (xx.xx)", "mean", "sd")
      )))
  )
)
tplyr_build(custom, tplyr_adsl)

# Several target variables in one layer, grouped by visit
multi <- tplyr_spec(
  cols = "TRTA",
  layers = tplyr_layers(group_desc(c("AVAL", "CHG"), by = "AVISIT"))
)
head(tplyr_build(multi, tplyr_adlb))


Create a shift layer

Description

Create a shift layer

Usage

group_shift(target_var, by = NULL, where = NULL, settings = layer_settings())

Arguments

target_var

Named character vector with row and column elements

by

Character string or vector for row grouping

where

Expression for filtering data for this layer

settings

A layer_settings object

Value

A tplyr_shift_layer object

Examples

# Baseline (rows) against post-baseline (columns) reference ranges
spec <- tplyr_spec(
  cols = "TRTA",
  layers = tplyr_layers(
    group_shift(c(row = "BNRIND", column = "ANRIND"))
  )
)
head(tplyr_build(spec, tplyr_adlb))

# Percentages relative to each baseline (column) group rather than the arm
by_col <- tplyr_spec(
  cols = "TRTA",
  layers = tplyr_layers(
    group_shift(c(row = "BNRIND", column = "ANRIND"),
                settings = layer_settings(shift_denom = "column"))
  )
)
head(tplyr_build(by_col, tplyr_adlb))


Harmonize column sets across layers and row-bind

Description

Harmonize column sets across layers and row-bind

Usage

harmonize_and_bind(layer_results)

Apply parenthesis hugging to a format group

Description

Shifts leading spaces from the formatted number to after the trailing literal, so that characters like ( hug the number.

Usage

hug_format_group(prefix, num_part, trailing_literal)

Arguments

prefix

Character vector of accumulated result so far

num_part

Character vector of formatted numbers (with leading spaces)

trailing_literal

Character string of the literal after this group

Value

Character vector with hugged result


Check if an object is a tplyr_label

Description

Check if an object is a tplyr_label

Usage

is_label(x)

Arguments

x

Object to check

Value

Logical


Which values a missing_count setting treats as missing

Description

NA, plus anything named in missing_values. Shared by the Missing-row computation and denom_exclude so the two cannot disagree about what "missing" means.

Usage

is_missing_value(x, missing_count)

Arguments

x

Vector of target-variable values

missing_count

The layer's missing_count setting

Value

Logical vector the same length as x


Check if an object is a tplyr_pop_data

Description

Check if an object is a tplyr_pop_data

Usage

is_pop_data(x)

Arguments

x

An object to check

Value

Logical

Examples

is_pop_data(pop_data(cols = "TRT01P"))
is_pop_data("TRT01P")


Check if an object is a tplyr_layer

Description

Check if an object is a tplyr_layer

Usage

is_tplyr_layer(x)

Arguments

x

Object to check

Value

Logical

Examples

is_tplyr_layer(group_count("SEX"))
is_tplyr_layer(group_desc("AGE"))
is_tplyr_layer("SEX")


Check if an object is a tplyr_spec

Description

Check if an object is a tplyr_spec

Usage

is_tplyr_spec(x)

Arguments

x

An object to check

Value

Logical

Examples

spec <- tplyr_spec(cols = "TRT01P", layers = tplyr_layers(group_count("SEX")))
is_tplyr_spec(spec)
is_tplyr_spec(mtcars)


Create a text label for use in by parameters

Description

Explicitly marks a string as a text label (not a data variable name). Useful when a label string might coincidentally match a column name.

Usage

label(x)

Arguments

x

Character string to use as a label

Value

A tplyr_label object

Examples

# A `by` string that matches no column is already treated as a label, but
# label() is explicit -- and necessary when the text matches a column name.
spec <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(
    group_count("AGEGR1", by = label("Age Group (y)"))
  )
)
head(tplyr_build(spec, tplyr_adsl))


Create layer settings

Description

Configuration object for all layer options. Unused parameters default to NULL and are ignored during build. Type-specific validation happens at build time.

Usage

layer_settings(
  format_strings = NULL,
  stat_columns = NULL,
  denoms_by = NULL,
  shift_denom = "total",
  denom_row = FALSE,
  denom_row_label = "n",
  denom_row_format = NULL,
  denom_where = NULL,
  denom_ignore = NULL,
  distinct_by = NULL,
  total_row = FALSE,
  total_row_label = "Total",
  total_row_count_missings = TRUE,
  missing_count = NULL,
  missing_subjects = FALSE,
  missing_subjects_label = "Missing",
  keep_levels = NULL,
  limit_data_by = NULL,
  custom_summaries = NULL,
  stats_as_columns = FALSE,
  precision_by = NULL,
  precision_on = NULL,
  precision_data = NULL,
  precision_cap = NULL,
  order_count_method = NULL,
  ordering_cols = NULL,
  result_order_var = NULL,
  outer_sort_position = NULL,
  risk_diff = NULL,
  ci_method = c("clopper_pearson", "wilson", "wald", "agresti_coull", "jeffreys"),
  ci_level = 0.95,
  assoc_test = NULL,
  pct_lt = NULL,
  pct_gt = NULL,
  zero_count_display = "full",
  name = NULL
)

Arguments

format_strings

Named list of f_str objects

stat_columns

Named list of f_str objects for count layers. Each entry produces its own result column per column group (e.g. one "n (\ name used as the column sub-label. Column label attributes follow the pattern "<column group> (N=n) | <stat name>". When set, it takes precedence over format_strings. Names may not contain " | " or "(N=", which are reserved by the label grammar.

denoms_by

Character vector of variable names for denominator grouping. This replaces (does not augment) the default denominator grouping, which is the column (cols) variable(s). To get per-column denominators that also break down by a by variable, you must list the cols variable(s) explicitly alongside the by variable(s) — e.g. denoms_by = c("TRT", "SEX"), not denoms_by = "SEX". Passing only the by variable collapses the denominator across the columns.

shift_denom

Denominator basis for shift layers. "total" (default) computes percentages out of the column (cols) total — i.e. the treatment arm. "column" computes them column-wise, out of each shift column group (the "from"/baseline group) within the arm, which is the standard "% within the from group" shift display; the header (N=) labels then reflect the per-column-group denominators. Ignored when denoms_by is set (which specifies the grouping explicitly).

denom_row

Logical, shift layers only. When TRUE, emit the per-column-group denominator (the same total used for the percentages) as an integer row above the shift-to rows — the "n" row of a threshold/normal-range shift table. Pairs naturally with shift_denom = "column". Defaults to FALSE.

denom_row_label

Character string, the row label for the denom_row row. Defaults to "n".

denom_row_format

An f_str object formatting the denom_row cells, shift layers only. Lets the denominator row carry its own width independent of the n_counts format (e.g. f_str("xx", "n") for a plain narrow integer). The f_str must reference a single variable (the denominator count is passed positionally). NULL (default) pads the integer to the width of the shift cells. An absent baseline group renders as 0 either way.

denom_where

Expression for separate denominator filter

denom_ignore

Character vector of values to exclude from denominators

distinct_by

Character string naming the variable for distinct counting

total_row

Logical, whether to add a total row

total_row_label

Character string for total row label

total_row_count_missings

Logical, include missing in total

missing_count

List configuring the Missing row. Recognized keys:

missing_values

Character vector of target values to fold into the Missing row alongside NA.

label

Row label; defaults to "Missing".

sort_value

Numeric sort key placing the row; defaults to Inf (last).

format

An f_str() overriding the layer's count format for this row.

denom_exclude

Logical. When TRUE, the rows counted as missing leave the layer's percentage denominator, so percentages are of the non-missing population. This applies to every row in the layer, including the Missing row itself and any total row. Defaults to FALSE.

Any other key is an error.

missing_subjects

Logical, add missing subjects row

missing_subjects_label

Character string for missing subjects label

keep_levels

Character vector of levels to keep

limit_data_by

Character vector for data limiting

custom_summaries

Named list of expressions for custom summaries

stats_as_columns

Logical, transpose stats to columns

precision_by

Character vector for precision grouping

precision_on

Character string for precision variable

precision_data

Data frame with external precision values

precision_cap

Named numeric vector c(int=, dec=)

order_count_method

Character, ordering method

ordering_cols

Character, which column drives ordering

result_order_var

Character, which result variable for ordering

outer_sort_position

Character, outer sort direction

risk_diff

List with risk difference configuration

ci_method

Method for the single-proportion confidence interval exposed through the ci_lower/ci_upper (and distinct_ci_lower/distinct_ci_upper) count-layer format keywords. One of "clopper_pearson" (default, exact / SAS PROC FREQ EXACT parity), "wilson" (score, matching stats::prop.test(correct = FALSE)), "wald", "agresti_coull", or "jeffreys". See proportion_ci.

ci_level

Numeric coverage probability for the single-proportion confidence interval keywords. Defaults to 0.95.

assoc_test

A assoc_test object attaching an association-test p-value column. Omnibus mode works on count, shift, and desc layers (a desc layer's continuous comparison, e.g. ANOVA/Kruskal); pairwise/per-level mode is count layers only.

pct_lt

Numeric less-than threshold for count-layer percents. A cell with a nonzero count whose percent would display below this value renders the percent as "<" followed by the threshold (e.g. pct_lt = 1 shows 1 ( <1%) instead of 1 ( 0%)). NULL disables.

pct_gt

Numeric greater-than threshold for count-layer percents. A cell whose percent is below 100 but would display above this value renders the percent as ">" followed by the threshold (e.g. pct_gt = 99 shows >99 for 99.6%). NULL disables.

zero_count_display

How to display count-layer cells whose count is zero: "full" (default) keeps the usual "0 ( 0%)"; "count_only" shows only the count field (e.g. " 0"); "blank" shows an empty string.

name

Character string, layer name for identification

Value

A tplyr_layer_settings object

Settings by Layer Type

Not all settings apply to every layer type. The table below shows which settings are applicable for each of the four layer types:

Setting Count Desc Shift Analyze
format_strings X X X X
stat_columns X
denoms_by X X X
shift_denom X
denom_row X
denom_row_label X
denom_row_format X
denom_where X X X
denom_ignore X X
distinct_by X X
total_row X
total_row_label X
total_row_count_missings X
missing_count X
missing_subjects X
missing_subjects_label X
keep_levels X
limit_data_by X
custom_summaries X
stats_as_columns X
precision_by X
precision_on X
precision_data X
precision_cap X
order_count_method X
ordering_cols X
result_order_var X
outer_sort_position X
risk_diff X
ci_method X
ci_level X
assoc_test X X X
pct_lt X
pct_gt X
zero_count_display X
name X X X X

Settings provided for an inapplicable layer type are silently ignored.

Examples

# Formats and special rows on a count layer
spec <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(
    group_count("AGEGR1", settings = layer_settings(
      format_strings = list(n_counts = f_str("xx (xx.x%)", "n", "pct")),
      total_row = TRUE,
      total_row_label = "Total subjects"
    ))
  )
)
tplyr_build(spec, tplyr_adsl)

# Denominators: percentages within each arm-by-sex cell rather than the arm
denom <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(
    group_count("AGEGR1", by = "SEX",
                settings = layer_settings(denoms_by = c("TRT01P", "SEX")))
  )
)
tplyr_build(denom, tplyr_adsl)

# Auto-precision on a desc layer: 'a' takes decimals from the data, and
# precision_cap bounds them.
prec <- tplyr_spec(
  cols = "TRTA",
  layers = tplyr_layers(
    group_desc("AVAL", by = "PARAMCD", settings = layer_settings(
      format_strings = list("Mean (SD)" = f_str("a.a+1 (a.a+2)", "mean", "sd")),
      precision_by = "PARAMCD",
      precision_cap = c(int = 3, dec = 2)
    ))
  )
)
head(tplyr_build(prec, tplyr_adlb))

# A custom summary adds a statistic the built-ins do not provide
cv <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(
    group_desc("AGE", settings = layer_settings(
      custom_summaries = list(cv = quote(sd(.var) / mean(.var) * 100)),
      format_strings = list("CV%" = f_str("xx.x", "cv"))
    ))
  )
)
tplyr_build(cv, tplyr_adsl)


Does a count layer's formats reference any CI keyword?

Description

Scans the layer's format_strings and stat_columns f_str ⁠$vars⁠ for one of the four confidence-interval keywords, so the (comparatively expensive) CI computation can be skipped entirely for layers that don't display one.

Usage

layer_uses_ci(settings)

Arguments

settings

A tplyr_layer_settings object

Value

Logical scalar


Build an equality filter expression

Description

Build an equality filter expression

Usage

make_eq_filter(var_name, value)

Build an inclusion filter expression

Description

Build an inclusion filter expression

Usage

make_in_filter(var_name, values)

Arguments

var_name

Character name of the variable

values

Vector of values for the inclusion set


Build an is.na() filter expression

Description

Build an is.na() filter expression

Usage

make_is_na_filter(var_name)

Build a filter for missing values (is.na OR %in% missing_values)

Description

Build a filter for missing values (is.na OR %in% missing_values)

Usage

make_missing_filter(var_name, missing_values = character(0))

Build an exclusion filter expression

Description

Build an exclusion filter expression

Usage

make_not_in_filter(var_name, values)

Arguments

var_name

Character name of the variable

values

Vector of values to exclude


Build a !is.na() filter expression

Description

Build a !is.na() filter expression

Usage

make_not_na_filter(var_name)

Attach an association-test result column to a wide layer result

Description

Adds a pval1 column carrying the formatted per-by-group result, placed on the first output row of each by group (blank elsewhere), with config$label as its label attribute.

Usage

merge_assoc_column(wide, assoc, by_rl_cols, by_data_vars, config)

Arguments

wide

data.table layer result (with rowlabel/res/ord columns).

assoc

data.table from compute_assoc_test().

by_rl_cols

Character vector of the rowlabel columns holding the by variable values (in by-variable order); empty when the layer has no by.

by_data_vars

Character vector of by data-variable names.

config

A tplyr_assoc_test object.


Combine pinned column levels with a layer's own

Description

The spec-level level set (every column-variable value in the table's data) takes precedence so a layer whose where empties a column group still emits that column. Any additional variable the layer knows about (a shift layer's own column variable) is carried through.

Usage

merge_col_levels(pinned, layer_levels)

Arguments

pinned

Named list of levels captured before layer filtering (or NULL)

layer_levels

Named list from get_col_levels() on the layer data

Value

Named list of levels


Attach pairwise per-level association-test columns to a wide layer result

Description

Appends one pval<k> column per comparison to the wide-format output, each carrying the formatted p-value on every target-level row (blank for special rows such as Total/Missing), with the per-comparison label as the column's label attribute.

Usage

merge_pairwise_assoc(
  wide,
  assoc_data,
  config,
  tv,
  by_data_vars,
  by_labels,
  reference
)

Arguments

wide

data.table in wide format (after cast_to_wide()).

assoc_data

data.table from compute_pairwise_assoc().

config

A tplyr_assoc_test object (pairwise mode).

tv

Character string naming the target variable.

by_data_vars

Character vector of by-variable names.

by_labels

Character vector of by string-labels (non-data by entries).

reference

Character(1) resolved reference arm level.


Attach pairwise association-test columns to a nested wide layer result

Description

Places each comparison's display string on every matching output row by an exact join on the rowlabel* columns (which uniquely identify a wide row across all nesting levels). Rows with no computed value – special rows such as Missing, or a Total row when total_row = FALSE – stay blank.

Usage

merge_pairwise_assoc_nested(
  wide,
  assoc_data,
  config,
  row_label_cols,
  reference
)

Arguments

wide

data.table in wide format (after cast_to_wide()).

assoc_data

data.table from compute_pairwise_assoc_nested().

config

A tplyr_assoc_test object (pairwise mode).

row_label_cols

Character vector of the rowlabel* column names.

reference

Character(1) resolved reference arm level.


Merge risk difference columns onto wide result

Description

Appends formatted risk difference columns to the wide-format output from cast_to_wide().

Usage

merge_risk_diff_columns(
  wide,
  rd_data,
  risk_diff_config,
  row_label_cols,
  tv,
  by_data_vars,
  by_labels = character(0)
)

Arguments

wide

data.table in wide format (after cast_to_wide)

rd_data

data.table with computed risk differences

risk_diff_config

List with comparisons, ci, format

row_label_cols

Character vector of row label column names

tv

Character string naming the target variable

by_data_vars

Character vector of by-variable names

by_labels

Character vector of constant by labels. Needed to find where the by data variables sit among the rowlabel columns — they follow the label columns, not rowlabel1.

Value

Modified wide data.table with rdiff columns appended


Grouping columns of a numeric-data snapshot

Description

Layer builders tag each snapshot with the columns that identify a row (see tag_numeric_group_cols()). Snapshots from an older build lack the attribute, so fall back to treating the non-numeric columns as grouping.

Usage

numeric_data_group_cols(nd)

Arguments

nd

A numeric-data snapshot data.frame

Value

Character vector of grouping column names


Build one pairwise 2x2 and render its display string

Description

Shared by the single-level and nested pairwise paths. Builds matrix(c(n_ref, n_cmp, N_ref - n_ref, N_cmp - n_cmp), nrow = 2), calls config$fn on it, and renders the return via format_assoc_return. A missing count/denominator or a zero denominator renders a blank (no test).

Usage

pairwise_cell_disp(n_ref, n_cmp, N_ref, N_cmp, config, group = NULL)

Arguments

n_ref, n_cmp

Event counts for the reference and comparison arm.

N_ref, N_cmp

Population denominators for the reference and comparison arm.

config

A tplyr_assoc_test object (pairwise mode).

group

Optional group identifier used when reporting a failure of config$fn.

Value

A length-1 character display string.


Parse a single format group

Description

Parse a single format group

Usage

parse_format_group(group_str)

Parse one side (int or dec) of a format group

Description

Parse one side (int or dec) of a format group

Usage

parse_format_part(part)

Parse a format string into groups and literals

Description

Parse a format string into groups and literals

Usage

parse_format_string(fmt)

Create a population data configuration

Description

Configuration object specifying how population data maps to the spec. The actual population data.frame is provided at build time via tplyr_build(spec, data, pop_data = ...).

Usage

pop_data(cols, where = NULL)

Arguments

cols

Character vector of column variable names in the population data. If named, names are the spec column names and values are the pop_data column names (e.g., c("TRTA" = "TRT01P")). If unnamed, maps positionally to spec cols.

where

Expression for filtering the population data (optional)

Value

A tplyr_pop_data object

Examples

# The AE data's TRTA maps to the subject-level TRT01P. Denominators and the
# header N then come from the population, not from the AE records.
spec <- tplyr_spec(
  cols = "TRTA",
  pop_data = pop_data(cols = c("TRTA" = "TRT01P")),
  layers = tplyr_layers(
    group_count("AEBODSYS",
                settings = layer_settings(distinct_by = "USUBJID"))
  )
)
built <- tplyr_build(spec, tplyr_adae, pop_data = tplyr_adsl)
head(built)

# Header N reflects the 254 enrolled subjects, not the 200 AE records
tplyr_header_n(built)

# Restrict the population to the safety set
saf <- pop_data(cols = c("TRTA" = "TRT01P"), where = SAFFL == "Y")
saf


Prepare the dcast column variable, respecting factor-level order

Description

For a single column variable, converts it to a factor ordered by col_levels so dcast() spreads columns in level order. For multiple column variables, builds the " | "-joined interaction column and, when any component is a factor, orders it by the cross-product of each variable's level order (outermost variable varies slowest). When no component is a factor the interaction is left as a character vector, so dcast() falls back to alphabetical order exactly as before.

Usage

prepare_cast_column(dt, cols, col_levels = NULL)

Arguments

dt

Long data.table about to be cast (mutated in place)

cols

Character vector of column variable names

col_levels

Named list from get_col_levels() (may be NULL/empty)

Value

The name of the variable to use on the RHS of the dcast formula


Confidence interval for a single binomial proportion

Description

Vectorized computation of a two-sided confidence interval for a single proportion x / n, using one of five standard methods. All methods are computed in closed form or via qbeta (no per-row binom.test loop), so the function scales to a full count table's worth of cells at once.

Usage

proportion_ci(
  x,
  n,
  method = c("clopper_pearson", "wilson", "wald", "agresti_coull", "jeffreys"),
  level = 0.95
)

Arguments

x

Numeric vector of event counts (numerators).

n

Numeric vector of trial counts (denominators). Recycled against x following the usual R rules.

method

One of "clopper_pearson" (default), "wilson", "wald", "agresti_coull", or "jeffreys".

level

Numeric coverage probability (default 0.95).

Details

The methods and their references:

clopper_pearson

Exact interval based on the beta distribution. Matches stats::binom.test() and SAS PROC FREQ ... EXACT (the clinical convention). This is the default.

wilson

Wilson score interval without continuity correction. Matches stats::prop.test(correct = FALSE).

wald

Normal-approximation ("simple asymptotic") interval, clamped to [0, 1].

agresti_coull

Adds z^2/2 pseudo-successes and pseudo-failures, then applies the Wald interval to the adjusted counts.

jeffreys

Bayesian interval using the Jeffreys Beta(0.5, 0.5) prior, with the standard boundary adjustments at x == 0 and x == n.

Edge cases: when n == 0 (or either input is NA) both bounds are NA; when x == 0 the lower bound is exactly 0; when x == n the upper bound is exactly 1.

Value

A data.table with two columns, lower and upper, giving the interval bounds as proportions in [0, 1] (multiply by 100 for the percentage scale).

Examples

proportion_ci(c(0, 12, 40), c(40, 40, 40), method = "clopper_pearson")


Reconstruct a single layer from ARD data

Description

Reconstruct a single layer from ARD data

Usage

reconstruct_layer_from_ard(layer_ard, layer, cols, layer_index)

Record a failure in user-supplied code

Description

A no-op outside collect_user_fn_errors(), so helpers stay callable from tests and from code paths that run outside a build.

Usage

record_user_fn_error(label, cond, group = NULL)

Arguments

label

What failed, e.g. "custom summary 'geo_mean'"

cond

The condition caught

group

Optional human-readable group identifier, e.g. "SEX = F, TRT01P = Placebo"

Value

Invisible NULL, called for its side effect


Re-attach total/distinct_total denominators after grid completion

Description

Grid completion introduces rows whose denominators come out NA from the left join; refill them from the pre-completion counts, keyed by denom_group (or fallback_cols when no denom_group applies).

Usage

refill_denom_totals(result, counts, denom_group, fallback_cols)

Rename ordering columns to the public output names

Description

Renames ordindx to ord_layer_index and ord1/ord2/... to ord_layer_1/ord_layer_2/...

Usage

rename_ord_columns(result)

Arguments

result

data.table

Value

Modified data.table (by reference)


Replace leading whitespace with a specified string

Description

Useful for HTML rendering where leading spaces are collapsed.

Usage

replace_leading_whitespace(x, replace_with = " ")

Arguments

x

Character vector

replace_with

Replacement string for each leading space

Value

Character vector with leading spaces replaced

Examples

# Indentation survives an HTML renderer that would collapse plain spaces
terms <- c("CARDIAC DISORDERS", "   ATRIAL FIBRILLATION")
out <- replace_leading_whitespace(terms)
out

# One replacement per leading space; interior spacing is untouched
replace_leading_whitespace("  A B", replace_with = "-")


Record an assoc_test return-shape mismatch

Description

Record an assoc_test return-shape mismatch

Usage

report_assoc_shape_mismatch(label, group, detail)

Resolve the reference arm level for a pairwise association test

Description

Returns config$reference when supplied, otherwise the first level of the first cols variable at build time (factor level order when the variable is a factor, else first value in appearance order).

Usage

resolve_assoc_reference(config, dt, cols)

Arguments

config

A tplyr_assoc_test object.

dt

data.table of source rows for the layer.

cols

Character vector of column variable names from the spec.

Value

Character(1) reference level.


Resolve per-comparison p-value column labels

Description

Default is "<reference> vs <comparison>"; a single configured label recycles across comparisons; a vector is used as-is.

Usage

resolve_pairwise_labels(config, reference)

Resolve population data column mapping

Description

Maps population data columns to spec columns. Handles named (explicit) and unnamed (positional) mapping.

Usage

resolve_pop_cols(pop_config, spec_cols)

Arguments

pop_config

A tplyr_pop_data object or NULL

spec_cols

Character vector of spec-level column names

Value

Character vector of column names to use in the population data


Resolve auto-precision widths for a format group

Description

Given a parsed format group and collected precision values, returns the effective integer width and decimal width.

Usage

resolve_precision(group, max_int, max_dec)

Arguments

group

A parsed format group (from parse_format_group)

max_int

Integer, the collected max integer width

max_dec

Integer, the collected max decimal precision

Value

list(int_width, dec_width)


Locate the rowlabel columns to join summary statistics back on

Description

The inverse of build_row_labels_long()'s layout: one rowlabel column per constant by label first, then one per by data variable, then the target variable last. Callers that merge per-group statistics (risk difference, pairwise p-values) onto the assembled table need the data variable columns; assuming they start at rowlabel1 keys the join against a constant-label column whenever by leads with a string label, matching nothing and leaving every cell blank.

Usage

resolve_rowlabel_join_cols(wide, by_labels, by_data_vars)

Arguments

wide

Assembled wide table

by_labels

Character vector of constant by labels

by_data_vars

Character vector of by data variable names

Value

List with tv_col (the target variable's rowlabel column) and by_cols (the by data variables' rowlabel columns, in by_data_vars order), or NULL when wide has no rowlabel columns


Restore the atomic type of the plain settings fields

Description

Restore the atomic type of the plain settings fields

Usage

restore_settings_field_types(raw)

Arguments

raw

Named list of parsed settings

Value

raw with each plain field coerced to its declared vector type


Percentage of a count against its denominator

Description

The one 0-vs-NA convention for the whole package. Without a usable denominator the percentage is undefined, so it is NA and renders blank — count and shift layers used to render 0, which for n > 0 is an affirmatively wrong number, while desc layers already used NA.

Usage

safe_pct(n, total)

Arguments

n

Numeric vector of counts

total

Numeric vector of denominators

Value

Numeric vector of percentages, NA where the denominator is NA or 0


Convert raw parsed JSON/YAML back to tplyr_spec

Description

Convert raw parsed JSON/YAML back to tplyr_spec

Usage

serializable_to_spec(raw)

Serialize the by parameter

Description

Serialize the by parameter

Usage

serialize_by(by)

Serialize an expression (or NULL)

Description

rlang::expr_deparse() wraps at 60 characters by default, which any realistic multi-condition filter exceeds. parse_expr() on read needs a single string, so the deparsed pieces are always collapsed to one.

Usage

serialize_expr(expr)

Serialize an f_str object

Description

Serialize an f_str object

Usage

serialize_f_str(fmt)

Serialize a function

Description

Serialize a function

Usage

serialize_function(fn)

Serialize a single layer

Description

Serialize a single layer

Usage

serialize_layer(layer)

Serialize layer settings

Description

Serialize layer settings

Usage

serialize_settings(settings)

Atomic-vector types of the plain layer settings

Description

JSON arrays always parse back as lists (simplifyVector = FALSE), which erases both the vector type and the distinction between a length-1 vector and a list. This table is the single source of truth used by deserialize_settings() to restore each plain setting to the vector type the build code expects. test-serialize.R asserts that every layer_settings() formal appears here or in serialize_special_fields, so a newly added setting cannot silently round-trip as a list.

Usage

settings_field_types()

Value

Named list of character vectors, keyed by storage mode


Sort column names by their numeric suffix

Description

Lexicographic sorting places "res10" before "res2"; ordering by the numeric suffix keeps columns in build order once a family has more than 9 members.

Usage

sort_by_numeric_suffix(x)

Sort bound layer results by layer index, then within-layer ord columns

Description

Sorts by reference. other_ord sorts lexicographically, which is stable for the single-digit ord counts layers produce today.

Usage

sort_by_ord_columns(result)

Sort nested count data for correct interleaving

Description

Sort nested count data for correct interleaving

Usage

sort_nested(
  combined,
  target_vars,
  by_data_vars,
  dt = NULL,
  outer_sort_position = NULL,
  order_count_method = NULL,
  result_order_var = "n",
  ordering_cols = NULL,
  cols = character(0)
)

Convert spec to a plain list suitable for JSON/YAML

Description

Convert spec to a plain list suitable for JSON/YAML

Usage

spec_to_serializable(spec)

Extract numeric values from formatted strings

Description

Extracts the Nth numeric value from a formatted tplyr2 string.

Usage

str_extract_num(x, index = 1L)

Arguments

x

Character vector of formatted strings

index

Integer, which numeric value to extract (1-based)

Value

Numeric vector

Examples

cells <- c(" 22 (25.6%)", "  9 (10.5%)", " 55 (64.0%)")

# Default pulls the count; index = 2 pulls the percent
str_extract_num(cells)
str_extract_num(cells, index = 2)

# Asking past the available numbers gives NA, as does an NA input
str_extract_num(c(" 5", NA), index = 2)

# Recover a sort key from an already-formatted table
built <- tplyr_build(
  tplyr_spec(cols = "TRT01P", layers = tplyr_layers(group_count("AGEGR1"))),
  tplyr_adsl
)
built[order(-str_extract_num(built$res1)), c("rowlabel1", "res1")]


Wrap strings to a specific width with hyphenation while preserving indentation

Description

Leverages stringr::str_wrap() under the hood, but takes extra steps to preserve any indentation that has been applied to a character element, and use hyphenated wrapping of single words that run longer than the allotted wrapping width.

Usage

str_indent_wrap(x, width = 10, tab_width = 5)

Arguments

x

An input character vector

width

The desired width of elements within the output character vector

tab_width

The number of spaces to which tabs should be converted

Details

stringr::str_wrap() is highly efficient, but in the context of table creation there are two features missing — hyphenation for long running strings that overflow width, and respect for pre-indentation of a character element. For example, in an adverse event table, you may have body system rows as an un-indented column, and preferred terms as indented columns. These strings may run long and require wrapping to not surpass the column width. Furthermore, for crowded tables a single word may be longer than the column width itself.

This function resolves these two issues, while minimizing additional overhead required to apply the wrapping of strings.

Note: This function automatically converts tabs to spaces. Tab width varies depending on font, so width cannot automatically be determined within a data frame. Users can specify the width via tab_width.

Value

A character vector with string wrapping applied

Examples

ex_text1 <- c("RENAL AND URINARY DISORDERS", "   NEPHROLITHIASIS")
ex_text2 <- c("RENAL AND URINARY DISORDERS", "\tNEPHROLITHIASIS")

cat(paste(str_indent_wrap(ex_text1, width = 8), collapse = "\n\n"), "\n")
cat(paste(str_indent_wrap(ex_text2, tab_width = 4), collapse = "\n\n"), "\n")

Name of the per-column-variable synthetic-row marker

Description

Records which column variable a duplicated row was created for, so a total group can skip copies made on its own variable while still spanning copies made for a different one.

Usage

synth_marker(col_var)

Arguments

col_var

Character(1) column variable name

Value

Character(1) marker column name


Tag a numeric-data snapshot with its grouping columns

Description

Records which columns identify a row rather than hold a statistic, so tplyr_stats_data() can subset to grouping columns plus one statistic without guessing from column types (a grouping variable can be numeric).

Usage

tag_numeric_group_cols(snapshot, group_cols)

Arguments

snapshot

data.table snapshot, modified by reference

group_cols

Character vector of candidate grouping column names

Value

snapshot, invisibly


Create a total group configuration

Description

Specifies that a synthetic "Total" column level should be added by duplicating all rows with the specified column variable set to the label.

Usage

total_group(col_var, label = "Total")

Arguments

col_var

Character string naming the column variable to totalize

label

Character string for the total group label (default: "Total")

Value

A tplyr_total_group object

Examples

# Adds a "Total" column spanning every arm, alongside the individual arms
spec <- tplyr_spec(
  cols = "TRT01P",
  total_groups = list(total_group("TRT01P")),
  layers = tplyr_layers(group_count("AGEGR1"))
)
tplyr_build(spec, tplyr_adsl)

# Rename the total column
all_pts <- tplyr_spec(
  cols = "TRT01P",
  total_groups = list(total_group("TRT01P", label = "All Patients")),
  layers = tplyr_layers(group_count("SEX"))
)
tplyr_build(all_pts, tplyr_adsl)


Get or set tplyr2 package options

Description

View and modify tplyr2-specific options. When called with no arguments, returns all current tplyr2 options with their defaults. When called with named arguments, sets those options.

Usage

tplyr2_options(...)

Arguments

...

Named arguments to set (e.g., IBMRounding = TRUE). Option names are automatically prefixed with tplyr2..

Details

Available options:

tplyr2.IBMRounding

Logical. Use round-half-away-from-zero instead of R's default banker's rounding. Default: FALSE.

tplyr2.quantile_type

Integer. Quantile algorithm type passed to quantile(). Default: 7.

tplyr2.precision_cap

Named numeric vector c(int=, dec=). Maximum int/dec widths for auto-precision. Default: NULL.

tplyr2.custom_summaries

Named list of expressions for global custom summary functions. Default: NULL.

tplyr2.scipen

Integer. scipen value used during tplyr_build() to prevent scientific notation. Default: 9999.

An unrecognized option name is an error rather than a silent no-op, so a misspelling cannot quietly leave the build on the default behavior.

Value

When called with no arguments, a named list of current option values. When called with arguments, invisibly returns the previous values.

Examples

# Inspect the current values
tplyr2_options()

# Setting returns the previous values, so the change can be undone
old <- tplyr2_options(IBMRounding = TRUE)
getOption("tplyr2.IBMRounding")
do.call(options, old)
getOption("tplyr2.IBMRounding")

# IBM (half-away-from-zero) rounding vs R's banker's rounding
fmt <- f_str("xx", "n")
apply_formats(fmt, n = 2.5)
old <- tplyr2_options(IBMRounding = TRUE)
apply_formats(fmt, n = 2.5)
do.call(options, old)

# A misspelled name errors instead of setting a dead option
try(tplyr2_options(IBMrounding = TRUE))


Adverse events analysis dataset

Description

A sample CDISC ADaM ADAE dataset from the PHUSE Test Data Factory. Contains adverse event records.

Usage

tplyr_adae

Format

A data.frame


Laboratory data analysis dataset

Description

A sample CDISC ADaM ADLB dataset from the PHUSE Test Data Factory. Contains laboratory test results.

Usage

tplyr_adlb

Format

A data.frame


Subject-level analysis dataset

Description

A sample CDISC ADaM ADSL dataset from the PHUSE Test Data Factory. Contains subject-level demographics and baseline characteristics.

Usage

tplyr_adsl

Format

A data.frame


Build a tplyr2 table from a spec and data

Description

Executes the table specification against the provided data, producing a formatted output data frame.

Usage

tplyr_build(spec, data, pop_data = NULL, metadata = FALSE, ...)

Arguments

spec

A tplyr_spec object (or path to a JSON/YAML spec file)

data

A data.frame to process

pop_data

Optional population data.frame (overrides spec pop_data)

metadata

If TRUE, attach cell-level metadata enabling traceability back to source data rows via tplyr_meta_result() and tplyr_meta_subset().

...

Additional named arguments overriding spec-level parameters. Names must match a field of spec (or where/pop_data); an unrecognized name is an error rather than a silent no-op. Because ... is evaluated eagerly, a where override must be a character string or a quoted expression, not the bare expression tplyr_spec() accepts.

Value

A data.frame with rowlabel, res, and ord columns

See Also

tplyr_spec() to build the specification, and tplyr_numeric_data() for the unformatted values behind the cells.

Examples

spec <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(group_count("AGEGR1"))
)
tplyr_build(spec, tplyr_adsl)

# Override spec fields at build time without editing the spec. Overrides go
# through `...`, which evaluates eagerly, so a `where` must be a string or
# quoted -- not the bare expression tplyr_spec() accepts.
tplyr_build(spec, tplyr_adsl, where = "SEX == 'F'")
tplyr_build(spec, tplyr_adsl, where = quote(SEX == "F"))

# Population data supplies the denominators and the header N
pop_spec <- tplyr_spec(
  cols = "TRTA",
  pop_data = pop_data(cols = c("TRTA" = "TRT01P")),
  layers = tplyr_layers(
    group_count("AEBODSYS",
                settings = layer_settings(distinct_by = "USUBJID"))
  )
)
head(tplyr_build(pop_spec, tplyr_adae, pop_data = tplyr_adsl))


Reconstruct a formatted table from ARD and a spec

Description

Takes Analysis Results Data (long format) and a tplyr_spec, then applies the spec's formatting rules to produce a formatted output table.

Usage

tplyr_from_ard(ard, spec)

Arguments

ard

A data.frame in ARD format (as produced by tplyr_to_ard())

spec

A tplyr_spec object defining the table structure

Value

A data.frame with the same structure as tplyr_build() output

See Also

tplyr_to_ard() to produce the ARD.

Examples

spec <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(group_desc("AGE"))
)
built <- tplyr_build(spec, tplyr_adsl)

# Round-tripping through the ARD reproduces the formatted cells, so a table
# can be rebuilt from stored results without the subject-level data
ard <- tplyr_to_ard(built)
recon <- tplyr_from_ard(ard, spec)
recon[, c("rowlabel1", "res1")]
identical(as.vector(recon$res1), as.vector(built$res1))

# Changing only the spec's formats re-renders the same numbers differently
respec <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(
    group_desc("AGE", settings = layer_settings(
      format_strings = list("Mean (SD)" = f_str("xx.xx (xx.xxx)", "mean", "sd"))))
  )
)
tplyr_from_ard(ard, respec)[, c("rowlabel1", "res1")]


Extract header N from a tplyr2 build result

Description

Returns the population-based header N values that were computed during tplyr_build(). Only available when population data was provided.

Usage

tplyr_header_n(result)

Arguments

result

A data.frame produced by tplyr_build()

Value

A data.frame with column variable levels and their N values, or NULL if no population data was used.

Examples

spec <- tplyr_spec(
  cols = "TRTA",
  pop_data = pop_data(cols = c("TRTA" = "TRT01P")),
  layers = tplyr_layers(group_count("AEBODSYS"))
)
built <- tplyr_build(spec, tplyr_adae, pop_data = tplyr_adsl)
tplyr_header_n(built)

# NULL when the build had no population data to draw an N from
no_pop <- tplyr_build(
  tplyr_spec(cols = "TRT01P", layers = tplyr_layers(group_count("SEX"))),
  tplyr_adsl
)
tplyr_header_n(no_pop)


Create a list of layers

Description

Wraps one or more layer objects into a validated list for use in tplyr_spec().

Usage

tplyr_layers(...)

Arguments

...

Layer objects created by group_count(), group_desc(), group_shift(), or group_analyze()

Value

A list of tplyr_layer objects

Examples

# Layers stack in the order given, and may mix types freely
layers <- tplyr_layers(
  group_desc("AGE"),
  group_count("SEX"),
  group_count("AGEGR1")
)
length(layers)

spec <- tplyr_spec(cols = "TRT01P", layers = layers)
tplyr_build(spec, tplyr_adsl)


Metadata object for a tplyr output cell

Description

Contains filter expressions that, when evaluated against the original data, reproduce the subset of rows that contributed to a specific cell in the output table.

Usage

tplyr_meta(
  names = character(0),
  filters = list(),
  layer_index = integer(0),
  anti_join = NULL,
  statistic = NULL
)

Arguments

names

Character vector of variable names relevant to this cell

filters

List of R language objects (call expressions) representing filter conditions

layer_index

Integer layer index (1-based)

anti_join

NULL or a tplyr_meta_anti_join object for missing subjects rows

statistic

NULL or a character string naming which statistic the cell displays (set for stat_columns layers, where the stat sub-columns of a column group share the same source-data filters)

Value

A tplyr_meta object

See Also

tplyr_meta_result() to retrieve one from a build.

Examples

# Usually obtained from a build rather than constructed by hand
m <- tplyr_meta(
  names = c("TRT01P", "AGEGR1"),
  filters = list(quote(TRT01P == "Placebo"), quote(AGEGR1 == "65-80")),
  layer_index = 1L
)
m

# The filters are ordinary language objects, so they can be applied directly
subset(tplyr_adsl, TRT01P == "Placebo" & AGEGR1 == "65-80")[1:3, c("USUBJID", "AGEGR1")]


Anti-join metadata for missing subjects

Description

Anti-join metadata for missing subjects

Usage

tplyr_meta_anti_join(join_meta, on)

Arguments

join_meta

A tplyr_meta object with filters for the population data

on

Character vector of join key variable names (e.g., "USUBJID")

Value

A tplyr_meta_anti_join object


Get metadata for a specific output cell

Description

Returns a tplyr_meta object containing the filter expressions that describe the source data for the specified cell.

Usage

tplyr_meta_result(result, row_id, column)

Arguments

result

A data.frame from tplyr_build() built with metadata = TRUE

row_id

Character row ID (from result$row_id or generate_row_ids())

column

Character column name (e.g., "res1")

Value

A tplyr_meta object, or NULL if no metadata for that cell

See Also

tplyr_meta_subset() to fetch the source rows themselves.

Examples

spec <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(group_count("AGEGR1"))
)
built <- tplyr_build(spec, tplyr_adsl, metadata = TRUE)
built[, c("row_id", "rowlabel1", "res1")]

# The filters behind the Placebo / 65-80 cell
tplyr_meta_result(built, built$row_id[1], "res1")


Get source data rows for a specific output cell

Description

Evaluates the stored filter expressions against the original data to return the rows that contributed to the specified output cell.

Usage

tplyr_meta_subset(result, row_id, column, data, pop_data = NULL)

Arguments

result

A data.frame from tplyr_build() built with metadata = TRUE

row_id

Character row ID

column

Character column name (e.g., "res1")

data

The original data.frame that was passed to tplyr_build()

pop_data

Optional population data.frame, required when the cell represents a missing subjects row (anti-join)

Value

A data.frame subset of the original data, or NULL if no metadata

Examples

spec <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(group_count("AGEGR1"))
)
built <- tplyr_build(spec, tplyr_adsl, metadata = TRUE)
built[, c("row_id", "rowlabel1", "res1")]

# Trace the first cell back to the subjects it counted
src <- tplyr_meta_subset(built, built$row_id[1], "res1", tplyr_adsl)
nrow(src)
head(src[, c("USUBJID", "TRT01P", "AGEGR1")])

# The row count matches the number displayed in the cell
built$res1[1]


Retrieve raw numeric data from a tplyr_build result

Description

Returns the unformatted numeric data that was computed during the build process, before formatting and pivoting to wide format.

Usage

tplyr_numeric_data(result, layer = NULL)

Arguments

result

A data.frame produced by tplyr_build()

layer

Integer layer index (1-based), or NULL for all layers

Value

If layer is specified, a data.frame of raw statistics for that layer. If layer is NULL, a named list of data.frames keyed by layer index. Returns NULL if numeric data was not retained.

See Also

tplyr_stats_data() for a single statistic with its grouping columns.

Examples

spec <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(
    group_count("AGEGR1"),
    group_desc("AGE")
  )
)
built <- tplyr_build(spec, tplyr_adsl)

# One data.frame per layer, keyed by layer index
names(tplyr_numeric_data(built))

# The counts behind the formatted cells, before rounding and padding
head(tplyr_numeric_data(built, 1))

# Every statistic the desc layer computed, including unused ones
names(tplyr_numeric_data(built, 2))


Read a tplyr_spec from JSON or YAML

Description

Deserializes a spec from a file. Expressions are reconstructed from their string representations.

Usage

tplyr_read_spec(path)

Arguments

path

File path to a JSON or YAML spec file

Value

A tplyr_spec object

See Also

tplyr_write_spec() to write one.

Examples

spec <- tplyr_spec(
  cols = "TRT01P",
  where = SAFFL == "Y",
  layers = tplyr_layers(group_count("AGEGR1", by = "SEX"))
)

path <- file.path(tempdir(), "spec.json")
tplyr_write_spec(spec, path)

# The round trip reproduces the spec, and the same table
spec2 <- tplyr_read_spec(path)
spec2
identical(tplyr_build(spec, tplyr_adsl), tplyr_build(spec2, tplyr_adsl))

# tplyr_build() also accepts a spec file path directly
head(tplyr_build(path, tplyr_adsl))

unlink(path)


Round numbers with optional IBM rounding

Description

When getOption("tplyr2.IBMRounding", FALSE) is TRUE, uses round-half-away-from-zero (IBM convention) instead of R's default banker's rounding (round half to even).

Usage

tplyr_round(x, digits = 0)

Arguments

x

Numeric vector

digits

Number of decimal places

Value

Numeric vector


Create a tplyr2 table specification

Description

The spec is a pure configuration object describing what to compute. No data processing occurs until tplyr_build() is called.

Usage

tplyr_spec(
  cols,
  where = NULL,
  pop_data = NULL,
  total_groups = NULL,
  custom_groups = NULL,
  layers = tplyr_layers(),
  settings = NULL
)

Arguments

cols

Character vector of column variable names

where

Expression for global data filter (optional)

pop_data

A pop_data() object for population-based features (optional)

total_groups

List of total_group() objects (optional)

custom_groups

List of custom_group() objects (optional)

layers

A list of layer objects from tplyr_layers()

settings

Additional spec-level settings (optional)

Value

A tplyr_spec object

See Also

tplyr_build() to execute a spec, tplyr_layers() to assemble layers, and layer_settings() for per-layer configuration.

Examples

# A spec is inert configuration -- nothing is computed until tplyr_build()
spec <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(
    group_count("AGEGR1"),
    group_desc("AGE")
  )
)
spec

tplyr_build(spec, tplyr_adsl)

# A global `where` filter applies to every layer
safety <- tplyr_spec(
  cols = "TRT01P",
  where = SAFFL == "Y",
  layers = tplyr_layers(group_count("SEX"))
)
tplyr_build(safety, tplyr_adsl)


Retrieve raw statistic values from a tplyr_build result

Description

Filters the raw numeric data for a specific layer and statistic. Use tplyr_numeric_data() to get every statistic for the layer.

Usage

tplyr_stats_data(result, layer, statistic)

Arguments

result

A data.frame produced by tplyr_build()

layer

Integer layer index (1-based)

statistic

Character string naming the statistic column to extract (e.g., "n", "pct", "mean", "sd")

Value

A data.frame with the layer's grouping columns and the requested statistic. Returns NULL if the layer has no numeric data or does not compute the statistic.

Examples

spec <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(group_desc("AGE"))
)
built <- tplyr_build(spec, tplyr_adsl)
tplyr_stats_data(built, 1, "mean")


Convert tplyr_build output to Analysis Results Data (ARD) format

Description

Transforms the numeric data attached to a tplyr_build() result into a long-format data frame with one row per statistic per group combination. This is compatible with the CDISC Analysis Results Data standard.

Usage

tplyr_to_ard(result)

Arguments

result

A data.frame produced by tplyr_build()

Value

A data.frame in long format with columns:

analysis_id

Integer layer index

stat_name

Character name of the statistic

stat_value

Numeric value of the statistic

...

Grouping columns from the original data

See Also

tplyr_from_ard() to rebuild a formatted table from an ARD.

Examples

spec <- tplyr_spec(
  cols = "TRT01P",
  layers = tplyr_layers(
    group_count("AGEGR1"),
    group_desc("AGE")
  )
)
built <- tplyr_build(spec, tplyr_adsl)

ard <- tplyr_to_ard(built)
head(ard)

# One row per statistic per group; analysis_id identifies the layer
table(ard$analysis_id)
unique(ard$stat_name[ard$analysis_id == 2])


Write a tplyr_spec to JSON or YAML

Description

Serializes a spec object to a file. The format is determined by the file extension: .json for JSON, .yaml or .yml for YAML.

Usage

tplyr_write_spec(spec, path)

Arguments

spec

A tplyr_spec object

path

File path. Extension determines format.

Details

Expressions (e.g., where clauses) are deparsed to strings and reconstructed on read. Format string objects (f_str) are stored as their component parts and regenerated on read.

Value

Invisible file path

See Also

tplyr_read_spec() to read one back.

Examples

spec <- tplyr_spec(
  cols = "TRT01P",
  where = SAFFL == "Y",
  layers = tplyr_layers(
    group_count("AGEGR1", by = "SEX", settings = layer_settings(
      denoms_by = c("TRT01P", "SEX"),
      format_strings = list(n_counts = f_str("xx (xx.x%)", "n", "pct"))))
  )
)

path <- file.path(tempdir(), "spec.json")
tplyr_write_spec(spec, path)
cat(readLines(path), sep = "\n")

# YAML is chosen by the file extension
if (requireNamespace("yaml", quietly = TRUE)) {
  ypath <- file.path(tempdir(), "spec.yaml")
  tplyr_write_spec(spec, ypath)
  cat(readLines(ypath), sep = "\n")
  unlink(ypath)
}
unlink(path)


Translate a group value to filter expressions

Description

When a column value corresponds to a total group or custom group label, translates back to the appropriate filter. Total groups produce no filter (all values pass). Custom groups produce a %in% filter with component values.

Usage

translate_group_value(value, col_var, total_groups, custom_groups)

Arguments

value

The column value from the output (e.g., "Total", "Active")

col_var

The column variable name

total_groups

List of tplyr_total_group objects

custom_groups

List of tplyr_custom_group objects

Value

A list with filters (list of call expressions) and is_total (logical)


Transpose stats-as-columns

Description

Transposes the standard wide output so that statistics become columns. Without a by variable, treatment groups become the rows and stat names become the columns. With a by variable, the by groups stay as rows and each column is a treatment x statistic combination (issue #20) — e.g. one "Arm A | Mean" and "Arm A | n" column per treatment — so the by dimension is preserved instead of being collapsed.

Usage

transpose_stats_to_columns(wide)

Arguments

wide

data.table from standard desc processing

Value

Transposed data.table


Transpose desc stats to columns while keeping by groups as rows

Description

Produces one row per by-group combination and one result column per treatment x statistic, ordered treatment-major then statistic. Result columns carry a "<treatment label> | <stat name>" label attribute following the same grammar as count-layer stat_columns.

Usage

transpose_stats_with_by(wide, res_cols, trt_labels, by_cols, stat_col)

Validate data compatibility at build time

Description

Checks that the columns referenced in the spec actually exist in the data. Called after data conversion to data.table.

Usage

validate_build_data(spec, dt)

Arguments

spec

A tplyr_spec object

dt

A data.table

Value

Invisible TRUE if valid


Validate that every layer produces the same result-column shape

Description

Result columns are aligned positionally by name across layers. A shift layer emits one column per cols level crossed with its shift-column variable, and a stats_as_columns desc layer emits one per level crossed with each statistic. Either alongside a layer with the plain one-column-per- level shape leaves the combined table's res columns meaning different things in different row blocks, with only the first layer's column labels retained — so the values appear under the wrong treatment arm.

Usage

validate_column_shape_alignment(layers)

Arguments

layers

List of tplyr_layer objects

Value

Invisible TRUE if valid


Validate denoms_by against the layer's grouping variables

Description

Most denominator merges join on intersect(denom_group, names(x)). A denoms_by naming a variable that is not one of the layer's grouping columns silently shrinks the join-key set, leaving the denominator table with several rows per remaining key — so the merge either multiplies table rows or attaches another group's denominator, with no error. Pinning the invariant here makes every one of those intersects provably a no-op.

Usage

validate_denoms_by(layer, index, cols, dt_names)

Arguments

layer

A tplyr_layer object

index

Integer layer index

cols

Character vector of spec-level column variables

dt_names

Column names of the build data

Value

Invisible TRUE


Validate format strings in layer settings

Description

Validate format strings in layer settings

Usage

validate_format_strings(fmt_list, layer_index)

Arguments

fmt_list

A named list expected to contain f_str objects

layer_index

Integer layer index (for error messages)

Value

Invisible TRUE if valid


Validate a single layer

Description

Validate a single layer

Usage

validate_layer(layer, index, cols = NULL)

Arguments

layer

A tplyr_layer object

index

Integer layer index (for error messages)

cols

Character vector of spec column variables (for cross-checks such as pairwise assoc_test); may be NULL when validating a layer in isolation.

Value

Invisible TRUE if valid


Validate that format string vars are valid stats for the layer type

Description

Issues warnings (not errors) for unrecognized statistic names, since custom summaries can add arbitrary stat names.

Usage

validate_layer_stats(layer, index)

Arguments

layer

A tplyr_layer object

index

Integer layer index

Value

Invisible TRUE


Validate the keys of a missing_count configuration

Description

missing_count is a free-form list, so an unrecognized key used to be accepted and then never read — the table built without the requested behavior and nothing pointed at the mistake.

Usage

validate_missing_count(missing_count, index)

Arguments

missing_count

The layer's missing_count setting

index

Integer layer index

Value

Invisible TRUE


Warn when pop_data does not cover the analysis data's column levels

Description

A column level present in the analysis data but absent from the population (an arm recoded "Xanomeline High Dose" vs "High Dose") yields an NA denominator for every one of its cells.

Usage

validate_pop_data_coverage(dt, pop_dt, cols)

Arguments

dt

Analysis data.table

pop_dt

Population data.table, or NULL

cols

Character vector of column variables

Value

Invisible TRUE


Validate a tplyr_spec object structurally

Description

Checks that the spec has the correct class and structure. Called after overrides are applied but before data is processed.

Usage

validate_spec(spec)

Arguments

spec

A tplyr_spec object

Value

Invisible TRUE if valid, otherwise stops with informative error


Validate stat_columns in layer settings

Description

Validate stat_columns in layer settings

Usage

validate_stat_columns(stat_cols, layer_index)

Arguments

stat_cols

A named list expected to contain f_str objects

layer_index

Integer layer index (for error messages)

Value

Invisible TRUE if valid


Validate stat_columns consistency across layers

Description

Layers using stat_columns emit one res column per statistic per column group, while other layers emit one per column group. harmonize_and_bind() aligns layers positionally by res column name, so mixing the two shapes in one spec would silently place results under the wrong column labels.

Usage

validate_stat_columns_alignment(layers)

Arguments

layers

List of tplyr_layer objects

Value

Invisible TRUE if valid


Emit the collected user-code failures as a single warning

Description

Emit the collected user-code failures as a single warning

Usage

warn_user_fn_errors(entries)

Arguments

entries

List of entries recorded by record_user_fn_error()

Value

Invisible NULL


Zero-fill count statistics left NA by grid completion or merges

Description

Counts left NA by grid completion are genuine zeros. Percentages are not: a percentage is only zero when a usable denominator says so, and filling one whose denominator is missing or zero would print a number that was never computed (#76). Those stay NA and render blank.

Usage

zero_fill_stats(dt)

Arguments

dt

data.table to modify by reference

Value

dt, invisibly