Chapter 5 Annotations

Annotations are crucial for charts as they provide context, insights and clarity, helping readers better understand the data. Key reasons for using annotations include:

  • highlighting key points, with arrows or label to draw attention to important data points or outliers
  • providing context, with dotted or dashed lines to show time periods or significant events
  • supporting the narrative, which can reinforce a story or explain changes, especially in time series charts
  • adding clarity, with units, data sources or definitions to make charts more informative
  • avoiding misinterpretation, to guide readers on how to read the chart correctly

Annotations improve readability but are not accessible to screen readers. To ensure inclusivity, include annotation details in alternative text.

Next, explore how to add various types of annotations.

5.1 Lines

Using lines as annotations allows you to highlight trends or events on the chart.

There are several different ways to plot a segment on a chart. One of the simplest ways is using the geom_segment() function.

The geom_segment() function is easy to use and requires only a few key arguments. At a minimum, you need to provide the starting and ending coordinates of the line on both the x and y axes. These coordinates are specified inside the aes() function.

Key points to remember:

  • coordinates can be strings, numbers or dates
  • if using dates, wrap the date in the as.Date() function, e.g. x = as.Date("2023-08-15")

This flexibility allows geom_segment() to handle a wide range of data types for creating custom lines in your charts.

Code
geom_segment(aes(x = "", xend = "", y = "", yend = ""), 
             colour = "grey85", linetype = "dashed")
  • x = where along the x axis the line should start from
  • xend = where along the x axis the line should end
  • y = where along the y axis the line should start from
  • yend = where along the y axis the line should end
  • colour = colour of the line
  • linetype = type of line. Dashed, dotted

Using this format, you can add as many lines as you need on the chart by layering as many geom_segment() layers as you like.

The following examples use the cycling_newham dataset. This dataset provides information about how often adults in the London Borough of Newham cycled each week between 2016 and 2021, specifically for travel purposes, such as commuting to work.

ONS_Code Area_name Mode Purpose Frequency Year Prop_adults_cycling
E09000025 Newham Cycling Travel At least once per week 2021 6.897274
E09000025 Newham Cycling Travel At least once per week 2020 4.958700
E09000025 Newham Cycling Travel At least once per week 2019 8.732026
E09000025 Newham Cycling Travel At least once per week 2018 5.556300
E09000025 Newham Cycling Travel At least once per week 2017 6.862400
E09000025 Newham Cycling Travel At least once per week 2016 5.113000
Code
ggplot(data = cycling_newham) +
  geom_line(aes(y = Prop_adults_cycling, x = Year, group = Frequency, color = Frequency)) +
  scale_y_continuous(limits = c(0, 10), breaks = seq(from = 0, to = 10, by = 2)) +
  dftplotr::scale_colour_dft(palette = "country.lane") +
  labs(title = "Proportion of adults cycling for travel in Newham per week",
       x = "Year", 
       y = "Proportion of adults") +
  line_theme 

Let’s add some context to this chart by describing the fall in adults cycling in 2020. In this context, it was down to the COVID-19 lockdown restrictions. We want to draw a straight perpendicular line through the year 2020, so let’s begin by passing some arguments through the geom_segment() function:

  • x = "2020" because this is the coordinate where we want the line to begin along the x axis.
  • xend = "2020" because we want it to remain at 2020 along every y coordinate
  • y = 0 because we want it to start at the bottom of the chart
  • yend = 9.5 because we want the line to reach the top of the chart
  • we can also pass a colour using the linewidth and linetype argument to differentiate the line from the actual charting lines on the chart
Code
ggplot(data = cycling_newham) +
  geom_line(aes(y = Prop_adults_cycling, x = Year, group = Frequency, color = Frequency)) +
  scale_y_continuous(limits = c(0, 10), breaks = seq(from = 0, to = 10, by = 2)) +
  dftplotr::scale_colour_dft(palette = "country.lane") +
  labs(title = "Proportion of adults cycling for travel in Newham per week",
       x = "Year", 
       y = "Proportion of adults") +
  line_theme +
  # add our line segment at "2020"
  geom_segment(aes(x = "2020", 
                   xend = "2020", 
                   y = 9.5, 
                   yend = 0
                   ), 
               colour = "grey70", 
               linetype = "dashed")
