Skip to contents

tfrmt offers the ability to align value and set column widths. Columns can be aligned in the following ways:

  • Character alignment
    • Left-align
    • Right-align
    • Align on one or more single characters (e.g., decimal alignment)
  • Positional alignment
    • Align by any number of positions across the formatted values

Column widths are set as either the number of pixels wide they are, or the percentage of the total table with.

Alignment and width is specified via the col_style_plan, which accepts a series of col_style_structures as inputs.

Alignment is achieved by padding the values with character spaces; this padding ensures that alignment is robust and agnostic to the output format. Width is done during post-processing and creation of the table output.

Style Structure

col_style_structure has four arguments: the columns in the final table to be aligned, the alignment desired, the alignment type, and the widths to apply to those columns. Each col_style_structure requires at least one of alignment and width to be defined. Optionally both can be assigned too.

The column values that are specified are to match the contents of the column variable that is specified in the tfrmt object. When multiple values are provided to column, the last value is used as the reference column.

When the col_style_plan() is applied to the data, the most recent alignment and width is applied to the data, so be careful when adding new col_style_structure’s, as the output may change more than anticipated if the new element is not specific enough.

Alignment

Alignment Examples - Character

Let’s take a look at how alignment can be applied to the example below, which contains a variety of different parameters which are formatted differently.

Expand for the code used to produce the example data
dat <- tribble(
  ~label     , ~param, ~column    , ~ value,   ~ord, 
  "n"        ,"n"     , "trt1"     ,12,        1, 
  "mean (sd)","mean"  , "trt1"     ,12.332837, 2,
  "mean (sd)","sd"    , "trt1"     ,4.3454547, 2,
  "median"   ,"median", "trt1"     ,14,        3, 
  "[q1, q3]" ,"q1"    , "trt1"     ,10,        4,
  "[q1, q3]" ,"q3"    , "trt1"     ,20,        4,
  "n"        ,"n"     , "trt2"     ,24,        1,
  "mean (sd)","mean"  , "trt2"     ,15.438737, 2,
  "mean (sd)","sd"    , "trt2"     ,6.723827,  2, 
  "median"   ,"median", "trt2"     ,16,        3, 
  "[q1, q3]" ,"q1"    , "trt2"     ,11,        4, 
  "[q1, q3]" ,"q3"    , "trt2"     ,22,        4,
  "n"        ,"pval"  , "p-value"  ,NA,        1, 
  "mean (sd)","pval"  , "p-value"  ,0.00002,   2, 
  "median"   ,"pval"  , "p-value"  ,0.051211,  3, 
  "[q1, q3]" ,"pval"  , "p-value"  ,NA,        4)
head(dat)
#> # A tibble: 6 × 5
#>   label     param  column value   ord
#>   <chr>     <chr>  <chr>  <dbl> <dbl>
#> 1 n         n      trt1   12        1
#> 2 mean (sd) mean   trt1   12.3      2
#> 3 mean (sd) sd     trt1    4.35     2
#> 4 median    median trt1   14        3
#> 5 [q1, q3]  q1     trt1   10        4
#> 6 [q1, q3]  q3     trt1   20        4

tfrmt(
  label = label,
  column = column,
  param = param,
  value = value,
  sorting_cols = c(ord),
  col_plan = col_plan(-ord), 
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt("xx", missing = " ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt_combine("{mean} ({sd})", 
                                mean = frmt("xx.x"), 
                                sd = frmt("xx.xx"),
                                missing=" ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt_combine("[{q1}, {q3}]", 
                                q1 = frmt("xx.x"), 
                                q3 = frmt("xx.x"),
                                missing=" ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   pval = frmt_when(">0.99" ~ ">0.99",
                                    "<0.001" ~ "<0.001",
                                    "<0.05" ~ frmt("x.xxx*"),
                                    TRUE ~ frmt("x.xxx", missing = "")))
  )
) %>% 
  print_to_gt(dat)
trt1 trt2 p-value
n 12 24
mean (sd) 12.3 ( 4.35) 15.4 ( 6.72) <0.001
median 14 16 0.051
[q1, q3] [10.0, 20.0] [11.0, 22.0]

Column alignment can improve this table by making it easier to read. Let’s start by left-aligning our p-value column. Notice that by providing a col_style_plan, any variables that are not covered in the plan will be left-aligned by default.

tfrmt(
  label = label,
  column = column,
  param = param,
  value = value,
  sorting_cols = c(ord),
  col_plan = col_plan(-ord), 
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt("xx", missing = " ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt_combine("{mean} ({sd})", 
                                mean = frmt("xx.x"), 
                                sd = frmt("xx.xx"),
                                missing=" ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt_combine("[{q1}, {q3}]", 
                                q1 = frmt("xx.x"), 
                                q3 = frmt("xx.x"),
                                missing=" ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   pval = frmt_when(">0.99" ~ ">0.99",
                                    "<0.001" ~ "<0.001",
                                    "<0.05" ~ frmt("x.xxx*"),
                                    TRUE ~ frmt("x.xxx", missing = "")))
  ), 
  col_style_plan =  col_style_plan(
    col_style_structure(col = `p-value`, align = "left", type = "char")
  )
  ) %>% 
  print_to_gt(dat)
