3.10 Tables
Cross reference tables
Using bookdown
cmd: \@ref(tab:chunk-label)
.
Note that you must provide caption
option in knitr::kable()
. Otherwise the table won’t be numbered.
And see Table \@ref(tab:mtcars).
```{r mtcars, echo=FALSE}
knitr::kable(mtcars[1:5, 1:5], caption = "The mtcars data.")
```
Refer to the Table 3.1.
mpg | cyl | disp | hp | drat | |
---|---|---|---|---|---|
Mazda RX4 | 21.0 | 6 | 160 | 110 | 3.90 |
Mazda RX4 Wag | 21.0 | 6 | 160 | 110 | 3.90 |
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 |
knitr::kable(x, format="pipe")
is useful when you want to copy-and-paste R output from console to other document, e.g., markdown.
knitr::kable(mtcars[1:5, 1:5], format = "pipe")
| | mpg| cyl| disp| hp| drat|
|:-----------------|----:|---:|----:|---:|----:|
|Mazda RX4 | 21.0| 6| 160| 110| 3.90|
|Mazda RX4 Wag | 21.0| 6| 160| 110| 3.90|
|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|
3.10.1 knitr::kable
knitr::kable(x, digits, caption=NULL, escape=TRUE)
Create tables in LaTeX, HTML, Markdown and reStructuredText.
caption
The table caption. In order to number the table, mut specify thecaption
argument.format
Possible values arelatex
,html
,pipe
(Pandoc’s pipe tables),simple
(Pandoc’s simple tables),rst
, andjira
.The value of this argument will be automatically determined if the function is called within a knitr document.
digits
Maximum number of digits for numeric columns, passed toround()
.col.names
Rename columns.escape=TRUE
Whether to escape special characters when producing HTML or LaTeX tables. Default isTRUE
, special characters will either be escaped or substituted. For example,$
is escaped as\$
,_
is escaped as\_
, and\
is substituted with\textbackslash{}
- When set to
FALSE
, you have to make sure yourself that special characters will not trigger syntax errors in LaTeX or HTML. - Common special LaTeX characters include
#
,%
,&
,{
, and}
. Common special HTML characters include&
,<
,>
, and"
. You need to be cautious when generating tables withescape = FALSE
, and make sure you are using the special characters in the right way. It is a very common mistake to useescape = FALSE
and include%
or_
in column names or the caption of a LaTeX table without realizing that they are special.
- When set to
align
Column alignment: a character vector consisting of'l'
(left),'c'
(center) and/or'r'
(right).- By default or if
align = NULL
, numeric columns are right-aligned, and other columns are left-aligned. - If only one character is provided, that will apply to all columns.
- If a vector is provided, will map to each individual column specifically.
- By default or if
Missing values (
NA
) in the table are displayed asNA
by default. If you want to display them with other characters, you can set the optionknitr.kable.NA
, e.g.options(knitr.kable.NA = '')
in the YAML to hideNA
values.booktabs = TRUE
use the booktabs packagelinesep = ""
remove the extra space after every five rows in kable output (withbooktabs
option)
# For Markdown tables, use `pipe` format
> knitr::kable(head(mtcars[, 1:4]), format = "pipe")
| | mpg| cyl| disp| hp|
|:-----------------|----:|---:|----:|---:|
|Mazda RX4 | 21.0| 6| 160| 110|
|Mazda RX4 Wag | 21.0| 6| 160| 110|
|Datsun 710 | 22.8| 4| 108| 93|
|Hornet 4 Drive | 21.4| 6| 258| 110|
|Hornet Sportabout | 18.7| 8| 360| 175|
|Valiant | 18.1| 6| 225| 105|
# For Plain tables in txt, `simple` is useful
> knitr::kable(head(mtcars[, 1:4]), format = "simple")
mpg cyl disp hp
------------------ ----- ---- ----- ----
Mazda RX4 21.0 6 160 110
Mazda RX4 Wag 21.0 6 160 110
Datsun 710 22.8 4 108 93
Hornet 4 Drive 21.4 6 258 110
Hornet Sportabout 18.7 8 360 175
Valiant 18.1 6 225 105
3.10.2 Data frame printing
To show the tibble
information (number of row/columns, and group information) along with paged output, we can write a custom function by modifying the print.paged_df
function (which is used internally by rmarkdown for the df_print
feature) and use CSS to nicely format the output.
https://stackoverflow.com/a/76014674/10108921
Paged df
- https://bookdown.org/yihui/rmarkdown/html-document.html#tab:paged
- https://github.com/rstudio/rmarkdown/issues/1403
---
title: "Use caption with df_print set to page"
date: "2025-06-17"
output:
bookdown::html_document2:
df_print: paged
---
When the df_print
option is set to paged
, tables are printed as HTML tables with support for pagination over rows and columns.
The possible values of the df_print
option for the html_document
format.
Option | Description |
---|---|
default |
Call the print.data.frame generic method; console output prefixed by ## ; |
kable |
Use the knitr::kable function; looks nice but with no navigation for rows and columns, neither column types. |
tibble |
Use the tibble::print.tbl_df function, this provides groups and counts of rows and columns info as if printing a tibble . |
paged |
Use rmarkdown::paged_table to create a pageable table; paged looks best but slows down compilation significantly; |
A custom function | Use the function to create the table |
The possible values of the df_print
option for the pdf_document
format: default
, kable
, tibble
, paged
, or a custom function.
paged print
```{r echo=TRUE, paged.print=TRUE}
ggplot2::diamonds
```
default output
```{r echo=TRUE, paged.print=FALSE}
ggplot2::diamonds
```
kable output
```{r echo=TRUE}
knitr::kable(ggplot2::diamonds[1:10, ])
```
Note that kable
output doesn’t provide tibble information.
Available options for paged
tables:
Option | Description |
---|---|
max.print | The number of rows to print. |
rows.print | The number of rows to display. |
cols.print | The number of columns to display. |
cols.min.print | The minimum number of columns to display. |
pages.print | The number of pages to display under page navigation. |
paged.print | When set to FALSE turns off paged tables. |
rownames.print | When set to FALSE turns off row names. |
These options are specified in each chunk like below:
For pdf_document, it is possible to write LaTex code directly.
Do not forget the equal sign before latex
, i.e., it is =latex
instead of latex
.
3.10.3 Stargazer
stargazer
print nice tables in Rmd
documents and R
scripts:
Passing a data frame to stargazer package creates a summary statistic table.
Passing a regression object creates a nice regression table.
Support tables output in multiple formats:
text
,latex
, andhtml
.- In
R
scripts, usetype = "text"
for a quick view of results.
- In
stargaer
does NOT work withanova
table, usepander::pander
instead.
Text table
Specify stargazer(type = "text")
```{r descrptive-analysis-text, comment = ''}
apply(data[,-1], 2, get_stat) %>%
stargazer(type = "text", digits=2)
```
The text output looks like the following.
===============================================
Dependent variable:
---------------------------
delta_infl
-----------------------------------------------
unemp -0.091
(0.126)
Constant 0.518
(0.743)
-----------------------------------------------
Observations 203
R2 0.003
Adjusted R2 -0.002
Residual Std. Error 2.833 (df = 201)
F Statistic 0.517 (df = 1; 201)
===============================================
Note: *p<0.1; **p<0.05; ***p<0.01
By default, stargazer
uses ***
, **
, and *
to denote statistical significance at the one, five, and ten percent levels (* p<0.1; ** p<0.05; *** p<0.01
). In contrast, summary.lm
uses * p<0.05, ** p<0.01, *** p< 0.001
.
You can change the cutoffs for significance using star.cutoffs = c(0.05, 0.01, 0.001)
.
There is one empty line after each coefficient, to remove the empty lines, specify no.space = TRUE
.
The regression table with all empty lines removed:
===============================================
Dependent variable:
---------------------------
delta_infl
-----------------------------------------------
unemp -0.091
(0.126)
Constant 0.518
(0.743)
-----------------------------------------------
Observations 203
R2 0.003
Adjusted R2 -0.002
Residual Std. Error 2.833 (df = 201)
F Statistic 0.517 (df = 1; 201)
===============================================
Note: *p<0.1; **p<0.05; ***p<0.01
HTML table
Note that you need to specify results="asis"
in the chunk options. This option tells knitr
to treat verbatim code blocks “as is.” Otherwise, instead of your table, you will see the raw html or latex code.
- Note that
*
’s do not show properly in html output, see Fig. 3.9, need to specify in the footnote (notes
) manually.

