+ - 0:00:00
Notes for current slide
Notes for next slide

Visualizing Data (in R)

An opinionated style guide



June Choe

Phonetics Lab

2020-10-23

1 / 51

Why?

2 / 51

Why?

Why bother making your plots look nice?

2 / 51

Why?

Why bother making your plots look nice?

  • Helps people remember your results better

2 / 51

Why?

Why bother making your plots look nice?

  • Helps people remember your results better

  • Makes your findings look more credible

2 / 51

Why?

Why bother making your plots look nice?

  • Helps people remember your results better

  • Makes your findings look more credible

  • Increases the chance of your work being shared

2 / 51

Why?

Why bother making your plots look nice?

  • Helps people remember your results better

  • Makes your findings look more credible

  • Increases the chance of your work being shared

  • Shows respect for your audience


2 / 51

Why?

Why bother making your plots look nice?

  • Helps people remember your results better

  • Makes your findings look more credible

  • Increases the chance of your work being shared

  • Shows respect for your audience


Goal of this presentation

2 / 51

Why?

Why bother making your plots look nice?

  • Helps people remember your results better

  • Makes your findings look more credible

  • Increases the chance of your work being shared

  • Shows respect for your audience


Goal of this presentation

  • Share practical tips for improving readability

2 / 51

Why?

Why bother making your plots look nice?

  • Helps people remember your results better

  • Makes your findings look more credible

  • Increases the chance of your work being shared

  • Shows respect for your audience


Goal of this presentation

  • Share practical tips for improving readability

  • Demonstrate implementations of these ideas (w/ code)

2 / 51

Outline

3 / 51

Outline

Four practical tips for improving data visualizations

3 / 51

Outline

Four practical tips for improving data visualizations

  • Make your text readable

3 / 51

Outline

Four practical tips for improving data visualizations

  • Make your text readable

  • Be generous about margins and spacing

3 / 51

Outline

Four practical tips for improving data visualizations

  • Make your text readable

  • Be generous about margins and spacing

  • Make your legends clear

3 / 51

Outline

Four practical tips for improving data visualizations

  • Make your text readable

  • Be generous about margins and spacing

  • Make your legends clear

  • Make color easy on your reader's eyes

3 / 51

Outline

Four practical tips for improving data visualizations

  • Make your text readable

  • Be generous about margins and spacing

  • Make your legends clear

  • Make color easy on your reader's eyes

Showcases

3 / 51

Outline

Four practical tips for improving data visualizations

  • Make your text readable

  • Be generous about margins and spacing

  • Make your legends clear

  • Make color easy on your reader's eyes

Showcases

  • Vowel formant plot

  • Vowel space plot

  • Bar plot of proportions

  • Multiple categorical levels

  • Animations

3 / 51

Preliminaries

Work with the {ggplot2} ecosystem in R

  • Widely used in academia

  • Easy to use and highly customizable

  • Tons of free resources for learning

  • Lots of extensions

4 / 51

Preliminaries

Work with the {ggplot2} ecosystem in R

  • Widely used in academia

  • Easy to use and highly customizable

  • Tons of free resources for learning

  • Lots of extensions

library(scales)
library(colorspace)
library(ggtext)
library(lemon)
library(gganimate)
# library(patchwork)
# library(gghighlight)
# library(ggforce)
# library(ggrepel)
5 / 51

How does it work?

Source: https://www.youtube.com/watch?v=h29g21z0a68

Source: https://www.youtube.com/watch?v=h29g21z0a68

6 / 51
state_election_votes
# A tibble: 1,097 x 3
State demVote Year
<chr> <dbl> <dbl>
1 Alabama 0.85 1932
2 Arizona 0.67 1932
3 Arkansas 0.86 1932
4 California 0.580 1932
5 Colorado 0.55 1932
6 Connecticut 0.47 1932
7 Delaware 0.48 1932
8 Florida 0.74 1932
9 Georgia 0.92 1932
10 Idaho 0.59 1932
# ... with 1,087 more rows
6 / 51
state_election_votes %>%
filter(State %in%
c("Pennsylvania",
"Illinois",
"California")
)
# A tibble: 66 x 3
State demVote Year
<chr> <dbl> <dbl>
1 California 0.580 1932
2 Illinois 0.55 1932
3 Pennsylvania 0.45 1932
4 California 0.67 1936
5 Illinois 0.580 1936
6 Pennsylvania 0.570 1936
7 California 0.570 1940
8 Illinois 0.51 1940
9 Pennsylvania 0.53 1940
10 California 0.56 1944
# ... with 56 more rows
6 / 51
state_election_votes %>%
filter(State %in%
c("Pennsylvania",
"Illinois",
"California")
) %>%
ggplot()

6 / 51
state_election_votes %>%
filter(State %in%
c("Pennsylvania",
"Illinois",
"California")
) %>%
ggplot() +
aes(
x = Year,
y = demVote,
color = State
)

6 / 51
state_election_votes %>%
filter(State %in%
c("Pennsylvania",
"Illinois",
"California")
) %>%
ggplot() +
aes(
x = Year,
y = demVote,
color = State
) +
geom_point()

6 / 51
state_election_votes %>%
filter(State %in%
c("Pennsylvania",
"Illinois",
"California")
) %>%
ggplot() +
aes(
x = Year,
y = demVote,
color = State
) +
geom_point() +
scale_y_continuous(
labels = percent_format(accuracy = 1)
)

6 / 51
state_election_votes %>%
filter(State %in%
c("Pennsylvania",
"Illinois",
"California")
) %>%
ggplot() +
aes(
x = Year,
y = demVote,
color = State
) +
geom_point() +
scale_y_continuous(
labels = percent_format(accuracy = 1)
) +
scale_x_continuous(
breaks = pretty_breaks(n= 5)
)

6 / 51
state_election_votes %>%
filter(State %in%
c("Pennsylvania",
"Illinois",
"California")
) %>%
ggplot() +
aes(
x = Year,
y = demVote,
color = State
) +
geom_point() +
scale_y_continuous(
labels = percent_format(accuracy = 1)
) +
scale_x_continuous(
breaks = pretty_breaks(n= 5)
) +
labs(
y = "Democrat Votes",
title = "Go Vote!"
)

6 / 51
state_election_votes %>%
filter(State %in%
c("Pennsylvania",
"Illinois",
"California")
) %>%
ggplot() +
aes(
x = Year,
y = demVote,
color = State
) +
geom_point() +
scale_y_continuous(
labels = percent_format(accuracy = 1)
) +
scale_x_continuous(
breaks = pretty_breaks(n= 5)
) +
labs(
y = "Democrat Votes",
title = "Go Vote!"
)

6 / 51
state_election_votes %>%
filter(State %in%
c("Pennsylvania",
"Illinois",
"California")
) %>%
ggplot() +
aes(
x = Year,
y = demVote,
color = State
) +
geom_point() +
scale_y_continuous(
labels = percent_format(accuracy = 1)
) +
scale_x_continuous(
breaks = pretty_breaks(n= 5)
) +
labs(
y = "Democrat Votes",
title = "Go Vote!"
)

6 / 51
state_election_votes %>%
filter(State %in%
c("Pennsylvania",
"Illinois",
"California")
) %>%
ggplot() +
aes(
x = Year,
y = demVote,
color = State
) +
geom_line() +
scale_y_continuous(
labels = percent_format(accuracy = 1)
) +
scale_x_continuous(
breaks = pretty_breaks(n= 5)
) +
labs(
y = "Democrat Votes",
title = "Go Vote!"
)

6 / 51
state_election_votes %>%
filter(State %in%
c("Pennsylvania",
"Illinois",
"California")
) %>%
ggplot() +
aes(
x = Year,
y = demVote,
color = State
) +
geom_line(size = 1) +
scale_y_continuous(
labels = percent_format(accuracy = 1)
) +
scale_x_continuous(
breaks = pretty_breaks(n= 5)
) +
labs(
y = "Democrat Votes",
title = "Go Vote!"
)

6 / 51

Yay a plot!

7 / 51

Yay a plot... ?

A few problems

  • Text is small and narrow

  • Plot elements are squished together

  • Color doesn't grab attention

  • Legend is off to the side on its own

8 / 51

1. Text

Many different ways to style text:

9 / 51

1. Text

Many different ways to style text:

  • font size

9 / 51

1. Text

Many different ways to style text:

  • font size

  • Font face (bold, italic, small caps)

9 / 51

1. Text

Many different ways to style text:

  • font size

  • Font face (bold, italic, small caps)

  • Font family ( Times New Roman, Calibri, Arial, Hi friends )

9 / 51

1. Text

Many different ways to style text:

  • font size

  • Font face (bold, italic, small caps)

  • Font family ( Times New Roman, Calibri, Arial, Hi friends )

  • Font color, line height, letter spacing, angle, weight, etc.

9 / 51

1. Text

Many different ways to style text:

  • font size

  • Font face (bold, italic, small caps)

  • Font family ( Times New Roman, Calibri, Arial, Hi friends )

  • Font color, line height, letter spacing, angle, weight, etc.


Unless you make your plots with html/css/js, you'll likely only have access to:

9 / 51

1. Text

Many different ways to style text:

  • font size

  • Font face (bold, italic, small caps)

  • Font family ( Times New Roman, Calibri, Arial, Hi friends )

  • Font color, line height, letter spacing, angle, weight, etc.


Unless you make your plots with html/css/js, you'll likely only have access to:

  • Font size, font family, and limited set of font styles

9 / 51

1. Text

Many different ways to style text:

  • font size

  • Font face (bold, italic, small caps)

  • Font family ( Times New Roman, Calibri, Arial, Hi friends )

  • Font color, line height, letter spacing, angle, weight, etc.


Unless you make your plots with html/css/js, you'll likely only have access to:

  • Font size, font family, and limited set of font styles

  • But you can get pretty far with these!

9 / 51
state_election_plot

9 / 51
state_election_plot +
theme(text = element_text(family = "Roboto"))

9 / 51
state_election_plot +
theme(text = element_text(family = "Roboto")) +
theme(text = element_text(size = 15))

9 / 51
state_election_plot +
theme(text = element_text(family = "Roboto")) +
theme(text = element_text(size = 15)) +
theme(plot.title = element_text(size = 20))

9 / 51
state_election_plot +
theme(text = element_text(family = "Roboto")) +
theme(text = element_text(size = 15)) +
theme(plot.title = element_text(size = 20)) +
theme(plot.title = element_text(family = "Roboto Slab"))

9 / 51
state_election_plot +
theme(text = element_text(family = "Roboto")) +
theme(text = element_text(size = 15)) +
theme(plot.title = element_text(size = 20)) +
theme(plot.title = element_text(family = "Roboto Slab")) +
theme(plot.title.position = "plot")

9 / 51
state_election_plot +
theme(text = element_text(family = "Roboto")) +
theme(text = element_text(size = 15)) +
theme(plot.title = element_text(size = 20)) +
theme(plot.title = element_text(family = "Roboto Slab")) +
theme(plot.title.position = "plot") +
labs(x = "Election Year")

9 / 51
state_election_plot +
theme(text = element_text(family = "Roboto")) +
theme(text = element_text(size = 15)) +
theme(plot.title = element_text(size = 20)) +
theme(plot.title = element_text(family = "Roboto Slab")) +
theme(plot.title.position = "plot") +
labs(x = "Election Year") +
labs(y = NULL)

9 / 51
state_election_plot +
theme(text = element_text(family = "Roboto")) +
theme(text = element_text(size = 15)) +
theme(plot.title = element_text(size = 20)) +
theme(plot.title = element_text(family = "Roboto Slab")) +
theme(plot.title.position = "plot") +
labs(x = "Election Year") +
labs(y = NULL) +
labs(title = "Percent of democrat votes by state")

9 / 51
state_election_plot +
theme(text = element_text(family = "Roboto")) +
theme(text = element_text(size = 15)) +
theme(plot.title = element_text(size = 20)) +
theme(plot.title = element_text(family = "Roboto Slab")) +
theme(plot.title.position = "plot") +
labs(x = "Election Year") +
labs(y = NULL) +
labs(title = "Percent of democrat votes by state") +
labs(subtitle = "We're a swing state! Go vote!")

9 / 51
state_election_plot +
theme(text = element_text(family = "Roboto")) +
theme(text = element_text(size = 15)) +
theme(plot.title = element_text(size = 20)) +
theme(plot.title = element_text(family = "Roboto Slab")) +
theme(plot.title.position = "plot") +
labs(x = "Election Year") +
labs(y = NULL) +
labs(title = "Percent of democrat votes by state") +
labs(subtitle = "We're a swing state! Go vote!") +
theme(plot.subtitle = element_text(face = "italic"))

9 / 51
state_election_plot +
theme(text = element_text(family = "Adelle")) +
theme(text = element_text(size = 15)) +
theme(plot.title = element_text(size = 20)) +
theme(plot.title = element_text(family = "Roboto Slab")) +
theme(plot.title.position = "plot") +
labs(x = "Election Year") +
labs(y = NULL) +
labs(title = "Percent of democrat votes by state") +
labs(subtitle = "We're a swing state! Go vote!") +
theme(plot.subtitle = element_text(face = "italic"))

9 / 51
state_election_plot +
theme(text = element_text(family = "Bitter")) +
theme(text = element_text(size = 15)) +
theme(plot.title = element_text(size = 20)) +
theme(plot.title = element_text(family = "Roboto Slab")) +
theme(plot.title.position = "plot") +
labs(x = "Election Year") +
labs(y = NULL) +
labs(title = "Percent of democrat votes by state") +
labs(subtitle = "We're a swing state! Go vote!") +
theme(plot.subtitle = element_text(face = "italic"))

9 / 51
state_election_plot +
theme(text = element_text(family = "Futura Bk BT")) +
theme(text = element_text(size = 15)) +
theme(plot.title = element_text(size = 20)) +
theme(plot.title = element_text(family = "Roboto Slab")) +
theme(plot.title.position = "plot") +
labs(x = "Election Year") +
labs(y = NULL) +
labs(title = "Percent of democrat votes by state") +
labs(subtitle = "We're a swing state! Go vote!") +
theme(plot.subtitle = element_text(face = "italic"))

9 / 51
state_election_plot +
theme(text = element_text(family = "Montserrat")) +
theme(text = element_text(size = 15)) +
theme(plot.title = element_text(size = 20)) +
theme(plot.title = element_text(family = "Roboto Slab")) +
theme(plot.title.position = "plot") +
labs(x = "Election Year") +
labs(y = NULL) +
labs(title = "Percent of democrat votes by state") +
labs(subtitle = "We're a swing state! Go vote!") +
theme(plot.subtitle = element_text(face = "italic"))

9 / 51
state_election_plot +
theme(text = element_text(family = "Montserrat Medium")) +
theme(text = element_text(size = 15)) +
theme(plot.title = element_text(size = 20)) +
theme(plot.title = element_text(family = "Roboto Slab")) +
theme(plot.title.position = "plot") +
labs(x = "Election Year") +
labs(y = NULL) +
labs(title = "Percent of democrat votes by state") +
labs(subtitle = "We're a swing state! Go vote!") +
theme(plot.subtitle = element_text(face = "italic"))

9 / 51
state_election_plot +
theme(text = element_text(family = "Arial")) +
theme(text = element_text(size = 15)) +
theme(plot.title = element_text(size = 20)) +
theme(plot.title = element_text(family = "Roboto Slab")) +
theme(plot.title.position = "plot") +
labs(x = "Election Year") +
labs(y = NULL) +
labs(title = "Percent of democrat votes by state") +
labs(subtitle = "We're a swing state! Go vote!") +
theme(plot.subtitle = element_text(face = "italic"))

9 / 51
state_election_plot +
theme(text = element_text(family = "xkcd")) +
theme(text = element_text(size = 15)) +
theme(plot.title = element_text(size = 20)) +
theme(plot.title = element_text(family = "Roboto Slab")) +
theme(plot.title.position = "plot") +
labs(x = "Election Year") +
labs(y = NULL) +
labs(title = "Percent of democrat votes by state") +
labs(subtitle = "We're a swing state! Go vote!") +
theme(plot.subtitle = element_text(face = "italic"))

