$$~$$

My previous workflow was pretty tedious, as after preparing tables in R (data frames), I would export them to Excel, then copy from Excel into Word, and finally format the table in Word. Whenever I would make minor changes, it would take quite a bit of time to repeat these steps.

Fortunately, I found a package that suits my needs nicely, flextable. However, I only really need my tables in APA style (Times New Roman size 12, only horizontal lines, header row in bold, double-spaced, etc.), so I made a function just with the default settings I like to simplify my life.

### Getting Started

Let’s first load the demo data. This data set comes with base R (meaning you have it too and can directly type this command into your R console).

data("mtcars")
# Let's take a smaller sample of this data for demonstration purposes.
(dataset <- head(mtcars[1:6]))
##                    mpg cyl disp  hp drat    wt
## Mazda RX4         21.0   6  160 110 3.90 2.620
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875
## Datsun 710        22.8   4  108  93 3.85 2.320
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215
## Hornet Sportabout 18.7   8  360 175 3.15 3.440
## Valiant           18.1   6  225 105 2.76 3.460

Source the function from my github:

eval(parse("https://raw.githubusercontent.com/RemPsyc/niceplots/master/niceTableFunction.R",
encoding = 'UTF-8'))

Note: Here we cannot use the regular source() function because it involves special UTF-8 characters (i.e., greek letters for statistical symbols, such as Beta β, eta η, etc.)

$$~$$

### Make the basic table

This will open the table in your RStudio viewer.

*Warning:* running the function below for the first time will install and load the following
packages (if they are not already installed and loaded on your machine): dplyr and flextable.
Note: This will run many lines of code on your console and could take 5 minutes or more.
niceTable(dataset)
 mpg cyl disp hp drat wt 21.0 6 160 110 3.90 2.620 21.0 6 160 110 3.90 2.875 22.8 4 108 93 3.85 2.320 21.4 6 258 110 3.08 3.215 18.7 8 360 175 3.15 3.440 18.1 6 225 105 2.76 3.460

### Save as object

We can save the flextable as an object, which we can later further edit, or export to another software (e.g., Microsoft Word).

my_table <- niceTable(dataset)

### Save table to Word

save_as_docx(my_table, path = "~/nicetablehere.docx")
# This will save to, e.g., "C:/Users/Username/Documents/".
# You can change the path to where you would like to save it.
# If you do change the path manually, remember to use "R" slashes ('/' rather than '\').
# Also remember to specify the .docx extension of the file.

That’s it! Simple eh?

$$~$$

$$~$$

Let’s setup a more ‘credible’ table with actual statistics for demonstration.

We first need a bit of complicated code to create a regression model and extract some relevant statistical information.

model <- lm(mpg ~ cyl * wt * disp, mtcars)
stats.table <- as.data.frame(summary(model)$coefficients) stats.table <- cbind(row.names(stats.table), stats.table) names(stats.table) <- c("Model", "B", "SE", "t", "p") stats.table[c(2:4)] <- round(stats.table[c(2:4)], 2) stats.table$p <- round(stats.table\$p, 3)

The dataframe looks like this:

stats.table
##                   Model      B    SE     t     p
## (Intercept) (Intercept) 107.72 23.32  4.62 0.000
## cyl                 cyl -10.81  4.34 -2.49 0.020
## wt                   wt -24.76  8.47 -2.92 0.007
## disp               disp  -0.59  0.21 -2.79 0.010
## cyl:wt           cyl:wt   2.91  1.42  2.05 0.051
## cyl:disp       cyl:disp   0.08  0.03  2.81 0.010
## wt:disp         wt:disp   0.18  0.07  2.69 0.013
## cyl:wt:disp cyl:wt:disp  -0.02  0.01 -2.71 0.012

Now we can apply our function!

niceTable(stats.table)
 Model β SE t p (Intercept) 107.72 23.32 4.62 < .001 cyl -10.81 4.34 -2.49 .020 wt -24.76 8.47 -2.92 .007 disp -0.59 0.21 -2.79 .010 cyl:wt 2.91 1.42 2.05 .051 cyl:disp 0.08 0.03 2.81 .010 wt:disp 0.18 0.07 2.69 .013 cyl:wt:disp -0.02 0.01 -2.71 .012

As you can see, it automatically formatted the p, t, and SE values to italic, and the beta to β. It also formatted p values as < .001 and stripped the leading zeros (it will do the same for correlations r, R2, sr2).

Note: in order for this to work automatically, your columns must be named correctly. Currently the function will make the following conversions: p, t, SE, SD, M, F, b, r, and df to italic; R2 and sr2 to italic squared, np2 to italic η subscript-p squared, and B to β. Not seeing a symbol that should be there? Contact me and I’ll add it!

Let’s test this by simply changing our data frame names for the exercise.

test <- head(mtcars)
names(test) <- c("SD", "df", "M", "F", "b", "np2", "B", "p", "r", "R2", "sr2")
test[, 10:11] <- test[, 10:11]/10
niceTable(test)
 SD df M F b ηp2 β p r R2 sr2 21.0 6 160 110 3.90 2.620 16.46 < .001 1.0 .40 .40 21.0 6 160 110 3.90 2.875 17.02 < .001 1.0 .40 .40 22.8 4 108 93 3.85 2.320 18.61 1.00 1.0 .40 .10 21.4 6 258 110 3.08 3.215 19.44 1.00 .00 .30 .10 18.7 8 360 175 3.15 3.440 17.02 < .001 .00 .30 .20 18.1 6 225 105 2.76 3.460 20.22 1.00 .00 .30 .10

$$~$$

$$~$$

### Further editing

Often, one will need to tweak a table for a particular situation. Have no fear. This function outputs a flextable object, which can be ‘easily’ edited via the regular flextable functions. For an intro to flextable functions, see: https://cran.r-project.org/web/packages/flextable/vignettes/overview.html.

But just for a few quick formatting examples:

my_table %>%
italic(j = 1, part = "body") %>%
bg(bg = "gray", part = "header") %>%
color(color = "blue", part = "header") %>%
color(~ drat > 3.5, ~ drat + disp, color = "red") %>%
bold(~ drat > 3.5, ~ wt + hp, bold = TRUE) %>%
set_header_labels(mpg = "Miles/(US) gallon",
cyl = "Number of cylinders",
wt = "Weight (1000 lbs)")
 Miles/(US) gallon Number of cylinders disp hp drat Weight (1000 lbs) 21.0 6 160 110 3.90 2.620 21.0 6 160 110 3.90 2.875 22.8 4 108 93 3.85 2.320 21.4 6 258 110 3.08 3.215 18.7 8 360 175 3.15 3.440 18.1 6 225 105 2.76 3.460

$$~$$

$$~$$

### Concluding Statement

Make sure to check out this page again if you use the code after a time or if you encounter errors, as I periodically update or improve the code.

You can always edit the function to suit your purposes, or contact me for questions or requests to modify this function at remitheriault.wixsite.com/site/contact! Thanks for reading my guide! :) $$~$$

$$~$$

$$~$$

$$~$$

$$~$$

Updated 2020-09-09

$$~$$

$$~$$

$$~$$

$$~$$

$$~$$

$$~$$