The footer under a table is a template you can edit. Everything printed there — the weight
line, the colour legend, the significance-stars key — is a <placeholder> in the table's
subtext, and everything you write is a line: the order of the lines is the order of the footer.
get_subtext() shows it, set_subtext() replaces it, and dropping <legend> drops the legend, in
the console too. set_legend_words() re-states what that legend calls a measure, for a table
grading the same ladder on another quantity. See ?tabxplor-footer.
A note, or a second table, under a table. set_footer_tabs() takes a tabxplor_tab and
renders it as a table, or any other data.frame and renders it as a grey note; tab_note() sets
that note's headers, alignment and footnote.
Data bars. set_bars() draws a bar chart inside the table — in html and in Excel — scaled to
the column's own largest data cell, or to a ceiling you state.
options(tabxplor.print = "md"). A bare table prints as markdown instead of in the console or
the Viewer, which is what a Quarto or R Markdown notebook knitted without pandoc needs.
A wide html table scrolls instead of widening the page, in a document, on a pkgdown site, in the Viewer and in jamovi alike. Its title stays outside the box, and printing lifts the clip.
tab_html(cells = ) — write back what get_data = TRUE reads. Hand back the same data.frame
with some cells edited and each edit is written verbatim into its <td>, keeping the cell's
colours, alignment and tooltip. This is the supported way to splice an input box, a link or a badge
into a tabxplor table.
The jamovi module is now built for macOS (Apple silicon and Intel), Windows and Linux, on both jamovi lines, and published as downloadable files. It is installed by sideloading, not from jamovi's library: the procedure and the links are in the README and on the package website.
Two bugs with weighted data, both silent. A variable whose name is not syntactic (Age group,
Household weight) broke every formula built from names: with design_effect = TRUE the
design-based tests returned NA with no message, and tab_reg(wt = ) stopped on a parse error.
A subtext written by a user is escaped in html. It is now shown, never executed — which
matters for a table shared inside jamovi, where an html result can run scripts.
Significance stars are now .05 / .01 / .001, the discipline's usual scale, instead of
.10 / .05 / .01. At the default confidence level a greyed cell can therefore no longer carry
a star.
display = "odds" prints the odds behind a percentage — the middle rung between a percentage
and an odds ratio.
Options set in .Rprofile are no longer overwritten when the package loads. tabxplor.print
and tabxplor.theme set before library(tabxplor) now hold.
A regression's multiplicative count measure is named RoM (ratio of means) rather than IRR, so a
column is headed Model_RoM; measure = "IRR" is still accepted.
The weight footer no longer mentions intervals and tests that are not in the table: a weighted
table showing none of them prints only "Weighted by <wt>."
A col_var span header is wrapped and compacted like every other header. It was the one
header no rule owned, so a long variable name widened the whole block. One visible consequence:
its spaces are now narrow no-break spaces in html, as every other header's already were — code
that matches a span's text literally has to allow for that.
A host table and its subordinate share one footer, instead of printing the colour legend twice in html and not at all in the console.
French translations: every multiplicative comparison that is not an odds ratio now reads ratio, and six mistranslated strings that were printing in English are fixed.
tab() is the unified entry point. It takes several row_vars and col_vars, merged into one
table or returned as a list with output_list = TRUE, and composes with tab_vars;
col_vars = a*b crosses two column variables. tab_many() is a soft-deprecated alias.tab_reg() — colour-coded regression tables (linear, logistic, Poisson, multinomial, ordinal),
on weighted and survey data, with model comparison, marginal effects and every export format. Its
estimand is a cascade, family → link → measure → effect. See vignette("tabxplor-reg").
color = "adjustment" colours that gap and tests it; empirical = FALSE turns it off.shape = is the cure — fit a continuous predictor as
quantile groups, a curve, or a log / sqrt transformation.jmvtabreg); Crosstables gains a reference-level
picker, level merging, export, tooltips and the new options, each named after its R argument.tab_counts() builds a full colour-coded table from already-aggregated counts instead of
microdata. forest_plot() draws any tabxplor table as estimates with their intervals, stars and
own cell colours, returning a modifiable ggplot; reg_check_plots() draws the model checks.survey::svydesign() as data and strata, clusters, fpc
and calibration reach every interval, test and colour; options(tabxplor.design_effect = TRUE) does
the same, exactly, for a plain weight column. A weighted table's footer states its basis.ci_method = c(cell =, diff =, mean_diff =, mean_ratio =). ci says
only where the interval sits; significance stars are opt-in (stars =) and read that interval.color = "contrib".color = TRUE is the smart per-column-type default, and every ladder is the same ladder written in
another measure, so a shade means the same deviation whichever measure a table is read on. OKLCH
palettes, set_color_palette(), color_breaks, a theme = "auto" dark mode, and black-and-white
publication palettes (theme = "print_ready") saying it all typographically."est", "est_ci", "est_base", …)
built on {} tokens — display = "{pct} (n={n})" — where {est} is whatever the column estimates
and {base} the level it sits on. It is post-hoc: set_display() on a finished table gives the
same table as asking at build time. Every cell of a percentage table now carries its odds ratio,
and display = "odds" prints the odds it is a ratio of.shape = decides how a number enters a table: quantile groups, bands at the mean and one
standard deviation either side, one level per value, or a "log" / "sqrt" transformation. A
numeric row_vars / tab_vars is grouped rather than exploded; a mean cell shows 49 (cv 36%).tab() arguments:
spread_vars (each level of a sub-table variable becomes a block of columns, with one
Total row and one n column per block)n = c("range", "min", "no") (how many people the table is about)n_min, common_totrow and na = "common_base".tab_export() is one entry point for every format, and tab_html() (the new name for
tab_kable()) renders through a new dependency-free engine, about 3× faster and restylable because
its geometry is CSS classes; tab_css() writes one stylesheet for a whole document. Also new:
options(tabxplor.print = "html") with hover tooltips, caption =, transpose = TRUE.openxlsx2: a ratio stays a real number that sorts and filters while
printing 1/2.11, column widths fit their content, a secondary number becomes a column of its own,
and tab_xl(check = "auto") draws the model-check plots under a regression table.tab_structure() says what a table is and what
can be done with it, tab_columns() what every numeric column estimates and how it is coloured,
fmt_attr() any one column fact by name, reg_measures() and reg_formulas() the same for models.as.matrix() and as.table() hand a table to base R — the numbers as a plain matrix, or a
base table with named dimnames — dropping the totals and the display-time rows, because a
correspondence analysis or a chi-squared test run on a table's own margins is wrong:
FactoMineR::CA(as.matrix(tab(gss_cat, race, marital))).options(tabxplor.lang = "fr"), a
lang = argument, or the locale), on a bilingual pkgdown website. Labelled data (haven):
value labels become factor levels. Parallel builds with options(tabxplor.parallel = TRUE).magrittr / stringr / crayon are dropped, so %>% is no longer
re-exported — use the base |> pipe. kableExtra and DescTools move to Suggests, Excel export
from openxlsx to openxlsx2, and survey / nnet / MASS become hard dependencies.add_pct and the chi-squared / ANOVA p-values are drawn at display time, not
stored as columns and rows. Read them with Total$n and get_test().diff field is a real difference, the cell/reference ratio
moving to ratio, and a cell shows a coefficient of variation instead of a standard deviation; a
numeric row_vars / tab_vars is grouped rather than exploded. shape = "values_to_levels" and
display = "mean_sd" restore the old output exactly.tab(na = "drop") with several col_vars drops each column's own missing values (the old
shared base is now na = "drop_all").pct_ratio, mean_ratio and mean_diff, and the background
channel keeps the two ratio scales' loudest rungs only. set_color_breaks() restores any of them.color = "contrib"
significance reads the adjusted residual on the unweighted n.tab() and its siblings taking ... right
after their variable arguments: an unnamed extra argument is refused, a typo gets a suggestion, and
an abbreviation that used to partial-match silently is refused. An unknown value now aborts too."Total" (or "Ensemble") is refused, naming the level: those
are tabxplor's own total-row labels. Rename it, or move them with options(tabxplor.total_names =).fmt column attributes: type is split into scale (what the column estimates) and pct_type
(which kind of percentage), ci_type is gone, and a new col_group names a column block's
sub-population. Only code building or inspecting fmt vectors is affected; see
vignette("tabxplor-programming").tab_transpose() is a supported reshape operation again (it was soft-deprecated in the
pre-release): it is the way to get a transposed object, and the only way to put a mean on a row,
since a number given to row_vars is always cut into levels. Use the exporters' transpose = TRUE
when only the output matters. A transposed column now claims only what its parts agreed on, by the
same rule every bind_rows() follows.tabxplor.total_names replaces the total_names /
totaltab_name / other_level arguments, and tabxplor.stars carries the star ladder.tab() could not use a column whose name was not syntactic: tab(data, x, `my var`) aborted
saying the column did not exist.NA as a real level (factor(..., exclude = NULL), common in imported data)
no longer crashes print(), format() or any export.pct = "col" and na = "drop_all" failed on an ordered row variable, on printing or
exporting; and tab(pct = "all", ci = "cell") errored, weighted or not.lang argument now works on Linux, and switching language mid-session keeps the new one.tab_spread() lost the table's whole test summary, and dplyr::bind_rows() on two grouped
tables lost the weight footnote, colour legend and caption.ref / ref2 accept "last", and errors are clearer for an unknown named ref, a variable
used on two axes, or an all-zero weight. tab() accepts a data.table and a logical col_var.dplyr::bind_rows() on two tables with different columns crashed on printing: the missing
cells come back all-NA, which the colour engine could not read. They now render blank everywhere.color = "ratio"
grades them all.tab_many() (a shim over tab()) and the step-by-step chain tab_pct() /
tab_tot() / tab_totaltab() / tab_ci() / tab_chi2().tab() arguments: singular row_var / col_var, sup_cols (use col_vars), filter (filter
upstream), names_prefix / names_sort (they belong to tab_spread()), add_n (use n =),
total_names / totaltab_name / other_level (use options(tabxplor.total_names =)), OR (use
display = "{or}" / ref2 = "cumulative"), ci = "diff" / "ratio" (use ci = "ref"), chi2
(use test), method_cell / method_diff (use ci_method), and "diff_ci" / "after_ci" /
"ci" (use color + color_signif).color_type, html_24_bit,
html_font, full_width, position, and tab_xl(n_min =, hide_near_zero =) — width, font and
placement are CSS rules now (tab_css()), and n_min is a tab() argument. Every other unknown
argument of tab_html() / tab_md() / tab_xl() / tab_css() / forest_plot() is an error
with a suggestion, as it already was on tab().tab_xl(print_color_legend =) → color_legend =, set_diff_type() →
set_ref_type(), the in_totrow cell field → row_kind (is_totrow() and x$in_totrow are
unchanged), and options(tabxplor.signif_levels) / options(tabxplor.signif_labels).fmt attribute type, which said both what a column estimates and which percentage it is:
get_type() / set_type() and fmt(type =) translate into scale + pct_type (see
?tabxplor-type) and are defunct in 2.1.0.tab() and tab_num() compute the same numbers, in one pass.tab_prepare() and complete_partial_totals() will become internal or be removed; tab_prepare()'s
work is done by tab() itself.tab_plot() and kable_tabxplor_style() — use tab_export() and tab_html().kableExtra HTML engine, with engine = (accepted and ignored) and the options
tabxplor.tab_kable_engine, tabxplor.always_add_css_in_tab_kable, tabxplor.kable_html_font.
kableExtra stays optional, and is no longer what opens a table in the Viewer: tab_html()
paints that page itself, to match the table's theme.method_ratio and its siblings, tabxplor.ci_print (use display = "base_ci" /
"base_moe"), tabxplor.compact, tabxplor.color_style_type.fmt attribute ci_type, with get_ci_type() / set_ci_type() and fmt()'s
ci_type = argument: the stored interval is always on the estimate's own scale.jmvtab() : added "Export to Excel" button to use tab_xl() in Jamovi UI.
Small bug corrections.
tab_many() : with several row_vars, adding compact = TRUE bind all tables
in a single one (but only works if no tab_vars are provided).
tab_compact() can be used to do the same on tab_plain().tab_chi2()). tab_pvalue_lines() do that from attr(tabs, "chi2").tabxplor_tab, arrange() now keeps the order of groups and totalstab_num(), if all means < 10, display 1 digit ; if all means < 1, display 2 digitstab_kable() now works with a list of tab, if all col_vars are the same and there are no tab_varstab_kable(), escape signif stars * with \ in .rmd only, otherwise it breaks the htmlci = "cell" didn't work with pct = "col" with non pct rowstab() and tab_many(), possibility to add unweighted counts (add_n = TRUE) ; and with row and column percentages a row or column with the other kind of percentage (add_pct = TRUE)kable_tabxplor_style() : same html table style than tab_kable(), but for any data.frame.color = "diff", a ×2 color rule was added<0.01% style), Chi2 number added in Chi2 tables.pct = "col"tab_kable()and tab_plot() : removed unwanted bold formattingjmvtab() : implementation of tab_many() for Jamovi, with a user interfacetab_plot() : print tables as ggplot, to export as imagestab_wrap_text() : function to wrap text in rownames and colnamestab_kable() : html tags in tables were no longer working and were appearing as text (knitr::kable() now needs a format = "html" argument)tab_kable() : a color_legend argument have been added, to possibly remove the legend.tab_color_legend had a mistake causing an errorfct_recode_helper() : helper function to recode multiple variables with forcats::fct_recode.complete_partial_totals() : complete partial total rows, total tables, and reference rows.tab_spread : incomplete subtables led to partial total rows, total tables and reference rows.tab_xl : with sheets = "unique", multiple empty sheets were created anywaycrayon() error with colors in tabs printing on R 4.2.2col_vartab_plain have been separated in two functions, tab_plain for factors, tab_num for numeric variablestab_plain and tab_num have been rewrited in data.table to gain speed with big databases.wt (weight), for them not to be added in counts (except in tab_plain)fmt_get_color_code() : get the html color codes of a table as a character vectortab_many : bug with totaltab when two numeric column variables (and a tabs_var)tab_spread not working with two tab_vars. Ok with a workaround, but would need to calculate one subtotal for each level of spread_vars in * tab_totaltab to fully work (and, then, to fully hierarchise total tables...).wt argument procudes missing values with NA ; NA in weight variable are now automatically removed (excepted in tab_plain)fmt vectors wasn't working no more with percentagestab_plain, col_var was not sorted anymore (names_sort = TRUE added in pivot_wider)tab_color_legend() was not working when some cols were colored and some not coloredtab() functions, correction was made to remove a R 4.1.2 dplyr warning message (data frame results in filter() are deprecated, use if_any() or if_all()).tab_kable, option to use html popover instead of tooltips, to be able to use it in rmarkdown with a floating table of content."blue_red" and "green_red").set_color_style().tab_core was deprecated and renamed tab_plain for more clarity. Added options to render a table with normal numeric vectors instead of fmt, and to render a plain data.frame instead of a tibble."tabxplor.ci_print" : "moe", for margin of errors, prints as 12%±1.1 ; "ci" prints the interval 11·13%.tab_kable, confidence intervals of type "cell with print type "moe" appear in subscript.tab_xl, colors now are the same and works in the same way that tab and tab_kable.tab argument color = "after_ci", when diff is negative, cells between 0 and -5% don't get colors.tab_plain with zero-rows dataframescolor = "contrib", no color when contribution is equal to the mean contribution (or a multiple of it).tab_kable, white spaces are producing unwanted text wrapping (in the middle of numbers)diff not printing good with type = "mean".kableExtra.tab and tab_many.tab_many not working with listed = "TRUE"tabxplor.