9 / 51

1. Text (End!)

state_election_plot +
theme(
text = element_text(size = 16, family = "Roboto"),
plot.title = element_text(size = 20, family = "Roboto Slab"),
plot.title.position = "plot",
plot.subtitle = element_text(face = "italic"),
axis.text = element_text(size = 14)
) +
labs(
x = "Election Year",
y = NULL,
title = "Percent of democrat votes by state",
subtitle = "We're a swing state! Go vote!"
)

Save our progress!

state_election_plot_A

10 / 51

1. Text (Before-After)

11 / 51

2. Margins & Spacing

12 / 51

2. Margins & Spacing

13 / 51

2. Margins & Spacing

14 / 51

2. Margins & Spacing

Base {ggplot2} themes don't have great margin defaults for:

15 / 51

2. Margins & Spacing

Base {ggplot2} themes don't have great margin defaults for:

  • Margins around plot

15 / 51

2. Margins & Spacing

Base {ggplot2} themes don't have great margin defaults for:

  • Margins around plot

  • Margins between plot title and panel

15 / 51

2. Margins & Spacing

Base {ggplot2} themes don't have great margin defaults for:

  • Margins around plot

  • Margins between plot title and panel

  • Margins between axis titles and panel

15 / 51

2. Margins & Spacing

Base {ggplot2} themes don't have great margin defaults for:

  • Margins around plot

  • Margins between plot title and panel

  • Margins between axis titles and panel

  • Margins between axis texts and axis title

15 / 51

2. Margins & Spacing

Base {ggplot2} themes don't have great margin defaults for:

  • Margins around plot

  • Margins between plot title and panel

  • Margins between axis titles and panel

  • Margins between axis texts and axis title


Know your margin/spacing elements!

  • margin(t = 0, r = 0, b = 0, l = 0, unit = c("pt", "mm", "cm", "in"))

  • hjust, vjust, and lineheight in element_text()

  • expand in scale_*()/coord_*()

15 / 51
state_election_plot_A

15 / 51
state_election_plot_A +
theme(
plot.background = element_rect(color = 'black')
)

15 / 51
state_election_plot_A +
theme(
plot.background = element_rect(color = 'black')
) +
theme(
plot.margin = margin(1, .8, .8, .8, "cm")
)

15 / 51
state_election_plot_A +
theme(
plot.background = element_rect(color = 'black')
) +
theme(
plot.margin = margin(1, .8, .8, .8, "cm")
) +
theme(
plot.title = element_text(margin = margin(b = .3, unit = "cm"))
)

15 / 51
state_election_plot_A +
theme(
plot.background = element_rect(color = 'black')
) +
theme(
plot.margin = margin(1, .8, .8, .8, "cm")
) +
theme(
plot.title = element_text(margin = margin(b = .3, unit = "cm"))
) +
theme(
plot.subtitle = element_text(margin = margin(b = .3, unit = "cm"))
)

15 / 51
state_election_plot_A +
theme(
plot.background = element_rect(color = 'black')
) +
theme(
plot.margin = margin(1, .8, .8, .8, "cm")
) +
theme(
plot.title = element_text(margin = margin(b = .3, unit = "cm"))
) +
theme(
plot.subtitle = element_text(margin = margin(b = .3, unit = "cm"))
) +
theme(
axis.text.x = element_text(margin = margin(t = .2, unit = "cm"))
)

15 / 51
state_election_plot_A +
theme(
plot.background = element_rect(color = 'black')
) +
theme(
plot.margin = margin(1, .8, .8, .8, "cm")
) +
theme(
plot.title = element_text(margin = margin(b = .3, unit = "cm"))
) +
theme(
plot.subtitle = element_text(margin = margin(b = .3, unit = "cm"))
) +
theme(
axis.text.x = element_text(margin = margin(t = .2, unit = "cm"))
) +
theme(
axis.text.y = element_text(margin = margin(r = .1, unit = "cm"))
)

15 / 51
state_election_plot_A +
theme(
plot.background = element_rect(color = 'black')
) +
theme(
plot.margin = margin(1, .8, .8, .8, "cm")
) +
theme(
plot.title = element_text(margin = margin(b = .3, unit = "cm"))
) +
theme(
plot.subtitle = element_text(margin = margin(b = .3, unit = "cm"))
) +
theme(
axis.text.x = element_text(margin = margin(t = .2, unit = "cm"))
) +
theme(
axis.text.y = element_text(margin = margin(r = .1, unit = "cm"))
) +
theme(
axis.title.x = element_text(margin = margin(t = .3, unit = "cm"))
)

15 / 51
state_election_plot_A +
theme(
plot.background = element_rect(color = 'black')
) +
theme(
plot.margin = margin(1, .8, .8, .8, "cm")
) +
theme(
plot.title = element_text(margin = margin(b = .3, unit = "cm"))
) +
theme(
plot.subtitle = element_text(margin = margin(b = .3, unit = "cm"))
) +
theme(
axis.text.x = element_text(margin = margin(t = .2, unit = "cm"))
) +
theme(
axis.text.y = element_text(margin = margin(r = .1, unit = "cm"))
) +
theme(
axis.title.x = element_text(margin = margin(t = .3, unit = "cm"))
) +
coord_cartesian(expand = FALSE)

15 / 51
state_election_plot_A +
theme(
plot.background = element_rect(color = 'black')
) +
theme(
plot.margin = margin(1, .8, .8, .8, "cm")
) +
theme(
plot.title = element_text(margin = margin(b = .3, unit = "cm"))
) +
theme(
plot.subtitle = element_text(margin = margin(b = .3, unit = "cm"))
) +
theme(
axis.text.x = element_text(margin = margin(t = .2, unit = "cm"))
) +
theme(
axis.text.y = element_text(margin = margin(r = .1, unit = "cm"))
) +
theme(
axis.title.x = element_text(margin = margin(t = .3, unit = "cm"))
) +
scale_x_continuous(expand = expansion(mult = 0, add = 3))

15 / 51
state_election_plot_A +
theme(
plot.background = element_rect(color = 'black')
) +
theme(
plot.margin = margin(1, .8, .8, .8, "cm")
) +
theme(
plot.title = element_text(margin = margin(b = .3, unit = "cm"))
) +
theme(
plot.subtitle = element_text(margin = margin(b = .3, unit = "cm"))
) +
theme(
axis.text.x = element_text(margin = margin(t = .2, unit = "cm"))
) +
theme(
axis.text.y = element_text(margin = margin(r = .1, unit = "cm"))
) +
theme(
axis.title.x = element_text(margin = margin(t = .3, unit = "cm"))
) +
scale_x_continuous(expand = expansion(mult = 0, add = 3), breaks = pretty_breaks(5))

15 / 51

2. Margins & Spacing (End!)

state_election_plot_A +
theme(
plot.margin = margin(1, .8, .8, .8, "cm"),
plot.title = element_text(margin = margin(b = .3, unit = "cm")),
plot.subtitle = element_text(margin = margin(b = .3, unit = "cm")),
axis.text.x = element_text(margin = margin(t = .2, unit = "cm")),
axis.text.y = element_text(margin = margin(r = .1, unit = "cm")),
axis.title.x = element_text(margin = margin(t = .3, unit = "cm"))
) +
scale_x_continuous(
expand = expansion(mult = 0, add = 3),
breaks = pretty_breaks(5)
)

Save our progress!

state_election_plot_B

16 / 51

2. Margins & Spacing (Before-After)

17 / 51

2. Margins & Spacing (Before-After)

18 / 51

3. Legends

19 / 51

3. Legends

Legends are really hard:

19 / 51

3. Legends

Legends are really hard:

  • They contain important info, but difficult to make them not look out of place

19 / 51

3. Legends

Legends are really hard:

  • They contain important info, but difficult to make them not look out of place

  • It's better not to have a legend, if you can get away with it

19 / 51

3. Legends

Legends are really hard:

  • They contain important info, but difficult to make them not look out of place

  • It's better not to have a legend, if you can get away with it

  • But sometimes we don't have the luxury of doing so

19 / 51

3. Legends

Legends are really hard:

  • They contain important info, but difficult to make them not look out of place

  • It's better not to have a legend, if you can get away with it

  • But sometimes we don't have the luxury of doing so


Alternative: consider labeling the data directly

19 / 51

20 / 51

3. Legends

Legends are really hard:

  • They contain important info, but difficult to make them not look out of place

  • It's better not to have a legend, if you can get away with it

  • But sometimes we don't have the luxury of doing so


Alternative: consider labeling the data directly

21 / 51

3. Legends

Legends are really hard:

  • They contain important info, but difficult to make them not look out of place

  • It's better not to have a legend, if you can get away with it

  • But sometimes we don't have the luxury of doing so


Alternative: consider labeling the data directly


But if you must have a legend, make it so that the reader can't help but to look at

21 / 51

3. Legends

Legends are really hard:

  • They contain important info, but difficult to make them not look out of place

  • It's better not to have a legend, if you can get away with it

  • But sometimes we don't have the luxury of doing so


Alternative: consider labeling the data directly


But if you must have a legend, make it so that the reader can't help but to look at

  • Positioned at the top-left or top-center of the plot

21 / 51

3. Legends

Legends are really hard:

  • They contain important info, but difficult to make them not look out of place

  • It's better not to have a legend, if you can get away with it

  • But sometimes we don't have the luxury of doing so


Alternative: consider labeling the data directly


But if you must have a legend, make it so that the reader can't help but to look at

  • Positioned at the top-left or top-center of the plot

  • Blend smoothly into the rest of the plot (NOT make them stand out!)

21 / 51
state_election_plot_B

21 / 51
state_election_plot_B +
theme(
legend.key = element_rect(fill = NA)
)

21 / 51
state_election_plot_B +
theme(
legend.key = element_rect(fill = NA)
) +
theme(
legend.position = c(.45, .93)
)

21 / 51
state_election_plot_B +
theme(
legend.key = element_rect(fill = NA)
) +
theme(
legend.position = c(.45, .93)
) +
theme(
legend.direction = "horizontal"
)

21 / 51
state_election_plot_B +
theme(
legend.key = element_rect(fill = NA)
) +
theme(
legend.position = c(.45, .93)
) +
theme(
legend.direction = "horizontal"
) +
theme(
legend.background = element_rect(fill = "grey92")
)

21 / 51
state_election_plot_B +
theme(
legend.key = element_rect(fill = NA)
) +
theme(
legend.position = c(.45, .93)
) +
theme(
legend.direction = "horizontal"
) +
theme(
legend.background = element_rect(fill = "grey92")
) +
scale_y_continuous(
expand = expansion(0, .05),
labels = percent_format(accuracy = 1)
)

21 / 51
state_election_plot_B +
theme(
legend.key = element_rect(fill = NA)
) +
theme(
legend.position = c(.45, .93)
) +
theme(
legend.direction = "horizontal"
) +
theme(
legend.background = element_rect(fill = "grey92")
) +
scale_y_continuous(
expand = expansion(0, .05),
labels = percent_format(accuracy = 1)
) +
labs(color = NULL)

21 / 51

3. Legends (End!)

state_election_plot_B +
theme(
legend.key = element_rect(fill = NA),
legend.position = c(.45, .93),
legend.direction = "horizontal",
legend.background = element_rect(fill = "grey92")
) +
scale_y_continuous(
expand = expansion(0, .05),
labels = percent_format(accuracy = 1)
) +
labs(color = NULL)

Save our progress!

state_election_plot_C

22 / 51

3. Legends (Before-After)

23 / 51

4. Color

24 / 51

4. Color

Colors are a double-edged sword

24 / 51

4. Color

Colors are a double-edged sword

  • Perception can vary widely depending on reader, medium, culture, etc.

24 / 51

4. Color

Colors are a double-edged sword

  • Perception can vary widely depending on reader, medium, culture, etc.

  • There are multiple, complex representations (RGB, wavelength, hex, HSV)

24 / 51

25 / 51

4. Color

Colors are a double-edged sword

  • Perception can vary widely depending on reader, medium, culture, etc.
  • There are multiple, complex representations (RGB, wavelength, hex, HSV)
26 / 51

4. Color

Colors are a double-edged sword

  • Perception can vary widely depending on reader, medium, culture, etc.
  • There are multiple, complex representations (RGB, wavelength, hex, HSV)


If you must, DO:

26 / 51

4. Color

Colors are a double-edged sword

  • Perception can vary widely depending on reader, medium, culture, etc.
  • There are multiple, complex representations (RGB, wavelength, hex, HSV)


If you must, DO:

  • Avoid pure colors (no random sampling from the rainbow!)

26 / 51

4. Color

Colors are a double-edged sword

  • Perception can vary widely depending on reader, medium, culture, etc.
  • There are multiple, complex representations (RGB, wavelength, hex, HSV)


If you must, DO:

  • Avoid pure colors (no random sampling from the rainbow!)

  • Contrast colors in more than one dimension

26 / 51

4. Color

Colors are a double-edged sword

  • Perception can vary widely depending on reader, medium, culture, etc.
  • There are multiple, complex representations (RGB, wavelength, hex, HSV)


If you must, DO:

  • Avoid pure colors (no random sampling from the rainbow!)
  • Contrast colors in more than one dimension


If you aren't sure, use pre-made palettes or play around with online color tools

29 / 51
30 / 51
state_election_plot_C

30 / 51
state_election_plot_C +
theme(panel.background = element_rect(fill = NA))

30 / 51
state_election_plot_C +
theme(panel.background = element_rect(fill = NA)) +
theme(legend.background = element_rect(fill = NA))

30 / 51
state_election_plot_C +
theme(panel.background = element_rect(fill = NA)) +
theme(legend.background = element_rect(fill = NA)) +
theme(axis.line = element_line())

30 / 51
state_election_plot_C +
theme(panel.background = element_rect(fill = NA)) +
theme(legend.background = element_rect(fill = NA)) +
theme(axis.line = element_line()) +
scale_color_manual(
values = c("#F8766D", "#00BA38", "#619CFF")
)

30 / 51
state_election_plot_C +
theme(panel.background = element_rect(fill = NA)) +
theme(legend.background = element_rect(fill = NA)) +
theme(axis.line = element_line()) +
scale_color_manual(
values = c("#F8766D", "#00BA38", "#619CFF")
) +
scale_color_manual(
values = c(
hex(HSV( 4, 0.56, 0.97)),
hex(HSV(138, 1, 0.73)),
hex(HSV(218, 0.62, 1))
)
)

30 / 51
state_election_plot_C +
theme(panel.background = element_rect(fill = NA)) +
theme(legend.background = element_rect(fill = NA)) +
theme(axis.line = element_line()) +
scale_color_manual(
values = c("#F8766D", "#00BA38", "#619CFF")
) +
scale_color_manual(
values = c(
hex(HSV( 4, 0.56, 0.97)),
hex(HSV(138, 1, 0.73)),
hex(HSV(218, 0.62, 1))
)
) +
scale_color_manual(
values = c(
hex(HSV( 0, 1, 1)),
hex(HSV(120, 1, 1)),
hex(HSV(210, 1, 1))
)
)

30 / 51
state_election_plot_C +
theme(panel.background = element_rect(fill = NA)) +
theme(legend.background = element_rect(fill = NA)) +
theme(axis.line = element_line()) +
scale_color_manual(
values = c("#F8766D", "#00BA38", "#619CFF")
) +
scale_color_manual(
values = c(
hex(HSV( 4, 0.56, 0.97)),
hex(HSV(138, 1, 0.73)),
hex(HSV(218, 0.62, 1))
)
) +
scale_color_manual(
values = c(
hex(HSV( 0, 1, 1)),
hex(HSV(120, 1, 1)),
hex(HSV(210, 1, 1))
)
) +
scale_color_manual(
values = c(
hex(HSV( 42, 0.56, 0.84)),
hex(HSV(133, 0.17, 0.57)),
hex(HSV(205, 0.75, 0.51))
)
)

