• flextable book
  • 1 Overview
    • 1.1 Introduction
    • 1.2 Create a flextable
      • 1.2.1 Build with a data.frame
      • 1.2.2 Transform to flextable
    • 1.3 Help and resources
    • 1.4 Walkthrough: simple example
  • 2 Make homogeneous tables
    • 2.1 Important default values
      • 2.1.1 Word multi-language fonts
    • 2.2 Default values for numbers
  • 3 Table design
    • 3.1 Table parts
    • 3.2 Visible columns
    • 3.3 Selectors
      • 3.3.1 Usage
      • 3.3.2 Selectors and flextable parts
  • 4 Rendering
    • 4.1 Simple export
    • 4.2 In RStudio
    • 4.3 R Markdown documents
      • 4.3.1 Knitr Chunk options
      • 4.3.2 Looping in R Mardown documents
      • 4.3.3 Limitations
    • 4.4 PowerPoint or Word documents with officer
    • 4.5 Using within shiny applications
    • 4.6 Automatic printing of data.frame as flextable
  • 5 Define visual properties
    • 5.1 Format specific parts
    • 5.2 Formatting functions
    • 5.3 Borders
      • 5.3.1 Inner and outer borders
      • 5.3.2 Add lines
      • 5.3.3 Surround cells
    • 5.4 Theme functions
      • 5.4.1 Available themes
      • 5.4.2 Define your own theme
  • 6 Header and footer
    • 6.1 Change header labels
    • 6.2 Separate collapsed colnames into multiple rows
    • 6.3 Add rows in header or footer
      • 6.3.1 Add a row of labels
      • 6.3.2 Add lines of text
      • 6.3.3 Define headers with a reference table
    • 6.4 footnotes
  • 7 Layout
    • 7.1 Cell merging
      • 7.1.1 vertical merging of similar values
      • 7.1.2 horizontal merging of similar values
      • 7.1.3 horizontal merging of columns
      • 7.1.4 general merging function
      • 7.1.5 delete merging informations
      • 7.1.6 Borders and merging
    • 7.2 Table sizes
      • 7.2.1 Table width
      • 7.2.2 Cell widths and heights
    • 7.3 Pagination
  • 8 Cell content
    • 8.1 Soft returns and tabulations
    • 8.2 Simple formatting of cell content
    • 8.3 Replace displayed labels
    • 8.4 Multi content
      • 8.4.1 Function mk_par
      • 8.4.2 Sugar functions for complex formatting
      • 8.4.3 Append or prepend content
    • 8.5 Images
    • 8.6 Images and limitations of PowerPoint
    • 8.7 Mini charts
      • 8.7.1 base plots and ggplot objects
      • 8.7.2 minibar
      • 8.7.3 linerange
  • 9 Transform objects into flextable
    • 9.1 Groups as row titles
    • 9.2 Dataset summary
    • 9.3 Models and tests
      • 9.3.1 GLM example
      • 9.3.2 LM example
      • 9.3.3 GAM example
      • 9.3.4 Hypothesis testing example
      • 9.3.5 kmeans
      • 9.3.6 pam
    • 9.4 xtable
  • 10 Crosstabs
    • 10.1 PROC FREQ
    • 10.2 Using ‘tables’
    • 10.3 Using tabulator
      • 10.3.1 Tabulate a dataset with tabulator
      • 10.3.2 Display additional data
      • 10.3.3 Design options
  • 11 Programming
    • 11.1 Part dimensions
    • 11.2 Function ‘before’
    • 11.3 Looping over columns with compose
  • 12 Captions and cross-references
    • 12.1 Captions with set_caption
    • 12.2 Captions with knitr chunk options
      • 12.2.1 ‘knitr’ chunk options for flextable captions
      • 12.2.2 Illustrations by formats
    • 12.3 Formatting captions
    • 12.4 Cross-references
  • 13 Plotting flextable
    • 13.1 plot method
      • 13.1.1 Save as PNG or SVG
    • 13.2 Grob options
    • 13.3 Option fit
    • 13.4 Option scaling
  • 14 Extensions
    • 14.1 ftExtra
    • 14.2 crosstable
    • 14.3 gtsummary
  • 15 Datasets used for illustrations
    • 15.1 Tennis players
    • 15.2 Diabetic data
    • 15.3 Fishes
    • 15.4 people
    • 15.5 Correlations
    • 15.6 Cancers
  • 16 Known Issues
    • 16.1 PDF issues
      • 16.1.1 wrap text and merged cells
    • 16.2 compose in purrr and flextable
  • Written by

Using the flextable R package

Chapter 6 Header and footer

flextable headers, footers and body can be augmented with rows and the displayed value can be changed.