Figure 3.9: Failed to show significance codes.
Use the following code to display the correct significance symbols. See Fig. 3.10 for the expected output.
```{r descrptive-analysis-html, results="asis"}
apply(data[,-1], 2, get_stat) %>%
stargazer(type = "html", digits=2,
notes = "<span>*</span>: p<0.1; <span>**</span>: <strong>p<0.05</strong>; <span>***</span>: p<0.01 <br> Standard errors in parentheses.",
notes.append = F)
```

Figure 3.10: Correct significance codes.
Common arguments:
type
specify output table format. Possible values:latex
(default for latex code),html
, andtext
. Need to specify tohtml
in html outputs.digits
an integer that indicates how many decimal places should be used. A value ofNULL
indicates that no rounding should be done at all, and that all available decimal places should be reported. Defaults to 3 digits.notes
a character vector containing notes to be included below the table.notes.append = FALSE
a logical value that indicates whethernotes
should be appended to the existing standard note(s) associated with the table’sstyle
(typically an explanation of significance cutoffs).- Defaults to
TRUE
. - If the argument’s value is set to
FALSE
, the character strings provided innotes
will replace any existing/default notes.
- Defaults to
notes.align
"l"
for left alignment,"r"
for right alignment, and"c"
for centering. This argument is not case-sensitive.single.row = TRUE
to put coefficients and standard errors on same lineno.space = TRUE
to remove the spaces after each line of coefficientsfont.size = "small"
to make font size smallercolumn.labels
a character vector of labels for columns in regression tables.This is useful to denote different regressions, informing the name/nature of the model, instead of using numers to identify them.
column.separate
a numeric vector that specifies howcolumn.labels
should be laid out across regression table columns. A value ofc(2, 1, 3)
, for instance, will apply the first label to the two first columns, the second label to the third column, and the third label will apply to the following three columns (i.e., columns number four, five and six).dep.var.labels
labels for dependent variablescovariate.labels
labels for covariates in the regression tables.Can provide latex symbols in the labels, need to escape special symbols though.
add.lines
add a row(s), such as reporting fixed effects.
Add a blank line under the stargazer
table:
with a blank line above and below.
Cross reference stargazer
tables.
In pdf output, use
Table \@ref(tab:reg-table)
orTable \ref{tab:reg-table}
.Table \@ref(tab:reg-table) summarize the regression results in a table. ```{r, include=TRUE, results='asis'} stargazer(capm_ml, FF_ml, type='latex', header=FALSE, digits=4, no.space = TRUE, title="Regression Results for META", label = "tab:reg-table") ```
header=FALSE
is to suppress the% Table created by stargazer
header. This applies to onlylatex
tables.label="tab:reg-table"
is to specify the cross reference label for the table.table.placement = "H"
set float toH
to fix positions. Places the float at precisely the location in the code. This requires thefloat
LaTeX package. Remember to load it in the YAML.Defaults to
"!htbp"
.The
htbp
controls where the table or figure is placed. Tables and figures do not need to go where you put them in the text. LATEX moves them around to prevent large areas of white space from appearing in your paper.h
(Here): Place the float here, i.e., approximately at the same point it occurs in the source text (however, not exactly at the spot)t
(Top): Place the table at the top of the current pageb
(Bottom): Place the table at the bottom of the current page.p
(Page): Place the table at the top of the next page.!
: Override internal parameters LaTeX uses for determining “good” float positions.
align = FALSE
a logical value indicating whether numeric values in the same column should be aligned at the decimal mark in LaTeX output.
In html output, cross references to stargazer tables are not so straightforward.
label
option instargazer
does not work. Cannot use chunk labels either.```{r fit-age, echo=FALSE, results='asis', fig.cap="Logistic regression of CHD on age."} # Use title caption from fig.cap tit <- knitr::opts_current$get("fig.cap") # Adding caption for html output tit_html <- paste0('<span id="tab:', knitr::opts_current$get("label"), '">(#tab:', knitr::opts_current$get("label"), ')</span>', tit) stargazer::stargazer(fit.age, label = paste0("tab:", knitr::opts_current$get("label")), title = ifelse(knitr::is_latex_output(), tit, tit_html), type = ifelse(knitr::is_latex_output(),"latex","html"), notes = "<span>*</span>: p<0.1; <span>**</span>: <strong>p<0.05</strong>; <span>***</span>: p<0.01 <br> Standard errors in parentheses.", notes.append = F, header = F ) ``` Here is another reference to stargazer Table \@ref(tab:fit-age).
Don’t change things unless it is absolutely necessary. Run the code chunk before compiling the whole website. It gets slowly as the website gets larger.
stargazer::stargazer()
the::
is necessary, andheader=F
is necessary and should be place at the end, otherwise will have errors as follows.Error in `.stargazer.wrap()`: ! argument is missing, with no default Backtrace: 1. stargazer::stargazer(...) 2. stargazer:::.stargazer.wrap(...) Execution halted Exited with status 1.
Another example if you don’t need to add footnotes.
```{r mytable, results='asis', fig.cap="This is my table."} # Use title caption from fig.cap tit <- knitr::opts_current$get("fig.cap") # Adding caption for html output tit_html <- paste0('<span id="tab:', knitr::opts_current$get("label"), '">(#tab:', knitr::opts_current$get("label"), ')</span>', tit) stargazer::stargazer(fit.age, label = paste0("tab:", knitr::opts_current$get("label")), title = ifelse(knitr::is_latex_output(), tit, tit_html), type = ifelse(knitr::is_latex_output(),"latex","html"), header = F ) ``` Here is a reference to stargazer Table \@ref(tab:mytable).
Alignment of Stargazer Tables
In PDF, the tables will be in the center by default.
However, when working with HTML output, you need to add CSS styling to adjust the table.
References:
3.10.4 kableExtra
The kableExtra package is designed to extend the basic functionality of tables produced using knitr::kable()
.
kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
bootstrap_options
A character vector for bootstrap table options. Please see package vignette or visit the w3schools’ Bootstrap Page for more information. Possible options includebasic
,striped
,bordered
,hover
,condensed
,responsive
andnone
.striped
alternating row colorshover
Use the:hover
selector ontr
(table row) to highlight table rows on mouse over.
full_width
ATRUE
orFALSE
variable controlling whether the HTML table should have 100% the preferable format forfull_width
. If not specified,TRUE
for a HTML table , will have full width by default but- this option will be set to
FALSE
for a LaTeX table.
latex_options
A character vector for LaTeX table options, i.e., won’t have effecs on html tables.Possible options:
Arguments Meanings striped
Add alternative row colors to the table. It will imports LaTeX
packagexcolor
if enabled.scale_down
useful for super wide table. It will automatically adjust the table to fit the page width. repeat_header
only meaningful in a long table environment. It will let the header row repeat on every page in that long table. hold_position
“hold” the floating table to the exact position. It is useful when the LaTeX
table is contained in atable
environment after you specified captions inkable()
. It will force the table to stay in the position where it was created in the document.HOLD_position
A stronger version of hold_position
. Requires the float package and specifies [H].
Rows and columns can be grouped via the functions pack_rows()
and add_header_above()
, respectively.
scroll_box(width = "100%", height = "500px")
let you create a fixed height table while making it scrollable. This function only works for html long tables.
# commonly used settings
table %>%
knitr::kable(digits = 5) %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE, latex_options="scale_down") %>%
scroll_box(width = "100%", height = "500px")
# escape=TRUE, this makes your life easier, will output the table exactly as it is
result <- read_csv("~/Documents/GDP/data/reg_result/IFE_result.csv")
result %>%
knitr::kable(digits = 5, escape=T) %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE, latex_options="scale_down")
# escape=FALSE, have to specify escape by replace `*` to `\\\\*`
result <- read_csv("~/Documents/GDP/data/reg_result/IFE_result.csv")
result <- result %>%
mutate(pval.symbol = gsub("[*]", "\\\\*", pval.symbol) )
result %>%
knitr::kable(digits = 5, escape=FALSE) %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE, latex_options="scale_down")
tables in pdf output
reg_data %>%
select(Date, adjusted, eRi, rmrf) %>%
head(10) %>%
knitr::kable(digits = c(0,2,4,4), escape=T, format = "latex", booktabs = TRUE, linesep = "" ) %>%
kable_styling(latex_options = c("striped"), full_width = FALSE, stripe_color = "gray!15")
knitr::kable()
arguments
format = "latex"
specifies the output format.align = "l"
specifies column alignment.booktabs = TRUE
is generally recommended for formatting LaTeX tables.linesep = ""
prevents default behavior of extra space every five rows.
kableExtra::kable_styling()
arguments
position = "left"
places table on left hand side of page.latex_options = c("striped", "repeat_header")
implements table striping with repeated headers for tables that span multiple pages.stripe_color = "gray!15"
species the stripe color using LaTeX color specification from the xcolor package - this specifies a mix of 15% gray and 85% white.
linebreak(x, align = "l", double_escape = F, linebreaker = "\n")
Make linebreak in LaTeX Table cells.
align="l"
Choose from “l”, “c” or “r”. Defaults to “l”.
Customize the looks for columns/rows
kableExtra::column_spec(kable_input)
this function allows users to select a column and then specify its look.
row_spec()
works similar with column_spec()
but defines specifications for rows.
- For the position of the target row, you don’t need to count in header rows or the group labeling rows.
row_spec(row = 0, align='c')
specify format of the header row. Here I want to center align headers.
Add header rows to group columns
add_header_above()
. The header variable is supposed to be a named character with the names as new column names and values as column span. For your convenience, if column span equals to 1, you can ignore the =1
part so the function below can be written as add_header_above(c("", "Group 1" = 2, "Group 2" = 2, "Group 3" = 2))
.
kbl(dt) %>%
kable_classic() %>%
add_header_above(c(" " = 1, "Group 1" = 2, "Group 2" = 2, "Group 3" = 2))
You can add another row of header on top.
Group rows
collapse_rows
will put repeating cells in columns into multi-row cells. The vertical alignment of the cell is controlled by valign
with default as “top”.
Not working for html output.
collapse_rows_dt <- data.frame(C1 = c(rep("a", 10), rep("b", 5)),
C2 = c(rep("c", 7), rep("d", 3), rep("c", 2), rep("d", 3)),
C3 = 1:15,
C4 = sample(c(0,1), 15, replace = TRUE))
kbl(collapse_rows_dt, align = "c") %>%
kable_paper(full_width = F) %>%
column_spec(1, bold = T) %>%
collapse_rows(columns = 1:2, valign = "top")
Empty string as column name in tibble
: use setNames
or attr
df <- tibble(" "=1)
setNames(df, "")
# # A tibble: 1 x 1
# ``
# <dbl>
# 1 1
attr(df, "names") <- c("")
footnote()
add footnotes to tables. There are four notation systems in footnote
, namely general
(no prefix for footnotes), number
, alphabet
and symbol
.
Math in rmd tables
knitr::kable(x, escape=TRUE)
escape=TRUE
whether to escape special characters when producing HTML or LaTeX tables.- Defaults to
TRUE
. - When
escape = FALSE
, you have to make sure that special characters will not trigger syntax errors in LaTeX or HTML.
- Defaults to
You need to escape \
passed into R code.
```{r, echo=FALSE}
library(knitr)
mathy.df <- data.frame(site = c("A", "B"),
b0 = c(3, 4),
BA = c(1, 2))
colnames(mathy.df) <- c("Site", "$\\beta_0$", "$\\beta_A$")
kable(mathy.df, escape=FALSE)
```
It is possible to edit Latex table directly in Rmd
.
- Don’t enclose in
$$
. - Use
\begin{table}
and start your table data.