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.
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()
:
merge_none(myft)
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)
# $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
anddim_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 |