# flextable layout

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

library(flextable)
library(officer)

## flextable col_keys

Parameter col_keys of function flextable define the variables to display and their order.

data <- iris[c(1:3, 51:53, 101:104),]
myft <- flextable(data, col_keys = c("Species", "Sepal.Length", "Petal.Length") )
myft
 Species Sepal.Length Petal.Length setosa 5.1 1.4 setosa 4.9 1.4 setosa 4.7 1.3 versicolor 7.0 4.7 versicolor 6.4 4.5 versicolor 6.9 4.9 virginica 6.3 6.0 virginica 5.8 5.1 virginica 7.1 5.9 virginica 6.3 5.6

If parameter col_keys has variables that are not existing in the dataset, they will be considered as blank columns and can be used as separators (in fact they can be use as you want, there is only no mapping of data associated).

myft <- flextable(
data = data,
col_keys = c("Species", "col_1", "Sepal.Length", "Petal.Length") )
myft <- theme_vanilla(myft)
myft <- autofit(myft)
myft <- empty_blanks(myft)
myft
 Species Sepal.Length Petal.Length setosa 5.1 1.4 setosa 4.9 1.4 setosa 4.7 1.3 versicolor 7.0 4.7 versicolor 6.4 4.5 versicolor 6.9 4.9 virginica 6.3 6.0 virginica 5.8 5.1 virginica 7.1 5.9 virginica 6.3 5.6

col_keys default values are the names of the data.frame used to fill the flextable.

## Change 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( iris ) )
ft <- set_header_labels(ft, Sepal.Length = "Sepal length",
Sepal.Width = "Sepal width", Petal.Length = "Petal length",
Petal.Width = "Petal width" )
ft
 Sepal length Sepal width Petal length 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

New header rows can be added at the top or bottom of the header. This part in documented in part Manage headers and footers.

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.

## 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

### 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

### 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

### 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

### 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.

### delete merging informations

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

merge_none(myft)
 letters1 letters2 number a d 1 b e 2 b b 3 c b 4

### 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
fix_border_issues(ft)
 a b 1 6 2 7 3 8 4 9 10

Use one of the following functions to add an header row or a footer row:

• Most needs will be statisfied 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.

The operation below is changing labels that will be displayed instead of the original values (the names of dataset).

ft <- flextable( head( iris ) )
ft <- set_header_labels(ft, Sepal.Length = "Sepal",
Sepal.Width = "Sepal", Petal.Length = "Petal",
Petal.Width = "Petal" )
# merge them
ft <- merge_at(ft, i = 1, j = 1:2, part = "header")
ft <- merge_at(ft, i = 1, j = 3:4, part = "header")
ft
 Sepal Petal 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

Now let’s add new row of labels.

### Add a row of labels

ft <- add_header_row(ft,
values = c("", "length", "width", "length", "width"), top = FALSE )
ft <- theme_box(ft)
 Sepal Petal Species length width length width 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

ft <- add_header_lines(ft,
values = c("this is a first line",
"this is a second line") )
ft <- theme_box(ft)
 this is a second line this is a first line Sepal Petal Species length width length width 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

### 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.

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.

typology <- data.frame(
col_keys = c( "Sepal.Length",
"Sepal.Width", "Petal.Length",
"Petal.Width", "Species" ),
type = c("double", "double", "double",
"double", "factor"),
what = c("Sepal", "Sepal", "Petal",
"Petal", "Species"),
measure = c("Length", "Width", "Length",
"Width", "Species"),
stringsAsFactors = FALSE )
 col_keys type what measure Sepal.Length double Sepal Length Sepal.Width double Sepal Width Petal.Length double Petal Length Petal.Width double Petal Width Species factor Species Species
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( head( iris ) )
ft <- set_header_df( ft, mapping = typology, key = "col_keys" )

ft <- merge_h(ft, part = "header")
ft <- merge_v(ft, part = "header")

ft <- theme_booktabs(ft)
ft <- autofit(ft)
ft <- fix_border_issues(ft)
 double factor Sepal Petal Species Length Width Length Width 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

## Table width

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

You can use another setting with function set_table_properties(). Alternative is ‘autofit’, an algorithm implemented by HTML and Word. It allows to size the table along an available width.

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

## Cell widths and heights

This oonly applies 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, fontsize = 13)
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

### Pretty dimensions

Function dim_pretty() is computing optimized widths and heights.

dim_pretty(ft_base)
#> $widths #> [1] 0.5089948 0.3719030 0.4881886 0.4523067 0.4998259 0.6012121 0.6012121 #> [8] 0.3287037 0.4046111 0.5044104 0.5032643 #> #>$heights
#> [1] 0.3220916 0.2800383 0.2800383 0.2800383 0.2800383 0.2800383 0.2800383

### Adjusts automatically cell widths and heights

Function autofit() optimises widths and heights of the flextable. This function is almost always to be called once when using flextable objects, it 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.5089948 0.3719030 0.4881886 0.4523067 0.4998259 0.6012121 0.6012121 0.3287037 #> am gear carb #> 0.4046111 0.5044104 0.5032643 #> #>$heights
#> [1] 0.3220916 0.2800383 0.2800383 0.2800383 0.2800383 0.2800383 0.2800383
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 (will be considered as "").

### 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.

ft <- autofit(ft_base)
ft <- width(ft, j = ~ mpg + cyl + disp, width = 2)
ft <- height_all( ft, height = .4 )
ft <- height( ft, i = 3, height = 1 )
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