Changelog
Source:NEWS.md
hvtiRtables 1.0.10
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, thebylevels and section names in every style and layout, and to the notes, the abbreviation key and the captionhv_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.
hvtiRtables 1.0.9
-
hv_tbl_summary()no longer fails when the calling session defines an object namedsdormedian. gtsummary turns each statistic in{mean}±{sd}or{median} [{p15}, {p85}]into a function by looking its name up from wheretbl_summary()was called, and from inside a package that lookup reaches the global environment beforepackage:stats, so a study whoseR/folder definedsd(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 holdingstats::sdandstats::medianand then only base, so nothing a user defines can shadow a statistic. Present in 1.0.7 and 1.0.8.
hvtiRtables 1.0.8
hv_man_table_save()andhv_man_table_save_jtcvs()always drop the “Variable” columnhv_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()andhv_man_table_display()keep it for the report view;show_variablestaysTRUEby default and no longer needs setting toFALSEfor 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:
- Medians are shown in brackets, each number to 2 significant digits and a value of 10 or more to the units place:
102 [63, 170],0.31 [0.21, 0.39]. The statistic note reads “Median [15th, 85th percentiles]”. - P values drop the leading zero:
.013,<.001,>.9. - A table mixing medians and means marks the cells of whichever statistic fewer rows use, a section sign on medians and a pilcrow on means, with a note for each; the row-label suffixes (“Age, Mean±SD”) and the “No. (%) or as labeled” note are gone.
- Mean ± SD is unchanged:
63±13, unspaced, EHB paired rounding. - Exact ties in a median or percentile round to even, as for mean +/- SD: 62.5 shows as 62, where gtsummary and SAS showed 63.
- In
hv_man_table_jtcvs()the mark is a lettered superscriptbwith its own note, so the test footnotes letter fromc(they wereb,c). - Passing
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.
- Medians are shown in brackets, each number to 2 significant digits and a value of 10 or more to the units place:
-
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".- The manuscript style lays out a comparison table as the submissions did: a full grid, a two-row header with the grouping spanning its levels, one overall
ncolumn, 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()takescaption, 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. - The SAS glossary maps
STYLE=tostyle =(CORR family only) andTBLTITLE=tocaption =. - The manuscript style refuses what it cannot lay out, each with an error that says what to do instead:
fontandfont_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 byhv_tbl_summary()(it reads the overall count and the grouping’s name that function records). - The manuscript’s label column is 2.0 in wide, so a Table 1 with Overall, two groups and a P value is 6.5 in and stays on a portrait Letter page.
-
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 withstyle = "report". -
hv_man_table_jtcvs()section rows now span the table in one cell; they were a label beside one merged blank cell. -
Existing tables change: the report shades its section rows (
#CAEDFBby default, every cell, unmerged), its header is now bold throughout (theN = nlines 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.
- The manuscript style lays out a comparison table as the submissions did: a full grid, a two-row header with the grouping spanning its levels, one overall
-
hv_man_table()no longer carries gtsummary’s own footnotes inside the table. A saved table withcompare = "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, andcompare = "both"added an “Abbreviation: CI = Confidence Interval” row: house rule 13 puts notes below the table. Existing tables change:- The dagger note now names the tests behind the p-values (“… Median [15th, 85th percentiles]; P values from the Wilcoxon rank sum test and Pearson’s chi-square test.”), and the dagger marks the p-value header as well as the statistic headers. Fisher’s exact test keeps its own double dagger and is not repeated. A table with no p-values has no test sentence. The manuscript style says it in its own words, “Values are … median [15th, 85th percentiles]; P values from the …”, and marks its comparison header the same way.
-
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. - A table showing a confidence interval (
compare = "both") definesCIin the key, beside anyabbreviationsyou pass (your own definition ofCIwins).
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 drawscontinuous_stat = "both", which the compare layout refuses.layout = "compare"is the default, and the report style takes nolayout.-
hv_man_table()’slayoutargument followsstyle, so a call passing every argument by position reaches...at the seventh, not the sixth. A named SAS argument such as%summarytable’sSTYLE=is caught by its name at any position; only an unnamed extra argument is reported at position 7. - Describe’s marks follow the notation standard:
*on each group’snand†on each statistic, with*Patients with non-missing data.and the dagger note below the table, andhv_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()andhv_test_footnotes_jtcvs()warn on every call and go in the next release. Until then their arguments keep their meaning:groupsandtrailingchoose the same columns, andstat_labelnames the statistic.-
Their output changes: the table is drawn in the describe layout, with the same columns as before but the manuscript’s grid, shading, notes (
*Patients with non-missing data.fora. Patients with data available.) and the document’s font. -
hv_man_table_save_jtcvs()writescaptionabove the table and the table’s own notes below it, ashv_man_table_save()does, and keepsabbreviations. It drops a test footnote thathv_test_footnotes_jtcvs()wrote when the table already names that test, as anhv_tbl_summary()table does in its dagger note and with Fisher’s mark on its P values. Every other positionalfootnotesentry keeps a lettered superscript on its cells, lettered froma, with its line after the table’s own notes; the unnamed test notes of a plain gtsummary table stay lettered the same way. - Given a flextable that is not a describe table,
hv_man_table_save_jtcvs()now writes that table’s default notes and header marks; it used to write only the lettered notes. - Move to
hv_man_table(tbl, style = "manuscript", layout = "describe")andhv_man_table_save(ft, file, caption = ); the test notes then come from the table.
-
Their output changes: the table is drawn in the describe layout, with the same columns as before but the manuscript’s grid, shading, notes (
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.docxis a download on the page.?hv_man_tableand?hv_table_stylelink 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.
hvtiRtables 1.0.7
- New
hv_man_table_display()adds to a flextable fromhv_man_table()whathv_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.
hvtiRtables 1.0.6
The README’s Installation section now leads with
hvtiR::install(), which installs the whole HVTI R family in one call, and then givespak::pak("ehrlinger/hvtiRtables")for this package alone.hv_tbl_summary()gainsmean_sd, the continuous variables to show as mean±SD while keeping the Wilcoxon or Kruskal-Wallis test.normalstill couples mean±SD to one-way ANOVA and is unchanged.hv_tbl_summary()gainsshow_variable, on by default: a “Variable” column beside the label holds each variable’s column name, as%summarytable’s report did.hv_man_table()andhv_man_table_jtcvs()both show it. Existing tables gain this column; passshow_variable = FALSEfor 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 howhvtiRpropensity::ps_stddiff()’s%stddiffstandardized difference reaches a table, besidecompare = "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()’strailingnow takes several columns, laid out in order. Its error for a malformedtrailingno longer says “of length 1”.hv_tbl_summary()gainscutexact. 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’sCUTEXACT=rule to reproduce a SAS table (cutexact = 50is 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 givenfootnotesthat 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()andhv_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 columnhv_tbl_summary()writes. It no longer falls back to another trailing column, which footnoted a joined standardized difference “Fisher exact test.”
hvtiRtables 1.0.5
- The Word tables from
hv_man_table_save()andhv_man_table_save_jtcvs()now match the SAS%summarytablelayout, after a review of two commented example tables:-
hv_tbl_summary()writes categorical cells as12 (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 headedgroupname_col. The Characteristic column is now left-justified. - The CORR dagger now marks each statistic column instead of the first
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. - In the JTCVS table, “Characteristic” spans both header rows instead of printing twice, and the section rows are no longer shaded blue. Each
nsub-header carries a superscripta, whichhv_man_table_save_jtcvs()explains first with “a. Patients with data available.” Theaused to print as plain text,na. Footnotes you pass now start atb.
-
-
hv_tbl_summary()has anormalargument, the macro’sCON1=: list continuous variables in it as well as incontinuous, and each is shown as mean±SD and tested with one-way ANOVA. Every other continuous variable keeps thecontinuous_statsummary 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’sDESCLABEL=1did. 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. - The footnotes and
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.
hvtiRtables 1.0.4
The vignettes are Quarto documents now, not R Markdown, like the rest of the HVTI family.
VignetteBuilderisquarto, and building them needs the Quarto CLI. The text and code are unchanged.The pkgdown site’s articles put the table of contents on the left and use the full width of the window, through
pkgdown/extra.css.Now requires R 4.4.0 or newer, up from 4.1.0, to match the rest of the HVTI family.
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.DESCRIPTIONnow declares the Quarto command line tool inSystemRequirements. The vignettes have always needed it to build; the field makes that visible to installers and toR CMD check.hv_tbl_summary(compare = "pvalue")andcompare = "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, andhv_test_footnotes_jtcvs()then returnedlist()because no test was recorded. The HVTI Recipes book published blank p-values for a week this way. ‘broom’ stays inSuggests, socompare = "smd"and"none"still work without it.testthatinSuggestsis now>= 3.1.7, the first release withlocal_mocked_bindings(), which the test for the ‘broom’ guard uses.
hvtiRtables 1.0.3
-
The em dashes in
R/documentation are gone. Six sat in roxygen blocks, andman/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.
hvtiRtables 1.0.2
-
hv_correlation_table()now de-duplicates repeatedmethodvalues. Each stratum/pair/method combination appears once, while the caller’s method order is preserved.
hvtiRtables 1.0.1
-
New
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 abystratum. It backs thedc-tablesjob template. -
Mean±SD cells now enforce EHB/Blackstone paired rounding.
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 undercontinuous_stat = "mean"and to the mean row under"both"; median/percentile rows are unchanged. -
The JTCVS renderer’s default mean label now follows house spacing.
hv_man_table_jtcvs()writes"No. (%) or Mean±SD", matchinghv_tbl_summary()and the CORR footnote text. -
CORR footnotes now follow the continuous statistic automatically.
hv_man_footnotes()acceptscontinuous_statandpercentiles, and anhv_tbl_summary()table carries the matching footnote throughhv_man_table()intohv_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%summarytabletables 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()gainscontinuous_stat."median"(default) keepsmedian (P<low>, P<high>);"mean"gives mean +/- SD, written64±12without 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_labelfollows the choice. Defaults taken from Rajes’s%summarytabletables. -
hv_tbl_summary()’soverallnow defaults toTRUE, matching the macro’sTOTALCOL=1and the stratified tables it replaces. Withby = NULLit is ignored rather than an error.hv_man_table()shows the new Overall column automatically;hv_man_table_jtcvs()shows it only whengroupsnamesstat_0, so existing JTCVS calls render as before until you add it. Passoverall = FALSEfor the old layout.
hvtiRtables 1.0.0
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:
-
Both house styles are complete and symmetric where they should be.
hv_man_table()andhv_man_table_jtcvs()both consumehv_tbl_summary()output, and the places the two families genuinely differ -captionon the JTCVS saver only, the two footnote shapes - are documented as differences rather than papered over. -
The SAS interface is documented from the macro side.
vignette("sas-migration")ports a%summarytableprogram end to end, including the defaults that differ and theQNTLDEF=5/quantile(type = 2)trap. -
Macro parameter names teach. Passing
class=,con1=ortbltitle=to any public function errors with the R argument and the function that takes it, resolved against the caller’s CORR/JTCVS family. -
The
dcprefix formally belongs here.hvtiRtemplates’ allocation map assigns thedc.*descriptive-table macro family to this package, so the%summarytableport 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.
hvtiRtables 0.9.7
New features
-
hv_man_table()now accepts anhv_tbl_summary()table. It splits each"{N_obs} ||| {stat}"cell into a flatNo.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 andhv_man_footnotes()ships a*footnote describing it. A plaingtsummary::tbl_summary()table carries no such convention and passes through unchanged. - A table where only some cells carry the convention is now rejected, through the same assertion the JTCVS renderer uses. Splitting it would have left the rest blank.
Bug fixes
- The house footnote symbols now attach to the count column when the table has one. With the split above, a sectioned table’s first column is
groupname_col, so the marker would otherwise have landed on the section-label column. - A CORR table missing the
"{N_obs} ||| {stat}"convention now raises an error naminghv_man_table(), nothv_man_table_jtcvs(). The internal assertion the two renderers share previously hardcoded the JTCVS renderer’s name in its message.
hvtiRtables 0.9.6
New features
-
hv_tbl_summary()gainsoverall =, the%summarytableTOTALCOL=equivalent, adding an Overall column across all groups. Defaults toFALSE; the macro’s own default isTOTALCOL=1. -
hv_tbl_summary(),hv_man_table(),hv_man_table_jtcvs(),hv_man_table_save(), andhv_man_table_save_jtcvs()now error on a%summarytableparameter name, naming the R argument and the function that takes it, rather than silently ignoring it. - New vignette, “Porting a
%summarytableprogram to R”.
Documentation
- The README’s migration table stated that
CON1=maps tocontinuous. It does not:CON1=was mean +/- SD with ANOVA, andcontinuousreproducesCON3=. Corrected.
Bug fixes
-
binaryvariables now pass an explicit event value togtsummaryinstead of letting it infer one. Its inference is type-sensitive in a way that hit the SAS import path: ahaven_labelledcolumn over a double base type – whathaven::read_sas()produces, since every SAS numeric is an 8-byte float – failed withSummary type is "dichotomous" but no summary value has been assigned., while the otherwise-identical integer-backed column worked. The event is theTRUE,1, orYesside in every accepted encoding.
hvtiRtables 0.9.5
Breaking changes
-
hv_man_table_jtcvs()now enforcesfont_sizeof 11 or 12, the same house rulehv_man_table()has always enforced. Calls passing any other value, or a vector, now error. -
abbreviationsmust be a character vector, as documented. A list previously worked by accident.
Bug fixes
-
abbreviationsandfootnotesare now type-checked before the empty-value shortcut. An empty value previously skipped the type check entirely, soabbreviations = list()was accepted whileabbreviations = list(N = "x")errored.NULLandcharacter(0)remain no-ops forabbreviations;NULLandlist()forfootnotes. -
hv_man_table_jtcvs()now errors whentblwas not built with the{N_obs} ||| {stat}statistic convention. It previously rendered a complete, correctly styled, entirely empty table. - Both savers now enforce one footnote-text contract, through shared code.
hv_man_table_save_jtcvs()errors when a footnote entry has notext;hv_man_table_save()now does the same for itssymbol -> textlist, which previously wrote the.docxforlist("*" = NULL)(header markedCharacteristic*, a footnote paragraph of"* "), and equally forNA("* 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[["*"]]forhv_man_table_save(),footnotes[[k]]$textforhv_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 insidegtsummary. -
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 incontinuouspreviously produced"{N} ||| NA (NA, NA)"cells, which satisfy the|||convention check because the convention genuinely is applied and only the statistic isNA— so the table rendered and saved as a complete, correctly styled, all-NAmanuscript table off nothing butgtsummarymessages.binarynow requires at most two distinct non-missing values AND a formgtsummarycan 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.categoricalkeeps no type rule. -
hv_man_table_jtcvs()validatesgroupsnames againsttbl$table_body, replacing a base-Rnon-character argumenterror. -
hv_man_table_jtcvs()now rejects agroupsname given twice, replacingflextable’sduplicated col_keys: n_stat_1, disp_stat_1— internal column names the caller never wrote. -
hv_tbl_summary()now rejects agroupssection holding no variables (e.g.list(Demo = character(0)), plausible whengroupsis built from a filter that returns nothing).list()was already caught; a named-but-empty section leaked the base-R “namesmust beNULLor a character vector, not an empty integer vector.”. -
hv_man_table_save_jtcvs()validatesfile, replacing a base-Ra character vector argument expectederror. -
hv_man_table_save_jtcvs()now checks eachfootnotesentry 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. - A footnote entry with no
colnow reports what arrived and listsft’s columns. The message previously ended at a bare colon with nothing after it. -
hv_tbl_summary()validatesbyin the package’s own vocabulary. - Every validation message’s
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 barea vector of length 8for a 200-row data frame (8 columns) anda vector of length 5for agtsummarytable — losing exactly the diagnostic it was written for. Those now readtbl_df of length 8andtbl_summary of length 5. - The
binarybucket 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 tocategorical) and for a factor whose only problem is an unused level (the fix isdroplevels()). Every other case keeps the “Recode to 0/1” fix.
Documentation
- New
?hvtiRtablespackage topic explaining which rendering mode to use, with both pipelines end to end. - New vignette walking a complete JTCVS table from data frame to checked
.docx. - Every function’s help now states its arguments’ accepted values exhaustively and carries a “Common mistakes” section.
hvtiRtables 0.9.4
New features
-
hv_check_docx()reads a written.docxand 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:framePrparagraphs,w:txbxContenttext 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()andhv_man_table_save_jtcvs()do not call it — run it on the path yourself when you want the check.
Bug fixes
-
hv_tbl_summary()now checks up front thatcompare = "smd"or"both"is used with exactly two groups, and errors namingbyand 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 abouttbl_summary(by)for a genuine 3+ group variable and for a single group, and, whenbywas a factor carrying an unused level, did not error at all but returnedestimateasNA, silently rendering an empty comparison column. That last case now errors too, with a hint pointing atdroplevels().compare = "pvalue"and"none"are unaffected and still work at any number of groups.
hvtiRtables 0.9.3
New features
-
hv_test_footnotes_jtcvs(): builds the lettered p-value footnotes the SAS%summarytablemacro emits, readinggtsummary’stest_namecolumn off anhv_tbl_summary()result and returning the listhv_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.
Bug fixes
-
hv_man_table_save_jtcvs()now validates each footnote’srowandcolagainst the table being rendered. A row index computed against a different object previously marked the wrong cell silently.
hvtiRtables 0.9.2
Bug fixes
-
hv_tbl_summary(compare = "both")reported a wrong standardized mean difference.add_difference()ran afteradd_p(), and in that ordergtsummaryoverwrites theestimatecolumn with a raw mean difference for continuous variables and leaves itNAfor binary and categorical ones. A table could render0.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 orderedadd_difference()thenadd_p(), which reproducesadd_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()’stest_namecolumn, whichadd_difference()had been overwriting with"smd".
hvtiRtables 0.9.1
New features
-
hv_tbl_summary(): a thin wrapper overgtsummary::tbl_summary()/add_p()/add_difference()modeled on the interface biostats team members already know from the%summarytableSAS 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 reportsmedian (P15, P85)by default, matchinghv_man_footnotes()’s house convention.compareadds a p-value, standardized mean difference, or both, as a trailing column. Returns a plaingtsummaryobject ready forhv_man_table_jtcvs(). See the README’s “Migrating from the%summarytableSAS macro” section for a parameter-mapping table and worked example. -
hv_man_table_jtcvs()gains astat_labelparameter so callers whose statistic is a median, not a mean, can set an accurate sub-header —hv_tbl_summary()sets this automatically.
hvtiRtables 0.9.0
New features
- Initial release.
hv_man_table()converts agtsummarytable 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.docxwith footnotes and an abbreviation key as text below the table.hv_man_footnotes()supplies the house-universal N and median/percentile footnotes used ashv_man_table_save()’s default. - JTCVS submission mode:
hv_man_table_jtcvs()builds a merged-headerflextable(spanning group headers, N/statistic column pairs) matching the JTCVS journal submission template, andhv_man_table_save_jtcvs()writes it to a.docxwith a boldTable N. Captionparagraph and lettered (a.,b., …) footnotes targeted to specific body cells. Section-header rows are bold with#CAEDFBshading and column widths are set explicitly, matching the canonical “Table Construction for Manuscripts” house example and avoiding the header/number wrappingflextable’s default column sizing produced.
Bug fixes
-
hv_man_table_jtcvs()’strailingargument is now validated: a name absent fromtbl$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.