The gt package is out on CRAN. If you want to produce presentation tables in R, you should definitely check it out – it’s written by the guys at RStudio and has the high quality you would expect.
Meanwhile, the huxtable package still might be useful. In particular, if you want to output to PDF (or HTML, Word, Powerpoint, Excel, RTF or Markdown), huxtable can do that.
Version 5.0.0 of huxtable is coming out shortly. This article describes some of its new features. Click the links on the left to learn more.
h | u | ||||
x | t | ||||
a | b | ||||
l | |||||
e |
You can now use markdown to format text in cell contents.
library(huxtable)
library(dplyr)
jams %>%
set_markdown_contents(1, 1:2,
c("*Type* of jam", "*Price* of jam")
) %>%
set_markdown_contents(3, 2, "~2.10~ **Sale!** 1.50")
Type of jam |
Price of jam |
Strawberry | 1.90 |
Raspberry |
|
Plum | 1.80 |
The set_markdown_contents()
is a shortcut function that sets the markdown
property to TRUE
.
For now, markdown is supported in HTML and LaTeX, with basic support for on-screen output.
Many tweaks have been made to how huxtables are displayed in LaTeX. In particular, the “adjustbox” TeX package is now used to centre tables, meaning that – at last – tables now stay robustly in the middle of the page.
iris_hux <- as_hux(head(iris), add_colnames = TRUE) %>%
theme_plain() %>%
set_position("center")
install.packages("huxtable")
iris_hux %>%
set_caption("Aw, no way") %>%
quick_pdf(file = "old-version.pdf")
remotes::install_github("hughjonesd/huxtable")
iris_hux %>%
set_caption("That's better") %>%
quick_pdf(file = "new-version.pdf")
This change needs a recent version of the “adjustbox” package from CTAN. huxtable::check_latex_dependencies()
will check this for you, and install_latex_dependencies()
will try to update you automatically.
There are other improvements too. Padding now works better, and cell wrapping is more sensible by default.
To make a coloured or styled border in huxtable, you used to have to write:
jams %>%
set_bottom_border(1, everywhere, 2) %>%
set_bottom_border_style(1, everywhere, "dashed") %>%
set_bottom_border_color(1, everywhere, "#078bcc")
Type | Price |
Strawberry | 1.90 |
Raspberry | 2.10 |
Plum | 1.80 |
This could get laborious. Huxtable 5.0.0 has a new brdr()
class to set all these features at once.
Type | Price |
Strawberry | 1.90 |
Raspberry | 2.10 |
Plum | 1.80 |
Border internals have also been reworked, fixing some long-standing bugs. The following code used to give a nasty surprise:
install.packages("huxtable")
as_hux(matrix(c("Multirow cell", rep("Cell", 8)), 3, 3)) %>%
set_bottom_border(1, everywhere, 0.4) %>%
set_rowspan(1, 1, 2) %>%
set_caption("Wait, why has my border moved?")
Wait, why has my border moved?
Multirow cell Cell Cell
─────────────────
Cell Cell
─────────────────
Cell Cell Cell
Column names: V1, V2, V3
It now does what you would expect:
remotes::install_github("hughjonesd/huxtable")
as_hux(matrix(c("Multirow cell", rep("Cell", 8)), 3, 3)) %>%
set_bottom_border(1, everywhere, 0.4) %>%
set_rowspan(1, 1, 2) %>%
set_caption("That's better")
That's better
Multirow cell Cell Cell
─────────────────
Cell Cell
Cell Cell Cell
Column names: V1, V2, V3
Terminal printing now also respects the huxtable position
, incidentally.
Lastly, there are new functions to quickly set vertical and horizontal borders:
Type | Price |
Strawberry | 1.90 |
Raspberry | 2.10 |
Plum | 1.80 |
Here’s a common problem: your table is too wide or long for the page.
library(dplyr)
car_hux <- mtcars %>%
head() %>%
select(
"Miles per gallon" = mpg,
"Cylinders" = cyl,
"Displacement" = disp,
"Horsepower" = hp,
"Drat, my table is too wide" = drat
) %>%
as_hux(add_rownames = "Model") %>%
set_header_cols(1, TRUE)
car_hux
Model | Miles per gallon | Cylinders | Displacement | Horsepower | Drat, my table is too wide |
Mazda RX4 | 21 | 6 | 160 | 110 | 3.9 |
Mazda RX4 Wag | 21 | 6 | 160 | 110 | 3.9 |
Datsun 710 | 22.8 | 4 | 108 | 93 | 3.85 |
Hornet 4 Drive | 21.4 | 6 | 258 | 110 | 3.08 |
Hornet Sportabout | 18.7 | 8 | 360 | 175 | 3.15 |
Valiant | 18.1 | 6 | 225 | 105 | 2.76 |
Huxtable now has some nice ways to deal with this. First, you can split your table in two:
Model | Miles per gallon | Cylinders |
Mazda RX4 | 21 | 6 |
Mazda RX4 Wag | 21 | 6 |
Datsun 710 | 22.8 | 4 |
Hornet 4 Drive | 21.4 | 6 |
Hornet Sportabout | 18.7 | 8 |
Valiant | 18.1 | 6 |
Model | Displacement | Horsepower | Drat, my table is too wide |
Mazda RX4 | 160 | 110 | 3.9 |
Mazda RX4 Wag | 160 | 110 | 3.9 |
Datsun 710 | 108 | 93 | 3.85 |
Hornet 4 Drive | 258 | 110 | 3.08 |
Hornet Sportabout | 360 | 175 | 3.15 |
Valiant | 225 | 105 | 2.76 |
Notice that both of the split tables still have the model names on the left. That’s because we set them as a header column, using some more new functionality. Header columns don’t change style by themselves, but you can apply your own styles easily.
Another way to change the table size is to restack it. Here, we restack our table of cars to go down the page.
Model | Miles per gallon | Cylinders | Displacement |
Mazda RX4 | 21 | 6 | 160 |
Mazda RX4 Wag | 21 | 6 | 160 |
Datsun 710 | 22.8 | 4 | 108 |
Hornet 4 Drive | 21.4 | 6 | 258 |
Hornet Sportabout | 18.7 | 8 | 360 |
Valiant | 18.1 | 6 | 225 |
Model | Horsepower | Drat, my table is too wide | |
Mazda RX4 | 110 | 3.9 | |
Mazda RX4 Wag | 110 | 3.9 | |
Datsun 710 | 93 | 3.85 | |
Hornet 4 Drive | 110 | 3.08 | |
Hornet Sportabout | 175 | 3.15 | |
Valiant | 105 | 2.76 |
style_header_rows()
can be used to give header rows their own look. Notice that header rows don’t have to be on top of the table.
As well as split_down()
and restack_down()
, there’s split_across()
and restack_across()
, for when your tables are too long. To explain how restacking works, a picture will help.
lego_hux <- as_hux(matrix(1:16, 4, 4, byrow = TRUE)) %>%
set_all_borders(brdr(2, color = "white")) %>%
set_text_color("white") %>%
set_background_color(1:2, 1:2, "#00695b") %>%
set_background_color(1:2, 3:4, "#32b8f0") %>%
set_background_color(3:4, 1:2, "#067ab8") %>%
set_background_color(3:4, 3:4, "#d14141")
lego_hux %>% set_caption("Original table")
1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 |
1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 |
5 | 6 | 7 | 8 | 13 | 14 | 15 | 16 |
1 | 2 |
5 | 6 |
9 | 10 |
13 | 14 |
3 | 4 |
7 | 8 |
11 | 12 |
15 | 16 |
By default, huxtable will warn you if your restacked table doesn’t fit evenly.
Huxtable now sets labels from the knitr chunk header by default.
This makes referencing from bookdown easy:
Some iris species are shown in \@ref(tab:mytable):
```{r mytable}
hux(head(iris))
```
Huxtable 5.0.0 sets sensible defaults for some arguments. So, instead of writing
jams <- jams %>%
set_bold(1, everywhere, TRUE) %>%
set_italic(everywhere, 1, TRUE) %>%
set_bottom_border(1, everywhere, 0.4)
you can just write
jams <- jams %>%
set_bold(1, everywhere) %>%
set_italic(everywhere, 1) %>%
set_bottom_border(1, everywhere)
(Why else would you use set_bold()
in the first place?)
Type | Price |
Strawberry | 1.90 |
Raspberry | 2.10 |
Plum | 1.80 |
Huxtable’s number formatting is powerful, but hasn’t been easy to use. fmt_pretty()
and fmt_percent()
help you print nice looking numbers.
jams$Sugar <- c("Sugar content", 0.4, 0.35, 0.45)
jams$Sales <- c("Monthly sales", 35000, 55500, 2000)
jams %>%
set_number_format(everywhere, "Sugar", fmt_percent(1)) %>%
set_number_format(everywhere, "Sales", fmt_pretty())
Type | Price | Sugar content | Monthly sales |
Strawberry | 1.90 | 40.0% | 35,000 |
Raspberry | 2.10 | 35.0% | 55,500 |
Plum | 1.80 | 45.0% | 2,000 |
To try out the new features in 5.0.0, run:
If you find a bug, report it on github.
You can go back to the CRAN version with:
Happy table making!