## Warning in geom_segment(aes(x = "2020", xend = "2020", y = 9.5, yend = 0), : All aesthetics have length 1, but the data has 18 rows.
## ℹ Please consider using `annotate()` or provide this layer with data containing
##   a single row.

A warning message appears because the line lacks context without accompanying text. To address this, we can add text to the line using the annotate() function.

There are many ways to use an annotate() function, but to use it for text is very simple. We just need to pass these arguments:

Code
annotate(
  geom = "text"
  x = coordinate,
  y = coordinate,
  size = size of text,
  label = "the text you want on the chart")
Code
ggplot(data = cycling_newham) +
  geom_line(aes(y = Prop_adults_cycling, x = Year, group = Frequency, color = Frequency)) +
  scale_y_continuous(limits = c(0, 10), breaks = seq(from = 0, to = 10, by = 2)) +
  dftplotr::scale_colour_dft(palette = "country.lane") +
  labs(title = "Proportion of adults cycling for travel in Newham per week",
       x = "Year", 
       y = "Proportion of adults") +
  line_theme +
##---------------------------------------------------------------- 
##---------------------------------------------------------------- 
  # add our line segment at "2020"
  geom_segment(aes(x = "2020", 
                   xend = "2020", 
                   y = 9.5, 
                   yend = 0
                   ), 
                   colour = "grey70", 
                   linetype = "dashed") +
  # add our text segment using the annotate()             
  annotate(geom = "text", 
           x = "2020", 
           y = 10, 
           size = 4,
           label = "National COVID-19 Lockdown")

5.1.1 Exercise

20:00

For the exercise we will be using this data and chart:

This dataset is called timeseries_travel_data which shows car travel usage data from April 2020 to December 2021, compared to a pre-COVID-19 baseline.

month_year transport date usage
Apr-2020 Cars 2020-04-01 32
Apr-2020 Cars 2020-04-02 32
Apr-2020 Cars 2020-04-03 34
Apr-2020 Cars 2020-04-04 28
Apr-2020 Cars 2020-04-05 25
Apr-2020 Cars 2020-04-06 34
Code
ggplot(data = timeseries_travel_data) +
  geom_line(aes(y = usage, x = date, group = "transport"), linewidth = 0.4) +
  geom_line(aes(y = 100, x = date), linetype = "dashed", colour = "red4") +
  scale_x_date(date_breaks = "3 month", date_labels = "%b-%Y") +
  scale_y_continuous(breaks = seq(from = 0, to = 110, by = 20)) +
  labs(title = "Usage of car travel compared to pre-covid baseline",
       x = "Date", y = "Usage") +
  line_theme

  1. Create 3 segments on the chart for the 3 national lockdowns using the geom_segment() function. The line should begin from y = 0 and either touch or cross the horizontal line at y = 100. Note that the x axis is made up of dates, so your x coordinates will follow this pattern: x = as.Date("yyyy-mm-dd")
  • Segment on 1st April 2020
  • Segment on 1st October 2020
  • Segment on 1st January 2021

Solution

Code
ggplot(data = timeseries_travel_data) +
  geom_line(aes(y = usage, x = date, group = "transport"), linewidth = 0.4) +
  geom_line(aes(y = 100, x = date), linetype = "dashed", colour = "red4") +
  scale_x_date(date_breaks = "3 month", date_labels = "%b-%Y") +
  scale_y_continuous(breaks = seq(from = 0, to = 110, by = 20)) +
  labs(title = "Usage of car travel compared to pre-covid baseline",
       x = "Date", y = "Usage") +
  line_theme +
##-----------------------------------------------------------
##-----------------------------------------------------------  
  # segment 1 at April 2020 
  geom_segment(aes(x = as.Date("2020-04-01"), 
                   xend = as.Date("2020-04-01"), 
                   y = 100, 
                   yend = 0), 
                   colour = "grey70", 
                   linetype = "dashed") +
  # segment 2 at October 2020
  geom_segment(aes(x = as.Date("2020-10-01"), 
                   xend = as.Date("2020-10-01"), 
                   y = 100, 
                   yend = 0), 
                   colour = "grey70", 
                   linetype = "dashed") +
  # segment 3 at January 2021
  geom_segment(aes(x = as.Date("2021-01-01"), 
                   xend = as.Date("2021-01-01"), 
                   y = 100, 
                   yend = 0), 
                   colour = "grey70", 
                   linetype = "dashed")
  1. Using solution code from Q1, add the following text annotation for each segment using the annotate() function.
  • “1st Lockdown”
  • “2nd Lockdown”
  • “3rd Lockdown”