6.1 Change header labels

Use set_header_labels() to replace labels of the bottom row of header. When the flextable is created, their values are the column names of the data.frame.

ft <- flextable(head(airquality)) 
ft <- set_header_labels(ft, Solar.R = "Solar R (lang)", 
    Temp = "Temperature (degrees F)", Wind = "Wind (mph)",
    Ozone = "Ozone (ppb)" )
ft <- set_table_properties(ft, layout = "autofit", width = .8)
ft

Ozone (ppb)

Solar R (lang)

Wind (mph)

Temperature (degrees F)

Month

Day

41

190

7.4

67

5

1

36

118

8.0

72

5

2

12

149

12.6

74

5

3

18

313

11.5

62

5

4

<na>

<na>

14.3

56

5

5

28

<na>

14.9

66

5

6

6.2 Separate collapsed colnames into multiple rows

Packages ‘dplyr’ and ‘data.table’ produce aggregated datasets with names representing the arrangements of columns and aggregations.

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)))
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
# # ℹ 2 more variables: flipper_length_avg <dbl>, flipper_length_sd <dbl>

Turning this data.frame to a flextable is not producing an organized version of the data.

ft_pen <- flextable(dat) |> 
  colformat_double() |>
  autofit()
ft_pen

species

island

bill_length_avg

bill_length_sd

bill_depth_avg

bill_depth_sd

flipper_length_avg

flipper_length_sd

Adelie

Biscoe

38.98

2.48

18.37

1.19

188.80

6.73

Adelie

Dream

38.50

2.47

18.25

1.13

189.73

6.59

Adelie

Torgersen

38.95

3.03

18.43

1.34

191.20

6.23

Chinstrap

Dream

48.83

3.34

18.42

1.14

195.82

7.13

Gentoo

Biscoe

47.50

3.08

14.98

0.98

217.19

6.48

Using separate_header() would produce a nicer presentation of the data.

ft_pen <- ft_pen |> 
  separate_header() |> 
  align(align = "center", part = "all") |>
  autofit()
ft_pen

species

island

bill

flipper

length

depth

length

avg

sd

avg

sd

avg

sd

Adelie

Biscoe

38.98

2.48

18.37

1.19

188.80

6.73

Adelie

Dream

38.50

2.47

18.25

1.13

189.73

6.59

Adelie

Torgersen

38.95

3.03

18.43

1.34

191.20

6.23

Chinstrap

Dream

48.83

3.34

18.42

1.14

195.82

7.13

Gentoo

Biscoe

47.50

3.08

14.98

0.98

217.19

6.48

6.3 Add rows in header or footer

New header rows can be added at the top or bottom of the header.

Under the hood, the names are in a single row data.frame associated with the header part of the flextable. You can add new rows later, they will be binded to that data.frame.

The functions named below are to be used to add a header line (or a footer line):

  • Most needs will be satisfied with functions add_header_row and add_footer_row. These are row oriented functions to let you add a single row of labels (that can be displayed along one or more columns in the new row).
  • Functions add_header and add_footer are columns oriented functions that will let you add several values (one for each new row) for a given column. If labels are stored in a data.frame, use functions set_header_df and set_footer_df.
  • Functions add_footer_lines and add_header_lines are sugar functions and should be used to add labels on one single row where all columns are merged together.

We will mainly demonstrate headers but same can be apply with footers.

Now let’s add new row of labels.

6.3.1 Add a row of labels

Use function add_header_row() : add an header row where with labels are associated with a number of columns to merge.

ft <- add_header_row(
  x = ft, values = c("air quality measurements", "time"),
  colwidths = c(4, 2))
ft <- theme_box(ft)
ft

air quality measurements

time

Ozone (ppb)

Solar R (lang)

Wind (mph)

Temperature (degrees F)

Month

Day

41

190

7.4

67

5

1

36

118

8.0

72

5

2

12

149

12.6

74

5

3

18

313

11.5

62

5

4

<na>

<na>

14.3

56

5

5

28

<na>

14.9

66

5

6

6.3.2 Add lines of text

Use function add_header_lines() : add labels in new header rows (all columns are merged).

ft <- add_header_lines(ft, 
  values = c("this is a first line", 
     "this is a second line") ) 
theme_box(ft)

this is a first line

this is a second line

air quality measurements

time

Ozone (ppb)

Solar R (lang)

Wind (mph)

Temperature (degrees F)

Month

Day

41

190

7.4

67

5

1

36

118

8.0

72

5

2

12

149

12.6

74

5

3

18

313

11.5

62

5

4

<na>

<na>

14.3

56

5

5

28

<na>

14.9

