October 19, 2019

Agenda

  • Overview of ggplot2
  • Rewind to tidyverse to discuss group_by() and summarise()
  • Build bar plots + big exercise
  • Build other plots + exercises

ggplot2

Plot types

Plot types

Plot types

Plot types

What we will learn

Requests to learn another plot type?

Plot types

1 discrete variable (plus other optional discrete and/or continuous variables)

1 continuous variable

Plot types

2 continuous variables

1 continuous variable + date variable

Let’s make sure you’re able to plot your data

library(tidyverse)
mpg %>% ggplot() + geom_point(aes(displ, hwy))

Let’s make sure you’re able to plot your data

  • If you see a plot, you’re ready to go!
  • If you do not, reinstall tidyverse and re-run the test code
install.packages('tidyverse')
library(tidyverse)
mpg %>% ggplot(aes(displ, hwy))) + geom_point()
  • If it still didn’t work, install ggplot2 and re-run the test code
install.packages('ggplot2')
library(ggplot2)
mpg %>% ggplot(aes(displ, hwy)) + geom_point()

And, read your data

library(tidyverse)
crime <- read_csv('https://bit.ly/2mcZLq4') %>% as.data.frame()
contr <- read_csv('https://bit.ly/2lQySrQ') %>% as.data.frame()

How to plot data

  1. Pick your data
  2. Pick your chart type (Geom)
  3. Program stuff like chart titles, axis names, axis types, and legends (Scales)
  4. Make it pretty (Themes)
  5. Keep tuning and reuse code

ggplot basics

Geoms

  • Every plot needs a ggplot() function and a geom layer
  • Separate layers and other plotting functions with +
ggplot() + geom_bar()       # create bar and stacked bar plots
ggplot() + geom_histogram() # create histograms
ggplot() + geom_point()     # create scatter plots
ggplot() + geom_line()      # create line plots
  • Your data is an argument in the ggplot() function
contr %>% ggplot() + geom_bar()
ggplot(contr) + geom_bar()

Geoms

  • Map your data to the plot with aes()
    • aes() indicates the variables that affect the chart aesthetics
    • aes() can be an argument in ggplot() or the geom
    • Many arguments in the aes() function
    • aes() arguments reference variables in your data frame
contr %>% ggplot(aes(primary_general)) + geom_bar()
contr %>% ggplot() + geom_bar(aes(primary_general))
aes(x = NULL, y = NULL, color = NULL
  , fill = NULL, alpha = NULL, label = NULL
  , shape = NULL, size = NULL, group = NULL
  , linetype = NULL
  )

Geoms

contr %>% ggplot(aes(primary_general)) + geom_bar()
contr %>% ggplot() + geom_bar(aes(primary_general))

Geoms

contr %>% ggplot(aes(primary_general, fill = primary_general)) + geom_bar()

Geoms

contr %>% ggplot(aes(primary_general, fill = party)) + geom_bar()

Exercise - 7 minutes

  • Build a bar chart with crime data that shows how many incidences occurred in sector
  • Only include these sector values: c('B', 'E', 'D', 'R', 'O', 'C', 'K')
  • Color the bars using crime_subcategory
  • Only include these crime_subcategory values: c('ROBBERY-STREET', 'THEFT-BICYCLE', 'AGGRAVATED ASSAULT', 'TRESPASS')

Hint

# Use to include/exclude values
filter()

Exercise - 7 minutes

  • Build a bar chart with crime data that shows how many incidences occurred in sector
  • Only include these sector values: c('B', 'E', 'D', 'R', 'O', 'C', 'K')
  • Color the bars using crime_subcategory
  • Only include these crime_subcategory values: c('ROBBERY-STREET', 'THEFT-BICYCLE', 'AGGRAVATED ASSAULT', 'TRESPASS')

Hint

crime %>%
  filter() %>%
  ggplot()

Exercise - 7 minutes

crime %>% 
  filter(
    sector %in% c('B', 'E', 'D', 'R', 'O', 'C', 'K') &
    crime_subcategory %in% c('ROBBERY-STREET', 'THEFT-BICYCLE'
                             , 'AGGRAVATED ASSAULT', 'TRESPASS')
    ) %>%
  ggplot(aes(sector, fill = crime_subcategory)) + 
  geom_bar()

Scales

Axis, legend, and chart titles