30 / 51
state_election_plot_C +
theme(panel.background = element_rect(fill = NA)) +
theme(legend.background = element_rect(fill = NA)) +
theme(axis.line = element_line()) +
scale_color_manual(
values = c("#F8766D", "#00BA38", "#619CFF")
) +
scale_color_manual(
values = c(
hex(HSV( 4, 0.56, 0.97)),
hex(HSV(138, 1, 0.73)),
hex(HSV(218, 0.62, 1))
)
) +
scale_color_manual(
values = c(
hex(HSV( 0, 1, 1)),
hex(HSV(120, 1, 1)),
hex(HSV(210, 1, 1))
)
) +
scale_color_manual(
values = c(
hex(HSV( 42, 0.56, 0.84)),
hex(HSV(133, 0.17, 0.57)),
hex(HSV(205, 0.75, 0.51))
)
) +
scale_color_manual(
values = c("#D6B25E", "#79917E", "#215982")
)

30 / 51
state_election_plot_C +
theme(panel.background = element_rect(fill = NA)) +
theme(legend.background = element_rect(fill = NA)) +
theme(axis.line = element_line()) +
scale_color_manual(
values = c("#F8766D", "#00BA38", "#619CFF")
) +
scale_color_manual(
values = c(
hex(HSV( 4, 0.56, 0.97)),
hex(HSV(138, 1, 0.73)),
hex(HSV(218, 0.62, 1))
)
) +
scale_color_manual(
values = c(
hex(HSV( 0, 1, 1)),
hex(HSV(120, 1, 1)),
hex(HSV(210, 1, 1))
)
) +
scale_color_manual(
values = c(
hex(HSV( 42, 0.56, 0.84)),
hex(HSV(133, 0.17, 0.57)),
hex(HSV(205, 0.75, 0.51))
)
) +
scale_color_manual(
values = c("#D6B25E", "#79917E", "#215982")
) +
geom_line(size = 1.5)

30 / 51
library(colorBlindness)


31 / 51
state_election_plot_C +
theme(panel.background = element_rect(fill = NA)) +
theme(legend.background = element_rect(fill = NA)) +
theme(axis.line = element_line()) +
geom_line(size = 1.5) +
ggthemes::scale_color_colorblind()

31 / 51
state_election_plot_C +
theme(panel.background = element_rect(fill = NA)) +
theme(legend.background = element_rect(fill = NA)) +
theme(axis.line = element_line()) +
geom_line(size = 1.5) +
nord::scale_color_nord(palette = "aurora", discrete = TRUE)

31 / 51
state_election_plot_C +
theme(panel.background = element_rect(fill = NA)) +
theme(legend.background = element_rect(fill = NA)) +
theme(axis.line = element_line()) +
geom_line(size = 1.5) +
ggsci::scale_color_simpsons()

31 / 51
state_election_plot_C +
theme(panel.background = element_rect(fill = NA)) +
theme(legend.background = element_rect(fill = NA)) +
theme(axis.line = element_line()) +
geom_line(size = 1.5) +
ghibli::scale_color_ghibli_d("SpiritedDark", direction = -1)

31 / 51
state_election_plot_C +
theme(panel.background = element_rect(fill = NA)) +
theme(legend.background = element_rect(fill = NA)) +
theme(axis.line = element_line()) +
geom_line(size = 1.5) +
scale_color_manual(values = wesanderson::wes_palette("Moonrise2", 3, "discrete"))

31 / 51
state_election_plot_C +
theme(panel.background = element_rect(fill = NA)) +
theme(legend.background = element_rect(fill = NA)) +
theme(axis.line = element_line()) +
geom_line(size = 1.5) +
palettetown::scale_color_poke(pokemon = "pikachu")

31 / 51
state_election_plot_C +
theme(panel.background = element_rect(fill = NA)) +
theme(legend.background = element_rect(fill = NA)) +
theme(axis.line = element_line()) +
geom_line(size = 1.5) +
scale_color_manual(values = LaCroixColoR::lacroix_palette("PeachPear", 3, "discrete"))

31 / 51
state_election_plot_C

31 / 51
state_election_plot_C +
theme(
panel.background = element_rect(fill = NA)
)

31 / 51
state_election_plot_C +
theme(
panel.background = element_rect(fill = NA)
) +
theme(
legend.background = element_rect(fill = NA)
)

31 / 51
state_election_plot_C +
theme(
panel.background = element_rect(fill = NA)
) +
theme(
legend.background = element_rect(fill = NA)
) +
theme(
axis.line = element_line()
)

31 / 51
state_election_plot_C +
theme(
panel.background = element_rect(fill = NA)
) +
theme(
legend.background = element_rect(fill = NA)
) +
theme(
axis.line = element_line()
) +
scale_color_manual(
values = c("#e1e1e1", "#e1e1e1", "#2b5e82")
)

31 / 51
state_election_plot_C +
theme(
panel.background = element_rect(fill = NA)
) +
theme(
legend.background = element_rect(fill = NA)
) +
theme(
axis.line = element_line()
) +
scale_color_manual(
values = c("#e1e1e1", "#e1e1e1", "#2b5e82")
) +
guides(
color = guide_none()
)

31 / 51
state_election_plot_C +
theme(
panel.background = element_rect(fill = NA)
) +
theme(
legend.background = element_rect(fill = NA)
) +
theme(
axis.line = element_line()
) +
scale_color_manual(
values = c("#e1e1e1", "#e1e1e1", "#2b5e82")
) +
guides(
color = guide_none()
) +
labs(subtitle = "<span style='color:#2b5e82'>Pennsylvania</span> is a swing state! Go vote!")

31 / 51
state_election_plot_C +
theme(
panel.background = element_rect(fill = NA)
) +
theme(
legend.background = element_rect(fill = NA)
) +
theme(
axis.line = element_line()
) +
scale_color_manual(
values = c("#e1e1e1", "#e1e1e1", "#2b5e82")
) +
guides(
color = guide_none()
) +
labs(subtitle = "<span style='color:#2b5e82'>Pennsylvania</span> is a swing state! Go vote!") +
theme(
plot.subtitle = ggtext::element_markdown()
)

31 / 51
state_election_plot_C +
theme(
panel.background = element_rect(fill = NA)
) +
theme(
legend.background = element_rect(fill = NA)
) +
theme(
axis.line = element_line()
) +
scale_color_manual(
values = c("#e1e1e1", "#e1e1e1", "#2b5e82")
) +
guides(
color = guide_none()
) +
labs(subtitle = "<span style='color:#2b5e82'>Pennsylvania</span> is a swing state! Go vote!") +
theme(
plot.subtitle = ggtext::element_markdown()
) +
geom_line(size = 1.5)

31 / 51
state_election_plot_C +
theme(
panel.background = element_rect(fill = NA)
) +
theme(
legend.background = element_rect(fill = NA)
) +
theme(
axis.line = element_line()
) +
scale_color_manual(
values = c("#e1e1e1", "#e1e1e1", "#2b5e82")
) +
guides(
color = guide_none()
) +
labs(subtitle = "<span style='color:#0E4369'>Pennsylvania</span> is a swing state! Go vote!") +
theme(
plot.subtitle = ggtext::element_markdown()
) +
geom_line(size = 1.5)

31 / 51
state_election_plot_C +
theme(
panel.background = element_rect(fill = NA)
) +
theme(
legend.background = element_rect(fill = NA)
) +
theme(
axis.line = element_line()
) +
scale_color_manual(
values = c("#e1e1e1", "#e1e1e1", "#2b5e82")
) +
guides(
color = guide_none()
) +
labs(subtitle = "<strong style='color:#0E4369'>Pennsylvania</strong> is a swing state! Go vote!") +
theme(
plot.subtitle = ggtext::element_markdown()
) +
geom_line(size = 1.5)

31 / 51

4. Colors (End!)

