Skip to contents

The body plan covers the formatting of numeric cell values. Within the body plan, format structures (frmt_structure) may be layered to specify formatting for different parameters. Formatting can be applied to specific group and/or label values, which we will cover in a bit. First, we will apply formats to all relevant values in the table, regardless of group or label value.

Formatting functions

The following formatting functions may be passed to frmt_structure:

Format (frmt)

The frmt object is used to specify how a value should appear in a table: its number of digits, any white space padding, or extra characters, such as percentages or parentheses. In pharma, it is a common convention to use x’s to represent data values in mock tables. As such, the frmt complies with this familiar convention. For example:

  • frmt(expression = "xxx.x%") displays 3.829765 as ” 3.8%” (note the leading whitespace!)
  • frmt(expression = "xxx.x%", missing = "Missing") displays NA as “Missing”
  • frmt(expression = "xxx.x", scientific = " x10^x") displays 1234.5678 as ” 1.2 x10^ 3”

Format when (frmt_when)

frmt_when is a way to format cells conditional on their values. frmt_when is similar to dplyr::case_when or if/else statements. For each condition, the left hand side is an expression as a string and the right hand side is the formatting to be applied. For example, the following code allows users to conditionally format the upper and lower bounds for p-values:

frmt_when(
    ">0.99" ~ ">0.99",
    "<0.001" ~ "<0.001",
    TRUE ~ frmt("x.xxx")
)

This will cause the values 0.0347, 1.00, and 0.000001 to appear as “0.035”, “>0.99”, and “<0.001”.

Format combine (frmt_combine)

frmt_combine is used to combine multiple values into a single cell. Within a frmt_combine, the values are referenced according to the values of the param variable. Glue package syntax is leveraged to help the user easily define how they want the combined values to appear. Further, the individual data values may be formatted using frmt or frmt_when. Some examples:

  • frmt_combine("({lower}, {upper})", lower = frmt("xx.x"), upper = frmt("xx.x")) will combine lower and upper bounds of a confidence interval into: “(xx.x, xx.x)”.

  • frmt_combine("{n} ({pct})", n = frmt("xxx"), pct = frmt("xx.x", missing = "")) will print “n (%)” if the percentage is non-missing, but just “n” otherwise.

  • frmt_combine("{n} ({pct})", n = frmt("xxx"), pct = frmt("xx.x", missing = ""), missing = "") will print “n (%)” if the percentage is non-missing, “n” if the percentage is missing but n is non-missing, and “” if both n and pct are missing.

Location options

There are a variety of ways for the user to specify formatting locations: group variable values and/or label values, or by param value. Let’s take a look at the various methods below, ranging from least specific to most specific.

An important detail is that passing a value of “.default” to group or label means that the format will be applied to ALL values within the group(s) or label variables.

Table-wide

A user can specify formatting for the entire table as such:

frmt(group = ".default", label = ".default", frmt("xx.x"))

Param-specific

For formatting specific values of the param variable, frmt objects must be named according to the param. The following code will format all values where the param value equals “pval”, regardless of group, label, or column value.

frmt(group = ".default", label = ".default", pval = frmt("x.xxx"))

Again, param names are required for using frmt_combine.

Label-specific

For formatting specific values of the label variable, these values are passed to the label argument. The following code will format all values where the label variable equals “mylab1” or “mylab2”, regardless of group, param, or column value.

frmt(group = ".default", label = c("mylab1","mylab2"), frmt("x.xxx"))

Group-specific

For formatting specific values of the group variable, these values are passed to the group argument. Note that the user may have multiple group variables. In the case of multiple group variables, the specifications are to be passed as a named list (named according to the group variables). The following code will format all values where group1=“A” and group2=“B”, regardless of label, param, or column value:

frmt(group = list(group1 = "A", group2 = "B"), label = ".default", frmt("x.xxx"))

Column-specific

In the case where formatting needs to differ between columns within a given group/label/param level, the user will need to incorporate column-level information into the param value. For example, if we have two columns, col1 and col2, but we want the mean for col1 to be rounded differently than col2, creating our param column as such will allow us to differentiate the mean values in the formatting: param = c("col1_mean", "col2_mean").

Multiple specifications

A user can be as specific as they’d like, by providing any of these in combination. For example, the following code will format values where group1=“A”, group2=“B”, the label variable equals “mylab” and the param variable equals “mean”:

frmt(group = list(group1 = "A", group2 = "B"), label = "mylab", mean = frmt("x.xxx"))

NOTE: the tfrmt_sigdig() function provides the ability to create a tfrmt with auto-precision based on the significance of the group/label value.

Layering format structures

The user may provide as many frmt_structure objects as needed. It is important to note that if there are overlapping frmt_structure objects, the last one specified will supersede the previous. In our CDISC demographics table example, the following frmt_structures are needed to cover all values:

body_plan(
    frmt_structure(group_val = ".default", label_val = ".default",
                   frmt_combine("{n} {pct}",
                                n = frmt("XXX"),
                                pct = frmt_when("==100" ~ "",
                                                "==0" ~ "",
                                                TRUE ~ frmt("(XX.X %)"))
                   )
    ),
    frmt_structure(group_val = ".default", label_val = "n", frmt("xxx")),
    frmt_structure(group_val = ".default", label_val = c("Mean", "Median", "Min","Max"), frmt("xxx.x")),
    frmt_structure(group_val = ".default", label_val = "SD", frmt("xxx.xx")),
    frmt_structure(group_val = ".default", label_val = ".default", p = frmt_when(">0.99" ~ ">0.99",
                                                                                 "<0.001" ~ "<0.001",
                                                                                 TRUE ~ frmt("x.xxx", missing = "")))
)

Help images