Making APA Tables with the gt Package
R
has always been a very powerful statistical analysis tool. With the development of ggplot
, it has also become an extremely powerful data visualization tool. However, in my experience, R
has lacked the ability to easily create nice tables, especially tables suitable for APA publication.
To be sure, there are a number of excellent table packages, all with their benefits and drawbacks. The ones I have personal experience with include:
- knitr::kable() -
kable()
can easily make some very nice tables in R Markdown. Just add it to the end of a pipe%>%
and you have yourself a very nice table. With a little work, and the addition ofkableExtra
, you may even be able to produce an APA-style table. In fact, here is a guide to doing just that. It requires a bit more work (e.g. adding LaTeX to YAML) but it is a really good option, especially for tables in Word. - DataTable::DT() - I love using the
DT
function for making interactive tables that are sortable, searchable, and offer pagination. I have not played around much with their styling. apaTables
is another package that produces APA tables out of the box, but only as Word or richtext outputs. They cannot be included in HTML or PDF. However, the use of apaTables functions is very useful for taking something like a regression model and getting it into the shape needed for a better table. I’ll have an example of this below.papaja
is an package that allows you to draft APA journal articles in R Markdown and creates tables withapa_table()
that render very nicely in Word or PDF but not HTML.
The gt
Package
gt
was recently (March 31, 2020) released by RStudio. The idea behind gt
follows the same philosophy that guides the tidyverse
: simplicity and standardized grammar. Specifically, gt
can be used to “construct a wide variety of useful tables with a cohesive set of table parts.”
With gt
, we can get very close (though not exact yet) to print-ready APA tables that can be rendered in R, R Markdown, HTML, and PDF formats. Let’s look at an example, break it down, learn how to modify it, learn how to simplify it, and then look at some use cases
Install gt
and load key packages
You can install gt
easily: install.packages("gt")
.
Here are the libraries we will need:
library(tidyverse)
library(gt)
Create a Basic gt
table
mtcars %>%
slice(1:5) %>%
gt()
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 |
Style the Borders
All APA tables have a black top border, a black border at the bottom of the column header, and a black bottom border. We can use the following code to recreate that look, as well as set the width and make the font size consistent with the table body:
mtcars %>%
slice(1:5) %>%
gt() %>%
tab_options(
# hide the top-most border
table.border.top.color = "white",
# make the title size match the body text
heading.title.font.size = px(16),
# change the column labels section
column_labels.border.top.width = 3,
column_labels.border.top.color = "black",
column_labels.border.bottom.width = 3,
column_labels.border.bottom.color = "black",
# change the bottom of the body
table_body.border.bottom.color = "black",
# hide the bottom-most line or footnotes
# will have a border
table.border.bottom.color = "white",
# make the width 100%
table.width = pct(100),
table.background.color = "white"
)
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 |
This is good, but it’s not perfect. We still have to deal with text centering, row striping, and internal borders, not to mention titling, adding a footnote, and, if needed, italcizing specific column labels.
One issue that I have not figured out is how to control the thickness of the black borders. Right now, for column_labels.border.top.width
, the width must be set to = 3
before any color changes. I have opened this as an issue on Github.
Styling the Table Body
mtcars %>%
slice(1:5) %>%
gt() %>%
tab_options(
table.border.top.color = "white",
heading.title.font.size = px(16),
column_labels.border.top.width = 3,
column_labels.border.top.color = "black",
column_labels.border.bottom.width = 3,
column_labels.border.bottom.color = "black",
table_body.border.bottom.color = "black",
table.border.bottom.color = "white",
table.width = pct(100),
table.background.color = "white"
) %>%
# center column text
cols_align(align="center") %>%
# set table style
tab_style(
style = list(
# remove horizontal lines
cell_borders(
sides = c("top", "bottom"),
color = "white",
weight = px(1)
),
#center text
cell_text(
align="center"
),
# remove row striping in Markdown documents
cell_fill(color = "white", alpha = NULL)
),
#do this for all columns and rows
locations = cells_body(
columns = everything(),
rows = everything()
))
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 |
This is looking very close to an APA table. However, that is a lot of code to get the basic APA look and feel. Can we simplify it?
Create an apa()
Function
The following will create an APA function that creates the basic APA table layout and includes the stylization for a title. It’s two arguments would be apa(x, title)
where x
= a data frame, and title
is a string in quotes.
apa <- function(x, title = " ") {
gt(x) %>%
tab_options(
table.border.top.color = "white",
heading.title.font.size = px(16),
column_labels.border.top.width = 3,
column_labels.border.top.color = "black",
column_labels.border.bottom.width = 3,
column_labels.border.bottom.color = "black",
table_body.border.bottom.color = "black",
table.border.bottom.color = "white",
table.width = pct(100),
table.background.color = "white"
) %>%
cols_align(align="center") %>%
tab_style(
style = list(
cell_borders(
sides = c("top", "bottom"),
color = "white",
weight = px(1)
),
cell_text(
align="center"
),
cell_fill(color = "white", alpha = NULL)
),
locations = cells_body(
columns = everything(),
rows = everything()
)
) %>%
#title setup
tab_header(
title = html("<i>", title, "</i>")
) %>%
opt_align_table_header(align = "left")
}
Let’s try it out:
mtcars %>%
slice(1:5) %>%
apa("Fuel consumption and aspects of automobile design and performance for 32 automobiles (1973-74 models)")
Fuel consumption and aspects of automobile design and performance for 32 automobiles (1973-74 models) | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
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 |
Add a Footnote
If we wanted to add a note, we would do so using an additional gt
function:
mtcars %>%
slice(1:5) %>%
apa("Fuel consumption and aspects of automobile design and performance for 32 automobiles (1973-74 models)") %>%
tab_footnote(
#footnote text
footnote = "This is a footnote.",
# add to the column labels section
locations = cells_column_labels(
# add to the "mpg" column
columns = vars(mpg))
)
Fuel consumption and aspects of automobile design and performance for 32 automobiles (1973-74 models) | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
mpg1 | 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 |
1
This is a footnote.
|
Italicize Column Text
In many APA tables, statical indicators such as p, M or n are italicized. We can do that here in the following manner:
mtcars %>%
slice(1:5) %>%
apa("Fuel consumption and aspects of automobile design and performance for 32 automobiles (1973-74 models)") %>%
tab_footnote(
footnote = "This is a footnote.",
locations = cells_column_labels(
columns = vars(mpg))
) %>%
# add an additional table style
tab_style(
style = list(
# change the text
cell_text(style="italic")
),
# specify the column
locations = cells_column_labels(
columns = vars(cyl)
)
)
Fuel consumption and aspects of automobile design and performance for 32 automobiles (1973-74 models) | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
mpg1 | 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 |
1
This is a footnote.
|
Uses
Using gt
to make APA tables could be useful if you are making HTML or PDF reports. Unfortunatley, they do not render at all correctly if you are knitting directly to Word. However, they can be outputted in RTF format, which can then be placed back into word. Here is an example
mtcars %>%
slice(1:5) %>%
gt() %>%
as_rtf() -> table
fileConn<-file("output.rtf")
writeLines(table, fileConn)
close(fileConn)
Use with apaTables
The package apaTables
is very useful for getting something into the shape for APA and has the function to export individual tables into word. We can also shape statistical results with apaTables
and then format that shape into an table with gt
.
Output Without apaTables
model <- lm(mpg ~ wt, mtcars)
summary(model)
##
## Call:
## lm(formula = mpg ~ wt, data = mtcars)
##
## Residuals:
## Min 1Q Median 3Q Max
## -4.5432 -2.3647 -0.1252 1.4096 6.8727
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 37.2851 1.8776 19.858 < 2e-16 ***
## wt -5.3445 0.5591 -9.559 1.29e-10 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 3.046 on 30 degrees of freedom
## Multiple R-squared: 0.7528, Adjusted R-squared: 0.7446
## F-statistic: 91.38 on 1 and 30 DF, p-value: 1.294e-10
Output with apaTables
model <- lm(mpg ~ wt, mtcars)
apaTables::apa.reg.table(model)
##
##
## Regression results using mpg as the criterion
##
##
## Predictor b b_95%_CI beta beta_95%_CI sr2 sr2_95%_CI r
## (Intercept) 37.29** [33.45, 41.12]
## wt -5.34** [-6.49, -4.20] -0.87 [-1.05, -0.68] .75 [.56, .83] -.87**
##
##
##
## Fit
##
##
## R2 = .753**
## 95% CI[.56,.83]
##
##
## Note. A significant b-weight indicates the beta-weight and semi-partial correlation are also significant.
## b represents unstandardized regression weights. beta indicates the standardized regression weights.
## sr2 represents the semi-partial correlation squared. r represents the zero-order correlation.
## Square brackets are used to enclose the lower and upper limits of a confidence interval.
## * indicates p < .05. ** indicates p < .01.
##
Output with apaTables
and gt
apa.reg.table
takes the regression results and builds table elements into a list. We can then use apa()
to grab the output stored in the named list elements
model <- lm(mpg ~ wt, mtcars)
apaTables::apa.reg.table(model)[["table_body"]] %>%
apa()
Predictor | b | b_95%_CI | beta | beta_95%_CI | sr2 | sr2_95%_CI | r | Fit |
---|---|---|---|---|---|---|---|---|
(Intercept) | 37.29** | [33.45, 41.12] | ||||||
wt | -5.34** | [-6.49, -4.20] | -0.87 | [-1.05, -0.68] | .75 | [.56, .83] | -.87** | |
R2 = .753** | ||||||||
95% CI[.56,.83] | ||||||||
Let’s take that even further:
data(mtcars)
model <- lm(mpg ~ wt, mtcars)
apatable <- apaTables::apa.reg.table(model)
apa(apatable[["table_body"]], apatable[["table_title"]]) %>%
tab_footnote(
footnote = apatable[["table_note"]],
locations = cells_column_labels(
columns = vars(b))
)
Regression results using mpg as the criterion | ||||||||
---|---|---|---|---|---|---|---|---|
Predictor | b1 | b_95%_CI | beta | beta_95%_CI | sr2 | sr2_95%_CI | r | Fit |
(Intercept) | 37.29** | [33.45, 41.12] | ||||||
wt | -5.34** | [-6.49, -4.20] | -0.87 | [-1.05, -0.68] | .75 | [.56, .83] | -.87** | |
R2 = .753** | ||||||||
95% CI[.56,.83] | ||||||||
1
Note. A significant b-weight indicates the beta-weight and semi-partial correlation are also significant.
b represents unstandardized regression weights. beta indicates the standardized regression weights.
sr2 represents the semi-partial correlation squared. r represents the zero-order correlation.
Square brackets are used to enclose the lower and upper limits of a confidence interval.
* indicates p < .05. ** indicates p < .01.
|
My examples may not be perfect or exact, but they give you a good idea about how you can use gt
to create HTML-based reports with APA-like tables.
If you have any suggestions for improving these tables, I’d love to hear them! I’m always looking to learn more.