state_election_plot_C +
geom_line(size = 1.5) +
theme(
panel.background = element_rect(fill = NA),
legend.background = element_rect(fill = NA),
axis.line = element_line(),
plot.subtitle = element_markdown()
) +
guides(color = guide_none()) +
scale_color_manual(values = c("#e1e1e1", "#e1e1e1", "#2b5e82")) +
labs(
subtitle = "<strong style='color:#0E4369'>Pennsylvania</strong>
is a swing state! Go vote!"
)

Save our progress!

state_election_plot_D

32 / 51

4. Colors (Before-After)

33 / 51

4. Colors (Before-After)

34 / 51

35 / 51
state_election_plot

35 / 51
state_election_plot +
theme_classic(
base_family = "Roboto",
base_size = 16
)

35 / 51
state_election_plot +
theme_classic(
base_family = "Roboto",
base_size = 16
) +
guides(color = guide_none())

35 / 51
state_election_plot +
theme_classic(
base_family = "Roboto",
base_size = 16
) +
guides(color = guide_none()) +
geom_line(size = 1.5)

35 / 51
state_election_plot +
theme_classic(
base_family = "Roboto",
base_size = 16
) +
guides(color = guide_none()) +
geom_line(size = 1.5) +
scale_color_manual(
values = c("#e1e1e1", "#e1e1e1", "#2b5e82")
)

35 / 51
state_election_plot +
theme_classic(
base_family = "Roboto",
base_size = 16
) +
guides(color = guide_none()) +
geom_line(size = 1.5) +
scale_color_manual(
values = c("#e1e1e1", "#e1e1e1", "#2b5e82")
) +
labs(
y = NULL,
x = "Election Year",
title = "Percent of democrat votes by state",
subtitle = "<strong style='color:#0E4369'>Pennsylvania</strong> is a swing state! Go vote!"
)

35 / 51
state_election_plot +
theme_classic(
base_family = "Roboto",
base_size = 16
) +
guides(color = guide_none()) +
geom_line(size = 1.5) +
scale_color_manual(
values = c("#e1e1e1", "#e1e1e1", "#2b5e82")
) +
labs(
y = NULL,
x = "Election Year",
title = "Percent of democrat votes by state",
subtitle = "<strong style='color:#0E4369'>Pennsylvania</strong> is a swing state! Go vote!"
) +
theme(
plot.margin = margin(.8, 1, .7, .8, "cm"),
plot.title = element_text(
family = "Roboto Slab",
size = 24,
margin = margin(b = .3, unit = "cm")
),
plot.title.position = "plot",
plot.subtitle = element_markdown(
margin = margin(b = .3, unit = "cm")
),
axis.title.x = element_text(
margin = margin(t = .5, unit = "cm")
),
)

35 / 51

Showcasing

36 / 51

First, save our theme!

You can set global theme with theme_set() and theme_update():


  • theme_set() takes a custom theme as a argument (e.g., theme_bw(), theme_classic(), etc.)


  • theme_update() takes individual theme elements as arguments


theme_set(
theme_classic(
base_family = "Roboto",
base_size = 16
)
)
theme_update(
plot.margin = margin(.8, 1, .7, .8, "cm"),
plot.title = element_text(
family = "Roboto Slab",
size = 24,
margin = margin(b = .5, unit = "cm")
),
plot.title.position = "plot",
axis.title.x = element_text(
margin = margin(t = .5, unit = "cm")
)
)
37 / 51

1. Vowel Formant Plot

38 / 51
sim_vowel_data
# A tibble: 300 x 3
Vowel F1 F2
<chr> <dbl> <dbl>
1 i 371. 2431.
2 i 332. 2435.
3 i 286. 2630.
4 i 110. 2527.
5 i 302. 2315.
6 i 199. 2279.
7 i 152. 2303.
8 i 173. 2116.
9 i 258. 2540.
10 i 200. 2604.
# ... with 290 more rows
38 / 51
sim_vowel_data %>%
ggplot(aes(x = F2, y = F1))

38 / 51
sim_vowel_data %>%
ggplot(aes(x = F2, y = F1)) +
geom_text(aes(label = Vowel))

38 / 51
sim_vowel_data %>%
ggplot(aes(x = F2, y = F1)) +
geom_text(aes(label = Vowel)) +
scale_x_reverse(
position = "top",
breaks = pretty_breaks(5)
)

38 / 51
sim_vowel_data %>%
ggplot(aes(x = F2, y = F1)) +
geom_text(aes(label = Vowel)) +
scale_x_reverse(
position = "top",
breaks = pretty_breaks(5)
) +
scale_y_reverse(position = "right")

38 / 51
sim_vowel_data %>%
ggplot(aes(x = F2, y = F1)) +
geom_text(aes(label = Vowel)) +
scale_x_reverse(
position = "top",
breaks = pretty_breaks(5)
) +
scale_y_reverse(position = "right") +
theme(
plot.margin = margin(.5,.5, 1, 1, unit = "cm"),
axis.title.x.top = element_text(margin = margin(b = .2, unit = "cm")),
axis.title.y.right = element_text(
angle = 0, vjust = 0.5, margin = margin(l = .3, unit = "cm")
)
)

38 / 51
sim_vowel_data %>%
ggplot(aes(x = F2, y = F1)) +
geom_text(aes(label = Vowel)) +
scale_x_reverse(
position = "top",
breaks = pretty_breaks(5)
) +
scale_y_reverse(position = "right") +
theme(
plot.margin = margin(.5,.5, 1, 1, unit = "cm"),
axis.title.x.top = element_text(margin = margin(b = .2, unit = "cm")),
axis.title.y.right = element_text(
angle = 0, vjust = 0.5, margin = margin(l = .3, unit = "cm")
)
) +
stat_ellipse(aes(group = Vowel))

38 / 51

2. Vowel Space Plot

39 / 51
sim_vowel_data_all
# A tibble: 800 x 3
Vowel F1 F2
<chr> <dbl> <dbl>
1 i 371. 2431.
2 i 332. 2435.
3 i 286. 2630.
4 i 110. 2527.
5 i 302. 2315.
6 i 199. 2279.
7 i 152. 2303.
8 i 173. 2116.
9 i 258. 2540.
10 i 200. 2604.
# ... with 790 more rows
39 / 51
sim_vowel_data_all %>%
group_by(Vowel)
# A tibble: 800 x 3
# Groups: Vowel [16]
Vowel F1 F2
<chr> <dbl> <dbl>
1 i 371. 2431.
2 i 332. 2435.
3 i 286. 2630.
4 i 110. 2527.
5 i 302. 2315.
6 i 199. 2279.
7 i 152. 2303.
8 i 173. 2116.
9 i 258. 2540.
10 i 200. 2604.
# ... with 790 more rows
39 / 51
sim_vowel_data_all %>%
group_by(Vowel) %>%
summarize(across(c(F1, F2), mean), .groups = 'drop')
# A tibble: 16 x 3
Vowel F1 F2
<chr> <dbl> <dbl>
1 <U+0251> 740. 912.
2 <U+0252> 699. 762.
3 <U+0254> 498. 748.
4 <U+025B> 606. 1905.
5 <U+0264> 466. 1300.
6 <U+026F> 305. 1400.
7 <U+0276> 852. 1532.
8 <U+028C> 603. 1165.
9 a 842. 1617.
10 e 383. 2321.
11 i 224. 2394.
12 o 332. 620.
13 ø 373. 1924.
14 œ 597. 1699.
15 u 266. 614.
16 y 235. 2099.
39 / 51
sim_vowel_data_all %>%
group_by(Vowel) %>%
summarize(across(c(F1, F2), mean), .groups = 'drop') %>%
ggplot(aes(x = F2, y = F1))

39 / 51
sim_vowel_data_all %>%
group_by(Vowel) %>%
summarize(across(c(F1, F2), mean), .groups = 'drop') %>%
ggplot(aes(x = F2, y = F1)) +
geom_text(aes(label = Vowel), size = 6, family = "Charis SIL")

39 / 51
sim_vowel_data_all %>%
group_by(Vowel) %>%
summarize(across(c(F1, F2), mean), .groups = 'drop') %>%
ggplot(aes(x = F2, y = F1)) +
geom_text(aes(label = Vowel), size = 6, family = "Charis SIL") +
scale_x_reverse(
position = "top",
breaks = pretty_breaks(5),
expand = expansion(.1)
)

