| Title: | Clinical Table Styling Tools and Utilities |
|---|---|
| Description: | The primary motivation of this package is to take the things that are great about the R packages 'flextable' <https://davidgohel.github.io/flextable/> and 'officer' <https://davidgohel.github.io/officer/>, take the standard and complex pieces of formatting clinical tables for regulatory use, and simplify the tedious pieces. |
| Authors: | Mike Stackhouse [aut, cre] (ORCID: <https://orcid.org/0000-0001-6030-723X>), Ross Didenko [aut], Yevhenii Boiko [aut], Marat Zakirov [ctb], Roman Rogoza [ctb], Atorus Research, Inc. [cph], Incyte Corporation [cph] |
| Maintainer: | Mike Stackhouse <[email protected]> |
| License: | Apache License (>= 2) |
| Version: | 0.4.0 |
| Built: | 2026-10-01 07:45:37 UTC |
| Source: | https://github.com/atorus-research/clinify |
Convert a flextable into a clintable object
as_clintable(x, page_by = NULL, group_by = NULL)as_clintable(x, page_by = NULL, group_by = NULL)
x |
A flextable object |
page_by |
A variable in the input dataframe to use for pagination |
group_by |
A variable which will be used for grouping and attached as a label above the table headers |
There is no coerce_character argument here, unlike clintable().
A flextable arrives with its cell text already rendered, so the numeric
formatting this argument exists to avoid has already happened and coercing
the source data is no longer an option. The nearest equivalent is
flextable::set_formatter(x, values = as.character) before calling
as_clintable(), which rewrites every body cell from the stored data.
That is not the same operation: it replaces cell content, so any
chunk level work already done on the body - flextable::compose(),
flextable::colformat_*(), images, hyperlinks, equations - is discarded,
and columns keep the right alignment flextable gave them for being numeric.
Because that trade cannot be made safely on the user's behalf, it is left
to the caller. To get the coercion without the trade, build with
clintable(x, coerce_character = TRUE) instead.
A clintable object
ft <- flextable::flextable(mtcars) as_clintable(ft)ft <- flextable::flextable(mtcars) as_clintable(ft)
This function allows you to attach specified titles, footnotes, or a footnote page into clintable or clindoc object. The input can be provided either as a list of character vectors, or pre-built flextable.
clin_add_titles(x, ls = NULL, ft = NULL, align = NULL, tokens = NULL) clin_add_footnotes(x, ls = NULL, ft = NULL, align = NULL, tokens = NULL) clin_add_footnote_page(x, ls = NULL, ft = NULL, align = NULL, tokens = NULL)clin_add_titles(x, ls = NULL, ft = NULL, align = NULL, tokens = NULL) clin_add_footnotes(x, ls = NULL, ft = NULL, align = NULL, tokens = NULL) clin_add_footnote_page(x, ls = NULL, ft = NULL, align = NULL, tokens = NULL)
x |
a clintable object |
ls |
a list of character vectors, no more than 2 elements to a vector, or a data frame spec as described above |
ft |
A flextable object to use as the header |
align |
Where to place each line, as a character vector holding one
value per element of |
tokens |
Replacements for |
When using the ls parameter, each element of the list can contain no more than two
elements within each character vector. In a title, a single element will align center.
In a footnote, a single element will align to the left. For both titles and footnotes,
two elements will align split down the middle, with the left side element aligning left
and the right side element aligning right.
Use align to place a line somewhere other than its default. A line holding
a single element can go "left", "center", or "right"; a line holding two
elements is split down the middle by construction, which align spells
"split". NA leaves a line where it would have landed anyway.
Instead of a list, ls can be a data frame holding every line for a table
at once, so one object feeds the titles, the footnotes and a footnote page
together. Each of the three functions takes the rows that belong to it and
ignores the rest, and a surface with no rows is left alone. Rows are used in
the order they are given.
| column | holds |
type |
"title", "footnote", or "footnote_page" (plurals accepted) |
text1 |
the line, or its left hand side |
text2 |
the right hand side of a split line, blank or NA if there is none |
align |
as the align argument below, blank or NA for the default
|
Only type and text1 are required. Reading the spec in is left to you -
it is an ordinary data frame, so it can come from a spreadsheet, a CSV, a
database, or be written out by hand.
tokens fills in {NAME} placeholders, which is how a program path or a run
date gets into text that was written somewhere else. {PAGE} and
{NUMPAGES} are left alone - those become real Word page number fields when
the table renders, so do not pass them as tokens.
A clintable object
clintable(mtcars) |> clin_add_titles( list( c("Left", "Right"), c("Just the middle") ) ) |> clin_add_titles( list( c("Protocol: ABC", "Page {PAGE} of {NUMPAGES}"), "Table 14-2.01", "Summary of Demographic and Baseline Characteristics" ), # the title line stays centered, the one below it goes left align = c(NA, NA, "left") ) |> clin_add_footnotes( list( c( "Here's a footnote.", format(Sys.time(), "%H:%M %A, %B %d, %Y") ) ) ) |> clin_add_footnote_page( list( c( "Use when you have a lot of footnotes", "And you don't want to put them on every page" ) ) ) # Or keep every line for the table in one place and let each function take # the rows that belong to it spec <- data.frame( type = c("title", "title", "footnote"), text1 = c("Protocol: ABC", "Table 14-2.01", "Source: {FILE}"), text2 = c("Page {PAGE} of {NUMPAGES}", NA, NA), align = c("split", "center", "left") ) clintable(mtcars) |> clin_add_titles(spec, tokens = list(FILE = "programs/t14-2-01.R")) |> clin_add_footnotes(spec, tokens = list(FILE = "programs/t14-2-01.R"))clintable(mtcars) |> clin_add_titles( list( c("Left", "Right"), c("Just the middle") ) ) |> clin_add_titles( list( c("Protocol: ABC", "Page {PAGE} of {NUMPAGES}"), "Table 14-2.01", "Summary of Demographic and Baseline Characteristics" ), # the title line stays centered, the one below it goes left align = c(NA, NA, "left") ) |> clin_add_footnotes( list( c( "Here's a footnote.", format(Sys.time(), "%H:%M %A, %B %d, %Y") ) ) ) |> clin_add_footnote_page( list( c( "Use when you have a lot of footnotes", "And you don't want to put them on every page" ) ) ) # Or keep every line for the table in one place and let each function take # the rows that belong to it spec <- data.frame( type = c("title", "title", "footnote"), text1 = c("Protocol: ABC", "Table 14-2.01", "Source: {FILE}"), text2 = c("Page {PAGE} of {NUMPAGES}", NA, NA), align = c("split", "center", "left") ) clintable(mtcars) |> clin_add_titles(spec, tokens = list(FILE = "programs/t14-2-01.R")) |> clin_add_footnotes(spec, tokens = list(FILE = "programs/t14-2-01.R"))
This function configures alternating pages on a clintable object.
clin_alt_pages(x, key_cols, col_groups)clin_alt_pages(x, key_cols, col_groups)
x |
A clintable object |
key_cols |
A character vector of variable names |
col_groups |
A list of character vectors of variable names |
A clintable object
ct <- clintable(mtcars) clin_alt_pages( ct, key_cols = c("mpg", "cyl", "hp"), col_groups = list( c("disp", "drat", "wt"), c("qsec", "vs", "am"), c("gear", "carb") ) )ct <- clintable(mtcars) clin_alt_pages( ct, key_cols = c("mpg", "cyl", "hp"), col_groups = list( c("disp", "drat", "wt"), c("qsec", "vs", "am"), c("gear", "carb") ) )
This function uses the applies the functionality flextable::keep_with_next()
by automatically building the row indices using some grouping variable. Each group
identified by the variable (i.e. when the value of the variable changes) will be set
as a "keep_with_next" group in Word. Using this functionality, Word will attempt not to
break that group across pages, enabling smoother pagination without having to do specific
calculations of page breaks.
clin_auto_page(x, group_var, when = c("change", "notempty"), drop = FALSE)clin_auto_page(x, group_var, when = c("change", "notempty"), drop = FALSE)
x |
A clintable object |
group_var |
A string containing a variable name of the input dataset used to calculate groups |
when |
Character string indicating when to apply padding:
|
drop |
Keep or drop the 'group_var“ variable |
A clintable object
clintable(mtcars) |> clin_auto_page("gear")clintable(mtcars) |> clin_auto_page("gear")
Extraction of flextable print method with special handling of clintable pages and
clin_col_widths(x, ...)clin_col_widths(x, ...)
x |
A clintable object |
... |
Named parameters where the names are columns in the flextable and the values are decimals representing the percent of total width of the table |
A clintable object
ct <- clintable(mtcars) ct <- clin_alt_pages( ct, key_cols = c("mpg", "cyl", "hp"), col_groups = list( c("disp", "drat", "wt"), c("qsec", "vs", "am"), c("gear", "carb") ) ) |> clin_col_widths(mpg = .2, cyl = .2, disp = .15, vs = .15) print(ct)ct <- clintable(mtcars) ct <- clin_alt_pages( ct, key_cols = c("mpg", "cyl", "hp"), col_groups = list( c("disp", "drat", "wt"), c("qsec", "vs", "am"), c("gear", "carb") ) ) |> clin_col_widths(mpg = .2, cyl = .2, disp = .15, vs = .15) print(ct)
This function allows you to apply column headers named arguments
and character vectors. Separate elements of the character vector
are converted to separate levels of the output table header.
The in which the headers are applied goes from top to bottom,
so if you provide 3 elements for a column header, the first
element is applied to the top and the second to the bottom.
If one variable has three levels and other variable only have
one or two, the columns with less levels to the header will bind
to the bottom. So a column with two levels will apply to the
second and third row, and a column with one level with apply
the bottom row. Spanners are determined using cells of the same
text value, where horizontally adjacent cells holding the same
text are merged. Use the merge argument when a header row
legitimately repeats a label across adjacent columns and those
cells should be left alone - merged, they render as one label
centred over the whole run, so the repeats are not there to read
any more. That is most often wanted for the bottom row, which
holds each column's own label: six columns each labelled
"Baseline" come out as a single Baseline spanning all six
unless merge = "spanners" keeps that row out of it. merge
works a row at a time, so if a single row needs some of its
repeated cells merged but not others, leave that row out of
merge and span the intended cells with
flextable::merge_at().
clin_column_headers(x, ..., merge = TRUE)clin_column_headers(x, ..., merge = TRUE)
x |
A clintable object |
... |
Named arguments providing the column header text. Separate levels of the header are determined using separate elements of a character vector. |
merge |
Controls the automatic merging of identical, adjacent
header cells, which is what forms spanners. One thing to know: a custom |
The same result can be achieved using column labels on the
input dataframe to the clintable. If labels are present,
header levels will be separated using the delimitter "||" within
the label string. Headers built that way can have their merging
adjusted by calling clin_column_headers() with no header text and
only the merge argument, which leaves the header text as it is.
Called that way, any merging already on the header is cleared first -
including merges applied by hand with flextable::merge_at() or
flextable::merge_v() - so the rows named in merge end up being the
only merged rows.
A clintable object
clintable(iris) |> clin_column_headers( Sepal.Length = c("Flowers", "Sepal", "Length"), Sepal.Width = c("Flowers", "Sepal", "Width"), Petal.Length = c("Petal", "Length"), Petal.Width = c("Petal", "Width") ) # Keep the repeated bottom row cells separate, but still span # "Flowers" and "Petal" across the columns above them clintable(iris) |> clin_column_headers( Sepal.Length = c("Flowers", "Sepal", "Value"), Sepal.Width = c("Flowers", "Sepal", "Value"), Petal.Length = c("Petal", "Value"), Petal.Width = c("Petal", "Value"), merge = "spanners" ) # Headers coming from column labels can have their merging adjusted # without restating the header text iris2 <- iris attr(iris2$Sepal.Length, "label") <- "Flowers||Value" attr(iris2$Sepal.Width, "label") <- "Flowers||Value" clintable(iris2) |> clin_column_headers(merge = 1)clintable(iris) |> clin_column_headers( Sepal.Length = c("Flowers", "Sepal", "Length"), Sepal.Width = c("Flowers", "Sepal", "Width"), Petal.Length = c("Petal", "Length"), Petal.Width = c("Petal", "Width") ) # Keep the repeated bottom row cells separate, but still span # "Flowers" and "Petal" across the columns above them clintable(iris) |> clin_column_headers( Sepal.Length = c("Flowers", "Sepal", "Value"), Sepal.Width = c("Flowers", "Sepal", "Value"), Petal.Length = c("Petal", "Value"), Petal.Width = c("Petal", "Value"), merge = "spanners" ) # Headers coming from column labels can have their merging adjusted # without restating the header text iris2 <- iris attr(iris2$Sepal.Length, "label") <- "Flowers||Value" attr(iris2$Sepal.Width, "label") <- "Flowers||Value" clintable(iris2) |> clin_column_headers(merge = 1)
This function calculates the default table width based on the page width
and margins specified in the clinify_docx_default option.
clin_default_table_width()clin_default_table_width()
An rdocx object from the officer package
clin_default_table_width()clin_default_table_width()
Configure a clintable to table by a grouping variable, which will be used as a label
clin_group_by(x, group_by, caption_by = NULL, when = c("change", "notempty"))clin_group_by(x, group_by, caption_by = NULL, when = c("change", "notempty"))
x |
A clintable object |
group_by |
A character vector of variable names which will be used for grouping and attached as a label above the table headers |
caption_by |
A single element string of a variable name which will be used as a caption attached below the table body and above in the footer. Defaults to NULL. |
when |
Character string indicating how to identify groups and captions:
|
A clintable object
clintable(iris) |> clin_group_by("Species")clintable(iris) |> clin_group_by("Species")
Adds top padding to rows in a 'clintable“ based on changes in a grouping variable or non-empty values. Useful for visually separating groups in a table
clin_group_pad( x, pad_by, size = 9, when = c("change", "notempty"), drop = FALSE )clin_group_pad( x, pad_by, size = 9, when = c("change", "notempty"), drop = FALSE )
x |
A clintable |
pad_by |
A string indicating the column name used to detect group changes. |
size |
Numeric value for the base padding size (default is 9). |
when |
Character string indicating when to apply padding:
|
drop |
Keep or drop the padding variable used to identify padding locations |
A clintable object with modified padding.
ct <- clintable(mtcars) |> clin_group_pad('gear') ct <- clintable(mtcars) |> clin_group_pad('gear', size = 15)ct <- clintable(mtcars) |> clin_group_pad('gear') ct <- clintable(mtcars) |> clin_group_pad('gear', size = 15)
Three pieces of vertical space shape the header block, and they are named here for where they sit rather than for the padding that produces them, because the mapping between the two is not obvious:
clin_header_pad( x, above = NULL, below = NULL, rule_to_body = NULL, rows = NULL )clin_header_pad( x, above = NULL, below = NULL, rule_to_body = NULL, rows = NULL )
x |
A clintable object |
above |
Space above each header row, in points |
below |
Space below each header row, in points. The bottom row's is what sets how far the rule sits from the column labels |
rule_to_body |
Space between that rule and the first body row, in points. A single value - there is only one first body row per page |
rows |
Which header rows to space, as row numbers counting from the top. The default spaces every row; rows left out keep whatever spacing they already have |
above is the space over each header row. On a single row header that is
the buffer above the column labels; on a spanned header it also opens the
space between the levels, which is what a blank row above the header
normally looks like.
below is the space under each header row. The one that matters most is
the bottom row's, because a cell's bottom border sits at the bottom edge
of the cell, below its padding - so this is what decides how far the
rule is drawn from the column labels. It does not open space beneath the
rule.
rule_to_body is the space between that rule and the first row of the
table body, which is the one that has to come from the body side.
above and below apply to every row of the header by default, which is
the usual convention and matches flextable::padding(part = "header"). A
header row that needs a different gap can be given one either by passing a
value per row - above = c(18, 34) - or by aiming the call at particular
rows with rows, which leaves the others alone. That matters because the
spacing is applied as the table renders, after anything the caller did, so a
call covering every row would otherwise overwrite a per-row
flextable::padding() set beforehand.
rule_to_body is applied to the first row of every page, so a table split
over pages keeps the same gap under the rule throughout. If a group label is
added above the header it keeps its own spacing, since it is put there as
the table renders.
Called a second time, this refines what the first call set rather than replacing it: arguments this call does not name keep their earlier value.
Spacing is given in points, which is what flextable measures cell padding in. Whatever is set here replaces the header padding clinify starts with.
A clintable object
# A blank row's worth of space around each header row, the rule close under # the labels, and a little air before the body starts clintable(mtcars) |> clin_header_pad(above = 18, below = 4, rule_to_body = 6)# A blank row's worth of space around each header row, the rule close under # the labels, and a little air before the body starts clintable(mtcars) |> clin_header_pad(above = 18, below = 4, rule_to_body = 6)
Configure pagination using a page variable
clin_page_by(x, page_by, max_rows = 10)clin_page_by(x, page_by, max_rows = 10)
x |
A clintable object |
page_by |
A variable in the input dataframe to use for pagination |
max_rows |
If no page_by, the maximum rows allowed per page |
A clintable object
dat <- mtcars dat["page"] <- c( rep(1, 10), rep(2, 10), rep(3, 10), c(4, 4) ) clintable(dat) |> clin_page_by("page") clintable(mtcars) |> clin_page_by(max_rows = 10)dat <- mtcars dat["page"] <- c( rep(1, 10), rep(2, 10), rep(3, 10), c(4, 4) ) clintable(dat) |> clin_page_by("page") clintable(mtcars) |> clin_page_by(max_rows = 10)
This helper function will find placeholder text and replace the fields of
the flextable object with the appropriate page number fields. The function
will search for the text {PAGE} and replace with the word field for current
pages, and {NUMPAGES} for total pages. This allows you to current and total
page fields within Word documents. Note that this is intended to be used in
the defaults for clinify_titles_default or clinify_footnotes_default.
clin_replace_pagenums(x)clin_replace_pagenums(x)
x |
A clintable object |
A clintable object
title <- new_title_footnote( list( # We'll add tools to automate paging c("Protocol: CDISCPILOT01", "Page {PAGE} of {NUMPAGES}"), c("Table 14-2.01"), c("Summary of Demographic and Baseline Characteristics") ), "titles" ) title <- clin_replace_pagenums(title) footnote <- new_title_footnote( list( # We'll add tools to automate paging c("Page {PAGE}", "Total Pages: {NUMPAGES}") ), "footnotes" ) footnote <- clin_replace_pagenums(footnote)title <- new_title_footnote( list( # We'll add tools to automate paging c("Protocol: CDISCPILOT01", "Page {PAGE} of {NUMPAGES}"), c("Table 14-2.01"), c("Summary of Demographic and Baseline Characteristics") ), "titles" ) title <- clin_replace_pagenums(title) footnote <- new_title_footnote( list( # We'll add tools to automate paging c("Page {PAGE}", "Total Pages: {NUMPAGES}") ), "footnotes" ) footnote <- clin_replace_pagenums(footnote)
Regulatory outputs are usually specified to an exact row pitch, and the rendered height of a row is what decides how much fits on a page. flextable leaves rows at a nominal quarter inch with a rule of "auto", which lets the renderer size them however it likes. This records the pitch you want and applies it when the table renders.
clin_row_height( x, body = NULL, title = NULL, footnote = NULL, header = NULL, header_leading = NULL, rule = c("atleast", "exact", "auto"), unit = c("pt", "in", "cm", "mm") )clin_row_height( x, body = NULL, title = NULL, footnote = NULL, header = NULL, header_leading = NULL, rule = c("atleast", "exact", "auto"), unit = c("pt", "in", "cm", "mm") )
x |
A clintable object |
body |
Row pitch for the table body |
title |
Row pitch for the title lines |
footnote |
Row pitch for the footnote lines, and for a footnote page |
header |
Row pitch for the column header rows. A floor under
|
header_leading |
Leading of the lines within the header, as a multiple
of single spacing - |
rule |
How the renderer should treat the pitch. |
unit |
Unit the pitches are given in. Row pitch is normally specified in points, so that is the default. |
The surfaces are set separately because they are separate tables: the table body, the column header, and the title and footnote blocks that go into the Word header and footer. Group label and caption rows, which clinify inserts while it renders, take the body pitch.
The column header has two levers rather than one, and they do different
things. header bounds the header rows the same way body bounds the body
rows, so with the default rule = "atleast" it is a floor: a header cell
holding three lines still grows past it. header_leading is what closes the
gap between those lines, so it is the one to reach for when a wrapped arm
label sits looser than a reference output. They can be used together.
Called a second time, this refines what the first call set rather than replacing it: arguments this call does not name keep their earlier value. So a house wide pitch can be set once and a single table can add an exception without restating the rest.
The height is applied to whole parts, so it is a pitch for every row of the
surface rather than a per-row height. Anything already set with
flextable::height() or flextable::height_all() is replaced. Because the
pitch is applied after the default styling functions run, it also holds when
an organisation's clinify_table_default() sets a house pitch of its own -
the table's own setting wins.
A clintable object
clintable(mtcars) |> clin_row_height(body = 15.35, title = 11.4, footnote = 11.4) # Or in inches clintable(mtcars) |> clin_row_height(body = 0.213, unit = "in") # A wrapped header label sitting too loose: bound the header rows and close # up the lines inside them clintable(mtcars) |> clin_column_headers(mpg = "Miles\nper\ngallon") |> clin_row_height(header = 13, header_leading = 0.75)clintable(mtcars) |> clin_row_height(body = 15.35, title = 11.4, footnote = 11.4) # Or in inches clintable(mtcars) |> clin_row_height(body = 0.213, unit = "in") # A wrapped header label sitting too loose: bound the header rows and close # up the lines inside them clintable(mtcars) |> clin_column_headers(mpg = "Miles\nper\ngallon") |> clin_row_height(header = 13, header_leading = 0.75)
Regulatory arm spanner tables carry a thin horizontal rule directly under each spanner label, running across only the columns that spanner covers, so that the label reads as a heading over its own block of columns. The columns are worked out from the header that is on the table, so the rule follows the spanners as the layout changes instead of having to be given as column numbers that then have to be kept in step with it.
clin_spanner_rule(x, border = TRUE, rows = NULL)clin_spanner_rule(x, border = TRUE, rows = NULL)
x |
A clintable object |
border |
The pen to draw the rule with. |
rows |
Header rows to rule, numbered from the top down. |
A spanner is a run of header cells that has been merged together, which is
what clin_column_headers() makes of adjacent cells holding the same text.
Two kinds of run are deliberately left alone:
A run of blank cells. That is the empty space over a stub column, or over a trailing p-value column, rather than a spanner - clinify fills the header levels a column does not use, so those cells merge into a run of their own.
Anything in the bottom row of the header. That row holds the individual column labels, so a merged run in it is a label sitting over two columns rather than a spanner, and the rule under the bottom row is the one the styling function draws across the whole table.
Called a second time, this refines what the first call set rather than replacing it: arguments this call does not name keep their earlier value.
The rule is drawn as the table renders, after the default styling function
has run. That is what makes it survive a house style: the stock
clinify_table_default() opens with flextable::border_remove(), which
would wipe a border applied any earlier, and a house style is free to draw
its header rules in a pen of its own.
A clintable object
df <- data.frame( stub = c("Male", "Female"), a_lo = c("5 (10%)", "7 (14%)"), a_hi = c("2 (4%)", "3 (6%)"), b_lo = c("6 (12%)", "8 (16%)"), b_hi = c("1 (2%)", "4 (8%)") ) ct <- clintable(df, use_labels = FALSE) |> clin_column_headers( stub = "", a_lo = c("Drug A (N=50)", "Low"), a_hi = c("Drug A (N=50)", "High"), b_lo = c("Drug B (N=50)", "Low"), b_hi = c("Drug B (N=50)", "High") ) # A rule under each arm spanner, over that arm's two columns only, with the # stub left un-ruled clin_spanner_rule(ct) # The same rule in a dashed pen clin_spanner_rule(ct, border = officer::fp_border(style = "dashed"))df <- data.frame( stub = c("Male", "Female"), a_lo = c("5 (10%)", "7 (14%)"), a_hi = c("2 (4%)", "3 (6%)"), b_lo = c("6 (12%)", "8 (16%)"), b_hi = c("1 (2%)", "4 (8%)") ) ct <- clintable(df, use_labels = FALSE) |> clin_column_headers( stub = "", a_lo = c("Drug A (N=50)", "Low"), a_hi = c("Drug A (N=50)", "High"), b_lo = c("Drug B (N=50)", "Low"), b_hi = c("Drug B (N=50)", "High") ) # A rule under each arm spanner, over that arm's two columns only, with the # stub left un-ruled clin_spanner_rule(ct) # The same rule in a dashed pen clin_spanner_rule(ct, border = officer::fp_border(style = "dashed"))
flextable centres a table on the page. Regulatory outputs are usually
flush left, and a narrow table sometimes wants to be centred deliberately.
The choice is recorded on the clintable and applied when the table renders,
after the default styling function has run, so it holds even when an
organisation's own clinify_table_default() rebuilds the table properties.
clin_table_align(x, align)clin_table_align(x, align)
x |
A clintable object |
align |
One of "left", "center", or "right" |
This is only about where the table sits across the page. How wide it is, and
how that width is divided between the columns, is clin_col_widths().
A clintable object
clintable(mtcars) |> clin_table_align("left")clintable(mtcars) |> clin_table_align("left")
clindoc objectThese functions handle the conversion of a clintable object into a clindoc
object.
clindoc(...) as_clindoc(x)clindoc(...) as_clindoc(x)
... |
|
x |
A |
as_clindoc() is intended for a single clintable object and extracts all
necessary title and footnote information to apply to the document
clindoc() can accept clintable objects as separate parameters or as a
list of clintable objects. If a single clintable is passed, this function
simply calls as_clindoc() internally.
When a multiple clintable objects are passed to clindoc(), titles and footnotes
should be applied directly to the clindoc object using clin_add_title(),
clin_add_footnote(), or clin_add_footnote_page(). Title and footnote information
on the individual clintable objects will be ignored.
a clindoc object, inherited from an officer::rdocx object
ct <- clintable(mtcars) clindoc(ct)ct <- clintable(mtcars) clindoc(ct)
These functions apply default styling to clintable objects used for
clinical tables, including titles and footnotes. The styling includes
removing borders, setting font properties, and adjusting table width,
line spacing, and padding.
clinify_titles_default(x, ...) clinify_footnotes_default(x, ...) clinify_table_default(x, ...) clinify_caption_default(x, ...) clinify_grouplabel_default(x, ...) clinify_docx_default()clinify_titles_default(x, ...) clinify_footnotes_default(x, ...) clinify_table_default(x, ...) clinify_caption_default(x, ...) clinify_grouplabel_default(x, ...) clinify_docx_default()
x |
A |
... |
Additional arguments (currently unused). |
A clintable object with the applied styling.
op <- options() sect <- clinify_docx_default() # Save out options to grab defaults options( clinify_docx_default = sect, clinify_titles_default = clinify_titles_default, clinify_footnotes_default = clinify_footnotes_default, clinify_table_default = clinify_table_default, clinify_caption_default = clinify_caption_default, clinify_grouplabel_default = clinify_grouplabel_default ) options(op)op <- options() sect <- clinify_docx_default() # Save out options to grab defaults options( clinify_docx_default = sect, clinify_titles_default = clinify_titles_default, clinify_footnotes_default = clinify_footnotes_default, clinify_table_default = clinify_table_default, clinify_caption_default = clinify_caption_default, clinify_grouplabel_default = clinify_grouplabel_default ) options(op)
A clintable object directly inherits from a flextable object. This function
will pass all necessary parameters flextable::flextable() and conver the
object to a clintable
clintable( x, page_by = NULL, group_by = NULL, use_labels = TRUE, coerce_character = FALSE, ... )clintable( x, page_by = NULL, group_by = NULL, use_labels = TRUE, coerce_character = FALSE, ... )
x |
A data frame |
page_by |
A variable in the input dataframe to use for pagination |
group_by |
A character vector of variable names which will be used for grouping and attached as a label above the table headers |
use_labels |
Use variable labels as column headers. Nested levels can be
achieved using the string "||" as a delimitter. Horizontally adjacent cells
using identical words will be merged, which can be adjusted afterwards using
the |
coerce_character |
Coerce every column of |
... |
Parameters to pass to |
A clintable object
flextable bakes cell text in when the table is built, and it formats a
double column as a whole with format(x, trim = TRUE, scientific = FALSE, big.mark = ","). Because that decision is column wide, a clinical summary
column holding a count in one row and a statistic in another - necessarily a
double - is reformatted against its neighbours: c(86, 75.2) renders the
count as "86.0", c(1234, 12.5) renders it as "1,234.0", and
c(1234567.891, 2) is rounded to seven significant digits as
"1,234,568". Values that were already formatted upstream are therefore
silently changed, and nothing errors to say so.
coerce_character = TRUE runs as.character() over every column first, so
each value carries into the table as its own string and no column wide
decision is made. It replaces the lapply(x, as.character) line that
otherwise has to be written ahead of every table. Column label attributes
survive the coercion, so use_labels still finds them. Factors coerce to
their levels rather than their integer codes.
Two side effects are worth knowing about. Numeric columns lose the right
alignment flextable's default theme gives them, since alignment follows
column type; use clin_table_align() or flextable::align() to put it
back. And flextable's formula selectors compare against the coerced values,
so bold(i = ~ n > 5) becomes a string comparison and quietly selects
different rows.
as.character(NA) is NA_character_, and flextable's default na_str is
"", so an NA still renders as a blank cell. NA is deliberately not
replaced with "", which is safe in a body column but changes the meaning
of a pagination variable.
clin_page_by() splits where the page variable changes, as does
clin_group_by() by default, and that comparison is x != lag(x). It is
NA wherever either side is NA, and those rows are dropped rather than
treated as splits. So a page_by, group_by, or caption_by column that
is padded - carrying its value only on the first row of each block, NA
below - collapses to a single page with no group label. A variable used that
way needs clin_group_by(when = "notempty"), which tests against "" and
handles NA just as well, and clin_page_by() offers no such option so its
page variable has to carry a value on every row.
Padding and a change comparison do not go together whichever the pad is, but
they fail differently, and the NA failure is the quieter one: "" padding
makes each padded row look like a change and splits on every one of them,
which is hard to miss, where NA padding drops the splits and leaves a
plausible looking single page.
clintable(mtcars) # A summary column holding a count and a mean is a double, so flextable # would render the count 86 as "86.0". Coercion keeps it as written. summary_dat <- data.frame( row_label = c("n", "Mean"), trt_a = c(86, 75.2) ) clintable(summary_dat, coerce_character = TRUE)clintable(mtcars) # A summary column holding a count and a mean is a double, so flextable # would render the count 86 as "86.0". Coercion keeps it as written. summary_dat <- data.frame( row_label = c("n", "Mean"), trt_a = c(86, 75.2) ) clintable(summary_dat, coerce_character = TRUE)
Assigns sequential page numbers to elements of a vector, grouping by unique values and allocating a specified number of rows per page. The input vector must be presorted by group.
make_grouped_pagenums(var, rows)make_grouped_pagenums(var, rows)
var |
A vector of group labels, presorted so that identical values are contiguous. |
rows |
Integer. The maximum number of rows per page. |
The function splits the input vector into groups, then assigns page numbers within each group so that each page contains up to 'rows“ items. Page numbers increment sequentially across groups. If the input is not presorted by group, the function will throw an error.
An integer vector of the same length as 'var“, indicating the assigned page number for each element.
library(dplyr) iris |> mutate( page = make_grouped_pagenums(Species, 5) )library(dplyr) iris |> mutate( page = make_grouped_pagenums(Species, 5) )
Create a new title or footnote flextable
new_title_footnote( x, sect = c("titles", "footnotes", "footnote_page"), align = NULL )new_title_footnote( x, sect = c("titles", "footnotes", "footnote_page"), align = NULL )
x |
a list of character vectors, no more than 3 elements to a vector. |
sect |
Either "titles" or "footnotes" |
align |
Where to place each line - |
A flextable object
title <- new_title_footnote( list( # We'll add tools to automate paging c("Protocol: CDISCPILOT01", "Page {PAGE} of {NUMPAGES}"), c("Table 14-2.01"), c("Summary of Demographic and Baseline Characteristics") ), "titles" ) footnote <- new_title_footnote( list( # We'll add tools to automate paging c("Page {PAGE}", "Total Pages: {NUMPAGES}") ), "footnotes" )title <- new_title_footnote( list( # We'll add tools to automate paging c("Protocol: CDISCPILOT01", "Page {PAGE} of {NUMPAGES}"), c("Table 14-2.01"), c("Summary of Demographic and Baseline Characteristics") ), "titles" ) footnote <- new_title_footnote( list( # We'll add tools to automate paging c("Page {PAGE}", "Total Pages: {NUMPAGES}") ), "footnotes" )
Extraction of flextable print method with special handling of clintable pages and
## S3 method for class 'clintable' print(x, n = 3, nrows = 15, apply_defaults = TRUE, ...) ## S3 method for class 'clintable' knit_print(x, n = 3, nrows = 15, apply_defaults = TRUE, ...)## S3 method for class 'clintable' print(x, n = 3, nrows = 15, apply_defaults = TRUE, ...) ## S3 method for class 'clintable' knit_print(x, n = 3, nrows = 15, apply_defaults = TRUE, ...)
x |
A clintable object |
n |
Number of pages within the clintable to print. Only used when pagination is configured |
nrows |
Number of rows to print. Only used when rows aren't configured within the pagination method |
apply_defaults |
Apply default styles. These styles are stored in the options clinify_header_default, clinify_footer_default, and clinify_table_default respectively. Defaults to true. |
... |
Additional parameters passed to flextable print method |
Invisible
ct <- clintable(mtcars) print(ct) ct <- clin_alt_pages( ct, key_cols = c("mpg", "cyl", "hp"), col_groups = list( c("disp", "drat", "wt"), c("qsec", "vs", "am"), c("gear", "carb") ) ) print(ct)ct <- clintable(mtcars) print(ct) ct <- clin_alt_pages( ct, key_cols = c("mpg", "cyl", "hp"), col_groups = list( c("disp", "drat", "wt"), c("qsec", "vs", "am"), c("gear", "carb") ) ) print(ct)
Write a clinify table out to a docx file
write_clindoc(x, file)write_clindoc(x, file)
x |
a clintable object |
file |
The file path to which the file should be written |
Invisible
ct <- clintable(mtcars) ct <- clin_alt_pages( ct, key_cols = c("mpg", "cyl", "hp"), col_groups = list( c("disp", "drat", "wt"), c("qsec", "vs", "am"), c("gear", "carb") ) ) # Get document object directly doc <- clindoc(ct) # Write out docx file write_clindoc(ct, file.path(tempdir(), "demo.docx"))ct <- clintable(mtcars) ct <- clin_alt_pages( ct, key_cols = c("mpg", "cyl", "hp"), col_groups = list( c("disp", "drat", "wt"), c("qsec", "vs", "am"), c("gear", "carb") ) ) # Get document object directly doc <- clindoc(ct) # Write out docx file write_clindoc(ct, file.path(tempdir(), "demo.docx"))