Graph info

Should I use this graph?


This graph requires:

✅ a categorical variable

✅ a numeric (continuous) variable

✅ a numeric (date) variable

Description

Slope graphs show changes in a numeric value (displayed on the y axis) typically over two points in time (along the x axis). The values for each group or unit of measurement are connected by lines, and any differences between the two time points are represented by the slope of the lines (hence the name, ‘slope chart’).

We can build slope graphs in ggplot2 using the geom_line() and geom_point() functions.

Getting set up

PACKAGES:

Install packages.

Code
install.packages("palmerpenguins")
library(palmerpenguins)
library(ggplot2)

DATA:

Artwork by @allison_horst

We’ll be using the penguins data for this graph, but slightly restructured.

Code
peng_slope <- palmerpenguins::penguins |>
    dplyr::filter(year < 2009) |>
    dplyr::group_by(year, island) |>
    dplyr::summarise(across(
        .cols = contains("mm"), 
        .fns = mean, 
            na.rm = TRUE, 
        .names = "avg_{.col}")) |>
    dplyr::ungroup()
glimpse(peng_slope)
Rows: 6
Columns: 5
$ year                  <int> 2007, 2007, 2007, 2008, 2008, 2008
$ island                <fct> Biscoe, Dream, Torgersen, Biscoe, Dream, Torgers…
$ avg_bill_length_mm    <dbl> 45.03864, 44.53913, 38.80000, 44.62031, 43.75588…
$ avg_bill_depth_mm     <dbl> 15.54091, 18.57391, 19.02105, 15.82500, 18.39706…
$ avg_flipper_length_mm <dbl> 207.5227, 189.8478, 189.2632, 209.6875, 195.0294…

The grammar

CODE:

Create labels with labs()

Initialize the graph with ggplot() and provide data

Map year to the x, avg_bill_depth_mm to y, and island to group

Add a geom_line() layer, mapping island to color, and setting the size to 2

Add a geom_point() layer, mapping color to island, and setting size to 4

We’ll adjust the x axis with scale_x_continuous(), manually setting the breaks and moving the position to the "top" of the graph

Code
labs_slope <- labs(
        title = "Changes in Bill Depth of Palmer Penguins", 
        subtitle = "Years 2007 & 2008",
        x = "Year", y = "Bill Depth (mm)", 
        color = "Island")

ggp2_slope <- ggplot(data = peng_slope, 
    mapping = aes(x = year,
                y = avg_bill_depth_mm, 
                group = island)) +
  geom_line(aes(color = island), 
                size = 2, show.legend = FALSE) +
  geom_point(aes(color = island), 
                size = 4) + 
  scale_x_continuous(
                breaks = c(2007, 2008), 
                position = "top")

ggp2_slope + 
    labs_slope

GRAPH:

More info

We can also use faceting with slope graphs to add a third categorical variable.

DATA:

We’ll be using the penguins dataset again, but group remove the missing values and group it by year, island, and sex.

Code
peng_grp_slope <- palmerpenguins::penguins |>
    dplyr::select(year, sex, island,
                  contains("mm")) |> 
    tidyr::drop_na() |> 
    dplyr::filter(year != 2007) |>
    dplyr::group_by(year, sex, island) |>
    dplyr::summarise(across(
        .cols = contains("mm"), 
        .fns = mean, 
            na.rm = TRUE, 
        .names = "avg_{.col}")) |>
    dplyr::ungroup()
glimpse(peng_grp_slope)
Rows: 12
Columns: 6
$ year                  <int> 2008, 2008, 2008, 2008, 2008, 2008, 2009, 2009, …
$ sex                   <fct> female, female, female, male, male, male, female…
$ island                <fct> Biscoe, Dream, Torgersen, Biscoe, Dream, Torgers…
$ avg_bill_length_mm    <dbl> 42.78387, 41.42353, 36.61250, 46.35000, 46.08824…
$ avg_bill_depth_mm     <dbl> 15.02903, 17.52941, 17.40000, 16.64062, 19.26471…
$ avg_flipper_length_mm <dbl> 205.3226, 190.9412, 190.0000, 213.7812, 199.1176…

GRAPH:

Create labels with labs()

Initialize the graph with ggplot() and provide data

Map year to the x, avg_bill_depth_mm to y, and island to group

Add a geom_line() layer, mapping island to color, and setting the size to 2

Add a geom_point() layer, mapping color to island, and setting size to 4

We’ll adjust the x axis with scale_x_continuous(), manually setting the breaks and moving the position to the "top" of the graph

We’ll duplicate the the y axis with sec.axis, setting dup_axis() to the same name of the previous y label.

Finally, we facet the graph by sex, adjust the size of the text, and move the legend to the "bottom" of the graph.

Code
labs_grp_slope <- labs(
    title = "Changes in Bill Depth of Palmer Penguins",
    subtitle = "Years 2008 & 2009",
    x = "",
    color = "Island")

ggp2_grp_slope <- ggplot(data = peng_grp_slope,
    mapping = aes(x = year,
        y = avg_bill_depth_mm,
        group = island)) +
    geom_line(aes(color = island),
        size = 2, show.legend = FALSE) +
    geom_point(aes(color = island),
        size = 4) +
    scale_x_continuous(breaks = c(2008, 2009),
        position = "top") +
    scale_y_continuous(name = "Bill Depth (mm)",
        sec.axis = dup_axis(name = "Bill Depth (mm)")) +
    facet_wrap(. ~ sex,
        ncol = 2) +
    theme_minimal(base_size = 14) +
    theme(
        legend.position = "bottom",
        axis.text.x = element_text(size = 9),
        axis.text.y = element_text(size = 9),
        strip.text = element_text(size = 10))

ggp2_grp_slope +
    labs_grp_slope