Chapter 7 Layout

flextable layout can be easily managed. A set of functions will let you merge cells, add title rows, change the widths or heights.

7.1 Cell merging

To illustrate functions, we will use a basic flextable example:

dat <- data.frame(
  letters1 = c("a", "b", "b", "c"), 
  letters2 = c("d", "e", "b", "b"), 
  number = 1:4, stringsAsFactors = FALSE )

myft <- flextable(dat)
myft <- theme_box(myft)
myft

letters1

letters2

number

a

d

1

b

e

2

b

b

3

c

b

4

7.1.1 vertical merging of similar values

merge_v() will merge adjacent duplicated cells for each column of the selection.

merge_v(myft, j = ~ letters1 + letters2 )

letters1

letters2

number

a

d

1

b

e

2

b

3

c

4

7.1.2 horizontal merging of similar values

merge_h() will merge adjacent duplicated cells for each row of the selection.

merge_h(myft)

letters1

letters2

number

a

d

1

b

e

2

b

3

c

b

4

7.1.3 horizontal merging of columns

Function merge_h_range is close to the previous one but merge all colums between a range of columns.

merge_h_range(myft, 
  i =  ~ number < 3, 
  j1 = "letters1", j2 = "letters2")

letters1

letters2

number

a

1

b

2

b

b

3

c

b

4

7.1.4 general merging function

merge_at() will merge cells for a given continuous selection of rows and cells. The result is a single cell.

myft %>% 
  merge_at(
    i = 1:2, j = 1:2)

letters1

letters2

number

a

1

2

b

b

3

c

b

4

Note that the content that is rendered is not the result of the concatenation of each paragraphs contained into the merge cells. Only one paragraph will be kept, the top left one of all merge cells.

7.1.5 delete merging informations

If you want to get rid of all merging (i.e. for development purposes), use merge_none():

letters1

letters2

number

a

d

1

b

e

2

b

b

3

c

b

4

7.1.6 Borders and merging

When cells are merged, the rendered borders will be those of the first cell. If a column is made of three merged cells, the bottom border that will be seen will be the bottom border of the first cell in the column. From a user point of view, this is wrong, the bottom should be the one defined for cell 3. Function fix_border_issues is trying to fix that issue.

ft <- data.frame(a = 1:5, b = 6:10) %>%
  flextable() %>% theme_box() %>%
  merge_at(i = 4:5, j = 1, part = "body") %>%
  hline(i = 5, part = "body",
        border = fp_border(color = "orange", width = 3) )
ft

a

b

1

6

2

7

3

8

4

9

10

a

b

1

6

2

7

3

8

4

9

10

7.2 Table sizes

Widths or heights must be used wisely. Each output format has its own specificities. flextable tries to make the displays identical between each format but differences may occur and sometimes need to be taken into account.

For example: :

  • the PowerPoint format does not support automatic sizing (with set_table_properties(layout = "autofit")).
  • automatic sizing is preferable when the output is PDF because of the smaller font sizes and the display optimization capabilities of the PDF engine.

7.2.1 Table width

By default, table width is fixed. This setting allows to have the same rendering with Word, PDF, HTML and PowerPoint formats.

You can use another setting with function set_table_properties() when argument layout is set to ‘autofit’, an algorithm implemented by HTML, PDF and Word.

When layout is set to autofit, you can also size the table along an available width with argument width, for example, 1 means 100% of the available width. Note this is ignored when output is PDF. Its default value is 0, as an effect, it only use necessary width to display all content.

ft <- qflextable(head(airquality))
set_table_properties(ft, layout = "autofit")

Ozone

Solar.R

Wind

Temp

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

set_table_properties(ft, width = .5, layout = "autofit")

Ozone

Solar.R

Wind

Temp

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

set_table_properties(ft, width = 1, layout = "autofit")

Ozone

Solar.R

Wind

Temp

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

7.2.2 Cell widths and heights

This part applies only when layout is “fixed”.

The default sizes of flextable columns and rows are set by default values. This will drive to inadequate rows heights and columns widths in some cases. You can use function dim to get flextable dimensions.

ft_base <- flextable(head(mtcars))
ft_base <- theme_vader(ft_base)
ft_base

mpg

cyl

disp

hp

drat

wt

qsec

vs

am

gear

carb

21.0

6

160

110

3.90

2.620

16.46

0

1

4

4

21.0

6

160

110

3.90

2.875

17.02

0

1

4

4

22.8

4

108

93

3.85

2.320

18.61

1

1

4

1

21.4

6

258

110

3.08

3.215

19.44