Axis names

  • Keep names short-ish
  • Consider including units in axis name
  • It is possible you don’t need an axis name

2 options

# Option 1
labs(x = 'X Axis Title', y = 'Y Axis Title')

# Option 2
xlab('X Axis Title')
ylab('Y Axis Title')

Axis, legend, and chart titles

contr %>% 
  filter(! primary_general %in% NA) %>% 
  ggplot(aes(primary_general, fill = primary_general)) + 
  geom_bar() + 
  labs(x = 'Election Type', y = 'Donations (#)')

Axis, legend, and chart titles

Try adding axis names to the sector plot you made during the exercise

crime %>% 
  filter(
    sector %in% c('B', 'E', 'D', 'R', 'O', 'C', 'K') &
    crime_subcategory %in% c('ROBBERY-STREET', 'THEFT-BICYCLE'
                             , 'AGGRAVATED ASSAULT', 'TRESPASS')
    ) %>%
  ggplot(aes(sector, fill = crime_subcategory)) + geom_bar() + 
  labs(x = 'District Sectors', y = 'Incidences by Event\nClearance Group (#)')

Axis, legend, and chart titles

Legend names

  • Keep names short
  • Be mindful of what the legend is for
    • Color? Fill? Size? etc.
  • Consider hiding the legend title for a clean look
labs(fill = '')
labs(fill = element_blank())
labs(fill = NULL)
labs(colour = 'Check out these colors')

Axis, legend, and chart titles

crime %>% 
  filter(
    sector %in% c('B', 'E', 'D', 'R', 'O', 'C', 'K') &
    crime_subcategory %in% c('ROBBERY-STREET', 'THEFT-BICYCLE'
                             , 'AGGRAVATED ASSAULT', 'TRESPASS')
    ) %>%
  ggplot(aes(sector, fill = crime_subcategory)) + geom_bar() + 
  labs(x = 'Election Type', y = 'Donations (#)', fill = 'Check out these colors')

Axis, legend, and chart titles

Try removing the legend name from your sector plot

Axis, legend, and chart titles

Try removing the legend name from your sector plot

crime %>% 
  filter(sector %in% c('B', 'E', 'D', 'R', 'O', 'C', 'K')) %>%
  ggplot(aes(sector, fill = crime_subcategory)) + geom_bar() + 
  labs(x = 'District Sectors', y = 'Incidences by Event\nClearance Group (#)'
       , fill = element_blank())

Axis, legend, and chart titles

Chart titles and subtitles

  • Consider making titles (or subtitles) descriptive
  • Don’t over use subtitles
# Option 1
labs(title = NULL, subtitle = NULL)

# Option 2
ggtitle(title = NULL, subtitle = NULL)

Axis, legend, and chart titles

contr %>% 
  ggplot(aes(primary_general, fill = primary_general)) + 
  geom_bar() + 
  labs(
    x = 'Election Type'
    , y = 'Donations (#)'
    , fill = element_blank()
    , title = 'Number of Donations by Election Type'
    , subtitle = 'Over 6,000 full election cycle donations'
    )

Axis, legend, and chart titles

Axis, legend, and chart titles

Try adding a title to the sector plot

Axis, legend, and chart titles

Try adding a title to the sector plot

crime %>% 
  filter(
    sector %in% c('B', 'E', 'D', 'R', 'O', 'C', 'K') &
    crime_subcategory %in% c('ROBBERY-STREET', 'THEFT-BICYCLE'
                             , 'AGGRAVATED ASSAULT', 'TRESPASS')
    ) %>%
  ggplot(aes(sector, fill = crime_subcategory)) + geom_bar() + 
  labs(x = 'District Sectors', y = 'Incidences by Event\nClearance Group (#)'
       , fill = element_blank(), title = 'An Amazing Title'
       )

Axis units

  • Change axis units
  • This is a good idea and you should do it when its relevant
  • Good for x and y axes
install.packages('scales')
library(scales)

scale_y_continuous(labels = percent) # Add a percentage sign to numbers on axis
scale_y_continuous(labels = dollar)  # Add a dollar sign to numbers on axis
scale_y_continuous(labels = comma)   # Add a comma to numbers on axis

Axis units

