Skip to contents

ltsummary 0.9.0

  • add_difference() gains the "cohens_d", "hedges_g", "paired_cohens_d" and "paired_hedges_g" methods, the standardized mean differences gtsummary computes with effectsize, here in base R: the difference in means over the pooled standard deviation (or over the root mean of the two variances, with Welch’s degrees of freedom, when test.args passes pooled_sd = FALSE), the mean of the pair differences over their standard deviation for the paired forms, the noncentral t interval, and the exact small-sample correction for Hedges’ g. test.args also accepts mu and alternative; a name effectsize would ignore is an error here. The interval solves the noncentral t equations exactly where effectsize approximates them with optim(), so the limits agree to within 1e-6 and the formatted cells match. effectsize joins Suggests as the test oracle, as car does for add_vif().

ltsummary 0.8.0

  • The mirrored interface moves from gtsummary 2.5.1 to gtsummary 2.6.1, the CRAN release of 2026-09-04 (decisions/0021). The 2.6 releases change no table defaults and deprecate nothing; their additions are adopted below. lt 0.4 is supported as is: its new em dash for missing cells never shows because as_lt() blanks every missing cell before rendering, and spanning headers remain a single row.
  • theme_ltsummary_language() gains Bosnian ("ba"), and the embedded translation table is gtsummary 2.6.1’s: the French strings were revised there, so the p-value header reads “Valeur p” and the Welch and Student t-tests are named apart.
  • modify_abbreviation() follows the released form of gtsummary 2.6.0: prefix is two strings, singular and plural (c("Key", "Keys"); c("", "") drops the leading text and its separator), prefix, sep1 and sep2 default to the new theme elements "modify_abbreviation-arg:prefix", "modify_abbreviation-arg:sep1" and "modify_abbreviation-arg:sep2", only the default prefix is translated, and the values persist across calls. A single-string prefix, accepted since 0.2.0, is an error now.
  • add_difference() gains levels, the two by levels to compare in the order levels[1] minus levels[2]: required when by has more than two levels, and a way to flip the direction when it has two. The table keeps every group’s column, and a header footnote names the pair, as in gtsummary 2.6.0.
  • sort_hierarchical() gains by_level, one level of the by variable whose counts alone rank the rows of a "descending" sort, as in gtsummary 2.6.0.
  • add_difference() gains a method for tbl_hierarchical() tables: a “Rate Difference” column with the difference between the event rates of two by levels on every row, chosen and ordered with levels, shown through the statistic pattern and formatted by estimate_fun, with a footnote naming the pair, as in gtsummary 2.6.0. gtsummary computes it on its cards ARD; ltsummary subtracts the stored rates, so sorted and filtered tables work too. See ?add_difference_hierarchical.
  • without_ltsummary_theme() evaluates an expression with no theme active, the package defaults, and then restores the theme, the counterpart of gtsummary 2.6.0’s without_gtsummary_theme().
  • add_significance_stars() adds stars for small p-values next to the estimates of a regression table, or the p-values of any other table, with the pattern, thresholds, hide_ci, hide_p and hide_se arguments. theme_ltsummary_journal("qjecon") now applies it to regression tables, with the standard error under the estimate, so the journal theme is complete.
  • add_vif() adds the variance inflation factors of a regression model, or the generalized factors with their degrees of freedom and the adjusted form when a term has several coefficients, with the statistic and estimate_fun arguments. The factors are computed in base R from the coefficient covariance, as car::vif() does; car stays a test oracle in Suggests.