39 / 51
sim_vowel_data_all %>%
group_by(Vowel) %>%
summarize(across(c(F1, F2), mean), .groups = 'drop') %>%
ggplot(aes(x = F2, y = F1)) +
geom_text(aes(label = Vowel), size = 6, family = "Charis SIL") +
scale_x_reverse(
position = "top",
breaks = pretty_breaks(5),
expand = expansion(.1)
) +
scale_y_reverse(
position = "right",
expand = expansion(.1)
)

39 / 51
sim_vowel_data_all %>%
group_by(Vowel) %>%
summarize(across(c(F1, F2), mean), .groups = 'drop') %>%
ggplot(aes(x = F2, y = F1)) +
geom_text(aes(label = Vowel), size = 6, family = "Charis SIL") +
scale_x_reverse(
position = "top",
breaks = pretty_breaks(5),
expand = expansion(.1)
) +
scale_y_reverse(
position = "right",
expand = expansion(.1)
) +
theme(
plot.margin = margin(.5,.5, 1, 1, unit = "cm"),
axis.title.x.top = element_text(margin = margin(b = .2, unit = "cm")),
axis.title.y.right = element_text(
angle = 0, vjust = 0.5, margin = margin(l = .3, unit = "cm")
)
)

39 / 51
sim_vowel_data_all %>%
group_by(Vowel) %>%
summarize(across(c(F1, F2), mean), .groups = 'drop') %>%
ggplot(aes(x = F2, y = F1)) +
geom_text(aes(label = Vowel), size = 6, family = "Charis SIL") +
scale_x_reverse(
position = "top",
breaks = pretty_breaks(5),
expand = expansion(.1)
) +
scale_y_reverse(
position = "right",
expand = expansion(.1)
) +
theme(
plot.margin = margin(.5,.5, 1, 1, unit = "cm"),
axis.title.x.top = element_text(margin = margin(b = .2, unit = "cm")),
axis.title.y.right = element_text(
angle = 0, vjust = 0.5, margin = margin(l = .3, unit = "cm")
)
) +
stat_chull(
fill = NA,
color = "black",
linetype = 2
)

39 / 51

3. Bar Plot of Proportions

40 / 51
read_csv("https://raw.githubusercontent.com/yjunechoe/Semantic-Persistence/master/processed.csv")
# A tibble: 4,516 x 10
Value Item Cond Group Subject Time Answer Accuracy Type logRT
<chr> <chr> <chr> <chr> <chr> <dbl> <chr> <dbl> <chr> <dbl>
1 Yes Awaken~ Subje~ B 5cfa77e907f7dd~ 917 No 0 Criti~ 6.82
2 No Awaken~ Subje~ B 5c1d21196036e4~ 2624 No 1 Criti~ 7.87
3 No Awaken~ Subje~ B 5d730aab6b4b16~ 2809 No 1 Criti~ 7.94
4 No Awaken~ Subje~ B 5ddef0fae454cd~ 1587 No 1 Criti~ 7.37
5 No Awaken~ Subje~ B 5e7a8e8b11bf56~ 1697 No 1 Criti~ 7.44
6 No Awaken~ Verb A 5d4613a2da9cb6~ 1484 No 1 Criti~ 7.30
7 No Awaken~ Verb A 579e1e2b275be6~ 1556 No 1 Criti~ 7.35
8 No Awaken~ Verb A 5dfe69ed11d879~ 1699 No 1 Criti~ 7.44
9 No Awaken~ Verb A 5b9442cecd3808~ 2159 No 1 Criti~ 7.68
10 No Awaken~ Verb A 5e7f3328849917~ 1132 No 1 Criti~ 7.03
# ... with 4,506 more rows
40 / 51
read_csv("https://raw.githubusercontent.com/yjunechoe/Semantic-Persistence/master/processed.csv") %>%
filter(Type == "Critical")
# A tibble: 1,466 x 10
Value Item Cond Group Subject Time Answer Accuracy Type logRT
<chr> <chr> <chr> <chr> <chr> <dbl> <chr> <dbl> <chr> <dbl>
1 Yes Awaken~ Subje~ B 5cfa77e907f7dd~ 917 No 0 Criti~ 6.82
2 No Awaken~ Subje~ B 5c1d21196036e4~ 2624 No 1 Criti~ 7.87
3 No Awaken~ Subje~ B 5d730aab6b4b16~ 2809 No 1 Criti~ 7.94
4 No Awaken~ Subje~ B 5ddef0fae454cd~ 1587 No 1 Criti~ 7.37
5 No Awaken~ Subje~ B 5e7a8e8b11bf56~ 1697 No 1 Criti~ 7.44
6 No Awaken~ Verb A 5d4613a2da9cb6~ 1484 No 1 Criti~ 7.30
7 No Awaken~ Verb A 579e1e2b275be6~ 1556 No 1 Criti~ 7.35
8 No Awaken~ Verb A 5dfe69ed11d879~ 1699 No 1 Criti~ 7.44
9 No Awaken~ Verb A 5b9442cecd3808~ 2159 No 1 Criti~ 7.68
10 No Awaken~ Verb A 5e7f3328849917~ 1132 No 1 Criti~ 7.03
# ... with 1,456 more rows
40 / 51
read_csv("https://raw.githubusercontent.com/yjunechoe/Semantic-Persistence/master/processed.csv") %>%
filter(Type == "Critical") %>%
group_by(Cond, Group)
# A tibble: 1,466 x 10
# Groups: Cond, Group [4]
Value Item Cond Group Subject Time Answer Accuracy Type logRT
<chr> <chr> <chr> <chr> <chr> <dbl> <chr> <dbl> <chr> <dbl>
1 Yes Awaken~ Subje~ B 5cfa77e907f7dd~ 917 No 0 Criti~ 6.82
2 No Awaken~ Subje~ B 5c1d21196036e4~ 2624 No 1 Criti~ 7.87
3 No Awaken~ Subje~ B 5d730aab6b4b16~ 2809 No 1 Criti~ 7.94
4 No Awaken~ Subje~ B 5ddef0fae454cd~ 1587 No 1 Criti~ 7.37
5 No Awaken~ Subje~ B 5e7a8e8b11bf56~ 1697 No 1 Criti~ 7.44
6 No Awaken~ Verb A 5d4613a2da9cb6~ 1484 No 1 Criti~ 7.30
7 No Awaken~ Verb A 579e1e2b275be6~ 1556 No 1 Criti~ 7.35
8 No Awaken~ Verb A 5dfe69ed11d879~ 1699 No 1 Criti~ 7.44
9 No Awaken~ Verb A 5b9442cecd3808~ 2159 No 1 Criti~ 7.68
10 No Awaken~ Verb A 5e7f3328849917~ 1132 No 1 Criti~ 7.03
# ... with 1,456 more rows
40 / 51
read_csv("https://raw.githubusercontent.com/yjunechoe/Semantic-Persistence/master/processed.csv") %>%
filter(Type == "Critical") %>%
group_by(Cond, Group) %>%
summarize(Accuracy = mean(Accuracy, na.rm = TRUE), .groups = 'drop')
# A tibble: 4 x 3
Cond Group Accuracy
<chr> <chr> <dbl>
1 Subject A 0.875
2 Subject B 0.780
3 Verb A 0.846
4 Verb B 0.710
40 / 51
read_csv("https://raw.githubusercontent.com/yjunechoe/Semantic-Persistence/master/processed.csv") %>%
filter(Type == "Critical") %>%
group_by(Cond, Group) %>%
summarize(Accuracy = mean(Accuracy, na.rm = TRUE), .groups = 'drop') %>%
ggplot(aes(x = Cond, y = Accuracy, fill = Group))

40 / 51
read_csv("https://raw.githubusercontent.com/yjunechoe/Semantic-Persistence/master/processed.csv") %>%
filter(Type == "Critical") %>%
group_by(Cond, Group) %>%
summarize(Accuracy = mean(Accuracy, na.rm = TRUE), .groups = 'drop') %>%
ggplot(aes(x = Cond, y = Accuracy, fill = Group)) +
geom_col(position = "dodge", color = "white", width = .7, size = 2)

