install.packages("tinytable",
repos = c("https://vincentarelbundock.r-universe.dev", "https://cran.r-project.org"))
Tiny Tables
tinytable
is a small but powerful R
package to draw HTML, LaTeX, Word, PDF, Markdown, and Typst tables. The interface is minimalist, but it gives users direct and convenient access to powerful frameworks to create endlessly customizable tables.
Install the latest version from R-Universe or CRAN:
This tutorial introduces the main functions of the package. It is also available as a single PDF document.
Load the library and set some global options:
library(tinytable)
options(tinytable_tt_digits = 3)
options(tinytable_theme_placement_latex_float = "H")
Draw a first table:
<- mtcars[1:4, 1:5]
x tt(x)
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 |
Width
The width
arguments indicating what proportion of the line width the table should cover. This argument accepts a number between 0 and 1 to control the whole table width, or a vector of numeric values between 0 and 1, representing each column.
tt(x, width = 0.5)
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 |
tt(x, width = 1)
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 |
We can control individual columns by supplying a vector. In that case, the sum of width
elements determines the full table width. For example, this table takes 70% of available width, with the first column 3 times as large as the other ones.
tt(x, width = c(.3, .1, .1, .1, .1))
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 |
When the sum of the width
vector exceeds 1, it is automatically normalized to full-width. This is convenient when we only want to specify column width in relative terms:
tt(x, width = c(3, 2, 1, 1, 1))
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 |
When specifying a table width
, the text is automatically wrapped to appropriate size:
<- data.frame(
lorem Lorem = "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.",
Ipsum = " Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos."
)
tt(lorem, width = 3/4)
Lorem | Ipsum |
---|---|
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. | Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos. |
Footnotes
The notes
argument accepts single strings or named lists of strings:
<- "Fusce id ipsum consequat ante pellentesque iaculis eu a ipsum. Mauris id ex in nulla consectetur aliquam. In nec tempus diam. Aliquam arcu nibh, dapibus id ex vestibulum, feugiat consequat erat. Morbi feugiat dapibus malesuada. Quisque vel ullamcorper felis. Aenean a sem at nisi tempor pretium sit amet quis lacus."
n
tt(lorem, notes = n, width = 1)
Lorem | Ipsum |
---|---|
Fusce id ipsum consequat ante pellentesque iaculis eu a ipsum. Mauris id ex in nulla consectetur aliquam. In nec tempus diam. Aliquam arcu nibh, dapibus id ex vestibulum, feugiat consequat erat. Morbi feugiat dapibus malesuada. Quisque vel ullamcorper felis. Aenean a sem at nisi tempor pretium sit amet quis lacus. | |
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. | Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos. |
When notes
is a named list, the names are used as identifiers and displayed as superscripts:
tt(x, notes = list(a = "Blah.", b = "Blah blah."))
mpg | cyl | disp | hp | drat |
---|---|---|---|---|
a Blah. | ||||
b Blah blah. | ||||
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 |
We can also add markers in individual cells by providing coordinates:
tt(x, notes = list(
a = list(i = 0:1, j = 1, text = "Blah."),
b = "Blah blah."
) )
mpga | cyl | disp | hp | drat |
---|---|---|---|---|
a Blah. | ||||
b Blah blah. | ||||
21 a | 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 |
Line breaks and text wrapping
Manual line breaks work sligthly different in LaTeX (PDF) or HTML. This table shows the two strategies. For HTML, we insert a <br>
tag. For LaTeX, we wrap the string in curly braces {}
, and then insert two (escaped) backslashes: \\\\
<- data.frame(
d "{Sed ut \\\\ perspiciatis unde}",
"dicta sunt<br> explicabo. Nemo"
|> setNames(c("LaTeX line break", "HTML line break"))
) tt(d, width = 1)
LaTeX line break | HTML line break |
---|---|
{Sed ut \\ perspiciatis unde} | dicta sunt explicabo. Nemo |
Output formats
tinytable
can produce tables in HTML, Word, Markdown, LaTeX, Typst, PDF, or PNG format. An appropriate output format for printing is automatically selected based on (1) whether the function is called interactively, (2) is called within RStudio, and (3) the output format of the Rmarkdown or Quarto document, if applicable. Alternatively, users can specify the print format in print()
or by setting a global option:
tt(x) |> print("markdown")
tt(x) |> print("html")
tt(x) |> print("latex")
options(tinytable_print_output = "markdown")
With the save_tt()
function, users can also save tables directly to PNG (images), PDF or Word documents, and to any of the basic formats. All we need to do is supply a valid file name with the appropriate extension (ex: .png
, .html
, .pdf
, etc.):
tt(x) |> save_tt("path/to/file.png")
tt(x) |> save_tt("path/to/file.pdf")
tt(x) |> save_tt("path/to/file.docx")
tt(x) |> save_tt("path/to/file.html")
tt(x) |> save_tt("path/to/file.tex")
tt(x) |> save_tt("path/to/file.md")
save_tt()
can also return a string with the table in it, for further processing in R
. In the first case, the table is printed to console with cat()
. In the second case, it returns as a single string as an R
object.
tt(mtcars[1:10, 1:5]) |>
group_tt(
i = list(
"Hello" = 3,
"World" = 8),
j = list(
"Foo" = 2:3,
"Bar" = 4:5)) |>
print("markdown")
+------+-----+------+-----+------+
| | Foo | Bar |
+------+-----+------+-----+------+
| mpg | cyl | disp | hp | drat |
+======+=====+======+=====+======+
| 21 | 6 | 160 | 110 | 3.9 |
+------+-----+------+-----+------+
| 21 | 6 | 160 | 110 | 3.9 |
+------+-----+------+-----+------+
| Hello |
+------+-----+------+-----+------+
| 22.8 | 4 | 108 | 93 | 3.85 |
+------+-----+------+-----+------+
| 21.4 | 6 | 258 | 110 | 3.08 |
+------+-----+------+-----+------+
| 18.7 | 8 | 360 | 175 | 3.15 |
+------+-----+------+-----+------+
| 18.1 | 6 | 225 | 105 | 2.76 |
+------+-----+------+-----+------+
| 14.3 | 8 | 360 | 245 | 3.21 |
+------+-----+------+-----+------+
| World |
+------+-----+------+-----+------+
| 24.4 | 4 | 147 | 62 | 3.69 |
+------+-----+------+-----+------+
| 22.8 | 4 | 141 | 95 | 3.92 |
+------+-----+------+-----+------+
| 19.2 | 6 | 168 | 123 | 3.92 |
+------+-----+------+-----+------+
tt(mtcars[1:10, 1:5]) |>
group_tt(
i = list(
"Hello" = 3,
"World" = 8),
j = list(
"Foo" = 2:3,
"Bar" = 4:5)) |>
save_tt("markdown")
[1] "+------+-----+------+-----+------+\n| | Foo | Bar |\n+------+-----+------+-----+------+\n| mpg | cyl | disp | hp | drat |\n+======+=====+======+=====+======+\n| 21 | 6 | 160 | 110 | 3.9 |\n+------+-----+------+-----+------+\n| 21 | 6 | 160 | 110 | 3.9 |\n+------+-----+------+-----+------+\n| Hello |\n+------+-----+------+-----+------+\n| 22.8 | 4 | 108 | 93 | 3.85 |\n+------+-----+------+-----+------+\n| 21.4 | 6 | 258 | 110 | 3.08 |\n+------+-----+------+-----+------+\n| 18.7 | 8 | 360 | 175 | 3.15 |\n+------+-----+------+-----+------+\n| 18.1 | 6 | 225 | 105 | 2.76 |\n+------+-----+------+-----+------+\n| 14.3 | 8 | 360 | 245 | 3.21 |\n+------+-----+------+-----+------+\n| World |\n+------+-----+------+-----+------+\n| 24.4 | 4 | 147 | 62 | 3.69 |\n+------+-----+------+-----+------+\n| 22.8 | 4 | 141 | 95 | 3.92 |\n+------+-----+------+-----+------+\n| 19.2 | 6 | 168 | 123 | 3.92 |\n+------+-----+------+-----+------+"
Combination and exploration
Tables can be explored, modified, and combined using many of the usual base R
functions:
<- tt(mtcars[1:2, 1:2])
a a
mpg | cyl |
---|---|
21 | 6 |
21 | 6 |
dim(a)
[1] 2 2
ncol(a)
[1] 2
nrow(a)
[1] 2
colnames(a)
[1] "mpg" "cyl"
Tables can be combined with the usual rbind()
function:
<- tt(mtcars[1:3, 1:2], caption = "Combine two tiny tables.")
a <- tt(mtcars[4:5, 8:10])
b
rbind(a, b)
mpg | cyl | vs | am | gear |
---|---|---|---|---|
21 | 6 | |||
21 | 6 | |||
22.8 | 4 | |||
vs | am | gear | ||
1 | 0 | 3 | ||
0 | 0 | 3 |
rbind(a, b) |> format_tt(replace = "")
mpg | cyl | vs | am | gear |
---|---|---|---|---|
21 | 6 | |||
21 | 6 | |||
22.8 | 4 | |||
vs | am | gear | ||
1 | 0 | 3 | ||
0 | 0 | 3 |
The rbind2()
S4 method is slightly more flexible than rbind()
, as it supports arguments headers
and use.names
.
Omit y
header:
rbind2(a, b, headers = FALSE)
mpg | cyl | vs | am | gear |
---|---|---|---|---|
21 | 6 | |||
21 | 6 | |||
22.8 | 4 | |||
1 | 0 | 3 | ||
0 | 0 | 3 |
Bind tables by position rather than column names:
rbind2(a, b, use_names = FALSE)
mpg | cyl | gear |
---|---|---|
21 | 6 | |
21 | 6 | |
22.8 | 4 | |
vs | am | gear |
1 | 0 | 3 |
0 | 0 | 3 |
Renaming columns
As noted above, tinytable
tries to be standards-compliant, by defining methods for many base R
functions. The benefit of this approach is that instead of having to learn a tinytable
-specific syntax, users can rename columns using all the tools they already know:
<- tt(mtcars[1:2, 1:2])
a colnames(a) <- c("a", "b")
a
a | b |
---|---|
21 | 6 |
21 | 6 |
In a pipe-based workflow, we can use the setNames()
function from base R
:
1:2, 1:2] |>
mtcars[tt() |>
setNames(c("a", "b"))
a | b |
---|---|
21 | 6 |
21 | 6 |