Solution

Code
ggplot(data = timeseries_travel_data) +
  geom_line(aes(y = usage, x = date, group = "transport"), linewidth = 0.4) +
  geom_line(aes(y = 100, x = date), linetype = "dashed", colour = "red4") +
  scale_x_date(date_breaks = "3 month", date_labels = "%b-%Y") +
  scale_y_continuous(breaks = seq(from = 0, to = 110, by = 20)) +
  labs(title = "Usage of car travel compared to pre-covid baseline",
       x = "Date", y = "Usage") +
  line_theme +
##-----------------------------------------------------------
##-----------------------------------------------------------  
  # segment 1 at April 2020 
  geom_segment(aes(x = as.Date("2020-04-01"), 
                   xend = as.Date("2020-04-01"), 
                   y = 100, 
                   yend = 0), 
                   colour = "grey70", 
                   linetype = "dashed") +
  # text segment at April 2020
  annotate("text", 
           x = as.Date("2020-04-01"), 
           y = 107, 
           label = "1st Lockdown", 
           size = 3) +
  ##-----------------------------------------------------------
  # segment 2 at October 2020
  geom_segment(aes(x = as.Date("2020-10-01"), 
                   xend = as.Date("2020-10-01"), 
                   y = 100, 
                   yend = 0), 
                   colour = "grey70", 
                   linetype = "dashed") +
  # text segment at October 2020
  annotate("text", 
           x = as.Date("2020-10-01"), 
           y = 107, 
           label = "2nd Lockdown", 
           size = 3) +
  ##-----------------------------------------------------------
  # segment 3 at January 2021
  geom_segment(aes(x = as.Date("2021-01-01"), 
                   xend = as.Date("2021-01-01"), 
                   y = 100, 
                   yend = 0), 
                   colour = "grey70", 
                   linetype = "dashed") +
  # text at segment October 2020            
  annotate("text",
           x = as.Date("2021-01-01"),
           y = 104,
           label = "3rd lockdown",
           size = 3)

5.2 Text annotations

Text annotations can make charts easier to read and more accessible, especially for multi-line charts where category names are distinguished only by color. People with color vision deficiencies may struggle to match category names to the correct lines. Adding labels directly to the lines solves this issue.

To improve the cycling chart, labels can be attached to the lines using geom_text_repel() and the legend can be removed. Unlike geom_text(), geom_text_repel() prevents text labels from overlapping by repelling them from each other and the data points.

Before using geom_text_repel(), some preparation is needed. This includes creating a separate table for the labels and mapping them to the correct locations on the chart. If the original dataset is used directly, labels will appear at all data points, which looks like this:

Let’s start by preparing the data. The labels you need and their placement on the chart will guide how you create the labels table.

For this chart, the goal is to add a single label at the end of each line, showing the cycling frequency. This requires filtering the data to include only three observations from the year 2021. This filtered data will serve as the labels table.

Code
line_labels <- cycling_newham  %>%
  dplyr::filter(Year == "2021")
ONS_Code Area_name Mode Purpose Frequency Year Prop_adults_cycling
E09000025 Newham Cycling Travel At least once per week 2021 6.8972739
E09000025 Newham Cycling Travel At least 3 times per week 2021 2.8714894
E09000025 Newham Cycling Travel At least 5 times per week 2021 0.9865256

Now that we have a labelled data table, we can plot this information in the chart. There are many arguments in the geom_text_repel() function, and you definitely do not have to use them all, but they are useful for getting your labels looking nice:

  • data = your labels data table
  • aes(x = "", y = "", group = "how your lines grouped", label = "your label column")
  • segment.color = colour of the line connecting the text to the line. Its best to choose "transparent" for this.
  • colour =colour of text
  • size = size of text
  • nudge_x = adjust position of text horizontally
  • nudge_y = adjust position of text vertically
Code
ggplot(data = cycling_newham) +
  geom_line(aes(y = Prop_adults_cycling, x = Year, group = Frequency, color = Frequency)) +
  scale_y_continuous(limits = c(0, 10), breaks = seq(from = 0, to = 10, by = 2)) +
  scale_colour_brewer(palette = "Dark2") +
  line_theme +
  #remove the legend from the chart
  theme(legend.position = "none") +
  labs(title = "Proportion of adults cycling for travel in Newham per week",
       x = "Year", y = "Proportion of adults") +