trt1 trt2 p-value
n 12 24       
mean (sd) 12.3 ( 4.35) 15.4 ( 6.72) <0.001
median 14 16 0.051 
[q1, q3] [10.0, 20.0] [11.0, 22.0]       

This alignment isn’t quite right as we have the < in one value but not the other. Applying a decimal alignment would be a better fit:

tfrmt(
  label = label,
  column = column,
  param = param,
  value = value,
  sorting_cols = c(ord),
  col_plan = col_plan(-ord), 
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt("xx", missing = " ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt_combine("{mean} ({sd})", 
                                mean = frmt("xx.x"), 
                                sd = frmt("xx.xx"),
                                missing=" ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt_combine("[{q1}, {q3}]", 
                                q1 = frmt("xx.x"), 
                                q3 = frmt("xx.x"),
                                missing=" ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   pval = frmt_when(">0.99" ~ ">0.99",
                                    "<0.001" ~ "<0.001",
                                    "<0.05" ~ frmt("x.xxx*"),
                                    TRUE ~ frmt("x.xxx", missing = "")))
  ), 
  col_style_plan =  col_style_plan(
    col_style_structure(col = `p-value`, align = c("."), type = "char"))
  ) %>% 
  print_to_gt(dat)
trt1 trt2 p-value
n 12 24       
mean (sd) 12.3 ( 4.35) 15.4 ( 6.72) <0.001
median 14 16  0.051
[q1, q3] [10.0, 20.0] [11.0, 22.0]       

For our other two columns, we have a mix of values represented. In this case, we want to align on the first set of digits. In other words, we will align on the first instance of a decimal, comma, or space:

tfrmt(
  label = label,
  column = column,
  param = param,
  value = value,
  sorting_cols = c(ord),
  col_plan = col_plan(-ord), 
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt("xx", missing = " ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt_combine("{mean} ({sd})", 
                                mean = frmt("xx.x"), 
                                sd = frmt("xx.xx"),
                                missing=" ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt_combine("[{q1}, {q3}]", 
                                q1 = frmt("xx.x"), 
                                q3 = frmt("xx.x"),
                                missing=" ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   pval = frmt_when(">0.99" ~ ">0.99",
                                    "<0.001" ~ "<0.001",
                                    "<0.05" ~ frmt("x.xxx*"),
                                    TRUE ~ frmt("x.xxx", missing = "")))
  ), 
  col_style_plan =  col_style_plan(
    col_style_structure(col = `p-value`, align = c("."), type = "char"),
    col_style_structure(col = starts_with("trt"), align = c(".", ",", " "), type = "char")
    )
  ) %>% 
  print_to_gt(dat)
trt1 trt2 p-value
n  12            24                 
mean (sd)  12.3 ( 4.35)  15.4 ( 6.72) <0.001
median  14            16            0.051
[q1, q3] [10.0, 20.0]  [11.0, 22.0]        

Finally, for the purpose of demonstrating our options, we can align each column differently (left, right, character for the three columns respectively):

tfrmt(
  label = label,
  column = column,
  param = param,
  value = value,
  sorting_cols = c(ord),
  col_plan = col_plan(-ord), 
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt("xx", missing = " ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt_combine("{mean} ({sd})", 
                                mean = frmt("xx.x"), 
                                sd = frmt("xx.xx"),
                                missing=" ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt_combine("[{q1}, {q3}]", 
                                q1 = frmt("xx.x"), 
                                q3 = frmt("xx.x"),
                                missing=" ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   pval = frmt_when(">0.99" ~ ">0.99",
                                    "<0.001" ~ "<0.001",
                                    "<0.05" ~ frmt("x.xxx*"),
                                    TRUE ~ frmt("x.xxx", missing = "")))
  ), 
  col_style_plan =  col_style_plan(
    col_style_structure(col = `p-value`, align = c("."), type = "char"),
    col_style_structure(col = trt1, align = "left", type = "char"),
    col_style_structure(col = trt2, align = "right", type = "char"))
  ) %>% 
  print_to_gt(dat)
trt1 trt2 p-value
n 12                     24       
mean (sd) 12.3 ( 4.35) 15.4 ( 6.72) <0.001
median 14                     16  0.051
[q1, q3] [10.0, 20.0] [11.0, 22.0]       

Alignment Examples - Positional

For the ability to align across multiple characters and/or positions, positional alignment gives us the most flexibility. As such, it also requires a more granular representation of how we wish to align our values. For instance, instead of specifying an alignment on the first decimal: align = ".", we provide a character vector representation of our formatted cells with vertical bars placed in any position we wish to align: align = c("xx|.x", "x|.x").

