Skip to contents

The purpose of the column plan (col_plan) is to allow the user to specify how columns in the final table should appear in regards to their labels and ordering. Similar to the column styling plan (col_style_plan), col_plan refers to the final columns of the table, i.e., the values found in the column variable(s) from the input dataset. The col_plan is like an advanced version of dplyr’s select function; just like select, the user can add, drop, order, and/or rename columns all in one step. What sets the col_plan apart, however, is the ability to also specify column spanners and labels in a hierarchical fashion, as well as preferentially selecting the last instance a column is selected. For column spanning, multiple column columns need to exist in the input dataset.

Let’s look at the workflow in more detail with the following dataset which includes a single column variable:

dat <- tribble(
  ~group,     ~label,  ~my_col,    ~parm, ~val,
  "g1", "rowlabel1",  "col1"  ,  "value",    1,
  "g1", "rowlabel1",  "col2"  ,  "value",    1,
  "g1", "rowlabel1",  "mycol3",  "value",    1,
  "g1", "rowlabel1",  "col4"  ,  "value",    1,
  "g1", "rowlabel1",  "mycol5",  "value",    1,
  "g1", "rowlabel2",  "col1"  ,  "value",    2,
  "g1", "rowlabel2",  "col2"  ,  "value",    2,
  "g1", "rowlabel2",  "mycol3",  "value",    2,
  "g1", "rowlabel2",  "col4"  ,  "value",    2,
  "g1", "rowlabel2",  "mycol5",  "value",    2,
  "g2", "rowlabel3",  "col1"  ,  "value",    3,
  "g2", "rowlabel3",  "col2"  ,  "value",    3,
  "g2", "rowlabel3",  "mycol3",  "value",    3,
  "g2", "rowlabel3",  "col4"  ,  "value",    3,
  "g2", "rowlabel3",  "mycol5",  "value",    3)

This is what this data looks like formatted as a basic table.

tfrmt(
  group = group,
  label = label,
  param = parm,
  value = val,
  column = my_col,
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", frmt("x"))
  )
) %>% 
  print_to_gt(dat)
col1 col2 mycol3 col4 mycol5
g1




  rowlabel1 1 1 1 1 1
  rowlabel2 2 2 2 2 2
g2




  rowlabel3 3 3 3 3 3

Simple Column Selection

In the case of a single column variable with no column spanners, col_plan behaves similarly to dplyr::select.

If we want to remove one of the columns we specify within a col_plan:

tfrmt(
  group = group,
  label = label,
  param = parm,
  value = val,
  column = my_col,
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", frmt("x"))
  ),
  col_plan = col_plan(
    -mycol5
  )
) %>% 
  print_to_gt(dat)
col1 col2 mycol3 col4
g1



  rowlabel1 1 1 1 1
  rowlabel2 2 2 2 2
g2



  rowlabel3 3 3 3 3

Just like dplyr::select, we can also reorder, rename, and remove columns, using tidyselect syntax if we’d like:

tfrmt(
  group = group,
  label = label,
  param = parm,
  value = val,
  column = my_col,
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", frmt("x"))
  ),
  col_plan = col_plan(
    # reordering
    group, 
    label, 
    starts_with("col"),
    # renaming
    new_col_3 = mycol3,  
    # removing
    -mycol5            
  )
) %>% 
  print_to_gt(dat)
col1 col2 col4 new_col_3
g1



  rowlabel1 1 1 1 1
  rowlabel2 2 2 2 2
g2



  rowlabel3 3 3 3 3

Unlike dplyr::select though, col_plan respects the last time a column is defined in the plan. This allows for reordering/moving a column to the end very easily.

tfrmt(
  group = group,
  label = label,
  param = parm,
  value = val,
  column = my_col,
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", frmt("x"))
  ),
  col_plan = col_plan(
    group, 
    label, 
    starts_with("col"),
    everything(),
    col1 # moved to end
  )
) %>% 
  print_to_gt(dat)
col2 col4 mycol3 mycol5 col1
g1




  rowlabel1 1 1 1 1 1
  rowlabel2 2 2 2 2 2
g2




  rowlabel3 3 3 3 3 3

Naming the Group-Label Header

It is also possible to provide a combined header for the group and label columns - this is termed the “stub” in {gt}. To achieve this, rename the group variable in the column plan, just as you would with other columns. If multiple group variables exist, any of them can be renamed. If more than one is renamed, {tfrmt} will use the highest level group name available.

tfrmt(
  group = group,
  label = label,
  param = parm,
  value = val,
  column = my_col,
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", frmt("x"))
  ),
  col_plan = col_plan(
    my_grp = group, # rename group
    label, 
    starts_with("col"),
    everything(),
    col1         
  )
) %>% 
  print_to_gt(dat)
my_grp col2 col4 mycol3 mycol5 col1
g1




  rowlabel1 1 1 1 1 1
  rowlabel2 2 2 2 2 2
g2




  rowlabel3 3 3 3 3 3

Note that it is not currently possible to provide individual column headers if there are multiple group/label columns.

Editing and Moving Column Spanners

Multiple column variables are used to form the hierarchy of column spanners and column labels, which is driven by the order of the column variables. The first variable specified represents the highest level spanner, while the last variable specified represents the lowest level column label.

Let’s consider an example dataset with multiple column variables. This dataset has three tiers, span2 with one unique value, span1 with two unique values and my_col which has 4 unique values. The NA’s indicate there should be no spanning over those values.