##----------------------------------------------------- 
##-----------------------------------------------------
  ## Adding labels here
  geom_text_repel(
    data = line_labels, aes(x = Year,
                            y = Prop_adults_cycling, 
                            group = Frequency, 
                            label = Frequency), 
                         colour = "grey8", 
                         segment.color = 'transparent',
                         nudge_x = 1.2, 
                         nudge_y = 0, 
                         size = 3) +
##----------------------------------------------------- 
##-----------------------------------------------------  
  # segment 1 at x = "2020" 
  geom_segment(aes(x = "2020", 
                   xend = "2020", 
                   y = 9.5, 
                   yend = 0), 
                   colour = "grey70", 
                   linetype = "dashed") +
  # text at segment             
  annotate("text", 
           x = "2020", 
           y = 10, 
           label = "COVID-19 Lockdown", 
           size = 4)

5.2.1 Exercise

15:00

For this exercise we have a pre-made labels data table time_series_label that we are going to use to label the baseline line in our chart.

month_year transport date usage line_label
Dec-2021 Cars 2021-12-29 73 Baseline

Using your chart from Exercise 5.1.1:

  1. Plot the time_series_label in the geom_text_repel() function in order to label the baseline.
  2. Is the label not in the location you were hoping? Try swapping out y = usage with y = 100.

Solution

Code
ggplot(data = timeseries_travel_data) +
  geom_line(aes(y = usage, x = date, group = "transport"), linewidth = 0.4) +
  geom_line(aes(y = 100, x = date), linetype = "dashed", colour = "red4") +
  scale_x_date(date_breaks = "3 month", date_labels = "%b-%Y") +
  scale_y_continuous(breaks = seq(from = 0, to = 110, by = 20)) +
  labs(title = "Usage of car travel compared to pre-COVID-19 baseline",
       x = "Date", y = "Usage") +
  line_theme +
##-----------------------------------------------------------------------    
##-----------------------------------------------------------------------    
  # Adding labels here
  geom_text_repel(data = time_series_label, 
                  aes(x = date,
                      y = 100, 
                      label = line_label), 
                  colour = "grey8", 
                  segment.color = 'transparent',
                  nudge_x = 7, 
                  nudge_y = 1, 
                  size = 3) +
##---------------------------------------------------------------------
##--------------------------------------------------------------------- 
  # segment 1 at April 2020 
  geom_segment(aes(x = as.Date("2020-04-01"), 
                   xend = as.Date("2020-04-01"), 
                   y = 100, 
                   yend = 0), 
                   colour = "grey70", 
                   linetype = "dashed") +
  # text at April 2020             
  annotate("text",
           x = as.Date("2020-04-01"),
           y = 107,
           size = 3,
           label = "1st lockdown")+
  # segment 2 at October 2020
  geom_segment(aes(x = as.Date("2020-10-01"), 
                   xend = as.Date("2020-10-01"), 
                   y = 100, 
                   yend = 0), 
                   colour = "grey70", 
                   linetype = "dashed") +
  # text at October 2020            
  annotate("text",
           x = as.Date("2020-10-01"),
           y = 107,
           size = 3,
           label = "2nd lockdown") +
  # segment 3 at January 2021
  geom_segment(aes(x = as.Date("2021-01-06"), 
                   xend = as.Date("2021-01-06"), 
                   y = 100, 
                   yend = 0), 
                   colour = "grey70", 
                   linetype = "dashed") +
  # text at January 2021           
  annotate("text",
           x = as.Date("2021-01-06"),
           y = 104,
           size = 3,
           label = "3rd lockdown")

5.3 Arrows

Arrows are an effective way to highlight key data points or changes in trends, helping to guide the narrative of a chart.

You can choose between straight or curved arrows, depending on your preference.

Straight arrows are simple to create using the geom_segment() function with a few additional arguments. Unlike other segments, these arrows won’t cut through chart lines and are often not perpendicular, so all x and y values need to be specified. Text can also be added near the arrow using the annotate() function.

geom_segment():

  • x = where along the x axis the line should start from
  • xend = where along the x axis the line should end
  • y = where along the y axis the line should start from
  • yend = where along the y axis the line should end
  • linewidth = thickness of the line
  • arrow = arrow(length = unit(0.2, "cm"))) = using an arrow function to set the arrow width and unit