1

0

3

1

18.7

8

360

175

3.15

3.440

17.02

0

0

3

2

18.1

6

225

105

2.76

3.460

20.22

1

0

3

1

dim(ft_base)
# $widths
#  mpg  cyl disp   hp drat   wt qsec   vs   am gear carb 
# 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 
# 
# $heights
# [1] 0.25 0.25 0.25 0.25 0.25 0.25 0.25

7.2.2.1 Pretty dimensions

Function dim_pretty() is computing optimized widths and heights.

dim_pretty(ft_base)
# $widths
#  [1] 0.4811560 0.3602318 0.4640729 0.4102128 0.4728009 0.5377016 0.5377016
#  [8] 0.3109967 0.3904442 0.4863779 0.4850351
# 
# $heights
# [1] 0.3009259 0.2610157 0.2610157 0.2610157 0.2610157 0.2610157 0.2610157

7.2.2.2 Adjusts automatically cell widths and heights

Function autofit() optimises widths and heights of the flextable. This function makes compact tables.

autofit was not my biggest naming idea as users are thinking it is the ‘Microsoft Word feature’ (see set_table_properties)

ft <- autofit(ft_base, add_w = 0, add_h = 0)

dim(ft)
# $widths
#       mpg       cyl      disp        hp      drat        wt      qsec        vs 
# 0.4811560 0.3602318 0.4640729 0.4102128 0.4728009 0.5377016 0.5377016 0.3109967 
#        am      gear      carb 
# 0.3904442 0.4863779 0.4850351 
# 
# $heights
# [1] 0.3009259 0.2610157 0.2610157 0.2610157 0.2610157 0.2610157 0.2610157
ft

mpg

cyl

disp

hp

drat

wt

qsec

vs

am

gear

carb

21.0

6

160

110

3.90

2.620

16.46

0

1

4

4

21.0

6

160

110

3.90

2.875

17.02

0

1

4

4

22.8

4

108

93

3.85

2.320

18.61

1

1

4

1

21.4

6

258

110

3.08

3.215

19.44

1

0

3

1

18.7

8

360

175

3.15

3.440

17.02

0

0

3

2

18.1

6

225

105

2.76

3.460

20.22

1

0

3

1

Soft returns (a line break in a paragraph) support : function autofit and dim_pretty do not support soft returns and may return wrong results (backslash n will be considered as ““).

7.2.2.3 Adjusts manually cell widths and heights

Function width() and height() let you control dimensions of a flextable. height_all() is an helper function to set the same height to each part of the table.

Function height() has no effect when the rule for line height is set to “auto”, which is the default case, except with PowerPoint which does not support this automatic line height adjustment feature. You can define that rule with function hrule.

Function hrule support three options :

  • “atleast”: height should be at least the value specified,
  • “exact” : height should be exactly the value specified,
  • “auto”, the default value : height is determined based on the height of the contents, so the value is ignored.

The following illustration is using dataset “correlations” (see table 15.5).

cor_color <- function(x){
  col_palette <- c("#D73027", "#F46D43", "#FDAE61", "#FEE08B", 
                   "#D9EF8B", "#A6D96A", "#66BD63", "#1A9850")
  mycut <- cut(x, 
    breaks = c(-1, -0.75, -0.5, -0.25, 0, 0.25, 0.5, 0.75, 1), 
    include.lowest = TRUE, label = FALSE)
  col_palette[mycut]
}

std_border <- fp_border(color = "white")

ft <- flextable(correlations) %>% 
  border_outer(part="all", border = std_border ) %>%
  border_inner(border = std_border, part="all") %>%
  compose(i = 1, j = 1, value = as_paragraph(""), part = "header") %>% 
  compose(j = ~ . -rowname, value = as_paragraph(""), part = "body") %>% 
  bg(j = ~ . -rowname, bg = cor_color) 
ft

mpg

cyl

disp

hp

drat

wt

qsec

vs

am

gear

carb

mpg

cyl

disp

hp

drat

wt

qsec

vs

am

gear

carb

To give a more regular appearance, all cells will be sized to 0.5 inches in width and height.

ft <- height(ft, height = .5) %>% 
  hrule(rule = "exact", part = "body") %>% 
  width(width =  .5) %>% 
  set_table_properties(layout = "fixed")
ft

mpg

cyl

disp

hp

drat

wt

qsec

vs

am

gear

carb

mpg

cyl

disp

hp

drat

wt

qsec

vs

am

gear

carb


  1. flextable create a flextable from tabular with columns keys named as COL1, COL2, COL3, …↩︎