contr %>% 
  filter(! primary_general %in% NA) %>% 
  ggplot(aes(primary_general, fill = primary_general)) + 
  geom_bar() + 
  labs(
    x = 'Election Type'
    , y = 'Donations (#)'
    , fill = element_blank()
    , title = 'Number of Donations by Election Type'
    , subtitle = 'Over 6,000 full election cycle donations'
    ) + 
  scale_y_continuous(labels = comma) 

Axis units

Themes

Themes

  • Change layer and background colors
  • Change fonts
  • Change plot borders/boundaries and ticks
  • Pre-built themes vs. custom themes
    • ggplot2 themes
    • ggthemes themes
install.packages('ggthemes')
library(ggthemes)

Pre-built themes

Selected ggplot2 themes

theme_classic()
theme_minimal()
theme_dark()

Selected ggthemes themes

theme_stata() + scale_colour_stata() # scale_fill_stata()
theme_economist() + scale_colour_economist() # scale_fill_economist()
theme_fivethirtyeight() + scale_color_fivethirtyeight() # scale_fill_fivethirtyeight()
theme_wsj() + scale_colour_wsj() # scale_fill_wsj()
theme_pander() + scale_colour_pander() # scale_fill_pander()
theme_hc(bgcolor = "darkunica") + scale_colour_hc("darkunica") # scale_fill_hc("darkunica")

Pre-built themes

contr %>% 
  filter(! primary_general %in% NA) %>% 
  ggplot(aes(primary_general, fill = primary_general)) + 
  geom_bar() + 
  labs(
    x = 'Election Type'
    , y = 'Donations (#)'
    , fill = element_blank()
    , title = 'Number of Donations by Election Type'
    , subtitle = 'Over 6,000 full election cycle donations'
    ) + 
  scale_y_continuous(labels = comma) +
  theme_economist() + 
  scale_fill_economist()

Pre-built themes

Economist theme

Pre-built themes

Pre-built themes

Try adding a theme to the sector plot

Custom themes

  • You can create custom themes with theme()
  • Greater control over chart aesthestics
  • Use custom themes in place of pre-built themes if pre-built themes don’t cut it
  • Also, use custom themes to augment pre-built themes

Custom themes

theme(
  plot.title = element_text(size=14, face="bold", vjust=1)
  , plot.background = element_blank()
  , panel.grid.major = element_blank()
  , panel.grid.minor = element_blank()
  , panel.border = element_blank()
  , panel.background = element_blank()
  , axis.ticks = element_blank()
  , axis.text = element_text(colour="black", size=12)
  , axis.text.x = element_text(angle=45, hjust=1)
  , legend.title = element_blank()
  , legend.position = "none"
  , legend.text = element_text(size=12)
  )

Circling back to the Tidyverse to aggregate data with group_by() and summarise()

What you can do with group_by() and summarise()

  • Count, sum, average, and identify max and min values
  • Example questions you could answer
    • In contr, which office received the most money in campaign donations from 'MAYOR'?
    • In contr, which contributor_state saw the largest number of cash donations, excluding 'WA' and NA values?
    • In contr, what is the largest average donation amount by contributor_state?
    • In crime, how many crimes were reported (reported_year) one and two years after the year in which they occurred (occurred_year)?

How you use group_by() and summarise() to aggregate data

  • In group_by(), list the variables by which you want to aggregate data
  • In summarise(), create a variable and define the variable with an aggregation function
  • Use %>% to ‘link’ group_by() and summarise()
  • Aggregation functions
    • n(), n_distinct(), sum(), mean(), max(), min(), etc.
  • Perform multiple aggregations in a single summarise() function
  • Like COUNTIFS() and SUMIFS() in Excel. collapse() by() in Stata

Example
In contr, which office associated with 'NON PARTISAN' party values received the most money in donations?

contr %>% group_by(office, party) %>% summarise(dollars = sum(amount, na.rm = TRUE))

How you use group_by() and summarise() to aggregate data

Example
In contr, which office associated with 'NON PARTISAN' party values received the most money in donations?

contr %>% 
  group_by(office, party) %>% 
  summarise(dollars = sum(amount, na.rm = TRUE)) %>%
  filter(party %in% 'NON PARTISAN') %>% 
  arrange(desc(dollars)) %>% 
  head()
