Skip to contents
library(apa7)
library(dplyr)
library(flextable)
d <- mtcars |> 
  select(Gears = gear, Transmission = am) |> 
  mutate(Transmission = factor(Transmission, labels = c("Automatic", "Manual")))
  

The default output of the apa_chisq function is a contingency table with a chi-square test of independence in the table note. The output is a flextable, which can be modified with flextable commands.

apa_chisq(d)
#> Registered S3 method overwritten by 'ftExtra':
#>   method                  from     
#>   as_flextable.data.frame flextable

Gears

Transmission

3

4

5

n

%

n

%

n

%

Automatic

15

100.0%

4

33.3%

0

0.0%

Manual

0

0.0%

8

66.7%

5

100.0%

Note. χ2 (2) = 20.94, p < .001, Adj. Cramer’s V = .78

The table can be styled in many ways:

apa_chisq(
  d,
  font_size = 16,
  line_spacing = 3,
  text_color = "darkred",
  border_width = 2,
  border_color = "gray",
  family = "Arial"
)

Gears

Transmission

3

4

5

n

%

n

%

n

%

Automatic

15

100.0%

4

33.3%

0

0.0%

Manual

0

0.0%

8

66.7%

5

100.0%

Note. χ2 (2) = 20.94, p < .001, Adj. Cramer’s V = .78

# Automatic chi square note
apa_chisq(d)

Gears

Transmission

3

4

5

n

%

n

%

n

%

Automatic

15

100.0%

4

33.3%

0

0.0%

Manual

0

0.0%

8

66.7%

5

100.0%

Note. χ2 (2) = 20.94, p < .001, Adj. Cramer’s V = .78

# No note
apa_chisq(d, note = NA)

Gears

Transmission

3

4

5

n

%

n

%

n

%

Automatic

15

100.0%

4

33.3%

0

0.0%

Manual

0

0.0%

8

66.7%

5

100.0%

# Custom note
apa_chisq(d, note = "This is a *custom* note written in **markdown** $x > \\omega$.")

Gears

Transmission

3

4

5

n

%

n

%

n

%

Automatic

15

100.0%

4

33.3%

0

0.0%

Manual

0

0.0%

8

66.7%

5

100.0%

Note. This is a custom note written in markdown x > ω.

What if I want something completely different?

There are a lot of options out there. The flextable package has the proc_freq function, which has the ability to include row, column, and total percentages in the table.


mtcars %>% 
  proc_freq(row = "gear", 
            col = "vs")  %>%
  flextable::theme_apa()

gear

vs

0

1

Total

3

Count

12 (37.5%)

3 (9.4%)

15 (46.9%)

Mar. pct (1)

66.7% ; 80.0%

21.4% ; 20.0%

4

Count

2 (6.2%)

10 (31.2%)

12 (37.5%)

Mar. pct

11.1% ; 16.7%

71.4% ; 83.3%

5

Count

4 (12.5%)

1 (3.1%)

5 (15.6%)

Mar. pct

22.2% ; 80.0%

7.1% ; 20.0%

Total

Count

18 (56.2%)

14 (43.8%)

32 (100.0%)

(1) Columns and rows percentages

These can be turned off selectively:

mtcars %>% 
  proc_freq(row = "gear", 
            col = "vs",
            include.row_percent = FALSE, 
            include.column_percent = FALSE, 
            include.table_percent = FALSE)  %>%
  flextable::theme_apa() 

gear

vs

0

1

Total

3

12

3

15

4

2

10

12

5

4

1

5

Total

18

14

32

What if you want it to look a little different? Unfortunately, you might have to do some heavy lifting yourself. The flextable package’s tabulator function has considerable power in creating a wide variety of descriptive tables. In general, the tabulator function requires that you calculate the statistics first, and then you specify where they should go.

Here I calculate the means, standard deviations, and sample sizes of a variable.


mytable <- warpbreaks %>% 
  summarise(
    Mean = mean(breaks, na.rm = TRUE),
    stdev = sd(breaks, na.rm = TRUE),
    sample_size = sum(!is.na(breaks)),
    .by = c(wool, tension)
  ) %>%
  rename(Wool = wool) %>% 
  mutate(tension = factor(tension, labels = c("Low", "Medium", "High"))) %>% 
  flextable::tabulator(
    x = .,
    rows = "Wool",
    columns = "tension",
    M = as_paragraph(Mean),
    SD = as_paragraph(stdev),
    n = as_paragraph(sample_size)
    
  ) %>% 
  flextable::as_flextable()


my_column_names <- mytable$col_keys
header_row <- c("", rep("Tension", length(my_column_names) - 1)) %>% 
  as.list()
names(header_row) <- my_column_names

mytable %>%   
flextable::theme_apa() %>% 
  flextable::italic(i = 2, part = "header") %>% 
  flextable::add_header(values = header_row) %>% 
  flextable::merge_h(i = 1, "header") %>% 
  flextable::border(
    i = 1, 
    j = 1, 
    border.bottom = flextable::fp_border_default(
      style = "none", 
      color = "white"), 
    part = "header")

Tension

Wool

Low

Medium

High

M

SD

n

M

SD

n

M

SD

n

A

44.6

18.1

9

24.0

8.7

9

24.6

10.3

9

B

28.2

9.9

9

28.8

9.4

9

18.8

4.9

9