For example:

Code
ggplot(data = cycling_newham) +
  geom_line(aes(y = Prop_adults_cycling, x = Year, group = Frequency, color = Frequency)) +
  scale_y_continuous(limits = c(0, 10), breaks = seq(from = 0, to = 10, by = 2)) +
  scale_colour_brewer(palette = "Dark2") +
  line_theme +
  theme(legend.position = "none") +
  labs(title = "Proportion of adults cycling for travel in Newham per week",
       x = "Year", y = "Proportion of adults") +
  # Adding labels here
  geom_text_repel(data = line_labels, aes(x = Year, 
                                          y = Prop_adults_cycling, 
                                          group = Frequency, 
                                          label = Frequency), 
                  colour = "grey8", 
                  segment.color = 'transparent',
                  nudge_x = 1.5, 
                  nudge_y = 0, 
                  size = 3) +
##------------------------------------------------------------------------------------  
##------------------------------------------------------------------------------------ 
  # Adding a straight arrow pointing towards 2019 trend
  geom_segment(aes(x = "2017", 
                   xend = "2018", 
                   y = 9, 
                   yend = 8), 
              linewidth = 0.2,
              color = "grey20", 
              arrow = arrow(length = unit(0.2, "cm"))) +
  # Text 
  annotate("text", 
           x = "2017", 
           y = 9.5, 
           size = 3, 
           colour = "grey20", 
           label = "Improved cycling infrastructure in Newham") +
##-------------------------------------------------------------------------------------  
##-------------------------------------------------------------------------------------    
  # segment 1 at x = "2020" 
  geom_segment(aes(x = "2020", 
                   xend = "2020", 
                   y = 9.5, 
                   yend = 0), 
                   colour = "grey85", 
                   linetype = "dashed") +
  # text at segment             
  annotate("text", 
           x = "2020", 
           y = 10, 
           label = "COVID-19 Lockdown", 
           size = 4)

5.3.1 Exercise

15:00

  1. Plot at arrow on your chart from the previous exercise where:
  • x is 3rd August 2020
  • y = 60
  • yend = 80
  • adjust any other parameter you like
  1. Use an annotation function to add “Eat out to help out scheme” under the arrow.

Solution

Code
ggplot(data = timeseries_travel_data) +
  geom_line(aes(y = usage, x = date, group = "transport"), linewidth = 0.4) +
  geom_line(aes(y = 100, x = date), linetype = "dashed", colour = "red4") +
  scale_x_date(date_breaks = "3 month", date_labels = "%b-%Y") +
  scale_y_continuous(breaks = seq(from = 0, to = 110, by = 20)) +
  labs(title = "Usage of car travel compared to pre-COVID-19 baseline",
       x = "Date", y = "Usage") +
  line_theme +
  # Adding labels here
  geom_text_repel(
    data = time_series_label, aes(x = date,
                                  y = 100, 
                                  label = line_label), 
    colour = "grey8", 
    segment.color = 'transparent',
    nudge_x = 7, 
    nudge_y = 1, 
    size = 3) +
##-----------------------------------------------------------------
##----------------------------------------------------------------- 
## Straight arrow at August 2020
  geom_segment(aes(x = as.Date("2020-08-03"), 
                   xend = as.Date("2020-08-03"), 
                   y = 60, 
                   yend = 80), 
               linewidth = 0.2,
               color = "grey20", 
               arrow = arrow(length = unit(0.2, "cm"))) +
  annotate("text", 
           x = as.Date("2020-08-10"), 
           y = 56, 
           size = 3, 
           colour = "grey20", 
           label = "Eat out to help out scheme") +