40 / 51
read_csv("https://raw.githubusercontent.com/yjunechoe/Semantic-Persistence/master/processed.csv") %>%
filter(Type == "Critical") %>%
group_by(Cond, Group) %>%
summarize(Accuracy = mean(Accuracy, na.rm = TRUE), .groups = 'drop') %>%
ggplot(aes(x = Cond, y = Accuracy, fill = Group)) +
geom_col(position = "dodge", color = "white", width = .7, size = 2) +
scale_fill_manual(values = c("grey30", "grey70"))

40 / 51
read_csv("https://raw.githubusercontent.com/yjunechoe/Semantic-Persistence/master/processed.csv") %>%
filter(Type == "Critical") %>%
group_by(Cond, Group) %>%
summarize(Accuracy = mean(Accuracy, na.rm = TRUE), .groups = 'drop') %>%
ggplot(aes(x = Cond, y = Accuracy, fill = Group)) +
geom_col(position = "dodge", color = "white", width = .7, size = 2) +
scale_fill_manual(values = c("grey30", "grey70")) +
labs(
title = "Accuracy on Comprehension Task",
x = "Pitch Accent Condition", y = NULL,
fill = "Experiment Group"
)

40 / 51
read_csv("https://raw.githubusercontent.com/yjunechoe/Semantic-Persistence/master/processed.csv") %>%
filter(Type == "Critical") %>%
group_by(Cond, Group) %>%
summarize(Accuracy = mean(Accuracy, na.rm = TRUE), .groups = 'drop') %>%
ggplot(aes(x = Cond, y = Accuracy, fill = Group)) +
geom_col(position = "dodge", color = "white", width = .7, size = 2) +
scale_fill_manual(values = c("grey30", "grey70")) +
labs(
title = "Accuracy on Comprehension Task",
x = "Pitch Accent Condition", y = NULL,
fill = "Experiment Group"
) +
guides(fill = guide_legend(direction = "horizontal", title.position = "top"))

40 / 51
read_csv("https://raw.githubusercontent.com/yjunechoe/Semantic-Persistence/master/processed.csv") %>%
filter(Type == "Critical") %>%
group_by(Cond, Group) %>%
summarize(Accuracy = mean(Accuracy, na.rm = TRUE), .groups = 'drop') %>%
ggplot(aes(x = Cond, y = Accuracy, fill = Group)) +
geom_col(position = "dodge", color = "white", width = .7, size = 2) +
scale_fill_manual(values = c("grey30", "grey70")) +
labs(
title = "Accuracy on Comprehension Task",
x = "Pitch Accent Condition", y = NULL,
fill = "Experiment Group"
) +
guides(fill = guide_legend(direction = "horizontal", title.position = "top")) +
coord_capped_cart(
ylim = c(0.5, 1),
left = "top"
)

40 / 51
read_csv("https://raw.githubusercontent.com/yjunechoe/Semantic-Persistence/master/processed.csv") %>%
filter(Type == "Critical") %>%
group_by(Cond, Group) %>%
summarize(Accuracy = mean(Accuracy, na.rm = TRUE), .groups = 'drop') %>%
ggplot(aes(x = Cond, y = Accuracy, fill = Group)) +
geom_col(position = "dodge", color = "white", width = .7, size = 2) +
scale_fill_manual(values = c("grey30", "grey70")) +
labs(
title = "Accuracy on Comprehension Task",
x = "Pitch Accent Condition", y = NULL,
fill = "Experiment Group"
) +
guides(fill = guide_legend(direction = "horizontal", title.position = "top")) +
coord_capped_cart(
ylim = c(0.5, 1),
left = "top"
) +
theme(
axis.ticks.x = element_blank(),
axis.text.x = element_text(color = "black", margin = margin(t = .2, unit = "cm")),
legend.position = c(.3, .93),
plot.title = element_text(margin = margin(b = 1, unit = "cm"))
)

40 / 51
read_csv("https://raw.githubusercontent.com/yjunechoe/Semantic-Persistence/master/processed.csv") %>%
filter(Type == "Critical") %>%
group_by(Cond, Group) %>%
summarize(Accuracy = mean(Accuracy, na.rm = TRUE), .groups = 'drop') %>%
ggplot(aes(x = Cond, y = Accuracy, fill = Group)) +
geom_col(position = "dodge", color = "white", width = .7, size = 2) +
scale_fill_manual(values = c("grey30", "grey70")) +
labs(
title = "Accuracy on Comprehension Task",
x = "Pitch Accent Condition", y = NULL,
fill = "Experiment Group"
) +
guides(fill = guide_legend(direction = "horizontal", title.position = "top")) +
coord_capped_cart(
ylim = c(0.5, 1),
left = "top"
) +
theme(
axis.ticks.x = element_blank(),
axis.text.x = element_text(color = "black", margin = margin(t = .2, unit = "cm")),
legend.position = c(.3, .93),
plot.title = element_text(margin = margin(b = 1, unit = "cm"))
) +
scale_y_continuous(
expand = expansion(0, 0),
labels = percent_format(accuracy = 1)
)

40 / 51

4. Multiple Categorical Levels

41 / 51

Source: Husband & Patson (2020)

42 / 51
df <- crossing(level_1 = fct_inorder(c("Within", "Between")),
level_2 = fct_inorder(c("Some", "Number", "Or")),
level_3 = factor(c("Strong", "Weak")))
df$barheight <- c(.63, .35, .72, .55, .61, .15, .60, .55, .52, .63, .17, .16)
df %>%
ggplot(aes(level_3, barheight)) +
geom_col(
aes(fill = level_3),
show.legend = FALSE
) +
geom_errorbar(
aes(ymin = barheight - .05, ymax = barheight + .05),
width = .1) +
facet_grid(level_2 ~ level_1) +
theme_bw() +
scale_fill_manual(values = c('grey40', 'grey80')) +
ylim(0, 1) +
labs(
y = "Proportion of Strong Responses",
x = "Prime Type") +
theme_bw()

43 / 51

(Code)

44 / 51

(Code)

45 / 51

5. Animations: Vowel shift

46 / 51
read_csv("https://raw.githubusercontent.com/bodowinter/canadian_vowel_shift_analysis/master/processed_data/production_processed.csv") %>%
group_by(Gender, Vowel, BirthDecade = 10 * BirthYear %/% 10) %>%
summarize(across(F1:F2, mean), .groups = 'drop') %>%
filter(Gender == "F") %>%
ggplot(aes(F2, F1)) +
geom_text(aes(1450, 615, label = as.character(BirthDecade)),
color = "gray80", size = 48) +
stat_chull(fill = NA, color = "black", linetype = 2) +
geom_label(aes(label = Vowel), size = 6, family = "Charis SIL") +
scale_x_reverse(position = "top") +
scale_y_reverse(position = "right") +
theme(
plot.margin = margin(.5,.8, 1.2, 1, unit = "cm"),
axis.title.x.top = element_text(margin = margin(b = .2, unit = "cm")),
axis.title.y.right = element_text(angle = 0, vjust = 0.5, margin = margin(l = .3, unit = "cm"))
) +
coord_cartesian(clip = 'off') +
labs(title = "Canadian Vowel Shift", caption = "Source: Kettig & Winter (2017)") +
transition_states(BirthDecade) +
shadow_mark(
alpha = .1,
color = "grey",
exclude_layer = c(1, 2)
)



47 / 51

5. Animations: Eye-tracking

48 / 51
de Carvalho et al. (2017)

de Carvalho et al. (2017)

49 / 51

(Code)

50 / 51

Why?

2 / 51
Paused

Help

Keyboard shortcuts

, , Pg Up, k Go to previous slide
, , Pg Dn, Space, j Go to next slide
Home Go to first slide
End Go to last slide
Number + Return Go to specific slide
b / m / f Toggle blackout / mirrored / fullscreen mode
c Clone slideshow
p Toggle presenter mode
t Restart the presentation timer
?, h Toggle this help
Esc Back to slideshow