Study-supplied text can carry superscripts and subscripts, written as in
Pandoc: a label "BSA (m^2^)" raises the 2 and "HbA~1c~" lowers the 1c.
It applies to labels, levels, the by levels and section names in every
style and layout, and to the notes, the abbreviation key and the caption
hv_man_table_save() writes. A pair holds no whitespace, so "~5 years"
prints as typed, and text without markup is unchanged.
hv_check_docx() reports any markup a saved file still holds as plain
text, as a "markup" finding.
The table-style output tests now read fill, row height, font, font size and
note wording from hv_table_style() instead of repeating them, so a change
to the house style moves the expectations with it. One test still pins the
defaults. No change for users.
hv_tbl_summary() no longer fails when the calling session defines an
object named sd or median. gtsummary turns each statistic in
{mean}±{sd} or {median} [{p15}, {p85}] into a function by looking its
name up from where tbl_summary() was called, and from inside a package
that lookup reaches the global environment before package:stats, so a
study whose R/ folder defined sd (as hvtiRtemplates jobs source it into
the global environment) got "Value must be a named list of functions"
whenever a row showed mean±SD or a median. The call now runs from an
environment holding stats::sd and stats::median and then only base, so
nothing a user defines can shadow a statistic. Present in 1.0.7 and 1.0.8.hv_man_table_save() and hv_man_table_save_jtcvs() always drop the
"Variable" column hv_tbl_summary(show_variable = TRUE) adds, before
fitting the page, so a saved table is always a manuscript table and its
width and orientation are the manuscript table's. hv_man_table() and
hv_man_table_display() keep it for the report view; show_variable
stays TRUE by default and no longer needs setting to FALSE for a
manuscript. hv_man_table_jtcvs(), whose table is always a manuscript
table, no longer shows it.
Tables follow the house notation standard (dev/specs/2026-10-17-table-styles-design.md, section 5.2). Existing tables change:
102 [63, 170], 0.31 [0.21, 0.39]. The statistic note reads
"Median [15th, 85th percentiles]"..013, <.001, >.9.63±13, unspaced, EHB paired rounding.hv_man_table_jtcvs() the mark is a lettered superscript b with its own note, so the
test footnotes letter from c (they were b, c).footnotes = hv_man_footnotes() explicitly on a mixed table now errors unless the
footnotes carry the mark's note. § and ¶ are reserved on mixed tables; use || for a
study note.Tables are drawn in a style named by its role (dev/specs/2026-10-17-table-styles-design.md).
hv_table_style() holds a style's properties; hv_man_table(style =) takes "report"
(the default, today's table) or "manuscript".
n column, shaded
section rows spanning the table, a bold header and caption, 300-twip rows kept whole, and no font
of its own, so it takes the document's body font. Its notes begin with the plain symbol:
*Patients with non-missing data., †Values are No. (%) or median [15th, 85th percentiles].hv_man_table_save() takes caption, written bold above the table: the manuscript
style requires it, and a report may give one.hv_tbl_summary() carries each variable's overall non-missing count and the grouping's
name for the manuscript header.hv_man_table_display() shows the notes in the table's style, so a manuscript table's
notes begin with the plain symbol there as they do in the saved file.STYLE= to style = (CORR family only) and TBLTITLE= to
caption =.font and font_size (it sets no font), continuous_stat = "both"
in the compare layout (one statistic per group; the describe layout draws it), and a
table not built by hv_tbl_summary() (it reads the
overall count and the grouping's name that function records).hv_check_docx() checks merged cells: by default merges only in header rows and in
section rows that span the table, and none at all with style = "report".hv_man_table_jtcvs() section rows now span the table in one cell; they were a label
beside one merged blank cell.#CAEDFB by default,
every cell, unmerged), its header is now bold throughout (the N = n lines and the
marks were not), and both savers write US Letter pages instead of A4, so a wide table
now fits a 9.0 in landscape text block instead of 9.7 in.hv_man_table() no longer carries gtsummary's own footnotes inside the table. A saved table
with compare = "pvalue" (or "smd" or "both") ended in a footer row reading "1Wilcoxon
rank sum test; Pearson's Chi-squared test", with a raised digit on the p-value header, and
compare = "both" added an "Abbreviation: CI = Confidence Interval" row: house rule 13 puts
notes below the table. Existing tables change:
compare = "smd" and "both" head the difference column "Std. Diff." (gtsummary's
"Difference" was explained only by the footnote now gone), and the dagger note says "Std.
Diff. is the standardized mean difference, with its 95% CI." (the manuscript style: "Std.
Diff." or, under "both", "SMD", without the CI it does not show). The dagger marks that
header.compare = "both") defines CI in the key, beside any abbreviations you pass (your own
definition of CI wins).hv_check_docx() flags a last-row cell that opens with a superscript number, the form
gtsummary writes a footnote in, and one that starts "Abbreviation:". It returned no findings
for the tables above.
The manuscript style gains its second layout, "describe", for tables that describe
cohorts or repeated measures side by side (dev/specs/2026-10-17-table-styles-design.md,
section 5.1): hv_man_table(tbl, style = "manuscript", layout = "describe"). Each group
spans its own count and statistic, so every group has its count, and an Overall column and
comparison columns appear when the table carries them. Everything else is the comparison
layout's: the full grid, shaded section rows spanning the table, a bold header, notes that
begin with the plain symbol, no font of its own, and US Letter pages. The describe layout
draws continuous_stat = "both", which the compare layout refuses. layout = "compare" is
the default, and the report style takes no layout.
hv_man_table()'s layout argument follows style, so a call passing every argument
by position reaches ... at the seventh, not the sixth. A named SAS argument such as
%summarytable's STYLE= is caught by its name at any position; only an unnamed extra
argument is reported at position 7.* on each group's n and † on each
statistic, with *Patients with non-missing data. and the dagger note below the table,
and hv_man_table_save(ft, file, caption = ) writes the caption above it.hv_man_table_display() shows a describe table; it refused one before.Deprecated: hv_man_table_jtcvs(), hv_man_table_save_jtcvs() and
hv_test_footnotes_jtcvs() warn on every call and go in the next release. Until then their
arguments keep their meaning: groups and trailing choose the same columns, and
stat_label names the statistic.
*Patients with non-missing data. for a. Patients with data available.) and the document's font.hv_man_table_save_jtcvs() writes caption above the table and the table's own notes
below it, as hv_man_table_save() does, and keeps abbreviations. It drops a test
footnote that hv_test_footnotes_jtcvs() wrote when the table already names that test,
as an hv_tbl_summary() table does in its dagger note and with Fisher's mark on its P
values. Every other positional footnotes entry keeps a lettered superscript on its
cells, lettered from a, with its line after the table's own notes; the unnamed test
notes of a plain gtsummary table stay lettered the same way.hv_man_table_save_jtcvs() now writes
that table's default notes and header marks; it used to write only the lettered notes.hv_man_table(tbl, style = "manuscript", layout = "describe") and
hv_man_table_save(ft, file, caption = ); the test notes then come from the table.The package site gains a "Table styles" article: one synthetic table drawn in each style and
layout (report; manuscript, compare; manuscript, describe), beside the matrix of their
properties, and a table of the house rules saying which are content rules, binding every
style, and which are hand-edit rules, and which styles keep each. The matrix is written from
hv_table_style() when the site is built, so it is read from the style objects, not copied by hand. Each table's
saved .docx is a download on the page. ?hv_man_table and ?hv_table_style link to it.
The site keeps flextable tables on white in its dark theme (pkgdown/extra.css), as they
appear in Word, reference examples included.
hv_man_table_display() shows a manuscript table in the page's font and size. The manuscript
style sets no font, and in HTML its table fell back to the browser's default font, a serif,
so it looked set in the report's Times New Roman, while its notes were in Helvetica.
hv_man_table_display() adds to a flextable from hv_man_table()
what hv_man_table_save() writes around it in Word, so a report shows
the same table in HTML: the asterisk and dagger header marks, the
footnotes and the abbreviation key, the last two as footer lines. It
shares that code with the saver, so the two cannot disagree. Both savers
refuse its result, whose notes are rows inside the table.The README's Installation section now leads with hvtiR::install(), which
installs the whole HVTI R family in one call, and then gives
pak::pak("ehrlinger/hvtiRtables") for this package alone.
hv_tbl_summary() gains mean_sd, the continuous variables to show
as mean±SD while keeping the Wilcoxon or Kruskal-Wallis test. normal
still couples mean±SD to one-way ANOVA and is unchanged.
hv_tbl_summary() gains show_variable, on by default: a "Variable"
column beside the label holds each variable's column name, as
%summarytable's report did. hv_man_table() and
hv_man_table_jtcvs() both show it. Existing tables gain this column;
pass show_variable = FALSE for a manuscript.
New hv_tbl_compare() adds a comparison column you computed yourself,
one value on each variable's first row, rightmost in the table. It is
how hvtiRpropensity::ps_stddiff()'s %stddiff standardized difference
reaches a table, beside compare = "pvalue", without hvtiRtables
depending on hvtiRpropensity. compare = "smd" is unchanged; its help
now says it is gtsummary's generic SMD, not %stddiff's.
hv_man_table_jtcvs()'s trailing now takes several columns, laid out
in order. Its error for a malformed trailing no longer says "of
length 1".
hv_tbl_summary() gains cutexact. The default, "any", keeps the
rule used until now: Fisher's exact test when any cell expects fewer
than 5, so categorical p-values are unchanged. A number opts in to
%summarytable's CUTEXACT= rule to reproduce a SAS table
(cutexact = 50 is the macro's default). In the CORR table each
Fisher p-value now carries a superscript double dagger, footnoted
"Fisher exact test."; hv_man_table_save() stops if given footnotes
that leave that mark unexplained or file another note under it.
continuous_stat = "both" now shows mean±SD and the median side by side,
in a median column beside each group's statistic column, instead of
stacked sub-rows. Both renderers lay it out the same way. This changes
existing "both" tables: the statistic columns and their dagger now read
"No. (%) or Mean±SD", the median column names itself in its header, and
a two-group "both" table now saves in landscape.
hv_man_table_save() and hv_man_table_save_jtcvs() save a table wider
than a portrait page on a landscape page, and narrow its columns in
proportion when it is wider than landscape too, so the label and
rightmost columns are never clipped. A two-group "both" CORR table with
an Overall column measured 13 inches and lost both on a landscape page.
hv_check_docx() gains a fourth detector, "wide_table": a table wider
than its page's text block, which Word clips.
hv_test_footnotes_jtcvs() letters only the p-value column
hv_tbl_summary() writes. It no longer falls back to another trailing
column, which footnoted a joined standardized difference "Fisher exact
test."
hv_man_table_save() and hv_man_table_save_jtcvs()
now match the SAS %summarytable layout, after a review of two commented
example tables:
hv_tbl_summary() writes categorical cells as 12 (39), without the %
sign. The (%) is stated once, in the JTCVS sub-header or the CORR
dagger footnote.hv_man_table() puts each section ("Demography") on its own bold row in
the Characteristic column, above its first variable. Before, the sections
filled an extra column headed groupname_col. The Characteristic column
is now left-justified.No. column. Its text now covers both kinds of row, for example
"No. (%) or Median (15th, 85th percentile)."
hv_man_footnotes() returns the same wording.hv_man_table_jtcvs() takes its statistic sub-header from the table
(stat_label = NULL). The fixed "No. (%) or Mean±SD" default labeled
median tables as mean and SD.n
sub-header carries a superscript a, which hv_man_table_save_jtcvs()
explains first with "a. Patients with data available." The a used to
print as plain text, na. Footnotes you pass now start at b.hv_tbl_summary() has a normal argument, the macro's CON1=: list
continuous variables in it as well as in continuous, and each is shown as
mean±SD and tested with one-way ANOVA. Every other continuous variable keeps
the continuous_stat summary and its non-parametric test. When one table
shows both mean and median rows, each continuous row names its own statistic
("Age, Mean±SD"), as the macro's DESCLABEL=1 did. The header and the
dagger then read "No. (%) or as labeled".
hv_test_footnotes_jtcvs() footnotes the ANOVA as "One-way analysis of
variance."hv_man_table_save() writes a table with three or more statistic columns,
such as an Overall column and two groups, on a landscape page. In portrait,
Word clipped its right edge.Key: line under a table, and the JTCVS caption above it,
are now set in the table's own font (Times New Roman by default). They used
the Word template's default font.VignetteBuilder is quarto, and building them needs the
Quarto CLI. The text and code are unchanged.pkgdown/extra.css.hvtiR::install() installs the members together, and several
already required 4.4.0, so on an older R the install failed whatever this
package declared.DESCRIPTION now declares the Quarto command line tool in
SystemRequirements. The vignettes have always needed it to build; the
field makes that visible to installers and to R CMD check.hv_tbl_summary(compare = "pvalue") and compare = "both" now stop
with an error when 'broom' is not installed, instead of returning a table
with every p-value blank. gtsummary::add_p() runs its Wilcoxon test
through 'cardx', which needs 'broom'; without it gtsummary only warned,
and hv_test_footnotes_jtcvs() then returned list() because no test was
recorded. The HVTI Recipes book published blank p-values for a week this
way. 'broom' stays in Suggests, so compare = "smd" and "none" still
work without it.
testthat in Suggests is now >= 3.1.7, the first release with
local_mocked_bindings(), which the test for the 'broom' guard uses.
R/ documentation are gone. Six sat in roxygen
blocks, and man/ is generated from those blocks, so they reached
readers in the rendered help pages. A seventh sat in an ordinary code
comment. Replacements vary by sentence: parentheses around an aside, a
period between two independent clauses, and a verb where the dash stood
in for one. The released headings below are left as written. No
behavior changed.hv_correlation_table() now de-duplicates repeated method values.
Each stratum/pair/method combination appears once, while the caller's method
order is preserved.hv_correlation_table() ports the SAS correlation job
(proc corr spearman pearson fisher(biasadj=no alpha=.32)): pairwise
coefficients with Fisher intervals, a 68% interval by default, pairwise
deletion, and a by stratum. It backs the dc-tables job template.hv_tbl_summary() rounds each mean to the SD's first-significant-digit
place and the SD one place finer, retaining an extra place in both when the
SD begins with 1. Exact ties round to even. The rule applies to grouped and
Overall columns under continuous_stat = "mean" and to the mean row under
"both"; median/percentile rows are unchanged.hv_man_table_jtcvs() writes "No. (%) or Mean±SD", matching
hv_tbl_summary() and the CORR footnote text.hv_man_footnotes() accepts continuous_stat and percentiles, and an
hv_tbl_summary() table carries the matching footnote through
hv_man_table() into hv_man_table_save()'s default. Mean tables no
longer receive a median dagger, "both" names both statistics, and custom
percentile pairs no longer leave the default footnote stale. Custom values
use correct ordinal suffixes, including the 11th-13th exceptions. Hand-built
flextables retain the median/15th-85th house default.hv_tbl_summary()'s N column now counts non-missing values. It was
built from gtsummary's {N_obs}, which counts every row, so any variable
with missing data reported the full row count under a footnote reading
"Number of non-missing values." It now uses {N_nonmiss}, matching the
house rule and the %summarytable tables it replaces. Tables built with
earlier versions overstate n wherever a variable has missing values and
should be rebuilt. The {N_obs} ||| {stat} examples in the renderer
documentation, the README, and the convention error message now use
{N_nonmiss} too.hv_tbl_summary() gains continuous_stat. "median" (default)
keeps median (P<low>, P<high>); "mean" gives mean +/- SD, written
64±12 without spaces per the house table rules; "both" puts the two
on sub-rows under each continuous variable, with n shown once, so the
choice for the manuscript is a deleted row. The test is the same
non-parametric one whichever is shown. hv_stat_label follows the
choice. Defaults taken from Rajes's %summarytable tables.hv_tbl_summary()'s overall now defaults to TRUE, matching the
macro's TOTALCOL=1 and the stratified tables it replaces. With
by = NULL it is ignored rather than an error. hv_man_table() shows
the new Overall column automatically; hv_man_table_jtcvs() shows it
only when groups names stat_0, so existing JTCVS calls render as
before until you add it. Pass overall = FALSE for the old layout.First supported release. The package is now the HVTI CORR group's table
interface rather than a working draft: the two manuscript renderers, the
%summarytable migration path, and the checks that keep a written .docx
inside house rules are all in place and covered.
What the 1.0.0 claim means in practice:
hv_man_table() and hv_man_table_jtcvs() both consume hv_tbl_summary()
output, and the places the two families genuinely differ - caption on the
JTCVS saver only, the two footnote shapes - are documented as differences
rather than papered over.vignette("sas-migration")
ports a %summarytable program end to end, including the defaults that differ
and the QNTLDEF=5 / quantile(type = 2) trap.class=, con1= or tbltitle= to any
public function errors with the R argument and the function that takes it,
resolved against the caller's CORR/JTCVS family.dc prefix formally belongs here. hvtiRtemplates' allocation map
assigns the dc.* descriptive-table macro family to this package, so the
%summarytable port has a governing decision behind it rather than a
precedent.No API changes since 0.9.7. This release is the claim of support, not new behavior.
hv_man_table() now accepts an hv_tbl_summary() table. It splits
each "{N_obs} ||| {stat}" cell into a flat No. column immediately
before the statistic it counts — the same two values the JTCVS
renderer puts under a merged spanning header, without the merge.
Previously the separator rendered literally into the Word table
(98 ||| 46 (32, 63)), so the SAS-macro interface was usable only in
JTCVS mode. The count is kept rather than discarded because house
rule 8 requires it and hv_man_footnotes() ships a * footnote
describing it. A plain gtsummary::tbl_summary() table carries no
such convention and passes through unchanged.groupname_col, so the marker would otherwise have landed on the
section-label column."{N_obs} ||| {stat}" convention now raises
an error naming hv_man_table(), not hv_man_table_jtcvs(). The
internal assertion the two renderers share previously hardcoded the
JTCVS renderer's name in its message.hv_tbl_summary() gains overall =, the %summarytable TOTALCOL=
equivalent, adding an Overall column across all groups. Defaults to
FALSE; the macro's own default is TOTALCOL=1.hv_tbl_summary(), hv_man_table(), hv_man_table_jtcvs(),
hv_man_table_save(), and hv_man_table_save_jtcvs() now error on a
%summarytable parameter name, naming the R argument and the function
that takes it, rather than silently ignoring it.%summarytable program to R".CON1= maps to continuous.
It does not: CON1= was mean +/- SD with ANOVA, and continuous
reproduces CON3=. Corrected.binary variables now pass an explicit event value to gtsummary
instead of letting it infer one. Its inference is type-sensitive in a
way that hit the SAS import path: a haven_labelled column over a
double base type -- what haven::read_sas() produces, since every
SAS numeric is an 8-byte float -- failed with Summary type is "dichotomous" but no summary value has been assigned., while the
otherwise-identical integer-backed column worked. The event is the
TRUE, 1, or Yes side in every accepted encoding.hv_man_table_jtcvs() now enforces font_size of 11 or 12, the same
house rule hv_man_table() has always enforced. Calls passing any
other value, or a vector, now error.abbreviations must be a character vector, as documented. A list
previously worked by accident.abbreviations and footnotes are now type-checked before the
empty-value shortcut. An empty value previously skipped the type check
entirely, so abbreviations = list() was accepted while
abbreviations = list(N = "x") errored. NULL and character(0)
remain no-ops for abbreviations; NULL and list() for footnotes.hv_man_table_jtcvs() now errors when tbl was not built with the
{N_obs} ||| {stat} statistic convention. It previously rendered a
complete, correctly styled, entirely empty table.hv_man_table_save_jtcvs() errors when a footnote entry has no
text; hv_man_table_save() now does the same for its symbol -> text list, which previously wrote the .docx for list("*" = NULL) (header marked Characteristic*, a footnote paragraph of
"* "), and equally for NA ("* NA"), a number ("* 1"), and a
length-2 vector ("* a* b"). The two savers' messages share the
contract sentence but no longer share one fixed label or fix: each
names the bad entry the way its own caller would look for it
(footnotes[["*"]] for hv_man_table_save(),
footnotes[[k]]$text for hv_man_table_save_jtcvs()) instead of a
shared, list-position label that made a CORR caller count entries to
find their symbol.hv_tbl_summary() now enforces its documented "exactly one type
bucket" contract instead of failing inside gtsummary.hv_tbl_summary() now checks each variable's data against the bucket
it was put in, not just that the buckets don't overlap. A non-numeric
variable in continuous previously produced "{N} ||| NA (NA, NA)"
cells, which satisfy the ||| convention check because the
convention genuinely is applied and only the statistic is NA — so
the table rendered and saved as a complete, correctly styled, all-NA
manuscript table off nothing but gtsummary messages. binary now
requires at most two distinct non-missing values AND a form
gtsummary can dichotomize (logical, 0/1, Yes/No), which is
what removes the leaked "Summary type is "dichotomous" but no
summary value has been assigned." error. A column with no non-missing
values is rejected in any bucket. categorical keeps no type rule.hv_man_table_jtcvs() validates groups names against
tbl$table_body, replacing a base-R non-character argument error.hv_man_table_jtcvs() now rejects a groups name given twice,
replacing flextable's duplicated col_keys: n_stat_1, disp_stat_1
— internal column names the caller never wrote.hv_tbl_summary() now rejects a groups section holding no
variables (e.g. list(Demo = character(0)), plausible when groups
is built from a filter that returns nothing). list() was already
caught; a named-but-empty section leaked the base-R "names must be
NULL or a character vector, not an empty integer vector.".hv_man_table_save_jtcvs() validates file, replacing a base-R
a character vector argument expected error.hv_man_table_save_jtcvs() now checks each footnotes entry is a
list before reading its fields. Dropping the outer nesting
(footnotes = list(row =, col =, text =)), or passing a bare string,
leaked $ operator is invalid for atomic vectors.col now reports what arrived and lists
ft's columns. The message previously ended at a bare colon with
nothing after it.hv_tbl_summary() validates by in the package's own vocabulary.Received: clause now names the class
even when the value is not length 1. The clause exists for the
argument-order slip, where the class mismatch is the tell, but it
reported a bare a vector of length 8 for a 200-row data frame (8
columns) and a vector of length 5 for a gtsummary table — losing
exactly the diagnostic it was written for. Those now read
tbl_df of length 8 and tbl_summary of length 5.binary bucket error no longer always says "Recode to 0/1",
which was impossible advice for a constant column (already 0/1,
with no event to recode — the fix is moving it to categorical)
and for a factor whose only problem is an unused level (the fix is
droplevels()). Every other case keeps the "Recode to 0/1" fix.?hvtiRtables package topic explaining which rendering mode to
use, with both pipelines end to end..docx.hv_check_docx() reads a written .docx and reports the three
constructs the CORR manuscript table rules prohibit, returning one row
per finding and zero rows when the file is clean: floating layers
(w:framePr paragraphs, w:txbxContent text boxes), hidden spacer
columns (a column both entirely empty and under 0.1 inch wide), and
footnotes written as a row inside the table rather than as text below
it. The first two are structural and high confidence; the third is a
marker-prefix heuristic, so read it as a prompt to look rather than as
proof. It reads the file rather
than the object that produced it, so it catches violations introduced
anywhere in the pipeline, including by a hand edit after the fact.
hv_man_table_save() and hv_man_table_save_jtcvs() do not call it —
run it on the path yourself when you want the check.hv_tbl_summary() now checks up front that compare = "smd" or
"both" is used with exactly two groups, and errors naming by and
the group count if not. gtsummary::add_difference() requires two
groups and previously failed three different ways, none naming
anything the caller wrote: it threw an internal message about
tbl_summary(by) for a genuine 3+ group variable and for a single
group, and, when by was a factor carrying an unused level, did not
error at all but returned estimate as NA, silently rendering an
empty comparison column. That last case now errors too, with a hint
pointing at droplevels(). compare = "pvalue" and "none" are
unaffected and still work at any number of groups.hv_test_footnotes_jtcvs(): builds the lettered p-value footnotes the
SAS %summarytable macro emits, reading gtsummary's test_name
column off an hv_tbl_summary() result and returning the list
hv_man_table_save_jtcvs() already accepts. Letters follow a fixed
order (Wilcoxon, Kruskal-Wallis, chi-square, Fisher), filtered to the
tests used, so two tables using the same tests agree. ANOVA never
appears, since this package tests continuous variables
non-parametrically throughout.hv_man_table_save_jtcvs() now validates each footnote's row and
col against the table being rendered. A row index computed against a
different object previously marked the wrong cell silently.hv_tbl_summary(compare = "both") reported a wrong standardized mean
difference. add_difference() ran after add_p(), and in that order
gtsummary overwrites the estimate column with a raw mean difference
for continuous variables and leaves it NA for binary and categorical
ones. A table could render 0.7 (SMD -1.0) where the true SMD was
-0.03, under a column header saying SMD, and categorical variables
showed no SMD at all. The two calls are now ordered
add_difference() then add_p(), which reproduces
add_difference()'s own output exactly for continuous, binary, and
categorical variables alike. compare = "pvalue", "smd", and
"none" are unaffected, since none of them runs both calls.
The same reordering preserves add_p()'s test_name column, which
add_difference() had been overwriting with "smd".
hv_tbl_summary(): a thin wrapper over gtsummary::tbl_summary() /
add_p() / add_difference() modeled on the interface biostats team
members already know from the %summarytable SAS macro — a grouped,
ordered variable list and variable-type buckets
(continuous/binary/categorical), rather than gtsummary's own
tidyselect interface. Always uses a blanket non-parametric test for
continuous variables (no per-variable Gaussian classification) and
reports median (P15, P85) by default, matching hv_man_footnotes()'s
house convention. compare adds a p-value, standardized mean
difference, or both, as a trailing column. Returns a plain gtsummary
object ready for hv_man_table_jtcvs(). See the README's "Migrating
from the %summarytable SAS macro" section for a parameter-mapping
table and worked example.hv_man_table_jtcvs() gains a stat_label parameter so callers whose
statistic is a median, not a mean, can set an accurate sub-header —
hv_tbl_summary() sets this automatically.hv_man_table() converts a gtsummary table object
into a flextable complying with HVTI CORR's "Table Construction for
Manuscripts" rules (flat header, no merged cells, house font/rounding
rules). hv_man_table_save() writes it to a .docx with footnotes and
an abbreviation key as text below the table. hv_man_footnotes()
supplies the house-universal N and median/percentile footnotes used as
hv_man_table_save()'s default.hv_man_table_jtcvs() builds a merged-header
flextable (spanning group headers, N/statistic column pairs) matching
the JTCVS journal submission template, and hv_man_table_save_jtcvs()
writes it to a .docx with a bold Table N. Caption paragraph and
lettered (a., b., ...) footnotes targeted to specific body cells.
Section-header rows are bold with #CAEDFB shading and column widths
are set explicitly, matching the canonical "Table Construction for
Manuscripts" house example and avoiding the header/number wrapping
flextable's default column sizing produced.hv_man_table_jtcvs()'s trailing argument is now validated: a name
absent from tbl$table_body, an unnamed value, or a value of length
other than 1 now raises a clear error instead of either silently
dropping the column or failing later with an unrelated internal error.