90 Tables: kable, kableextra, and gt

Written by Yena Joo and last updated on 7 October 2021.

90.1 Introduction

In the research papers, tables are used all the time. However, the dataframe itself looks unorganized and latex-y when the R file is converted into PDF or HTML. To make nice and beautiful tables, we are going to learn how to use kable and kableextra.

In this lesson, you will learn how to:

  • Create Tables In LaTeX, HTML, Markdown
  • build common complex tables and manipulate table styles using kableExtra

Prerequisite skills include:

  • manipulate dataset
  • You don’t need much prerequisite for this chapter :)

Highlights:

  • How to create tables for HTML and PDF.
  • kable, kableExtra, gt

90.1.1 Packages

Packages knitr and kableExtra are needed. For the gt Table, gt package is needed.

90.2 Kable()

kable() function in knitr package is a table generator.

90.2.1 Arguments of kable()

kable(x, format, digits = getOption("digits"), row.names = NA, 
  col.names = NA, align, caption = NULL, label = NULL, 
  format.args = list(), escape = TRUE, ...)

Here are some important arguments of kable():

  • x: put the data frame of your choice.
  • format: possible values are “latex,” “html,” “simple,” “pipe,” “rst.”
  • digit: maximum number of digits for numeric columns.
  • row.names & col.names: column names and row names.

If you want the full descriptions of each argument, click here or type help("kable") into your console.

First, let’s use a built-in dataset mtcars as an example. We simply put the dataset name as the argument x of the function kbl or kable. Then, it creates the most basic table output as follows. Note that for R Markdown documents, the function uses the format “pipe” by default.

kable(x = head(mtcars))
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1

90.2.2 Formatting of kable

There are several arguments you can customize the tables.
For example, you can set the format of the table using format = "html". You can also add a title to the table using caption = "" argument. digits = allows you to round and format the numbers in the table.

Let’s try to create an HTML table with a caption.

dt <- head(mtcars[1:3,])
kable(x = dt, format = "html", caption = "Title of the table")
Table 90.1: Title of the table
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1

However, the basic HTML output of kable does not look so pretty, since it is just a plain HTML table without any styling.

We can also change the column names or row names using col.names or row.names. Let’s customize the table above into the format “simple,” as well as with changed column names.

kable(x = dt, format = "simple", caption = "Title of the table", col.names = c("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"))
Table 90.2: Title of the table
1 2 3 4 5 6 7 8 9 10 11
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1

Note that only the pipe and simple formats work in any output document format. Formats such as latex or html only work on the specific format of the document output.

90.3 kableExtra

The kableExtra package allows you to add a lot more features and options to your simple table you made using the function kable(). The package features the pipe operator, %>%, so you can pipe the table to add more features.

90.3.1 kable_styling()

To make the plain HTML table we just created look prettier, you can always apply themes using kable_styling() from the package kableExtra to make the tables look more fancy and neat.

The function has the following arguments:

kable_styling(
  kable_input,
  bootstrap_options = "basic",
  latex_options = "basic",
  full_width = NULL,
  position = "center",
  font_size = NULL,....

Details of the arguments can be found here.

First, let’s just try using the function without any argument. kable_styling() will automatically apply Twitter bootstrap theme to the table.

kable(x = head(mtcars[1:3,]))  %>%
  kable_styling()
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1

As you can see, it creates a nice and simple table.

Using kable_styling, you can also adjust the size and position of the table, font sizes, etc. as the following:

kable(x = dt, format = "html") %>%
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left", font_size = 10)
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1

You can try various options using the function kable_styling. Here are some more nice and detailed examples for a reference.

90.3.2 How to put multiple tables side by side

You can pass a list of dataframes to kable() which generates side-by-side tables. Here, I will split mtcars dataset into two tables, and put them side by side using kable(list(datasets)).

data1 <- head(mtcars[1:3, 1:3])
data2 <- head(mtcars[, 4:7])
knitr::kable(
  x = list(data1, data2), format = "html",
  caption = 'Tables side by side.',
  booktabs = TRUE, valign = 't'
) %>% kable_styling(bootstrap_options = "striped")
Table 90.3: Tables side by side.
mpg cyl disp
Mazda RX4 21.0 6 160
Mazda RX4 Wag 21.0 6 160
Datsun 710 22.8 4 108
hp drat wt qsec
Mazda RX4 110 3.90 2.620 16.46
Mazda RX4 Wag 110 3.90 2.875 17.02
Datsun 710 93 3.85 2.320 18.61
Hornet 4 Drive 110 3.08 3.215 19.44
Hornet Sportabout 175 3.15 3.440 17.02
Valiant 105 2.76 3.460 20.22

This feature only works for html and pdf output.

Another way to put tables side by side is to use kables().

kables(list(
  kable(data1, caption = "first table") %>% kable_styling(bootstrap_options = "striped"), 
  kable(data2, caption= "second table") %>% kable_styling(bootstrap_options = "striped"))) 
Table 90.4: first table
mpg cyl disp
Mazda RX4 21.0 6 160
Mazda RX4 Wag 21.0 6 160
Datsun 710 22.8 4 108
Table 90.4: second table
hp drat wt qsec
Mazda RX4 110 3.90 2.620 16.46
Mazda RX4 Wag 110 3.90 2.875 17.02
Datsun 710 93 3.85 2.320 18.61
Hornet 4 Drive 110 3.08 3.215 19.44
Hornet Sportabout 175 3.15 3.440 17.02
Valiant 105 2.76 3.460 20.22

By using kables function, you can pass the list of kable() objects to it. You can also set different titles for each table.

90.4 GT Table

The gt package is used to produce nice-looking display tables. Here, we distinguish between data tables(tibbles, dataframes, etc) and the display tables easily found in articles, and web pages.

In order to produce the gt table, gt package is needed.

Given that data is a tibble which we have a suitable input for gt.

We use gt() function. If we pass the tibble to the gt() function, we’ll get a gt Table as an output.

mt = tibble(head(mtcars))
mt_table = gt(data = mt)

# Show the gt Table
mt_table
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

90.4.1 Add parts to the gt Table

You can add titles and labels for various levels on the gt Tables. The picture below shows the parts you can put the title/labels at.

To add a title, you used the tab_header function to add labels or titles.

mt_table <- 
mt_table %>%
  tab_header(
    title = "This is a title",
    subtitle = "This is a subtitle"
  ) 
mt_table
This is a title
This is a subtitle
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

90.5 Exercises

90.5.1 Question 1

Create a table that has a title “This is a table,” bootstrap options being stripe, and having full width, with a right position, using the dataset data.

data <- head(mtcars)
data <- head(mtcars)
kable(x = data, caption = "This is a table", position = "right", full_width = T)
(#tab:q1_kable-solution)This is a table
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1

90.5.2 Question 2

Now, use kable_styling() to create the same table, but with striped bootstrap option.

data <- head(mtcars)
data <- head(mtcars)
kable(x = data, caption = "This is a table", position = "right", full_width = T) %>% kable_styling(bootstrap_options = 'striped')
(#tab:q2_kable-solution)This is a table
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1

90.5.3 Question 3

Put the following data frames side by side, with the title “Tables are side by side.” Drop the decimal places using the argument digits.

data_1 <- head(mtcars[1:2, 1:2])
data_2 <- head(mtcars[, 5:7])
kable(
  x = list(data_1, data_2),
  caption = 'Tables are side by side.', digits = 0
)
(#tab:q3_kable-solution)Tables are side by side.
mpg cyl
Mazda RX4 21 6
Mazda RX4 Wag 21 6
drat wt qsec
Mazda RX4 4 3 16
Mazda RX4 Wag 4 3 17
Datsun 710 4 2 19
Hornet 4 Drive 3 3 19
Hornet Sportabout 3 3 17
Valiant 3 3 20

90.5.4 Question 4

What is the purpose of using kable in the knitr package?
a. Because the dataframe itself looks ugly when R file is converted into PDF.
b. Because the dataframe itself looks ugly when R file is converted into HTML.
c. To customize the table.
d. All of the above.

90.5.5 Question 5

90.5.6 Question 6

90.5.7 Question 7

90.5.8 Question 8

90.5.9 Question 9

90.5.10 Question 10

90.6 Common Mistakes & Errors

You might get the following error message sometimes:

Error in dimnames(x) <- dn : length of 'dimnames' [2] not equal to array extent

This error message will pop up if you are trying to change the column names with different length of the vector than the number of columns. Make sure the length of the vector in your col.names argument matches the number of the columns in the dataset.

Also, make sure to choose the right format of kable that matches the format of the document. If you choose to put format = "pdf" in a HTML document output, you will get the following error:

could not find function "kable_pdf"

So be careful not to make these mistakes.

90.7 Next Steps

Create some fancy tables using kable & kableExtra :)

90.9 Exercises

90.9.1 Question 1

90.9.2 Question 2

90.9.3 Question 3

90.9.4 Question 4

90.9.5 Question 5

90.9.6 Question 6

90.9.7 Question 7

90.9.8 Question 8

90.9.9 Question 9

90.9.10 Question 10