Separate column names in header

library(flextable)
use_df_printer()
set_flextable_defaults(
  theme_fun = theme_booktabs,
  big.mark = " ", 
  font.color = "#666666",
  border.color = "#666666",
  padding = 3,
)

In the following example we aggregate the famous ‘penguins’ table.

First, let’s create a summary of the original dataset.

library(tidyverse)
library(palmerpenguins)

dat <- penguins |> 
  select(species, island, ends_with("mm")) |> 
  group_by(species, island) |> 
  summarise(
    across(
      where(is.numeric), 
      .fns = list(
        avg = ~ mean(.x, na.rm = TRUE),
        sd = ~ sd(.x, na.rm = TRUE)
      )
    ),
    .groups = "drop") |> 
  rename_with(~ tolower(gsub("_mm_", "_", .x, fixed = TRUE)))

print(dat)
## # A tibble: 5 × 8
##   species   island   bill_length_avg bill_length_sd bill_depth_avg bill_depth_sd
##   <fct>     <fct>              <dbl>          <dbl>          <dbl>         <dbl>
## 1 Adelie    Biscoe              39.0           2.48           18.4         1.19 
## 2 Adelie    Dream               38.5           2.47           18.3         1.13 
## 3 Adelie    Torgers…            39.0           3.03           18.4         1.34 
## 4 Chinstrap Dream               48.8           3.34           18.4         1.14 
## 5 Gentoo    Biscoe              47.5           3.08           15.0         0.981
## # … with 2 more variables: flipper_length_avg <dbl>, flipper_length_sd <dbl>

From this dataset, we create the ‘flextable’ and restructure header labels by using separate_header().

ft <- dat |> 
  flextable() |> 
  separate_header() |> 
  autofit()
ft

This flextable can be customized now so that we produce a prettier reporting table.

ft <- ft |> 
  theme_booktabs(bold_header = TRUE) |>
  footnote(i = 3, j = grep("_avg$", colnames(dat), value = TRUE), 
           part = "header",
           ref_symbols = "1", value = as_paragraph("Arithmetic Mean")) |> 
  footnote(i = 3, j = grep("_sd$", colnames(dat), value = TRUE), 
           part = "header",
           ref_symbols = "2", value = as_paragraph("Standard Deviation")) |> 
  align(align = "center", part = "all", j = 3:8) |> 
  merge_v(j = 1) |> 
  valign(j = 1, valign = "top") |> 
  colformat_double(digits = 2)
ft