## # A tibble: 6 x 3
## # Groups:   office [6]
##   office                party        dollars
##   <chr>                 <chr>          <dbl>
## 1 CITY COUNCIL MEMBER   NON PARTISAN 686644.
## 2 MAYOR                 NON PARTISAN 331237.
## 3 <NA>                  NON PARTISAN 208066.
## 4 PORT COMMISSIONER     NON PARTISAN 152623.
## 5 COUNTY COUNCIL MEMBER NON PARTISAN 146563.
## 6 COUNTY EXECUTIVE      NON PARTISAN 131929.

How you use group_by() and summarise() to aggregate data

Example
In contr, which contributor_state saw the largest number of cash donations (see cash_or_in_kind), excluding 'WA' and NA values?

contr %>% 
  filter(cash_or_in_kind %in% 'Cash' & ! contributor_state %in% c('WA', NA)) %>% 
  group_by(contributor_state) %>% 
  summarise(n = n()) %>% 
  arrange(desc(n)) %>% 
  head(5)
## # A tibble: 5 x 2
##   contributor_state     n
##   <chr>             <int>
## 1 CA                  423
## 2 OR                  213
## 3 NY                  128
## 4 DC                  121
## 5 TX                  116

How you use group_by() and summarise()

How would you turn the tabular output data into a chart?

contr %>% 
  filter(cash_or_in_kind %in% 'Cash' & ! contributor_state %in% c('WA', NA)) %>% 
  group_by(contributor_state) %>% 
  summarise(n = n()) %>% 
  arrange(desc(n)) %>% 
  head(5)
## # A tibble: 5 x 2
##   contributor_state     n
##   <chr>             <int>
## 1 CA                  423
## 2 OR                  213
## 3 NY                  128
## 4 DC                  121
## 5 TX                  116

How you use group_by() and summarise()

How would you turn the tabular output data into a chart?

contr %>% 
  filter(cash_or_in_kind %in% 'Cash' & ! contributor_state %in% c('WA', NA)) %>% 
  group_by(contributor_state) %>% 
  summarise(n = n()) %>% 
  arrange(desc(n)) %>% 
  head(5) %>% 
  ggplot(aes(x = contributor_state, y = n, fill = contributor_state)) + 
  geom_bar(stat = "identity") + 
  coord_flip() # coord_flip() is a new function

How you use group_by() and summarise()

How would you turn the tabular output data into a chart?

contr %>% 
  filter(cash_or_in_kind %in% 'Cash' & ! contributor_state %in% c('WA', NA)) %>% 
  group_by(contributor_state) %>% 
  summarise(n = n()) %>% 
  arrange(desc(n)) %>% 
  head(5) %>% 
  ggplot(aes(reorder(contributor_state, n), n, fill = contributor_state)) + # reorder() is a new function
  geom_bar(stat = "identity") + 
  coord_flip() # coord_flip() is a new function

How you use group_by() and summarise()

How would you turn the tabular output data into a chart?

contr %>% 
  filter(cash_or_in_kind %in% 'Cash' & ! contributor_state %in% c('WA', NA)) %>% 
  group_by(contributor_state) %>% 
  summarise(n = n()) %>% 
  arrange(desc(n)) %>% 
  head(5) %>% 
  ggplot(aes(reorder(contributor_state, n), n, fill = contributor_state)) + 
  geom_bar(stat = "identity") + 
  coord_flip() 

New argument and functions

geom_bar(stat = 'identity')   # IMPORTANT: use stat when working with aggregated data
reorder(contributor_state, n) # reorder() to sort rows/columns in your visualization
coord_flip()                  # coord_flip(): x becomes y; y becomes x

How you use group_by() and summarise()

Example
In contr, what is the largest average donation amount by contributor_state?

contr %>% 
  filter(! contributor_state %in% NA) %>% 
  group_by(contributor_state) %>% 
  summarise(avg_donation = mean(amount, na.rm = TRUE)) %>% 
  arrange(desc(avg_donation)) %>%
  head(5)
## # A tibble: 5 x 2
##   contributor_state avg_donation
##   <chr>                    <dbl>
## 1 MS                       1000 
## 2 UT                        750 
## 3 TN                        636.
## 4 MO                        595 
## 5 OK                        550

How you use group_by() and summarise()

How would you turn the tabular output data into a chart?

contr %>% 
  filter(! contributor_state %in% NA) %>% 
  group_by(contributor_state) %>% 
  summarise(avg_donation = mean(amount, na.rm = TRUE)) %>% 
  arrange(desc(avg_donation)) %>%
  head(5)