In our example from above, we can use this feature to align on multiple decimal places:

tf <- tfrmt(
  label = label,
  column = column,
  param = param,
  value = value,
  sorting_cols = c(ord),
  col_plan = col_plan(-ord), 
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt("xx", missing = " ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt_combine("{mean} ({sd})", 
                                mean = frmt("xx.x"), 
                                sd = frmt("xx.xx"),
                                missing=" ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt_combine("[{q1}, {q3}]", 
                                q1 = frmt("xx.x"), 
                                q3 = frmt("xx.x"),
                                missing=" ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   pval = frmt_when(">0.99" ~ ">0.99",
                                    "<0.001" ~ "<0.001",
                                    "<0.05" ~ frmt("x.xxx*"),
                                    TRUE ~ frmt("x.xxx", missing = "")))
  ), 
  col_style_plan =  col_style_plan(
    col_style_structure(col = `p-value`, align = c("."), type = "char"),
    col_style_structure(col = starts_with("trt"), 
                        align = c("xx|",
                                  "xx|.x ( x|.xx)",
                                  "[xx|.x, xx|.x]"), 
                        type = "pos")
  )
) 

tf %>%  print_to_gt(dat)
trt1 trt2 p-value
n  12            24                 
mean (sd)  12.3 ( 4.35)  15.4 ( 6.72) <0.001
median  14            16            0.051
[q1, q3] [10.0, 20.0]  [11.0, 22.0]        

Behind the scenes, {tfrmt} makes a few assumptions about how these vertical bars translate to alignment:

  • Any characters to the left of the first “|” will be left-padded as needed.
  • Any characters to the right of the final “|” will be right-padded as needed
  • Any characters between two “|”s will receive padding that is anchored to the first occurance of whitespace in that substring (e.g. “xx|.x (xx.|x)” will be padded between the “.x” and “(xx.”).)
    • If no whitespace is found, no padding will be applied to that portion of the string

It is important to note that if we are not creating a mock table, the align input should cover scenarios observed in the provided data. There is a helper function called display_val_frmts that helps to create the align input based on the tfrmt object (specifically its body_plan) and the provided data. The output of this helper function is a a bit of code that can be copied and modified by adding the vertical bars as desired:

display_val_frmts(tfrmt = tf, .data = dat, col = vars(starts_with("trt")))
#> c("xx",
#>   "xx.x ( x.xx)",
#>   "[xx.x, xx.x]")

Alignment of group and label columns

At this time, group and label columns will be left aligned by default. The user can adjust the alignment of these columns through gt directly.

Alignment via body_plan

It should be noted that in simple cases, the user can achieve desired alignment via the frmts in the body_plan. These frmt specifications allow us to pad values to a desired length. For example, frmt(xxx) will ensure values with fewer than 3 digits will be padded accordingly: 23 will become ” 23” and 9 will become ” 9”. In a straightforward table of values with similar scales, this may be sufficient. However in many cases the user may desire more control over alignment and the col_style_plan is the preferred method.

Width

Width is set as specific value in number of characters wide the column is allowed to be at most. This value is specified by passing a character or numeric value to the “width” argument of col_style_structure, taking the format of “##” or ##, where “##” is the number of characters.

Width can be applied to any of the columns in the table.

Example

Continuing the example from alignment, we set the widths of the columns in the table. Because “label” is output in the table, we can apply the widths to that column as well.

tfrmt(
  label = label,
  column = column,
  param = param,
  value = value,
  sorting_cols = c(ord),
  col_plan = col_plan(-ord), 
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt("xx", missing = " ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt_combine("{mean} ({sd})", 
                                mean = frmt("xx.x"), 
                                sd = frmt("xx.xx"),
                                missing=" ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   frmt_combine("[{q1}, {q3}]", 
                                q1 = frmt("xx.x"), 
                                q3 = frmt("xx.x"),
                                missing=" ")),
    frmt_structure(group_val = ".default", label_val = ".default", 
                   pval = frmt_when(">0.99" ~ ">0.99",
                                    "<0.001" ~ "<0.001",
                                    "<0.05" ~ frmt("x.xxx*"),
                                    TRUE ~ frmt("x.xxx", missing = "")))
  ), 
  col_style_plan =  col_style_plan(
    col_style_structure(col = label, width = "10"),
    col_style_structure(col = `p-value`, align = c("."), width = "10"),
    col_style_structure(col = trt1, align = "left", width = "5"),
    col_style_structure(col = trt2, align = "right", width = "5"))
  ) %>% 
  print_to_gt(dat)
trt1 trt2 p-value
n 12                     24       
mean (sd) 12.3 ( 4.35) 15.4 ( 6.72) <0.001
median 14                     16  0.051
[q1, q3] [10.0, 20.0] [11.0, 22.0]