Appendix J — Table Formatting

Flextable is a great package for formatting tables.

library(flextable)

J.1 Data

First, let’s get some data. I’ve included a subset of data for the first nine pokemon from Dave Parr’s pokedex package. We have some character and numeric columns, plus some missing data (not all pokemon have a secondary type).

# devtools::install_github("DaveParr/pokedex")
# data from pokedex::pokemon

pokemon <- data.frame(
  id = 1:9, 
  name = c("Bulbasaur", "Ivysaur", "Venusaur",
           "Charmander", "Charmeleon", "Charizard",
           "Squirtle", "Wartortle", "Blastoise"),
  height = c(0.7, 1, 2, 0.6, 1.1, 1.7, 0.5, 1, 1.6),
  weight = c(6.9, 13, 100, 8.5, 19, 90.5, 9, 22.5, 85.5), 
  type_1 = c("grass", "grass", "grass", 
             "fire", "fire", "fire", 
             "water", "water", "water"), 
  type_2 = c("poison", "poison", "poison", 
             NA, NA, "flying", 
             NA, NA, NA)
)

J.2 Basic table

Look at how the table displays by default. This will display in one way in RStudio, but a different way when you render the document, so also render it and look at the HTML version.

pokemon
Table J.1: A default table display
id name height weight type_1 type_2
1 Bulbasaur 0.7 6.9 grass poison
2 Ivysaur 1.0 13.0 grass poison
3 Venusaur 2.0 100.0 grass poison
4 Charmander 0.6 8.5 fire NA
5 Charmeleon 1.1 19.0 fire NA
6 Charizard 1.7 90.5 fire flying
7 Squirtle 0.5 9.0 water NA
8 Wartortle 1.0 22.5 water NA
9 Blastoise 1.6 85.5 water NA

Now see how it looks if you use flextable().

flextable(pokemon)
Table J.2: A basic flextable

id

name

height

weight

type_1

type_2

1

Bulbasaur

0.7

6.9

grass

poison

2

Ivysaur

1.0

13.0

grass

poison

3

Venusaur

2.0

100.0

grass

poison

4

Charmander

0.6

8.5

fire

5

Charmeleon

1.1

19.0

fire

6

Charizard

1.7

90.5

fire

flying

7

Squirtle

0.5

9.0

water

8

Wartortle

1.0

22.5

water

9

Blastoise

1.6

85.5

water

J.3 Cusomising tables

J.3.1 Subset/reorder columns

You can use the col_keys argument to select a subset of columns, or change their order. You can also do this with data wrangling before you send a data frame to flextable, but this can be easier in some instances.

flextable(pokemon, 
          col_keys = c("name", "weight", "height"))
Table J.3: Subsetting columns with col_keys

name

weight

height

Bulbasaur

6.9

0.7

Ivysaur

13.0

1.0

Venusaur

100.0

2.0

Charmander

8.5

0.6

Charmeleon

19.0

1.1

Charizard

90.5

1.7

Squirtle

9.0

0.5

Wartortle

22.5

1.0

Blastoise

85.5

1.6

J.3.3 Alignment

The defaults are usually correct, left-aligning text and right-aligning numbers, but you can also customise this using the align() function.

The code below centre aligns the first row of the header to “center”, and then right aligns the body cells in the “name” column.

flextable(pokemon) |>
  add_header_row(values = c("", "Measurements", "Types"),
                colwidths = c(2, 2, 2)) |>
  set_header_labels(type_1 = "primary", 
                    type_2 = "secondary") |>
  align(align = "center", i = 1, part = "header") |>
  align(align = "right", j = "name", part = "body")

Measurements

Types

id

name

height

weight

primary

secondary

1

Bulbasaur

0.7

6.9

grass

poison

2

Ivysaur

1.0

13.0

grass

poison

3

Venusaur

2.0

100.0

grass

poison

4

Charmander

0.6

8.5

fire

5

Charmeleon

1.1

19.0

fire

6

Charizard

1.7

90.5

fire

flying

7

Squirtle

0.5

9.0

water

8

Wartortle

1.0

22.5

water

9

Blastoise

1.6

85.5

water

Note

See if you can figure out what i and j mean, using trial-and-error first, and the help function if you get stuck.

J.4 Themes

There are some built-in themes you can use.

J.4.1 Alafoli

flextable(pokemon) |> theme_alafoli()
Table J.7: The alafoli theme

id

name

height

weight

type_1

type_2

1

Bulbasaur

0.7

6.9

grass

poison

2

Ivysaur

1.0

13.0

grass

poison

3

Venusaur

2.0

100.0

grass

poison

4

Charmander

0.6

8.5

fire

5

Charmeleon

1.1

19.0

fire

6

Charizard

1.7

90.5

fire

flying

7

Squirtle

0.5

9.0

water

8

Wartortle

1.0

22.5

water

9

Blastoise

1.6

85.5

water

J.4.2 APA

flextable(pokemon) |> theme_apa()
Table J.8: The apa theme

id

name

height

weight

type_1

type_2

1

Bulbasaur

0.70

6.90

grass

poison

2

Ivysaur

1.00

13.00

grass

poison

3

Venusaur