## # A tibble: 5 x 2
##   contributor_state avg_donation
##   <chr>                    <dbl>
## 1 MS                       1000 
## 2 UT                        750 
## 3 TN                        636.
## 4 MO                        595 
## 5 OK                        550

How you use group_by() and summarise()

How would you turn the tabular output data into a chart?

contr %>% 
  filter(! contributor_state %in% NA) %>% 
  group_by(contributor_state) %>% 
  summarise(avg_donation = mean(amount, na.rm = TRUE)) %>% 
  ggplot(aes(reorder(contributor_state, -avg_donation), avg_donation)) +
  geom_bar(stat = 'identity') + 
  theme_classic()

Exercise - 15 minutes

  • From the crime dataset, report the mean difference in reported_date and occurred_date values by sector.
    • The variable that tells us the difference between reported_date and occurred_date should be called date_dif
    • In your output of mean values by sector only report rows where the number of sector values in the dataset is greater than 100
    • You’ll use transmute and filter as well as group_by and summarise to solve this problem
    • The dataframe should have three variables: sector, date_dif, n
  • Create a bar plot that that shows date_dif values by sector

Hint

crime %>% 
  transmute(
    sector
    , date_dif = reported_date - occurred_date
  ) %>% 

Exercise - 15 minutes

  • From the crime dataset, report the mean difference in reported_date and occurred_date values by sector.
    • The variable that tells us the difference between reported_date and occurred_date should be called date_dif
    • In your output of mean values by sector only report rows where the number of sector values in the dataset is greater than 100
    • You’ll use transmute and filter as well as group_by and summarise to solve this problem
    • The dataframe should have three variables: sector, date_dif, n
  • Create a bar plot that that shows date_dif values by sector
crime %>% 
  transmute(
    sector
    , date_dif = reported_date - occurred_date
  ) %>% 
  group_by(sector) %>% 
  summarise(
    date_dif = mean(date_dif, na.rm = TRUE)
    , n = n()
  ) %>% 

Exercise - 15 minutes

  • From the crime dataset, report the mean difference in reported_date and occurred_date values by sector.
    • The variable that tells us the difference between reported_date and occurred_date should be called date_dif
    • In your output of mean values by sector only report rows where the number of sector values in the dataset is greater than 100
    • You’ll use transmute and filter as well as group_by and summarise to solve this problem
    • The dataframe should have three variables: sector, date_dif, n
  • Create a bar plot that that shows date_dif values by sector
crime %>% 
  transmute(
    sector
    , date_dif = reported_date - occurred_date
  ) %>% 
  group_by(sector) %>% 
  summarise(
    date_dif = mean(date_dif, na.rm = TRUE)
    , n = n()
  ) %>% 
  filter(n > 100) %>% 

Exercise - 15 minutes

crime %>% 
  transmute(
    sector
    , date_dif = reported_date - occurred_date
  ) %>% 
  group_by(sector) %>% 
  summarise(
    date_dif = mean(date_dif, na.rm = TRUE)
    , n = n()
  ) %>% 
  filter(n > 100) %>% 
  ggplot(aes(x = sector, y = date_dif)) +
  geom_bar(stat = 'identity')

Exercise - 15 minutes

Exercise - 5 minutes

  • Take an extra 5 minutes to do the following
    • Add a theme to your plot
    • Change the axis names
    • Add a plot title
    • Arrange the sector columns by date_dif
    • Remove NA sector values

Exercise - 5 minutes

Exercise - 5 minutes

crime %>% 
  transmute(
    sector
    , date_dif = reported_date - occurred_date
  ) %>% 
  group_by(sector) %>% 
  summarise(
    date_dif = mean(date_dif, na.rm = TRUE)
    , n = n()
  ) %>% 
  filter(n > 100 & ! sector %in% NA) %>% 
  ggplot(aes(reorder(sector, -date_dif), date_dif)) +
  geom_bar(stat = 'identity') + 
  labs(
    y = 'Average delay in reporting (days)'
    , x = 'Sectors'
    , title = 'Sector W sees the longest delay in events reporting'
    ) + 
  theme_classic()

Histograms, scatterplots, and line plots

Histograms: 1 continuous variable

  • bins is the argument you use to indicate the number of columns in your histogram
contr %>% 
  filter(amount > 0 & amount < 1000) %>%
  ggplot(aes(amount)) + geom_histogram() 

Histograms: 1 continuous variable

  • bins is the argument you use to indicate the number of columns in your histogram
contr %>% 
  filter(amount > 0 & amount < 1000) %>%
  ggplot(aes(amount)) + geom_histogram(bins = 10) 

Scatterplots: 2 continuous variables

contr %>% 
  filter(amount > 0 & amount < 1000000) %>%
  ggplot(aes(receipt_date, amount)) + 
  geom_point()

Scatterplots: 2 continuous variables

contr %>% 
  ggplot(aes(receipt_date, amount)) + 
  geom_point()
geom_count() # adds a size component to your scatterplot
geom_jitter() # adjusts cartesian location of point relative to other points

Line plot: 1 continuous variable + date variable

contr %>% 
  group_by(receipt_date) %>%
  summarise(amount = sum(amount)) %>% 
  ggplot(aes(x = receipt_date, y = amount)) +
  geom_line(stat = 'identity')

Line plot: 1 continuous variable + date variable

contr %>% 
  group_by(receipt_date) %>%
  summarise(amount = sum(amount)) %>% 
  filter(amount > 0) %>%  
  ggplot(aes(x = receipt_date, y = cumsum(amount))) + # cumsum() is a new function!
  geom_line(stat = 'identity')

Exercise - 5 minutes

  • With either dataset, contr or crime, create a scatterplot or line plot
  • Include one aes() arguments in addition to x and y
    • For example, size, shape, color or alpha
  • Line plots: 1 continuous variable + date variable
  • Scatterplot: 2 continuous variables
  • Use group_by() and summarise() if you would like
 crime %>% 
  filter(! precinct %in% NA) %>%
  ggplot(aes(reported_date, occurred_date, color = precinct)) + 
  geom_point() + 
  theme_classic()

Exercise - 5 minutes

 crime %>% 
  filter(! precinct %in% NA) %>%
  ggplot(aes(reported_date, occurred_date, color = precinct)) + 
  geom_point() + 
  theme_classic()

Exercise - 15 minutes

  • Create a chart from the crime dataset
  • Create a new variable with mutate() called occurred_time_ampm that tells whether an incident occurred in the AM or PM.
  • Make sure your axes are labeled correctly
  • Give your chart a title
  • Use occurred_time_ampm in the color or fill arguments in aes()
  • Use a pre-built theme

Exercise - 15 minutes

Exercise - 15 minutes

crime %>% 
  mutate(occurred_time_ampm = ifelse(occurred_time >= 1200, 'PM', 'AM')) %>% 
  filter(
    ! occurred_time_ampm %in% NA & 
    ! crime_subcategory %in% NA
    ) %>%
  group_by(crime_subcategory, occurred_time_ampm) %>%
  summarise(n = n()) %>%
  ungroup %>%
  group_by(crime_subcategory) %>%
  mutate(total = sum(n, na.rm = TRUE)) %>%
  filter(total >= 100) %>%
  ggplot(aes(reorder(crime_subcategory, n), n, fill = occurred_time_ampm)) + 
  geom_bar(stat = 'identity') + 
  coord_flip() + 
  theme_wsj() + 
  scale_colour_wsj() + 
  labs(title = 'Most incidence occur\nin the AM', fill = 'Time of Day')

Exercise - 10 minutes

  • Create a chart from the contr dataset
  • Make some comparison
  • Give your chart a title
  • Use a pre-built theme

Exercise - 10 minutes

Exercise - 10 minutes

contr %>% 
  filter(
    ! party %in% c(NA, 'OTHER', 'NONE') & 
    amount > 0 & 
    receipt_date >= '2008-01-01' & 
    receipt_date <= '2020-12-31'
    ) %>% 
  group_by(party, receipt_date) %>%
  summarise(amount = sum(amount)) %>%
  mutate(amount = cumsum(amount)) %>% # You can see that I use cumsum() in mutate()
  ggplot(aes(x = receipt_date, y = amount, color = party)) + 
  geom_line(size = 1, stat = 'identity') + 
  theme_wsj() + 
  scale_y_continuous(labels = dollar) +
  scale_colour_wsj() + 
  labs(
    title = 'Democrats receive nearly 1\nmillion more in donations than\nnext closest party',
    colour = element_blank()
    )