library(tinytable)
options(tinytable_tt_digits = 3)
options(tinytable_latex_placement = "H")
<- mtcars[1:4, 1:5] x
Groups and labels
The group_tt()
function can label groups of rows (i
) or columns (j
).
Rows
The i
argument accepts a named list of integers. The numbers identify the positions where row group labels are to be inserted. The names includes the text that should be inserted:
<- mtcars[1:9, 1:8]
dat
tt(dat) |>
group_tt(i = list(
"I like (fake) hamburgers" = 3,
"She prefers halloumi" = 4,
"They love tofu" = 7))
mpg | cyl | disp | hp | drat | wt | qsec | vs |
---|---|---|---|---|---|---|---|
21 | 6 | 160 | 110 | 3.9 | 2.62 | 16.5 | 0 |
21 | 6 | 160 | 110 | 3.9 | 2.88 | 17 | 0 |
I like (fake) hamburgers | |||||||
22.8 | 4 | 108 | 93 | 3.85 | 2.32 | 18.6 | 1 |
She prefers halloumi | |||||||
21.4 | 6 | 258 | 110 | 3.08 | 3.21 | 19.4 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.44 | 17 | 0 |
18.1 | 6 | 225 | 105 | 2.76 | 3.46 | 20.2 | 1 |
They love tofu | |||||||
14.3 | 8 | 360 | 245 | 3.21 | 3.57 | 15.8 | 0 |
24.4 | 4 | 147 | 62 | 3.69 | 3.19 | 20 | 1 |
22.8 | 4 | 141 | 95 | 3.92 | 3.15 | 22.9 | 1 |
The numbers in the i
list indicate that a label must be inserted at position # in the original table (without row groups). For example,
tt(head(iris)) |>
group_tt(i = list("After 0" = 1, "After 3a" = 4, "After 3b" = 4, "After 5" = 6))
Sepal.Length | Sepal.Width | Petal.Length | Petal.Width | Species |
---|---|---|---|---|
After 0 | ||||
5.1 | 3.5 | 1.4 | 0.2 | setosa |
4.9 | 3 | 1.4 | 0.2 | setosa |
4.7 | 3.2 | 1.3 | 0.2 | setosa |
After 3a | ||||
After 3b | ||||
4.6 | 3.1 | 1.5 | 0.2 | setosa |
5 | 3.6 | 1.4 | 0.2 | setosa |
After 5 | ||||
5.4 | 3.9 | 1.7 | 0.4 | setosa |
Styling row groups
We can style group rows in the same way as regular rows (caveat: not in Word or Markdown):
<- tt(dat) |>
tab group_tt(i = list(
"I like (fake) hamburgers" = 3,
"She prefers halloumi" = 4,
"They love tofu" = 7))
|> style_tt(
tab i = c(3, 5, 9),
align = "c",
color = "white",
background = "gray",
bold = TRUE)
mpg | cyl | disp | hp | drat | wt | qsec | vs |
---|---|---|---|---|---|---|---|
21 | 6 | 160 | 110 | 3.9 | 2.62 | 16.5 | 0 |
21 | 6 | 160 | 110 | 3.9 | 2.88 | 17 | 0 |
I like (fake) hamburgers | |||||||
22.8 | 4 | 108 | 93 | 3.85 | 2.32 | 18.6 | 1 |
She prefers halloumi | |||||||
21.4 | 6 | 258 | 110 | 3.08 | 3.21 | 19.4 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.44 | 17 | 0 |
18.1 | 6 | 225 | 105 | 2.76 | 3.46 | 20.2 | 1 |
They love tofu | |||||||
14.3 | 8 | 360 | 245 | 3.21 | 3.57 | 15.8 | 0 |
24.4 | 4 | 147 | 62 | 3.69 | 3.19 | 20 | 1 |
22.8 | 4 | 141 | 95 | 3.92 | 3.15 | 22.9 | 1 |
Calculating the location of rows can be cumbersome. Instead of doing this by hand, we can use the “groupi” shortcut to style rows and “~groupi” (the complement) to style all non-group rows.
|>
tab style_tt("groupi", color = "white", background = "teal") |>
style_tt("~groupi", j = 1, indent = 2)
mpg | cyl | disp | hp | drat | wt | qsec | vs |
---|---|---|---|---|---|---|---|
21 | 6 | 160 | 110 | 3.9 | 2.62 | 16.5 | 0 |
21 | 6 | 160 | 110 | 3.9 | 2.88 | 17 | 0 |
I like (fake) hamburgers | |||||||
22.8 | 4 | 108 | 93 | 3.85 | 2.32 | 18.6 | 1 |
She prefers halloumi | |||||||
21.4 | 6 | 258 | 110 | 3.08 | 3.21 | 19.4 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.44 | 17 | 0 |
18.1 | 6 | 225 | 105 | 2.76 | 3.46 | 20.2 | 1 |
They love tofu | |||||||
14.3 | 8 | 360 | 245 | 3.21 | 3.57 | 15.8 | 0 |
24.4 | 4 | 147 | 62 | 3.69 | 3.19 | 20 | 1 |
22.8 | 4 | 141 | 95 | 3.92 | 3.15 | 22.9 | 1 |
Automatic row groups
We can use the group_tt()
function to group rows and label them using spanners (almost) automatically. For example,
# subset and sort data
<- mtcars |>
df head(10) |>
sort_by(~am)
# draw table
tt(df) |> group_tt(i = df$am)
mpg | cyl | disp | hp | drat | wt | qsec | vs | am | gear | carb |
---|---|---|---|---|---|---|---|---|---|---|
0 | ||||||||||
21.4 | 6 | 258 | 110 | 3.08 | 3.21 | 19.4 | 1 | 0 | 3 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.44 | 17 | 0 | 0 | 3 | 2 |
18.1 | 6 | 225 | 105 | 2.76 | 3.46 | 20.2 | 1 | 0 | 3 | 1 |
14.3 | 8 | 360 | 245 | 3.21 | 3.57 | 15.8 | 0 | 0 | 3 | 4 |
24.4 | 4 | 147 | 62 | 3.69 | 3.19 | 20 | 1 | 0 | 4 | 2 |
22.8 | 4 | 141 | 95 | 3.92 | 3.15 | 22.9 | 1 | 0 | 4 | 2 |
19.2 | 6 | 168 | 123 | 3.92 | 3.44 | 18.3 | 1 | 0 | 4 | 4 |
1 | ||||||||||
21 | 6 | 160 | 110 | 3.9 | 2.62 | 16.5 | 0 | 1 | 4 | 4 |
21 | 6 | 160 | 110 | 3.9 | 2.88 | 17 | 0 | 1 | 4 | 4 |
22.8 | 4 | 108 | 93 | 3.85 | 2.32 | 18.6 | 1 | 1 | 4 | 1 |
Row matrix insertion
While the traditional group_tt(i = list(...))
approach is useful for adding individual labeled rows, sometimes you need to insert multiple rows of data at specific positions. The matrix insertion feature provides a more efficient way to do this.
Instead of creating multiple named list entries, you can specify row positions as an integer vector in i
and provide a character matrix in j
. This is particularly useful when you want to insert the same content (like headers or separators) at multiple positions:
<- matrix(colnames(iris))
rowmat
tt(head(iris, 7)) |>
group_tt(i = c(2, 5), j = rowmat)
Sepal.Length | Sepal.Width | Petal.Length | Petal.Width | Species |
---|---|---|---|---|
5.1 | 3.5 | 1.4 | 0.2 | setosa |
Sepal.Length | Sepal.Width | Petal.Length | Petal.Width | Species |
4.9 | 3 | 1.4 | 0.2 | setosa |
4.7 | 3.2 | 1.3 | 0.2 | setosa |
4.6 | 3.1 | 1.5 | 0.2 | setosa |
Sepal.Length | Sepal.Width | Petal.Length | Petal.Width | Species |
5 | 3.6 | 1.4 | 0.2 | setosa |
5.4 | 3.9 | 1.7 | 0.4 | setosa |
4.6 | 3.4 | 1.4 | 0.3 | setosa |
The matrix is expected to have the same number of columns as the table. However, if you provide a single-column matrix with a number of elements that is a multiple of the table’s column count, it will be automatically reshaped to match the table structure. This makes it easy to provide data in a linear format:
<- matrix(c(
rowmat "-", "-", "-", "-", "-",
"/", "/", "/", "/", "/"))
tt(head(iris, 7)) |> group_tt(i = 2, j = rowmat)
Sepal.Length | Sepal.Width | Petal.Length | Petal.Width | Species |
---|---|---|---|---|
5.1 | 3.5 | 1.4 | 0.2 | setosa |
- | - | - | - | - |
/ | / | / | / | / |
4.9 | 3 | 1.4 | 0.2 | setosa |
4.7 | 3.2 | 1.3 | 0.2 | setosa |
4.6 | 3.1 | 1.5 | 0.2 | setosa |
5 | 3.6 | 1.4 | 0.2 | setosa |
5.4 | 3.9 | 1.7 | 0.4 | setosa |
4.6 | 3.4 | 1.4 | 0.3 | setosa |
We can also insert rows of the group matrix in different positions:
tt(head(iris, 7)) |> group_tt(i = c(1, 8), j = rowmat)
Sepal.Length | Sepal.Width | Petal.Length | Petal.Width | Species |
---|---|---|---|---|
- | - | - | - | - |
5.1 | 3.5 | 1.4 | 0.2 | setosa |
4.9 | 3 | 1.4 | 0.2 | setosa |
4.7 | 3.2 | 1.3 | 0.2 | setosa |
4.6 | 3.1 | 1.5 | 0.2 | setosa |
5 | 3.6 | 1.4 | 0.2 | setosa |
5.4 | 3.9 | 1.7 | 0.4 | setosa |
4.6 | 3.4 | 1.4 | 0.3 | setosa |
/ | / | / | / | / |
Columns
The syntax for column groups is very similar, but we use the j
argument instead. The named list specifies the labels to appear in column-spanning labels, and the values must be a vector of consecutive and non-overlapping integers that indicate which columns are associated to which labels:
tt(dat) |>
group_tt(
j = list(
"Hamburgers" = 1:3,
"Halloumi" = 4:5,
"Tofu" = 7))
Hamburgers | Halloumi | Tofu | |||||
---|---|---|---|---|---|---|---|
mpg | cyl | disp | hp | drat | wt | qsec | vs |
21 | 6 | 160 | 110 | 3.9 | 2.62 | 16.5 | 0 |
21 | 6 | 160 | 110 | 3.9 | 2.88 | 17 | 0 |
22.8 | 4 | 108 | 93 | 3.85 | 2.32 | 18.6 | 1 |
21.4 | 6 | 258 | 110 | 3.08 | 3.21 | 19.4 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.44 | 17 | 0 |
18.1 | 6 | 225 | 105 | 2.76 | 3.46 | 20.2 | 1 |
14.3 | 8 | 360 | 245 | 3.21 | 3.57 | 15.8 | 0 |
24.4 | 4 | 147 | 62 | 3.69 | 3.19 | 20 | 1 |
22.8 | 4 | 141 | 95 | 3.92 | 3.15 | 22.9 | 1 |
We can stack several extra headers on top of one another:
<- mtcars[1:4, 1:5]
x tt(x) |>
group_tt(j = list("Foo" = 2:3, "Bar" = 5)) |>
group_tt(j = list("Hello" = 1:2, "World" = 4:5))
Hello | World | |||
---|---|---|---|---|
Foo | Bar | |||
mpg | cyl | disp | hp | drat |
21 | 6 | 160 | 110 | 3.9 |
21 | 6 | 160 | 110 | 3.9 |
22.8 | 4 | 108 | 93 | 3.85 |
21.4 | 6 | 258 | 110 | 3.08 |
Styling column groups
To style column headers, we use zero or negative indices:
tt(x) |>
group_tt(j = list("Foo" = 2:3, "Bar" = 5)) |>
group_tt(j = list("Hello" = 1:2, "World" = 4:5)) |>
style_tt(i = 0, color = "orange") |>
style_tt(i = -1, color = "teal") |>
style_tt(i = -2, color = "yellow")
Hello | World | |||
---|---|---|---|---|
Foo | Bar | |||
mpg | cyl | disp | hp | drat |
21 | 6 | 160 | 110 | 3.9 |
21 | 6 | 160 | 110 | 3.9 |
22.8 | 4 | 108 | 93 | 3.85 |
21.4 | 6 | 258 | 110 | 3.08 |
Alternatively, we can use string shortcuts:
tt(x) |>
group_tt(j = list("Foo" = 2:3, "Bar" = 5)) |>
group_tt(j = list("Hello" = 1:2, "World" = 4:5)) |>
style_tt("groupj", color = "orange") |>
style_tt("colnames", color = "teal")
Hello | World | |||
---|---|---|---|---|
Foo | Bar | |||
mpg | cyl | disp | hp | drat |
21 | 6 | 160 | 110 | 3.9 |
21 | 6 | 160 | 110 | 3.9 |
22.8 | 4 | 108 | 93 | 3.85 |
21.4 | 6 | 258 | 110 | 3.08 |
Here is a table with both row and column headers, as well as some styling:
<- mtcars[1:9, 1:8]
dat tt(dat) |>
group_tt(
i = list(
"I like (fake) hamburgers" = 3,
"She prefers halloumi" = 4,
"They love tofu" = 7
),j = list(
"Hamburgers" = 1:3,
"Halloumi" = 4:5,
"Tofu" = 7
)|>
) style_tt(
i = c(3, 5, 9),
align = "c",
background = "teal",
color = "white"
|>
) style_tt(i = -1, color = "teal")
Hamburgers | Halloumi | Tofu | |||||
---|---|---|---|---|---|---|---|
mpg | cyl | disp | hp | drat | wt | qsec | vs |
21 | 6 | 160 | 110 | 3.9 | 2.62 | 16.5 | 0 |
21 | 6 | 160 | 110 | 3.9 | 2.88 | 17 | 0 |
I like (fake) hamburgers | |||||||
22.8 | 4 | 108 | 93 | 3.85 | 2.32 | 18.6 | 1 |
She prefers halloumi | |||||||
21.4 | 6 | 258 | 110 | 3.08 | 3.21 | 19.4 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.44 | 17 | 0 |
18.1 | 6 | 225 | 105 | 2.76 | 3.46 | 20.2 | 1 |
They love tofu | |||||||
14.3 | 8 | 360 | 245 | 3.21 | 3.57 | 15.8 | 0 |
24.4 | 4 | 147 | 62 | 3.69 | 3.19 | 20 | 1 |
22.8 | 4 | 141 | 95 | 3.92 | 3.15 | 22.9 | 1 |
Column names with delimiters
Group labels can be specified using column names with delimiters. For example, some of the columns in this data frame have group identifiers. Note that the first column does not have a group identifier, and that the last column has a group identifier but no column name.
<- data.frame(
dat "A__D" = rnorm(3),
"A_B_D" = rnorm(3),
"A_B_" = rnorm(3),
"_C_E" = rnorm(3),
check.names = FALSE
)
tt(dat) |> group_tt(j = "_")
A | |||
---|---|---|---|
B | C | ||
D | D | B | E |
-1.402 | 0.615 | 0.806 | 0.456 |
-0.307 | 0.194 | -0.694 | 0.581 |
-2.502 | 0.563 | 1.571 | -1.747 |
Case studies
Repeated column names
In some contexts, users wish to repeat the column names to treat them as group labels. Consider this dataset:
library(tinytable)
library(magrittr)
= data.frame(
dat Region = as.character(state.region),
State = row.names(state.x77),
1:3]) |>
state.x77[, sort_by(~ Region + State) |>
subset(Region %in% c("North Central", "Northeast"))
= do.call(rbind, by(dat, dat$Region, head, n = 3))
dat row.names(dat) = NULL
dat
Region State Population Income Illiteracy
1 North Central Illinois 11197 5107 0.9
2 North Central Indiana 5313 4458 0.7
3 North Central Iowa 2861 4628 0.5
4 Northeast Connecticut 3100 5348 1.1
5 Northeast Maine 1058 3694 0.7
6 Northeast Massachusetts 5814 4755 1.1
Here, we may want to repeat the column names for every region. The group_tt()
function does not support this directly, but it is easy to achieve this effect by:
- Insert column names as new rows in the data.
- Creat a row group variable (here:
region
) - Style the column names and group labels
Normally, we would call style_tt(i = "groupi")
to style the row groups, but here we need the actual indices to also style one row below the groups. We can use the @group_index_i
slot to get the indices of the row groups.
<- unique(dat$Region)
region_names <- rep(match(region_names, dat$Region), each = 2)
region_indices
<- do.call(rbind, lapply(region_names, function(name) {
rowmat rbind(
c(name, rep("", 3)),
colnames(dat)[2:5]
)
}))
rowmat
[,1] [,2] [,3] [,4]
[1,] "North Central" "" "" ""
[2,] "State" "Population" "Income" "Illiteracy"
[3,] "Northeast" "" "" ""
[4,] "State" "Population" "Income" "Illiteracy"
<- tt(dat[, 2:5], colnames = FALSE) |>
tab group_tt(i = region_indices, j = rowmat)
<- tab@group_index_i[c(TRUE, diff(tab@group_index_i) != 1)]
idx
|>
tab style_tt(i = idx, j = 1, align = "c", colspan = 4, background = "lightgrey", line = "b") |>
style_tt(i = idx + 1, line = "tb")
North Central | |||
State | Population | Income | Illiteracy |
Illinois | 11197 | 5107 | 0.9 |
Indiana | 5313 | 4458 | 0.7 |
Iowa | 2861 | 4628 | 0.5 |
Northeast | |||
State | Population | Income | Illiteracy |
Connecticut | 3100 | 5348 | 1.1 |
Maine | 1058 | 3694 | 0.7 |
Massachusetts | 5814 | 4755 | 1.1 |