2.00

100.00

grass

poison

4

Charmander

0.60

8.50

fire

5

Charmeleon

1.10

19.00

fire

6

Charizard

1.70

90.50

fire

flying

7

Squirtle

0.50

9.00

water

8

Wartortle

1.00

22.50

water

9

Blastoise

1.60

85.50

water

J.4.3 Booktabs

flextable(pokemon) |> theme_booktabs()
Table J.9: The booktabs theme

id

name

height

weight

type_1

type_2

1

Bulbasaur

0.7

6.9

grass

poison

2

Ivysaur

1.0

13.0

grass

poison

3

Venusaur

2.0

100.0

grass

poison

4

Charmander

0.6

8.5

fire

5

Charmeleon

1.1

19.0

fire

6

Charizard

1.7

90.5

fire

flying

7

Squirtle

0.5

9.0

water

8

Wartortle

1.0

22.5

water

9

Blastoise

1.6

85.5

water

J.4.4 Box

flextable(pokemon) |> theme_box()
Table J.10: The box theme

id

name

height

weight

type_1

type_2

1

Bulbasaur

0.7

6.9

grass

poison

2

Ivysaur

1.0

13.0

grass

poison

3

Venusaur

2.0

100.0

grass

poison

4

Charmander

0.6

8.5

fire

5

Charmeleon

1.1

19.0

fire

6

Charizard

1.7

90.5

fire

flying

7

Squirtle

0.5

9.0

water

8

Wartortle

1.0

22.5

water

9

Blastoise

1.6

85.5

water

J.4.5 Tron

flextable(pokemon) |> theme_tron()
Table J.11: The tron theme

id

name

height

weight

type_1

type_2

1

Bulbasaur

0.7

6.9

grass

poison

2

Ivysaur

1.0

13.0

grass

poison

3

Venusaur

2.0

100.0

grass

poison

4

Charmander

0.6

8.5

fire

5

Charmeleon

1.1

19.0

fire

6

Charizard

1.7

90.5

fire

flying

7

Squirtle

0.5

9.0

water

8

Wartortle

1.0

22.5

water

9

Blastoise

1.6

85.5

water

J.4.6 Tron Legacy

flextable(pokemon) |> theme_tron_legacy()
Table J.12: The tron_legacy theme

id

name

height

weight

type_1

type_2

1

Bulbasaur

0.7

6.9

grass

poison

2

Ivysaur

1.0

13.0

grass

poison

3

Venusaur

2.0

100.0

grass

poison

4

Charmander

0.6

8.5

fire

5

Charmeleon

1.1

19.0

fire

6

Charizard

1.7

90.5

fire

flying

7

Squirtle

0.5

9.0

water

8

Wartortle

1.0

22.5

water

9

Blastoise

1.6

85.5

water

J.4.7 Vader

flextable(pokemon) |> theme_vader()
Table J.13: The vader theme

id

name

height

weight

type_1

type_2

1

Bulbasaur

0.7

6.9

grass

poison

2

Ivysaur

1.0

13.0

grass

poison

3

Venusaur

2.0

100.0

grass

poison

4

Charmander

0.6

8.5

fire

5

Charmeleon

1.1

19.0

fire

6

Charizard

1.7

90.5

fire

flying

7

Squirtle

0.5

9.0

water

8

Wartortle

1.0

22.5

water

9

Blastoise

1.6

85.5

water

J.4.8 Vanilla

flextable(pokemon) |> theme_vanilla()
Table J.14: The vanilla theme

id

name

height

weight

type_1

type_2

1

Bulbasaur

0.7

6.9

grass

poison

2

Ivysaur

1.0

13.0

grass

poison

3

Venusaur

2.0

100.0

grass

poison

4

Charmander

0.6

8.5

fire

5

Charmeleon

1.1

19.0

fire

6

Charizard

1.7

90.5

fire

flying

7

Squirtle

0.5

9.0

water

8

Wartortle

1.0

22.5

water

9

Blastoise

1.6

85.5

water

J.5 Defaults

You can set a ton of defaults using set_flextable_defaults(). Do this at the top of your script and all of the tables in your document will have consistent styles.

set_flextable_defaults(digits = 2, 
                       font.size = 16, 
                       theme_fun = theme_apa,
                       na_str = "(none)")
flextable(pokemon)

id

name

height

weight

type_1

type_2

1

Bulbasaur

0.70

6.90

grass

poison

2

Ivysaur

1.00

13.00

grass

poison

3

Venusaur

2.00

100.00

grass

poison

4

Charmander

0.60

8.50

fire

(none)

5

Charmeleon

1.10

19.00

fire

(none)

6

Charizard

1.70

90.50

fire

flying

7

Squirtle

0.50

9.00

water

(none)

8

Wartortle

1.00

22.50

water

(none)

9

Blastoise

1.60

85.50

water

(none)

J.6 Next Steps

You can learn a lot more about how to customisie tables from the flextable book.

  1. As a group, make a list of things you might want to do to tables, like highlight a row, add footnotes, include images, or set border styles.
  2. Divide up the list and each create a short tutorial for how to accomplish the thing, using just the pokemon table.
  3. Share your tutorial with the group!