Last active
December 8, 2021 10:22
-
-
Save yjunechoe/b7bc540f290044ffebec0a9031d586df to your computer and use it in GitHub Desktop.
{ggplot2} flipbook for Phonetics Lab (10/23/20) - style guide & showcasing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
title: "Visualizing Data (in R)" | |
subtitle: "An opinionated style guide" | |
author: "<br><br>June Choe<br><br>Phonetics Lab" | |
date: '2020-10-23' | |
output: | |
xaringan::moon_reader: | |
lib_dir: libs | |
css: [default, hygge, ninjutsu] | |
nature: | |
ratio: 16:10 | |
highlightStyle: 'solarized-light' | |
highlightLines: true | |
countIncrementalSlides: false | |
editor_options: | |
chunk_output_type: console | |
--- | |
```{css, echo = FALSE} | |
body { | |
font-family: Adelle; | |
} | |
a { | |
text-decoration: underline; | |
color: #23395B; | |
} | |
.inverse { | |
background-color: #23395B; | |
} | |
.remark-slide-content { | |
# background-color: #F9F9F9; | |
} | |
.remark-slide-content h1 { | |
font-size: 48; | |
} | |
strong, h1, h2, h3 { | |
color: #23395B; | |
} | |
.sc { | |
font-variant: small-caps; | |
} | |
.remark-code-line { | |
font-size: .8em; | |
line-height: 1.8em; | |
} | |
code.r.hljs.remark-code { | |
font-size: .8em; | |
line-height: 1.8em; | |
position: relative; | |
overflow-x: hidden; | |
color: black; | |
} | |
code.r.hljs.remark-code:hover { | |
overflow-x: visible; | |
width: 700px; | |
border-style: solid; | |
} | |
code.remark-inline-code { | |
font-family: Fira Code; | |
font-size: .8em; | |
} | |
.remark-slide-content{ | |
padding-top: .5em; | |
padding-left: 3em; | |
} | |
.pull-left { | |
float: left; | |
width: 45%; | |
} | |
.pull-right { | |
float: right; | |
width: 49%; | |
} | |
``` | |
```{r setup, echo = FALSE, message = FALSE, warning = FALSE} | |
library(tidyverse) | |
library(extrafont) | |
library(flipbookr) | |
library(xaringan) | |
library(xaringanExtra) | |
knitr::opts_chunk$set(fig.width = 6, message = FALSE, warning = FALSE, comment = " ", cache = F, dpi = 300) | |
set.seed(1234) | |
``` | |
# Why? | |
-- | |
**Why bother making your plots look nice?** | |
-- | |
- <p>Helps people <strong>remember</strong> your results better</p> | |
-- | |
- Makes your findings look more **credible** | |
-- | |
- Increases the chance of your work being **shared** | |
-- | |
- Shows **respect** for your audience | |
<br> | |
-- | |
**Goal of this presentation** | |
-- | |
- <p>Share practical tips for improving readability</p> | |
-- | |
- Demonstrate implementations of these ideas (w/ [code](https://gist.github.com/yjunechoe/b7bc540f290044ffebec0a9031d586df)) | |
--- | |
# Outline | |
-- | |
**Four practical tips for improving data visualizations** | |
-- | |
- <p>Make your <strong>text</strong> readable</p> | |
-- | |
- 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 | |
--- | |
# Preliminaries | |
.pull-left[ | |
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 | |
] | |
.pull-right[ | |
```{r, echo=FALSE, out.width="400px", fig.align="right"} | |
knitr::include_graphics("https://d33wubrfki0l68.cloudfront.net/2c6239d311be6d037c251c71c3902792f8c4ddd2/12f67/css/images/hex/ggplot2.png") | |
``` | |
] | |
--- | |
# Preliminaries | |
.pull-left[ | |
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 | |
```{r, message = FALSE} | |
library(scales) | |
library(colorspace) | |
library(ggtext) | |
library(lemon) | |
library(gganimate) | |
# library(patchwork) | |
# library(gghighlight) | |
# library(ggforce) | |
# library(ggrepel) | |
``` | |
] | |
.pull-right[ | |
<iframe src="https://exts.ggplot2.tidyverse.org/gallery/" height="450px" width="510px"> | |
] | |
--- | |
# How does it work? | |
```{r, echo=FALSE, out.width="450px", fig.align="center", fig.cap="Source: https://www.youtube.com/watch?v=h29g21z0a68"} | |
knitr::include_graphics("P_lab_ggplot2_files/ggplot_layers.png") | |
``` | |
--- | |
```{r, echo = FALSE, message = FALSE, warning = FALSE} | |
state_election_votes <- read_csv("https://vincentarelbundock.github.io/Rdatasets/csv/pscl/presidentialElections.csv") %>% | |
select(State = state, demVote, Year = year) %>% | |
mutate(demVote = round(demVote/100, 2)) | |
``` | |
```{r example-1, include = FALSE, dpi = 75} | |
state_election_votes %>% | |
filter(State %in% | |
c("Pennsylvania", | |
"Illinois", | |
"California") | |
) %>% | |
ggplot() + | |
aes( | |
x = Year, | |
y = demVote, | |
color = State | |
) + | |
geom_point() + #OMIT | |
geom_point() + #ROTATE | |
geom_line() + #ROTATE | |
geom_line(size = 1) + #ROTATE | |
scale_y_continuous( | |
labels = percent_format(accuracy = 1) | |
) + | |
scale_x_continuous( | |
breaks = pretty_breaks(n= 5) | |
) + | |
labs( | |
y = "Democrat Votes", | |
title = "Go Vote!" | |
) | |
``` | |
`r chunk_reveal("example-1", omit = "#ROTATE", break_type = "auto", widths = c(40, 60))` | |
--- | |
`r chunk_reveal("example-1", omit = "#OMIT", break_type = "rotate", widths = c(40, 60))` | |
--- | |
# Yay a plot! | |
```{r, echo = FALSE, dpi = 75} | |
state_election_plot <- 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 = "Percent of Democrat Votes", | |
title = "Go Vote!" | |
) | |
``` | |
.pull-left[ | |
```{r state_election_plot, echo = FALSE, fig.align="center", out.height="450px", dpi = 75} | |
state_election_plot | |
``` | |
] | |
.pull-right[ | |
] | |
--- | |
# Yay a plot... ? | |
.pull-left[ | |
```{r state_election_plot, echo = FALSE, fig.align="center", out.height="450px", dpi = 100} | |
``` | |
] | |
.pull-right[ | |
**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 | |
] | |
--- | |
#1. Text | |
Many different ways to style text: | |
-- | |
- <p><span style="font-size: .7em">font</span> <span style="font-size: 1.5em">size</span></p> | |
-- | |
- Font face (<strong style="color:black">bold</strong>, *italic*, <span style="font-variant: small-caps">small caps</span>) | |
-- | |
- Font family (<span style="font-family: Times New Roman"> Times New Roman</span>, <span style="font-family: Calibri"> Calibri</span>, <span style="font-family: Arial"> Arial</span>, <span style="font-family: Wingdings">Hi friends</span> ) | |
-- | |
- Font color, line height, letter spacing, angle, weight, etc. | |
-- | |
<br> | |
Unless you make your plots with html/css/js, you'll likely only have access to: | |
-- | |
- <p>Font size, font family, and limited set of font styles</p> | |
-- | |
- But you can get pretty far with these! | |
--- | |
```{r text, echo = FALSE, eval = FALSE} | |
state_election_plot + | |
theme(text = element_text(family = "Roboto")) + #OMIT | |
theme(text = element_text(family = "Adelle")) + #ROTATE | |
theme(text = element_text(family = "Bitter")) + #ROTATE | |
theme(text = element_text(family = "Futura Bk BT")) + #ROTATE | |
theme(text = element_text(family = "Montserrat")) + #ROTATE | |
theme(text = element_text(family = "Montserrat Medium")) + #ROTATE | |
theme(text = element_text(family = "Arial")) + #ROTATE | |
theme(text = element_text(family = "xkcd")) + #ROTATE | |
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")) | |
``` | |
`r chunk_reveal("text", omit = "#ROTATE", break_type = "auto", widths = c(40, 60))` | |
--- | |
`r chunk_reveal("text", omit = "#OMIT", break_type = "rotate", widths = c(40, 60))` | |
--- | |
#1. Text (End!) | |
.pull-left[ | |
```{r, echo = FALSE} | |
state_election_plot_A <- 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!" | |
) | |
``` | |
```{r text_final, eval = FALSE} | |
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! | |
```{r, eval = FALSE} | |
state_election_plot_A | |
``` | |
] | |
.pull-right[ | |
```{r text_final, echo = FALSE, out.width = "400px"} | |
``` | |
] | |
--- | |
#1. Text (Before-After) | |
.pull-left[ | |
```{r, echo = FALSE, out.width = "400px"} | |
state_election_plot | |
``` | |
] | |
.pull-right[ | |
```{r, echo = FALSE, out.width = "400px"} | |
state_election_plot_A | |
``` | |
] | |
--- | |
#2. Margins & Spacing | |
```{r, echo = FALSE, out.height = "450px", fig.align="center"} | |
state_election_plot_A | |
``` | |
--- | |
#2. Margins & Spacing | |
```{r, echo = FALSE, out.height = "450px", fig.align="center"} | |
state_election_plot_A + | |
theme( | |
plot.background = element_rect(color = "black", size = 1) | |
) | |
``` | |
--- | |
#2. Margins & Spacing | |
```{r, echo = FALSE, out.height = "450px", fig.align="center"} | |
state_election_plot_A + | |
theme( | |
plot.background = element_rect(color = "black", fill = "#FFFF88", size = 1) | |
) | |
``` | |
--- | |
#2. Margins & Spacing | |
Base {ggplot2} themes don't have _great_ margin defaults for: | |
-- | |
- <p>Margins around plot</p> | |
-- | |
- Margins between plot title and panel | |
-- | |
- Margins between axis titles and panel | |
-- | |
- Margins between axis texts and axis title | |
-- | |
<br> | |
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_*()` | |
--- | |
```{r margins, echo = FALSE, eval = FALSE, warning = FALSE} | |
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) + #OMIT | |
scale_x_continuous(expand = expansion(mult = 0, add = 3)) + #ROTATE | |
scale_x_continuous(expand = expansion(mult = 0, add = 3), breaks = pretty_breaks(5)) #ROTATE | |
``` | |
`r chunk_reveal("margins", omit = "#ROTATE", break_type = "auto", widths = c(40, 60))` | |
--- | |
`r chunk_reveal("margins", omit = "#OMIT", break_type = "rotate", widths = c(40, 60))` | |
--- | |
#2. Margins & Spacing (End!) | |
.pull-left[ | |
```{r, echo = FALSE, message = FALSE} | |
state_election_plot_B <- 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) | |
) | |
``` | |
```{r margins_final, eval = FALSE} | |
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! | |
```{r, eval = FALSE} | |
state_election_plot_B | |
``` | |
] | |
.pull-right[ | |
```{r margins_final, echo = FALSE, out.width = "400px"} | |
``` | |
] | |
--- | |
#2. Margins & Spacing (Before-After) | |
.pull-left[ | |
```{r, echo = FALSE, out.width = "400px"} | |
state_election_plot_A | |
``` | |
] | |
.pull-right[ | |
```{r, echo = FALSE, out.width = "400px"} | |
state_election_plot_B | |
``` | |
] | |
--- | |
class: inverse | |
#2. Margins & Spacing (Before-After) | |
.pull-left[ | |
```{r, echo = FALSE, out.width = "400px"} | |
state_election_plot_A | |
``` | |
] | |
.pull-right[ | |
```{r, echo = FALSE, out.width = "400px"} | |
state_election_plot_B | |
``` | |
] | |
--- | |
#3. Legends | |
-- | |
Legends are really hard: | |
-- | |
- <p>They contain important info, but difficult to make them not look out of place</p> | |
-- | |
- 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 | |
-- | |
<br> | |
Alternative: consider _labeling the data directly_ | |
--- | |
class: inverse, center, middle | |
```{r, echo = FALSE, out.width="550px"} | |
knitr::include_graphics("P_lab_ggplot2_files/538plots.gif") | |
``` | |
--- | |
#3. Legends | |
Legends are really hard: | |
- <p>They contain important info, but difficult to make them not look out of place</p> | |
- 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 | |
<br> | |
Alternative: consider _labeling the data directly_ | |
-- | |
<br> | |
But if you must have a legend, make it so that the reader **_can't help_** but to look at | |
-- | |
- <p>Positioned at the top-left or top-center of the plot</p> | |
-- | |
- Blend smoothly into the rest of the plot (_NOT_ make them stand out!) | |
--- | |
```{r legends2, echo = FALSE, eval = FALSE, warning = FALSE} | |
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) | |
``` | |
`r chunk_reveal("legends2", break_type = "auto", widths = c(40, 60))` | |
--- | |
#3. Legends (End!) | |
.pull-left[ | |
```{r, echo = FALSE, message = FALSE} | |
state_election_plot_C <- 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) | |
``` | |
```{r legends_final, eval = FALSE} | |
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! | |
```{r, eval = FALSE} | |
state_election_plot_C | |
``` | |
] | |
.pull-right[ | |
```{r legends_final, echo = FALSE, out.width = "400px"} | |
``` | |
] | |
--- | |
#3. Legends (Before-After) | |
.pull-left[ | |
```{r, echo = FALSE, out.width = "400px"} | |
state_election_plot_B | |
``` | |
] | |
.pull-right[ | |
```{r, echo = FALSE, out.width = "400px"} | |
state_election_plot_C | |
``` | |
] | |
--- | |
#4. Color | |
-- | |
Colors are a double-edged sword | |
-- | |
- <p>Perception can vary widely depending on reader, medium, culture, etc.</p> | |
-- | |
- There are multiple, complex representations (RGB, wavelength, hex, [HSV](https://colordesigner.io/convert/hextohsv)) | |
--- | |
class: center, middle | |
```{r, echo = FALSE, out.width = "600px"} | |
knitr::include_graphics("https://yjunechoe.github.io/posts/2020-10-22-analysis-of-everycolorbots-tweets/HSV.png") | |
``` | |
--- | |
#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](https://colordesigner.io/convert/hextohsv)) | |
-- | |
<br> | |
If you must, DO: | |
-- | |
- <p>Avoid pure colors (no random sampling from the rainbow!)</p> | |
-- | |
- Contrast colors in more than one dimension | |
--- | |
class: center, middle | |
```{r, echo = FALSE, out.width = "650px"} | |
knitr::include_graphics("P_lab_ggplot2_files/avoid_pure_colors.png") | |
``` | |
<br> | |
source: https://blog.datawrapper.de/beautifulcolors/ | |
--- | |
class: center, middle | |
```{r, echo = FALSE, out.width = "650px"} | |
knitr::include_graphics("P_lab_ggplot2_files/combine_diff_dimensions.png") | |
``` | |
<br> | |
source: https://blog.datawrapper.de/beautifulcolors/ | |
--- | |
#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](https://colordesigner.io/convert/hextohsv)) | |
<br> | |
If you must, DO: | |
- Avoid pure colors (no random sampling from the rainbow!) | |
- Contrast colors in more than one dimension | |
<br> | |
If you aren't sure, use [pre-made palettes](https://github.com/EmilHvitfeldt/paletteer) or play around with [online color tools](https://color.adobe.com/create/color-wheel) | |
--- | |
class: center, middle | |
<iframe src="https://paletton.com/" height="600px" width="1050px"> | |
--- | |
```{r colors1, echo = FALSE, eval = FALSE, warning = FALSE} | |
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) | |
``` | |
`r chunk_reveal("colors1", break_type = "auto", widths = c(40, 60))` | |
--- | |
```{r, eval=FALSE} | |
library(colorBlindness) | |
``` | |
<br> | |
```{r, echo = FALSE, fig.align="center", out.width="850px"} | |
knitr::include_graphics("P_lab_ggplot2_files/CBplot.png") | |
``` | |
```{r, echo = FALSE, eval = FALSE} | |
colorblind_plot <- 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("#D6B25E", "#79917E", "#215982") | |
) + | |
geom_line(size = 0.5) + | |
theme(legend.position = 0) + | |
theme(text = element_text(size = 12), | |
plot.title = element_text(size = 14), | |
plot.margin = margin(5, 5,0,0, "mm") | |
) | |
colorBlindness::cvdPlot(colorblind_plot) | |
``` | |
--- | |
```{r themes, echo = FALSE, eval = FALSE} | |
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() + #ROTATE | |
nord::scale_color_nord(palette = "aurora", discrete = TRUE) + #ROTATE | |
ggsci::scale_color_simpsons() + #ROTATE | |
ghibli::scale_color_ghibli_d("SpiritedDark", direction = -1) + #ROTATE | |
scale_color_manual(values = wesanderson::wes_palette("Moonrise2", 3, "discrete")) + #ROTATE | |
palettetown::scale_color_poke(pokemon = "pikachu") + #ROTATE | |
scale_color_manual(values = LaCroixColoR::lacroix_palette("PeachPear", 3, "discrete")) #ROTATE | |
``` | |
`r chunk_reveal("themes", break_type = "rotate", widths = c(40, 60))` | |
--- | |
```{r colors2, echo = FALSE, eval = FALSE, warning = FALSE} | |
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!") + #OMIT | |
labs(subtitle = "<span style='color:#0E4369'>Pennsylvania</span> is a swing state! Go vote!") + #ROTATE | |
labs(subtitle = "<strong style='color:#0E4369'>Pennsylvania</strong> is a swing state! Go vote!") + #ROTATE | |
theme( | |
plot.subtitle = ggtext::element_markdown() | |
) + | |
geom_line(size = 1.5) | |
``` | |
`r chunk_reveal("colors2", omit = "#ROTATE", break_type = "auto", widths = c(40, 60))` | |
--- | |
`r chunk_reveal("colors2", omit = "#OMIT", break_type = "rotate", widths = c(40, 60))` | |
--- | |
#4. Colors (End!) | |
.pull-left[ | |
```{r, echo = FALSE, message = FALSE} | |
state_election_plot_D <- 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!") | |
``` | |
```{r colors_final, eval = FALSE} | |
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! | |
```{r, eval = FALSE} | |
state_election_plot_D | |
``` | |
] | |
.pull-right[ | |
```{r colors_final, echo = FALSE, out.width = "400px"} | |
``` | |
] | |
--- | |
#4. Colors (Before-After) | |
.pull-left[ | |
```{r, echo = FALSE, out.width = "400px"} | |
state_election_plot_C | |
``` | |
] | |
.pull-right[ | |
```{r colors1, echo = FALSE, out.width = "400px"} | |
``` | |
] | |
--- | |
#4. Colors (Before-After) | |
.pull-left[ | |
```{r, echo = FALSE, out.width = "400px"} | |
state_election_plot_C | |
``` | |
] | |
.pull-right[ | |
```{r, echo = FALSE, out.width = "400px"} | |
state_election_plot_D | |
``` | |
] | |
--- | |
class: inverse, center, middle | |
```{r, echo = FALSE, out.width="500px"} | |
knitr::include_graphics("P_lab_ggplot2_files/final.gif") | |
``` | |
--- | |
```{r final, echo=FALSE, eval = FALSE} | |
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") | |
), | |
) | |
``` | |
`r chunk_reveal("final", break_type = "auto", widths = c(40, 60))` | |
--- | |
class: inverse, center, middle | |
# Showcasing | |
--- | |
# First, save our theme! | |
.pull-left[ | |
You can set global theme with `theme_set()` and `theme_update()`: | |
<br> | |
- `theme_set()` takes a custom theme as a argument (e.g., `theme_bw()`, `theme_classic()`, etc.) | |
<br> | |
- `theme_update()` takes individual theme elements as arguments | |
<br> | |
] | |
.pull-right[ | |
```{r} | |
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") | |
) | |
) | |
``` | |
] | |
--- | |
class: inverse, center, middle | |
## 1. Vowel Formant Plot | |
```{r vowel_data, echo = FALSE} | |
library(rvest) | |
sim_vowel_scraped_all <- read_html('https://en.wikipedia.org/wiki/Formant') %>% | |
html_node(xpath = '/html/body/div[3]/div[3]/div[5]/div[1]/table[2]') %>% | |
html_table() %>% | |
select(1:3) %>% | |
rename_all(~c("Vowel", "F1", "F2")) %>% | |
as_tibble() | |
sim_vowel_data_all <- sim_vowel_scraped_all %>% | |
mutate(data = map2(F1, F2, | |
~ MASS::mvrnorm( | |
50, mu = c(F1 = .x, F2 = .y), | |
Sigma = matrix( | |
c(80^2, 80*150*runif(1, -.5, .5), | |
80*150*runif(1, -.5, .5), 150^2), | |
nrow = 2) | |
) %>% | |
as_tibble() %>% | |
modify(abs) | |
) | |
) %>% | |
select(-c(F1, F2)) %>% | |
unnest(data) | |
sim_vowel_data <- sim_vowel_data_all %>% | |
filter(Vowel %in% c("i", "e", "ɛ", "œ", "a", "ɑ", "ʌ", "ɔ", "o", "u")) | |
``` | |
--- | |
```{r vowels1, echo = FALSE, eval=FALSE, fig.height=5, fig.width=7} | |
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)) | |
``` | |
`r chunk_reveal("vowels1", break_type = "auto", widths = c(40, 60))` | |
--- | |
class: inverse, center, middle | |
# 2. Vowel Space Plot | |
```{r stat_chull, echo = FALSE} | |
StatChull <- ggproto("StatChull", Stat, | |
compute_group = function(data, scales) { | |
data[chull(data$x, data$y), , drop = FALSE] | |
}, | |
required_aes = c("x", "y") | |
) | |
stat_chull <- function(mapping = NULL, data = NULL, geom = "polygon", | |
position = "identity", na.rm = FALSE, show.legend = NA, | |
inherit.aes = TRUE, ...) { | |
layer( | |
stat = StatChull, data = data, mapping = mapping, geom = geom, | |
position = position, show.legend = show.legend, inherit.aes = inherit.aes, | |
params = list(na.rm = na.rm, ...) | |
) | |
} | |
``` | |
--- | |
```{r vowels2, echo = FALSE, eval=FALSE} | |
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 | |
) | |
``` | |
`r chunk_reveal("vowels2", break_type = "auto", widths = c(40, 60))` | |
--- | |
class: inverse, center, middle | |
# 3. Bar Plot of Proportions | |
--- | |
```{r accuracy_bar, echo = FALSE, eval=FALSE} | |
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) | |
) | |
``` | |
`r chunk_reveal("accuracy_bar", break_type = "auto", widths = c(40, 60))` | |
--- | |
class: inverse, center, middle | |
# 4. Multiple Categorical Levels | |
--- | |
class: center, middle | |
```{r, echo = FALSE, out.height="500px"} | |
knitr::include_graphics("https://yjunechoe.github.io/posts/2020-09-20-plot-makeover-1/plot.png") | |
``` | |
Source: [Husband & Patson (2020)](https://amlap2020.github.io/a/272.pdf) | |
--- | |
.pull-left[ | |
```{r makeover, message = FALSE, eval=FALSE} | |
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() | |
``` | |
] | |
.pull-right[ | |
```{r, echo = FALSE, out.width="350px"} | |
knitr::include_graphics("https://yjunechoe.github.io/posts/2020-09-20-plot-makeover-1/plot-makeover-1_files/figure-html5/unnamed-chunk-3-1.png") | |
``` | |
] | |
--- | |
class: center, middle | |
```{r, echo = FALSE, out.height="500px"} | |
knitr::include_graphics("https://yjunechoe.github.io/posts/2020-09-20-plot-makeover-1/plot-makeover-1_files/figure-html5/after_bar_plot-1.png") | |
``` | |
([Code](https://yjunechoe.github.io/posts/2020-09-20-plot-makeover-1/)) | |
--- | |
class: center, middle | |
```{r, echo = FALSE, out.height="500px"} | |
knitr::include_graphics("https://yjunechoe.github.io/posts/2020-09-20-plot-makeover-1/plot-makeover-1_files/figure-html5/after_pointplot-1.png") | |
``` | |
([Code](https://yjunechoe.github.io/posts/2020-09-20-plot-makeover-1/)) | |
--- | |
class: inverse, center, middle | |
# 5. Animations: Vowel shift | |
--- | |
.pull-left[ | |
```{r canada, message = FALSE, eval=FALSE} | |
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) | |
) | |
``` | |
] | |
.pull-right[ | |
<br> | |
<br> | |
```{r, echo = FALSE, out.width="500px"} | |
knitr::include_graphics("P_lab_ggplot2_files/canada_vowel_shift.gif") | |
``` | |
] | |
--- | |
class: inverse, center, middle | |
# 5. Animations: Eye-tracking | |
--- | |
class: center, middle | |
```{r, echo = FALSE, out.height="500px", fig.cap="de Carvalho et al. (2017)"} | |
knitr::include_graphics("P_lab_ggplot2_files/eyetrack_original.png") | |
``` | |
--- | |
class: center, middle | |
```{r, echo = FALSE, out.height="500px"} | |
knitr::include_graphics("https://yjunechoe.github.io/static/dataviz/eyetracking_anim.gif") | |
``` | |
([Code](https://gist.github.com/yjunechoe/b39e92889768b26faaec3e0103d4af10)) | |
--- | |
# Resources | |
<span style = "font-variant: small-caps;">light</span> | |
- [The Glamour of Graphics](https://rstudio.com/resources/rstudioconf-2020/the-glamour-of-graphics/) (20-min video) | |
- [Gallery of plot tyes](https://www.data-to-viz.com/) | |
- [What to consider when choosing colors for data viz](https://blog.datawrapper.de/colors/) | |
- [Palettes (in R)](https://github.com/EmilHvitfeldt/r-color-palettes) | |
<span style = "font-variant: small-caps;">heavy</span> | |
- [Font Recommendations](https://practicaltypography.com/font-recommendations.html) (book chapter) | |
- [Theme elements in ggplot2](https://ggplot2.tidyverse.org/reference/theme.html) (documentation) | |
- [ggplot2 tutorial](https://www.youtube.com/watch?v=h29g21z0a68) (4-hour video, 2 parts) | |
- [ggplot2 book](https://ggplot2-book.org/) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment