31  Headlines

These are the pieces of a good graphic:

The first on that list is the first for a reason. The headline is an incredibly important part of any graphic: it’s often the first thing a reader will see. It’s got to entice people in, tell them a little bit about what they’re going to see, and help tell the story.

The second item is the chatter – the text underneath that headline. It needs to work with the headline to further the story, drive people toward the point, maybe add some context.

The two bits of text are extremely important. Let’s set up a chart and talk about how to do it wrong and how to do it better.

library(tidyverse)
library(ggrepel)

The data and the chart code isn’t important for you to follow along. The code is nothing special. The issues will be with the words that you’ll see below.

scoring <- read_csv("data/scoringoffense.csv")
Rows: 1253 Columns: 10
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (1): Name
dbl (9): G, TD, FG, 1XP, 2XP, Safety, Points, Points/G, Year

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
total <- read_csv("data/totaloffense.csv")
Rows: 1253 Columns: 9
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (1): Name
dbl (8): G, Rush Yards, Pass Yards, Plays, Total Yards, Yards/Play, Yards/G,...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
offense <- total |> left_join(scoring, by=c("Name", "Year"))

nu <- offense |> filter(Name == "Nebraska") |> filter(Year == 2018)
ggplot(offense, aes(x=`Yards/G`, y=`Points/G`)) + 
  geom_point(color="grey") + geom_smooth(method=lm, se=FALSE) + 
  labs(x="Total yards per game", y="Points per game", title="Headline here", subtitle="This is the chatter. It is chatter. Chatter.", caption="Source: NCAA | By Matt Waite") + 
  theme_minimal() + 
  theme(
    plot.title = element_text(size = 16, face = "bold"),
    axis.title = element_text(size = 8), 
    plot.subtitle = element_text(size=10), 
    panel.grid.minor = element_blank()
    ) +
  geom_point(data=nu, aes(x=`Yards/G`, y=`Points/G`), color="red") + 
  geom_text_repel(data=nu, aes(x=`Yards/G`, y=`Points/G`, label="Nebraska 2018"))
`geom_smooth()` using formula = 'y ~ x'

First, let’s start with some headline basics:

Given our graph, here’s a few that don’t work.

ggplot(offense, aes(x=`Yards/G`, y=`Points/G`)) + 
  geom_point(color="grey") + geom_smooth(method=lm, se=FALSE) + 
  labs(x="Total yards per game", y="Points per game", title="Nebraska's offense", subtitle="Nebraska's 2018 offense is the red dot.", caption="Source: NCAA | By Matt Waite") + 
  theme_minimal() + 
  theme(
    plot.title = element_text(size = 16, face = "bold"),
    axis.title = element_text(size = 8), 
    plot.subtitle = element_text(size=10), 
    panel.grid.minor = element_blank()
    ) +
  geom_point(data=nu, aes(x=`Yards/G`, y=`Points/G`), color="red") + 
  geom_text_repel(data=nu, aes(x=`Yards/G`, y=`Points/G`, label="Nebraska 2018"))
`geom_smooth()` using formula = 'y ~ x'

The problems here:

Another example:

ggplot(offense, aes(x=`Yards/G`, y=`Points/G`)) + 
  geom_point(color="grey") + geom_smooth(method=lm, se=FALSE) + 
  labs(x="Total yards per game", y="Points per game", title="Points per game vs total yards per game", subtitle="Nebraska's 2018 offense is below the blue line, which is bad.", caption="Source: NCAA | By Matt Waite") + 
  theme_minimal() + 
  theme(
    plot.title = element_text(size = 16, face = "bold"),
    axis.title = element_text(size = 8), 
    plot.subtitle = element_text(size=10), 
    panel.grid.minor = element_blank()
    ) +
  geom_point(data=nu, aes(x=`Yards/G`, y=`Points/G`), color="red") + 
  geom_text_repel(data=nu, aes(x=`Yards/G`, y=`Points/G`, label="Nebraska 2018"))
`geom_smooth()` using formula = 'y ~ x'

What’s wrong here?

Let’s try to do this better.

ggplot(offense, aes(x=`Yards/G`, y=`Points/G`)) + 
  geom_point(color="grey") + geom_smooth(method=lm, se=FALSE) + 
  labs(x="Total yards per game", y="Points per game", title="Nebraska's strength?", subtitle="The Husker's offense was supposed to power the team. It underperformed.", caption="Source: NCAA | By Matt Waite") + 
  theme_minimal() + 
  theme(
    plot.title = element_text(size = 16, face = "bold"),
    axis.title = element_text(size = 8), 
    plot.subtitle = element_text(size=10), 
    panel.grid.minor = element_blank()
    ) +
  geom_point(data=nu, aes(x=`Yards/G`, y=`Points/G`), color="red") + 
  geom_text_repel(data=nu, aes(x=`Yards/G`, y=`Points/G`, label="Nebraska 2018"))
`geom_smooth()` using formula = 'y ~ x'

What works here:

One more, same chart.

ggplot(offense, aes(x=`Yards/G`, y=`Points/G`)) + 
  geom_point(color="grey") + geom_smooth(method=lm, se=FALSE) + 
  labs(x="Total yards per game", y="Points per game", title="Nebraska's offense underperformed", subtitle="The Husker's should have scored nearly a touchdown more given their output.", caption="Source: NCAA | By Matt Waite") + 
  theme_minimal() + 
  theme(
    plot.title = element_text(size = 16, face = "bold"),
    axis.title = element_text(size = 8), 
    plot.subtitle = element_text(size=10), 
    panel.grid.minor = element_blank()
    ) +
  geom_point(data=nu, aes(x=`Yards/G`, y=`Points/G`), color="red") + 
  geom_text_repel(data=nu, aes(x=`Yards/G`, y=`Points/G`, label="Nebraska 2018"))
`geom_smooth()` using formula = 'y ~ x'

What works here:

Taking time to sharpen your headlines will make your graphics better.