ltsummary 0.7.0

  • tbl_hierarchical() and tbl_hierarchical_count() build nested rate and count tables (adverse events by system organ class and preferred term, for example) with the variables, id, denominator, by, include, statistic, overall_row, label and digits arguments. Rates count each subject once per cell via id, and an ordered-factor last variable tabulates each subject at its highest level. gtsummary computes these tables on its cards ARD stack; ltsummary counts directly in base R, and the outputs match cell for cell in the parity suite (decisions/0020). Two upstream failures are fixed rather than mirrored: an ordered factor in a count table (upstream crashes), and a count-table statistic using {N} or {p} (a clean error here).
  • add_overall() gains methods for both hierarchical classes; the overall column of a rate table counts each subject once across the whole data, and a count table without a denominator gets a plain "**Overall**" header.
  • sort_hierarchical() reorders the sections of a hierarchical table descending by their summed counts (ties keep their order, and sorting a variable outside include sums its children’s rates with a message) or alphanumerically, per variable. filter_hierarchical() keeps the rows of a target variable whose statistics satisfy an expression over n, N and p across the columns, the by values, per-column n_1-style statistics and the *_overall sums, with the var, keep_empty and quiet arguments; emptied sections lose their summary rows unless keep_empty, and the overall row always stays.
  • tbl_likert() builds a wide table of factor variables that share the same levels, one column per level, with the statistic, label, digits, include and sort arguments. Only {n}, {N} and {p} are available, the percentage denominator is each variable’s non-missing count, and the table carries no footnote, as in gtsummary. add_n() works on the table with its tbl_summary() interface.
  • tbl_wide_summary() places summary statistics wide, one column per element of the statistic character vector, with the label, digits, type, value, sort and include arguments. All variables must be of one summary kind, continuous or categorical/dichotomous, and the table carries no footnote and no missing rows, as in gtsummary. See decisions/0019 for the design of the three new summary builders.
  • tbl_custom_summary() computes each cell with a function you supply, called per cell with x, data, full_data, variable, by and strata exactly as gtsummary 2.5.1 calls it (the type and stat_display arguments its documentation promises are not passed there either). overall_row adds a row summarizing all observations, and add_overall(), add_p(), add_n(), add_stat_label(), inline_text() and the styling functions work as on tbl_summary(). ratio_summary() and proportion_summary() build ready-made stat_fns functions, the Poisson-test ratio and the base-R proportion intervals of add_ci(). continuous_summary() is hard-deprecated in gtsummary 2.5.1 and is not mirrored.
  • tbl_split_by_rows() and tbl_split_by_columns() split one table into a list of tables: after selected variables, after row numbers, at each value of a body column, or by groups of columns repeated next to the keys columns. The footnotes and caption arguments place the abbreviations, source notes and caption on the first, the last, or every table. The list prints one table after another, renders in knitr, litedown and pkgdown documents, and its class is c("ltsummary_split", "tbl_split", "list") so it never collides with gtsummary’s print method; see decisions/0018. print() arguments such as print_engine reach each table, and a groups column that does not exist raises a clean error naming it (upstream errors without a message).
  • add_variable_group_header() inserts a header row above a group of variables and indents the group, with the header, variables and indent arguments. The inserted row has row_type = "variable_group", so bold_labels() bolds the group’s variable labels but not the header, as in gtsummary.
  • combine_terms() collapses the terms a formula update removes from a regression model into one row, with a p-value from stats::anova() and the label and ... (passed to anova()) arguments. Two situations that error in gtsummary work here: tables built with conf.int = FALSE, and models whose data lives in a calling function’s environment (the reduced model is refit in the formula’s environment).
  • separate_p_footnotes() replaces the combined add_p() or add_difference() footnote with individual footnotes naming the test behind each p-value.
  • tbl_butcher() removes every element of a table except those needed to print it, plus any element named in include. Functions that add or modify statistics no longer run on the butchered table; inline_text() cell quoting still works.

ltsummary 0.6.0

  • add_difference_row() adds rows below each variable comparing every other level of the by variable against a reference level, with the statistic, test, group, header, adj.vars, test.args, conf.level, include, pvalue_fun and estimate_fun arguments. Each comparison runs on the two levels’ subset with the reference level first, so the estimate is reference minus compared, shown in the compared level’s column; the reference column shows an em dash. Two upstream bugs are fixed rather than mirrored: a statistic the method does not return raises a clean error naming the statistic and the method, and a numeric reference on a numeric by is accepted. See the addendum to decisions/0012.
  • Testing policy: quantitative expectations are now anchored to independent oracles computed in the tests (stats::/survival:: calls or hand arithmetic) instead of values pasted from gtsummary runs; formatting rules are hand-derived from the documented rounding cascades. Parity with gtsummary 2.5.1 is verified live in the parity suite, which gains the style_*() functions, the Poisson family and add_difference_row(). See decisions/0016.

ltsummary 0.5.0

ltsummary 0.4.0

The functions that combine tables, with the interface of gtsummary 2.5.1 and the computations in base R.

  • tbl_stack() appends two or more tables with the group_header, quiet, attr_order, tbl_ids and tbl_id_lbls arguments. A hidden tbl_id1 column records which table each row came from and every stored styling instruction is scoped to it, so the inputs keep their formatting, footnotes and merged columns. Group headers render as full-width lt row groups.
  • tbl_merge() joins tables side by side with the tab_spanner, merge_vars, tbl_ids and quiet arguments. Each table’s columns are renamed with its position (stat_1_1, estimate_2, …), its styling follows the renamed columns, and the spanning headers accept the {N}-style header statistics.
  • tbl_strata() and tbl_strata2() build one table per stratum and combine them, with the strata, .tbl_fun, .sep, .combine_with, .combine_args and .header arguments; the strata and their headers are recorded in df_strata. tbl_strata2() passes the evaluated header to .tbl_fun as .y. The deprecated .quiet argument is not mirrored.
  • tbl_strata_nested_stack() stacks the per-stratum tables with the strata as nested, indented row headers, with the row_header and quiet arguments. The row headers live in rows with a positive hidden tbl_indent_id1 column, so modify_bold(columns = label, rows = tbl_indent_id1 > 0) styles them.
  • inline_text() works on stacked and merged tables (and on tables built with as_ltsummary()): the cell is addressed by variable, level and column, or a pattern is glued over the row.
  • show_header_names() lists every header statistic a table carries, whatever its name.
  • Every new function is checked cell for cell against gtsummary 2.5.1 in the test suite when gtsummary and broom are installed; the regression examples also need broom.helpers and survival. See decisions/0013.

Changes to the regression tables since 0.3.0:

  • tbl_uvregression() is built on the stacking core: its table_body starts with a hidden tbl_id1 column and each model’s styling stays scoped to its own rows.
  • bold_labels() and friends on a stacked table with group headers target the label column, not the hidden group column.

ltsummary 0.3.0

Cross tables, survival tables, differences between groups and confidence intervals, with the interface of gtsummary 2.5.1 and the computations in base R.

  • tbl_cross() builds a cross table of two categorical variables with the row, col, label, statistic, digits, percent, margin, missing, missing_text and margin_text arguments. add_p() on a cross table compares the two variables, with source_note = TRUE to report the p-value below the table, and inline_text() selects cells with row_level and col_level.
  • tbl_survfit() summarizes survival::survfit() curves from a survfit object, a list of them, or a data frame with y and include: survival probabilities at times or survival quantiles at probs, with the statistic, label, label_header, estimate_fun, missing and type arguments. Competing-risks models show the probability of the first state. add_p() on a survival table computes the log-rank, G-rho family and Cox regression tests from the formula and data of the survfit() call, add_n() and add_nevent() add the counts, and inline_text() selects a column by time or prob. {time} and {prob} are available in label_header and modify_header(), and show_header_names() lists them. See decisions/0011.
  • add_difference() adds the difference between two groups with its confidence interval and p-value: the difference in means (t.test, paired.t.test, or ancova with adj.vars), the Hodges-Lehmann difference in location (wilcox.test), the difference in proportions (prop.test) and the standardized mean difference (smd, computed in base R as smd::smd() does), with the test, group, adj.vars, test.args, conf.level, include, pvalue_fun and estimate_fun arguments. add_p(adj.vars =) runs the same ANCOVA for continuous variables. The methods that need effectsize, emmeans or lme4 are not mirrored; see decisions/0012.
  • add_ci() adds the confidence interval of each cell’s proportion or mean next to the statistic column, with the method (wilson, wilson.no.correct, exact, wald, wald.no.correct, agresti.coull and jeffreys for proportions, t.test and wilcox.test for means, all in base R), include, statistic, conf.level, style_fun and pattern arguments. It follows the table’s percent denominator and covers the column added by add_overall().
  • add_stat() adds columns of statistics computed by your own functions, on the label, level or missing rows.
  • ?tests documents the methods of add_difference() and the tests of tbl_survfit() |> add_p() next to those of add_p(), and custom test functions receive adj.vars.
  • Every new function is checked cell for cell against gtsummary 2.5.1 in the test suite when gtsummary and broom are installed; the survival block also needs survival, the standardized mean differences need smd, and the ANCOVA needs broom.helpers.