##------------------------------------------------------------------  
##------------------------------------------------------------------ 
  # segment 1 at April 2020 
  geom_segment(aes(x = as.Date("2020-04-01"), 
                   xend = as.Date("2020-04-01"), 
                   y = 100, 
                   yend = 0), 
               colour = "grey85", 
              linetype = "dashed") +
  # text at April 2020             
  annotate("text",
           x = as.Date("2020-04-01"),
           y = 107,
           size = 3,
           label = "1st lockdown") +
  # segment 2 at October 2020
  geom_segment(aes(x = as.Date("2020-10-01"), 
                   xend = as.Date("2020-10-01"), 
                   y = 100, 
                   yend = 0), 
               colour = "grey85", 
               linetype = "dashed") +
  #  text at October 2020            
  annotate("text",
           x = as.Date("2020-10-01"),
           y = 107,
           size = 3,
           label = "2nd lockdown") +
  # segment 3 at January 2021
  geom_segment(aes(x = as.Date("2021-01-06"), 
                   xend = as.Date("2021-01-06"), 
                   y = 100, 
                   yend = 0), 
               colour = "grey85", 
               linetype = "dashed") +
  #  text at January 2021            
  annotate("text",
           x = as.Date("2021-01-06"),
           y = 104,
           size = 3,
           label = "3rd lockdown")

5.4 Curved Arrow

A curved arrow does the same thing as a straight arrow, but you may prefer this aesthetic.

To create a curved arrow, you can use a geom_curve() function. It is very similar to how we have used the segment function earlier, just a very slight difference. Some of the arguments that we need to pass through the geom_curve() function:

  • data = your data
  • aes() function:
    • x = coordinate
    • xend = coordinate
    • y = coordinate
    • yend = coordinate
  • linewidth = line thickness
  • curvature = which way you want it to curve
  • arrow = arrow(length = unit(0.2, "cm"))) = arrow function

And as usual, using the annotate() function to label the arrow.

Code
ggplot(data = cycling_newham) +
  geom_line(aes(y = Prop_adults_cycling, x = Year, group = Frequency, color = Frequency)) +
  scale_y_continuous(limits = c(0, 10), breaks = seq(from = 0, to = 10, by = 2)) +
  scale_colour_brewer(palette = "Dark2") +
  line_theme +
  theme(legend.position = "none") +
  labs(title = "Proportion of adults cycling for travel in Newham per week",
       x = "Year", y = "Proportion of adults") +
  # Adding labels here
  geom_text_repel(data = line_labels, aes(x = Year, 
                                          y = Prop_adults_cycling, 
                                          group = Frequency, 
                                          label = Frequency), 
                  colour = "grey8", 
                  segment.color = 'transparent',
                  nudge_x = 1.5, 
                  nudge_y = 0, 
                  size = 3) +
##-----------------------------------------------------------------
##---------------------------------------------------------------- 
  # Add curved arrow in 2021
  geom_curve(data = cycling_newham, aes(x = "2021", 
                                      y = 8.5, 
                                      xend = "2021", 
                                      yend = 7.5),  
             curvature = -0.2, 
             linewidth = 0.2, 
             colour = "grey8",
             arrow = arrow(length = unit(0.2, "cm"))) +
  # Text for curved arrow   
  annotate("text", 
          x = "2021", 
          y = 9, 
          size = 3, 
          colour = "grey20", 
          label = "Hybrid working") +
##---------------------------------------------------------------- 
##------------------------------------------------------------------  
  # segment 1 at x = 2020 
  geom_segment(aes(x = "2020", 
                   xend = "2020", 
                   y = 9.5, 
                   yend = 0), 
               colour = "grey70", 
               linetype = "dashed") +
  # text at segment             
  annotate("text", 
           x = "2020", 
           y = 10, 
           label = "COVID-19 Lockdown", 
           size = 4) +
  # Straight arrow at pointing at 2019 trend
  geom_segment(aes(x = "2017", 
                   xend = "2018", 
                   y = 9, 
                   yend = 8), 
              linewidth = 0.2,
              color = "grey20", 
              arrow = arrow(length = unit(0.2, "cm"))) +
  annotate("text", 
           x = "2017", 
           y = 9.5, 
           size = 3, 
           colour = "grey20", 
           label = "Improved cycling infrastructure in Newham")

5.4.1 Exercise

15:00

Using the chart created in Exercise 5.3.1:

  1. Plot a curved arrow on your chart where:
  • x is 1st Dec 2021
  • xend = 20th Dec 2021
  • y = 40
  • yend = 55
  • curvature = -0.2
  • add any other arguments you’d like to use
  1. Use an annotation function to add “Omicron COVID Strain” under the arrow.

Solution