dat <- tribble(
  ~group,     ~label,        ~span2,  ~span1,     ~my_col,    ~parm,   ~val,
  "g1", "rowlabel1",  "column cols", "cols 1,2", "col1"  ,  "value",    1,
  "g1", "rowlabel1",  "column cols", "cols 1,2", "col2"  ,  "value",    1,
  "g1", "rowlabel1",             NA,         NA, "mycol3",  "value",    1,
  "g1", "rowlabel1",  "column cols", "col 4"   , "col4"  ,  "value",    1,
  "g1", "rowlabel1",             NA,         NA, "mycol5",  "value",    1,
  "g1", "rowlabel2",  "column cols", "cols 1,2", "col1"  ,  "value",    2,
  "g1", "rowlabel2",  "column cols", "cols 1,2", "col2"  ,  "value",    2,
  "g1", "rowlabel2",             NA,        NA , "mycol3",  "value",    2,
  "g1", "rowlabel2",  "column cols", "col 4"   , "col4"  ,  "value",    2,
  "g1", "rowlabel2",             NA,         NA, "mycol5",  "value",    2,
  "g2", "rowlabel3",  "column cols", "cols 1,2", "col1"  ,  "value",    3,
  "g2", "rowlabel3",  "column cols", "cols 1,2", "col2"  ,  "value",    3,
  "g2", "rowlabel3",             NA,         NA, "mycol3",  "value",    3,
  "g2", "rowlabel3",  "column cols", "col 4"   , "col4"  ,  "value",    3,
  "g2", "rowlabel3",             NA,         NA, "mycol5",  "value",    3,
)

Similar to the case of 1 column variable, the user may remove and rename values for the lowest level column variable within col_plan. To edit or move the columns based on the the column spanners, span_structure must be used. Here we want to bring all the columns that start with “col” together, as well as rename mycol3 and drop mycol5.

tfrmt(
  group = group,
  label = label,
  param = parm,
  value = val,
  # specify spanner columns and unique column from data
  column = c(span2, span1, my_col),
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", frmt("x"))
  ),
  col_plan = col_plan(
    group,
    label,
    starts_with("col"),
    new_col_3 = mycol3,
    -mycol5
  )
) %>% 
  print_to_gt(dat)
column cols
cols 1,2 col 4 new_col_3
col1 col2 col4
g1



  rowlabel1 1 1 1 1
  rowlabel2 2 2 2 2
g2



  rowlabel3 3 3 3 3

Renaming column spanners can also be specified using span_structure. We can rename multiple spanners within the same level in the same span_structure - here "cols 1,2" becomes "first cols" and "col 4" becomes "just col4" for the span1 level. But when renaming multiple spanners in different levels we need to create a new span_structure for each level - so we write "column cols" becomes "most columns" for the span2 level in a separate span_structure.

tfrmt(
  group = group,
  label = label,
  param = parm,
  value = val,
  column = c(span2, span1, my_col),
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", frmt("x"))
  ),
  col_plan = col_plan(
    # rename column spanner in same level
    span_structure(span1 = c("first cols" = "cols 1,2",
                             "just col4" = "col 4")),
    # rename column spanner in different level
    span_structure(span2 = c("most columns" = "column cols")),
    group,
    label,
    starts_with("col"),
    new_col_3 = mycol3,
    -mycol5
  )
) %>% 
  print_to_gt(dat)
most columns
first cols just col4 new_col_3
col1 col2 col4
g1



  rowlabel1 1 1 1 1
  rowlabel2 2 2 2 2
g2



  rowlabel3 3 3 3 3

Let’s suppose we want to move the “col 4” column to the beginning and also reorder “col1” and “col2”. To achieve this, we can use span_structure. span_structure allows you to specify value(s) for a given column column, to specify the order. So can select "col 4" from span1. Then use another span_strcture to select "col2" and then "col1" from my_col when span1 equals "col 1,2",and finally all the other columns.

tfrmt(
  group = group,
  label = label,
  param = parm,
  value = val,
  column = c(span2, span1, my_col),
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", frmt("x"))
  ),
  col_plan = col_plan(
    group, 
    label, 
    # reordering spanners
    span_structure(span1 = c("col 4")),
    span_structure(span1 = c("cols 1,2"), my_col = c("col2", "col1")),
    everything(),
    new_col_3 = mycol3,  
    -mycol5            
  )
) %>% 
  print_to_gt(dat)
column cols
col 4 cols 1,2 new_col_3
col4 col2 col1
g1



  rowlabel1 1 1 1 1
  rowlabel2 2 2 2 2
g2



  rowlabel3 3 3 3 3

Reordering with multiple column variables is simplest when the lowest level column variable contains unique values (i.e., there is 1 value per column in the final table), like in the example above. But, that isn’t always the case take the following example:

dat <- tribble(
  ~group,     ~label,     ~span ,  ~my_col,    ~parm,   ~val,
  "g1",      "stats",  "Placebo" , "sd"     ,  "sd"  ,    1.435,
  "g1",      "stats",  "Placebo" , "mean"   ,  "mean",    2.843,
  "g1",      "stats",  "Treatment", "mean"   ,  "mean",    1.234,
  "g1",      "stats",  "Treatment", "sd"     ,  "sd"  ,    2.123,
)

For this table we want to ensure "Treatment" is always before "Placebo" and that "mean" comes before "sd". To do that we can make one span_structure that specifies both the order of the span level and the order of the my_col level.

tfrmt(
  group = group,
  label = label,
  param = parm,
  value = val,
  column = c(span, my_col),
  body_plan = body_plan(
    frmt_structure(group_val = ".default", label_val = ".default", frmt("x.xx"))
  ),
  col_plan = col_plan(
    group, 
    label, 
    span_structure(span = c("Treatment", "Placebo"),
                   my_col = c("mean", "sd"))
  )
) %>% 
  print_to_gt(dat)
Treatment Placebo
mean sd mean sd
g1



  stats 1.23 2.12 2.84 1.44

For more examples of col_plan see the examples or unusual table vignettes.