Chapter 6 Layout
flextable layout can be easily managed. A set of functions will let you merge
cells, add title rows, change the widths or heights.
6.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)
myftletters1 |
letters2 |
number |
|---|---|---|
a |
d |
1 |
b |
e |
2 |
b |
b |
3 |
c |
b |
4 |
6.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 |
6.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 |
6.1.3 horizontal merging of columns
Function merge_h_range is close to the previous one but merges
all columns 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 |
6.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.
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 paragraph contained in the merged cells. Only one paragraph will be kept, the top left one of all merged cells.
6.1.5 delete merging information
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 |
6.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
tries 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) )
fta |
b |
|---|---|
1 |
6 |
2 |
7 |
3 |
8 |
4 |
9 |
10 |
a |
b |
|---|---|
1 |
6 |
2 |
7 |
3 |
8 |
4 |
9 |
10 |
6.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.
6.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 |
14.3 |
56 |
5 |
5 |
||
28 |
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 |
14.3 |
56 |
5 |
5 |
||
28 |
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 |
14.3 |
56 |
5 |
5 |
||
28 |
14.9 |
66 |
5 |
6 |
6.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 lead to inadequate row heights and column 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_basempg |
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
6.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
6.2.2.2 Automatically adjust cell widths and heights
Function autofit() optimises widths and heights of the flextable.
This function makes compact tables.
autofitwas not my biggest naming idea as users are thinking it is the ‘Microsoft Word feature’ (see set_table_properties)
# $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
ftmpg |
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
autofitanddim_prettydo not support soft returns and may return wrong results (backslash n will be considered as ““).
6.2.2.3 Manually adjust cell widths and heights
Function width() and height() let you control dimensions of a flextable.
height_all() is a 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 supports 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 B.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)
ftmpg |
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")
ftmpg |
cyl |
disp |
hp |
drat |
wt |
qsec |
vs |
am |
gear |
carb |
|
|---|---|---|---|---|---|---|---|---|---|---|---|
mpg |
|||||||||||
cyl |
|||||||||||
disp |
|||||||||||
hp |
|||||||||||
drat |
|||||||||||
wt |
|||||||||||
qsec |
|||||||||||
vs |
|||||||||||
am |
|||||||||||
gear |
|||||||||||
carb |