66

5

6

6.3.3 Define headers with a reference table

Use set_header_df() with a data.frame as parameter. Columns of the dataset will be transposed and joined using a key column.

The following illustration is using dataset “people” (see table 15.6).

  1. The reference table

Variable col_keys define key values to match with flextable column keys (defined by argument col_keys of flextable() function).

This key column will not be displayed. Other variables will added as rows. Note that variables names are not displayed.

cancers_header
#    col_keys     line2     line3
# 1      time Follow-up Follow-up
# 2       1_1         I         1
# 3       2_1         I         2
# 4       3_1         I         3
# 5       1_2        II         1
# 6       2_2        II         2
# 7       3_2        II         3
# 8       1_3       III         1
# 9       2_3       III         2
# 10      3_3       III         3
  1. Use it as header rows

Then use set_header_df() with parameter key. key is the name of the column used to permform the join operation.

Order of columns matters, first column will be first row, second one will be the second row, etc.

ft <- flextable( cancers, col_keys = cancers_header$col_keys)
ft

time

1_1

2_1

3_1

1_2

2_2

3_2

1_3

2_3

3_3

1

9

5

1

12

4

1

42

28

19

2

2

2

1

7

3

1

26

19

11

3

9

3

1

5

5

3

12

10

7

4

10

2

1

10

4

1

10

5

6

5

1

2

0

4

2

0

5

0

3

6

3

2

1

3

1

0

4

3

3

7

1

2

0

4

4

2

1

2

3

colourer <- scales::col_numeric(
  palette = c("transparent", "red"),
  domain = c(0, 50))

set_header_df( ft, mapping = cancers_header, key = "col_keys" ) %>% 
  merge_v(part = "header", j = 1) %>% 
  merge_h(part = "header", i = 1) %>% 
  theme_booktabs(bold_header = TRUE) %>% 
  align(align = "center", part = "all") %>%
  bg(
    bg = colourer,
    j = ~ . -time,
    part = "body") %>%
  autofit() |> 
  vline(j = c(1, 4, 7), border = fp_border_default())

Follow-up

I

II

III

1

2

3

1

2

3

1

2

3

1

9

5

1

12

4

1

42

28

19

2

2

2

1

7

3

1

26

19

11

3

9

3

1

5

5

3

12

10

7

4

10

2

1

10

4

1

10

5

6

5

1

2

0

4

2

0

5

0

3

6

3

2

1

3

1

0

4

3

3

7

1

2

0

4

4

2

1

2

3

6.4 footnotes

Adding footnotes is possible by using function compose but it requires a two step approach (add the reference symbol and add the corresponding footnote in the footer part).

To make the process simpler, use function footnote that will ease the addition of footnotes.

ft <- flextable(head(iris))
ft <- footnote( ft, i = 1, j = 1:3,
            value = as_paragraph(
              c("This is footnote one",
                "This is footnote two",
                "This is footnote three")
            ),
            ref_symbols = c("a", "b", "c"),
            part = "header")
ft <- valign(ft, valign = "bottom", part = "header")
autofit(ft)

Sepal.Lengtha

Sepal.Widthb

Petal.Lengthc

Petal.Width

Species

5.1

3.5

1.4

0.2

setosa

4.9

3.0

1.4

0.2

setosa

4.7

3.2

1.3

0.2

setosa

4.6

3.1

1.5

0.2

setosa

5.0

3.6

1.4

0.2

setosa

5.4

3.9

1.7

0.4

setosa

aThis is footnote one

bThis is footnote two

cThis is footnote three

You can also add footnotes inline using the inline argument and specify a seperator string with sep (default “;”)

ft <- flextable(head(iris))
ft <- autofit(ft)
ft <- footnote( ft, i = 1, j = 1:2,
                value = as_paragraph(
                  c("This is footnote one",
                    "This is footnote two")
                ),
                ref_symbols = c("a", "b"),
                part = "header",inline=T)
ft <- footnote( ft, i = 1, j = 3:4,
                value = as_paragraph(
                  c("This is footnote three",
                    "This is footnote four")
                ),
                ref_symbols = c( "c","d"),
                part = "header",inline=T)
ft

Sepal.Lengtha

Sepal.Widthb

Petal.Lengthc

Petal.Widthd

Species

5.1

3.5

1.4

0.2

setosa

4.9

3.0

1.4

0.2

setosa

4.7

3.2

1.3

0.2

setosa

4.6

3.1

1.5

0.2

setosa

5.0

3.6

1.4

0.2

setosa

5.4

3.9

1.7

0.4

setosa

aThis is footnote one; bThis is footnote two; cThis is footnote three; dThis is footnote four;