Migrating from table.glue
Source:vignettes/migrating_from_table_glue.Rmd
migrating_from_table_glue.Rmdperiglue is a fork of table.glue with new
features, bug fixes, and a cleaner API. This vignette covers what
changed and how to update code that used table.glue.
Renamed functions
All table_* functions are now peri_*:
table.glue |
periglue |
|---|---|
table_glue() |
peri_glue() |
table_value() |
peri_value() |
table_pvalue() |
peri_pvalue() |
table_ester() |
peri_ester() |
table_estin() |
peri_estin() |
All other functions (round_spec(),
round_using_*(), format_*(),
bracket_*(), as_inline()) are unchanged.
New default rounding
table.glue used magnitude-based rounding by default —
the number of decimal places depended on the size of the value:
- values < 1 → 2 decimal places
- values 1–10 → 1 decimal place
- values > 10 → 0 decimal places
This meant a vector of values could be formatted inconsistently:
# Simulated mean ± SD pairs at different scales
peri_value(c(0.82, 4.7, 31.2), rspec = round_spec() |> round_using_magnitude())
#> [1] "0.82" "4.7" "31"periglue defaults to 1 decimal place for all
values, which is more predictable and appropriate for most
table cells:
peri_value(c(0.82, 4.7, 31.2))
#> [1] "0.8" "4.7" "31.2"If you preferred the old magnitude-based behaviour, pass an explicit
rspec:
rspec_mag <- round_spec() |>
round_using_magnitude(digits = c(2, 1, 0), breaks = c(1, 10, Inf))
peri_value(c(0.82, 4.7, 31.2), rspec = rspec_mag)
#> [1] "0.82" "4.7" "31"New way to set a session default
table.glue required users to rename rspec fields
manually before passing them to options():
# table.glue approach — no longer recommended
rspec <- round_spec() |> round_using_decimal(digits = 2)
names(rspec) <- paste("periglue", names(rspec), sep = ".")
options(rspec)This worked but was easy to get wrong, and CRAN discourages packages from modifying user options.
periglue provides
set_default_rounding_spec(), which stores the specification
in the package’s own internal environment rather than in global
options:
rspec <- round_spec() |> round_using_decimal(digits = 2)
set_default_rounding_spec(rspec)
peri_value(pi)
#> [1] "3.14"
peri_glue("mean (SD): {mean(mtcars$mpg)} ({sd(mtcars$mpg)})")
#> [1] "mean (SD): 20.09 (6.03)"Pass NULL to clear the default and revert to factory
settings:
set_default_rounding_spec(NULL)
peri_value(pi)
#> [1] "3.1"set_default_rounding_spec() returns the previous default
invisibly, making it easy to save and restore around a block of
code:
rspec_narrow <- round_spec() |> round_using_decimal(digits = 3)
old <- set_default_rounding_spec(rspec_narrow)
peri_value(pi)
#> [1] "3.142"
set_default_rounding_spec(old) # restore whatever was set before
peri_value(pi)
#> [1] "3.1"New function: peri_n_pct()
The most common cell format in demographic tables — a count with its
percentage — previously required peri_glue():
n <- c(48, 32, 20)
pct <- c(0.48, 0.32, 0.20)
# old approach — relies on n and pct being in scope
peri_glue("{n} ({round(100 * pct, 1)}%)")
#> [1] "48.0 (48.0%)" "32.0 (32.0%)" "20.0 (20.0%)"This works but rounds the percentage using the same specification as
everything else in the template, and gives no control over formatting
the count separately from the percentage. peri_n_pct()
handles both in one call:
peri_n_pct(n = n, pct = pct)
#> [1] "48 (48.0%)" "32 (32.0%)" "20 (20.0%)"Counts are always displayed as whole numbers regardless of the
rspec used for the percentage, and the formatting settings
(big mark, decimal mark, miss_replace) are inherited from a
single specification:
peri_n_pct(n = 12480, pct = 0.621)
#> [1] "12,480 (62.1%)"Missing percentages — common when a subgroup denominator is zero — are handled cleanly:
peri_n_pct(n = c(10, 0), pct = c(0.10, NaN))
#> [1] "10 (10.0%)" "0 (--)"The output format is customisable via the form
argument:
peri_n_pct(n = 48, pct = 0.48, form = "{n}/{100} [{pct}%]")
#> [1] "48/100 [48.0%]"Bug fix: peri_glue() no longer modifies the calling
environment
In table.glue, calling table_glue()
injected an internal helper function ..f into the calling
environment as a side effect. This was invisible in most cases but could
corrupt the caller’s scope, and would raise an error if the calling
environment happened to be locked (as can occur in certain
dplyr contexts).
peri_glue() now evaluates in a disposable child
environment, so nothing leaks:
Bug fix: format_decimal() validates mark width
table.glue silently accepted multi-character decimal
marks, which worked in older R versions but was deprecated and is
becoming an error in recent R. periglue catches this at the
point of specification rather than at formatting time:
round_spec() |> format_decimal(mark = "decimal!")
#> Error:
#> ! `mark` must be a single character, but 'decimal!' has 8 characters.