4  Formatting tables

5 Using {flextables} for pretty word tables

Output tables in word can be a little messy, because the default table format prints poorly to .docx formats.

starwars |> 
  select(1:7) |> 
  slice(1:10)
# A tibble: 10 × 7
   name               height  mass hair_color    skin_color eye_color birth_year
   <chr>               <int> <dbl> <chr>         <chr>      <chr>          <dbl>
 1 Luke Skywalker        172    77 blond         fair       blue            19  
 2 C-3PO                 167    75 <NA>          gold       yellow         112  
 3 R2-D2                  96    32 <NA>          white, bl… red             33  
 4 Darth Vader           202   136 none          white      yellow          41.9
 5 Leia Organa           150    49 brown         light      brown           19  
 6 Owen Lars             178   120 brown, grey   light      blue            52  
 7 Beru Whitesun Lars    165    75 brown         light      blue            47  
 8 R5-D4                  97    32 <NA>          white, red red             NA  
 9 Biggs Darklighter     183    84 black         light      brown           24  
10 Obi-Wan Kenobi        182    77 auburn, white fair       blue-gray       57  

Flex tables is a neat tool to get around this but requires a bit of setting up for specific formatting. A work around for this can be defining your own flextable themes for different formats and calling it depending on the table.

It is worthwhile to start with a base theme, which is applied to all tables.

flex_theme_base <- function(ft) {
  
  nr <- nrow_part(ft, part = "body")
  
  ft |>
    font(fontname = "Arial (Body)", part = "all") |>
    fontsize(size = 10, part = "all") |>
    align(align = "left", part = "all") |>
    valign(valign = "middle", part = "all") |>
    bold(part = "header") |>
    bold(i = seq_len(nr), j = 1, part = "body") |>
    bg(i = 1, bg = "#F0F0F0", part = "header") |>
    border_remove() |>
    border(border = officer::fp_border(color = "#CCCCCC"), part = "all") |>
    autofit()
}

Turning your ugly tables

starwars |> 
  select(1:7) |> 
  slice(1:10) |> 
  flextable() |>
  flex_theme_base() 

name

height

mass

hair_color

skin_color

eye_color

birth_year

Luke Skywalker

172

77

blond

fair

blue

19.0

C-3PO

167

75

gold

yellow

112.0

R2-D2

96

32

white, blue

red

33.0

Darth Vader

202

136

none

white

yellow

41.9

Leia Organa

150

49

brown

light

brown

19.0

Owen Lars

178

120

brown, grey

light

blue

52.0

Beru Whitesun Lars

165

75

brown

light

blue

47.0

R5-D4

97

32

white, red

red

Biggs Darklighter

183

84

black

light

brown

24.0

Obi-Wan Kenobi

182

77

auburn, white

fair

blue-gray

57.0

And then making more custom formats which override this

flex_theme_summary_column <- function(ft) {
  
  nr <- nrow_part(ft, part = "body")
  nc <- length(ft$col_keys)
  
  ft |>
    bg(
      i = seq_len(nr),
      j = nc,
      bg = "#a2c6f5",
      part = "body"
    )
}

And can be applied to relevant tables

starwars |> 
  select(1:7) |> 
  slice(1:10) |> 
  mutate(
    bmi = mass / ((height / 100) ^ 2)
  ) |>
  flextable() |>
  flex_theme_base() |> 
  flex_theme_summary_column()

name

height

mass

hair_color

skin_color

eye_color

birth_year

bmi

Luke Skywalker

172

77

blond

fair

blue

19.0

26.02758

C-3PO

167

75

gold

yellow

112.0

26.89232

R2-D2

96

32

white, blue

red

33.0

34.72222

Darth Vader

202

136

none

white

yellow

41.9

33.33007

Leia Organa

150

49

brown

light

brown

19.0

21.77778

Owen Lars

178

120

brown, grey

light

blue

52.0

37.87401

Beru Whitesun Lars

165

75

brown

light

blue

47.0

27.54821

R5-D4

97

32

white, red

red

34.00999

Biggs Darklighter

183

84

black

light

brown

24.0

25.08286

Obi-Wan Kenobi

182

77

auburn, white

fair

blue-gray

57.0

23.24598