Changes to the descriptive tables since 0.2.0:

  • Two rules of gtsummary’s result handling are adopted in add_p(): a test that fails leaves every statistic missing, so the hidden estimate, statistic and other columns exist either way, and a statistic column is added only when some test returns it.
  • add_p(adj.vars =) is no longer an error; continuous variables default to "ancova" when by has two levels.

ltsummary 0.2.0

Regression tables, with the interface of gtsummary 2.5.1 and the tidying done in base R.

  • tbl_regression() summarizes lm, glm and coxph models: estimates, confidence intervals and p-values, with label rows, reference rows and indented levels for categorical variables, interaction terms labelled by their parts, and the label, exponentiate, include, show_single_row, conf.level, intercept, estimate_fun, pvalue_fun, tidy_fun, add_estimate_to_reference_rows and conf.int arguments. Other model classes are tidied with broom::tidy() or a tidy_fun. The intervals are the ones broom reports: t-based for lm, profile likelihood for glm, Wald for coxph.
  • tbl_uvregression() fits one model per variable, with y or x, and stacks the results.
  • add_global_p() adds one p-value per variable from the type III tests of car::Anova(), computed in base R by global_pvalue_fun(); add_n() and add_nevent() add observation and event counts on label or level rows; add_glance_table() and add_glance_source_note() add model statistics, computed in base R by glance_fun_s3() for the three model classes.
  • add_q() adds q-values adjusted for multiple comparisons, sort_p() and filter_p() order and subset a table by p-value; all three work on summary tables too.
  • inline_text() gains methods for regression tables, with the estimate_fun argument and the pattern "{estimate} ({conf.level*100}% CI {conf.low}, {conf.high}; {p.value})".
  • The selectors all_interaction(), all_intercepts() and all_contrasts(); {N_event} in headers; show_header_names() lists N_event* when a table has events.
  • The output of every regression function is checked cell for cell against gtsummary 2.5.1 in the test suite when gtsummary, broom.helpers, car and parameters are installed. See decisions/0010 for the design.
  • gtsummary’s authors are credited in the README, DESCRIPTION and LICENSE.md: ltsummary re-implements the interface they designed, and its documentation follows theirs.

Changes to the descriptive tables since 0.1.0:

  • Documentation rewritten to the depth of gtsummary’s. Reference pages have argument sections where they help (tbl_summary(), add_p(), modify_table_styling(), tests) and numbered examples that render as tables; the reference index follows gtsummary’s grouping; six articles were added:
    • the tbl_summary() and inline_text() tutorials,
    • the modifier functions walkthrough,
    • the FAQ and gallery,
    • Quarto and R Markdown,
    • the definition of an ltsummary object.
  • Column selections combine positive and negative elements the way tidyselect does, e.g. include = c(age:grade, -marker) and statistic = c(everything(), -grade) ~ "{n}".
  • add_stat_label(label = variable ~ NA_character_) blanks the statistic label, as in gtsummary.
  • print() writes the table into the document when called while knitting, so print(tbl) in a loop with results = "asis" works.
  • as_lt() renders a single row of spanning headers, the most lt can show; modify_spanning_header(level = 2) stores the header and says so. See decisions/0009.
  • The parity tests against gtsummary also need broom, which gtsummary’s add_p() uses; broom is listed in Suggests and the tests skip without it.
  • A modify_footnote_body() whose rows matched no rows made the table fail to render; it is now ignored.
  • A logical vector inside c() in a column selection is treated as one mask, so the error for a vector of the wrong length reports that vector’s length.

ltsummary 0.1.0

First release. Descriptive summary tables with the interface of gtsummary 2.5.1, computed in base R and rendered with lt.