Code
ggplot(data = timeseries_travel_data) +
  geom_line(aes(y = usage, x = date, group = "transport"), linewidth = 0.4) +
  geom_line(aes(y = 100, x = date), linetype = "dashed", colour = "red4") +
  scale_x_date(date_breaks = "3 month", date_labels = "%b-%Y") +
  scale_y_continuous(breaks = seq(from = 0, to = 110, by = 20)) +
  labs(title = "Usage of car travel compared to pre-COVID-19 baseline",
       x = "Date", y = "Usage") +
  line_theme +
  # Adding labels here
  geom_text_repel(
    data = time_series_label, aes(x = date,
                                  y = 100, 
                                  label = line_label), 
    colour = "grey8", 
    segment.color = 'transparent',
    nudge_x = 7, 
    nudge_y = 1, 
    size = 3) +
##-----------------------------------------------------------------
##-----------------------------------------------------------------
  # Adding labels here
  geom_text_repel(data = time_series_label, aes(x = date, 
                                                y = 100, 
                                                label = line_label), 
                  colour = "grey8", 
                  segment.color = 'transparent',
                  nudge_x = 7, 
                  nudge_y = 1, 
                  size = 3) +
##----------------------------------------------------------------
##----------------------------------------------------------------   
  # Add curved arrow at Dec 2021 
  geom_curve(data = timeseries_travel_data, aes(x = as.Date("2021-12-01"), 
                                                y = 40, 
                                                xend = as.Date("2021-12-20"), 
                                                yend = 55),  
             curvature = -0.2, 
             linewidth = 0.2, 
             colour = "grey8",
             arrow = arrow(length = unit(0.2, "cm"))) +
  # Text for curved arrow   
  annotate("text", 
           x = as.Date("2021-12-01"), 
           y = 36, 
           size = 3, 
           colour = "grey20", 
           label = "Omnicron COVID Strain") +
##----------------------------------------------------------------
##----------------------------------------------------------------
  # Straight arrow at August 2020
  geom_segment(aes(x = as.Date("2020-08-03"), 
                   xend = as.Date("2020-08-03"), 
                   y = 60, 
                   yend = 80), 
               linewidth = 0.2,
               color = "grey20", 
               arrow = arrow(length = unit(0.2, "cm"))) +
  # Text for straight arrow
  annotate("text", 
           x = as.Date("2020-08-10"), 
           y = 56, 
           size = 3, 
           colour = "grey20", 
           label = "Eat out to help out scheme") +
  # segment 1 at April 2020 
  geom_segment(aes(x = as.Date("2020-04-01"), 
                   xend = as.Date("2020-04-01"), 
                   y = 100, 
                   yend = 0), 
                   colour = "grey70", 
                   linetype = "dashed") +
  #  text at April 2020             
  annotate("text",
           x = as.Date("2020-04-01"),
           y = 107,
           size = 3,
           label = "1st lockdown") +
  # segment 2 at October 2020
  geom_segment(aes(x = as.Date("2020-10-01"), 
                   xend = as.Date("2020-10-01"), 
                   y = 100, 
                   yend = 0), 
               colour = "grey70", 
               linetype = "dashed") +
  # text at October 2020            
  annotate("text",
           x = as.Date("2020-10-01"),
           y = 107,
           size = 3,
           label = "2nd lockdown") +
  # segment 3 at January 2021
  geom_segment(aes(x = as.Date("2021-01-06"), 
                   xend = as.Date("2021-01-06"), 
                   y = 100, 
                   yend = 0), 
               colour = "grey70", 
               linetype = "dashed") +
  # text at January 2021           
  annotate("text",
           x = as.Date("2021-01-06"),
           y = 104,
           size = 3,
           label = "3rd lockdown")

5.5 Transport Statistics Dissemination Playbook

At DfT, we have produced a useful tool called “Transport Statistics Dissemination Playbook” which provides a clear guidance to your statistics published on gov.uk. The playbook reflects recommendations and best practices from the Analysis Function, the Government Digital Service (GDS) and the Government Statistical Service (GSS).

For this course, it is recommended to read the playbook’s section on Charts and visuals which is for anybody needing to design charts. The section provides guidance and recommendations on selecting the appropriate chart, text, and colors to effectively communicate the data story conveyed by the chart.

5.6 Final note

Congratulations! You have reached the end of the tutor-led training session. You are welcome to continue your self-directed learning by completing the 60-minute exercise in Chapter 6!

Remember to complete the feedback form (it’s all anonymous) to help us improve your learning journey to coding at DfT.

Here are a few useful links: