Use Lines Segment and Rectangle Annotations in ggplot2 to Visualize U.S. Presidential Terms

In this article, we’ll visualize the continuity of US presidential terms from Dwight D. Eisenhower in 1953 to Donald Trump in 2021. Major techniques demonstrated in this article include:


Data cleanup

In this article, we’ll use the presidential dataset which is built in ggplot2. It shows the names of 12 U.S. presidents from Eisenhower to Trump, their start and end date of their terms, and their associated parties.

# packageslibrary(ggplot2)library(dplyr)library(tidyr)
# set global default themetheme_set(theme_minimal(base_size = 14))
presidential_2 <- presidential
# Update the Bush namepresidential_2$name[8] <- "H.W.Bush"presidential_2$name[10] <- "W.Bush"

Reorder the president names by the start date. It consists two critical steps:

  • Arrange the rows by the start date. The arrangement proceeds in descending order (by desc), and early rows in the dataset will be plotted at the bottom of the plot.

  • Convert the name variable to a nominal factor (noted as <fct> in the printed output) to “memorize” the current order of president names.

presidential_2.arranged <- presidential_2 %>%   arrange(desc(start)) %>%   mutate(name = factor(name, levels = name))
# ready for visualization!head(presidential_2.arranged, n = 4)

Output:

# A tibble: 4 × 4
name start end party
<fct> <date> <date> <chr>
1 Trump 2017-01-20 2021-01-20 Republican
2 Obama 2009-01-20 2017-01-20 Democratic
3 W.Bush 2001-01-20 2009-01-20 Republican
4 Clinton 1993-01-20 2001-01-20 Democratic

For the code above, you may also use factor(name, levels = name, ordered = T) to convert the name variable to an ordered factor (indicated as <ord>). In ggplot2 reordering, both a nominal <fct> and an ordered factor <ord> works the same. More details on ggplot2 graphic reordering from the basics to advanced skills can be found in this complete guide.

Visualization

Draw line segments to show the starting and ending year of the service terms of different Presidents. geom_segment() requires four aesthetics: x, y for the staring coordinate, and xend and yend for the ending coordinate of the line segment.

p1 <- presidential_2.arranged %>%   ggplot(aes(x = start, y = name, label = name,              color = party, fill = party)) +  geom_segment(aes(xend = end, yend = name),                linewidth = 4)p1

Add president names. By default, the texts are center justified relative to the x aesthetic (the starting year). Here instead, we use hjust to change the justification rule. The elements of the hjust vector is respectively applied to the president names in a bottom up order (from Trump to Eisenhower): the first value 0.3 shifts “Trump” to the left (so the text does not overflow beyond the plot boundary), and rep(0, 11) left-justifies the other 11 names to the left edge of the line segment.

p2 <- p1 + geom_text(  nudge_y = .35, fontface = "bold",   hjust = c(.3, rep(0, 11))) p2

Add the years of serving terms.

p3 <- p2 + geom_text(  # use format %Y to extract the year component from a Date    aes(label = paste(format(start, "%Y"), "~", format(end, "%Y"))),   nudge_y = -.35,   hjust = c(.6, rep(0, 11)),  size = 3.5) p3

Draw rectangles to highlight the serving terms and associated parties. geom_rect() requires four aesthetics to specify the coordinates of the four edges, respectively: xmin, xmax, ymin, and ymax. Use the infinite value Inf to draw rectangles extending across the entire axial range.

p4 <- p3 + geom_rect(  aes(xmin = start, xmax = end, ymin = -Inf, ymax = Inf),   alpha = .2, linewidth = .2, linetype = "dotted") p4

Adjust the color scale, plot aspect ratio, and themes.

# color scale of line segments and texts annotationsmyColors.light <- c("Democratic" = "steelblue2", "Republican" = "firebrick1")# color scale of the backgroundmyColors.dark <- c("Democratic" = "steelblue4", "Republican" = "firebrick4")
p5 <- p4 + # keep a long-narrow dimension coord_fixed(ratio = 2000, clip = "off") + # color / fill scale scale_color_manual(values = myColors.dark ) + scale_fill_manual(values = myColors.light) + theme_void() + theme(plot.margin = margin(rep(10, 4), unit = "pt"), legend.position = "none")p5

Add plot title with enriched colors using ggtext package:

  • Use HTML in the title string. The line breaks in the script (make by pressing the Enter or return key) makes the script easier to read, but will not be visible in the rendered graphic. If you want to make an indicated line break, use <br> anywhere desired. Alternatively, you can use automatic text wrapping (see the following bullet)

  • Use element_textbox_simple() in theme() in place of element_text() to render the HTML-masked title with automatic text wrapping. (Alternatively, use element_markdown() and HTML tag <br> to make indicated line breaks, as in this example.)

library(ggtext)
plot_title <- c( "Presidential Chronicles: A Tale of <span style='color: steelblue3;'>Democrats</span> and <span style='color: red3;'>Republicans</span> from Eisenhower to Trump – Unveiling the Power Shifts in the U.S.")
p6 <- p5 + ggtitle(plot_title)
p6 + theme( plot.title = element_textbox_simple( margin = margin(b = 5, l = 20, r = 20, unit = "pt"), size = 14))

Load Google font “Anton” to further enhance the title. Use showtext package to make it available to be used in ggplot2.

library(showtext)showtext_auto()font_add_google("Anton", "Anton")
p6 + theme( plot.title = element_textbox_simple( margin = margin(b = 5, l = 20, r = 20, unit = "pt"), size = 14, # use Google font "Anton" family = "Anton"))
library(ggplot2)library(dplyr)library(tidyr)
# set global default themetheme_set(theme_minimal(base_size = 14))
presidential_2 <- presidential
# Update the Bush namepresidential_2$name[8] <- "H.W.Bush"presidential_2$name[10] <- "W.Bush"
# Reorder the president names by the start datepresidential_2.arranged <- presidential_2 %>% arrange(desc(start)) %>% mutate(name = factor(name, levels = name))
# ready for visualization!head(presidential_2.arranged, n = 4)

# Draw line segments showing the starting and ending year of the terms. p1 <- presidential_2.arranged %>% ggplot(aes(x = start, y = name, label = name, color = party, fill = party)) + geom_segment(aes(xend = end, yend = name), linewidth = 4)p1

# Add president namesp2 <- p1 + geom_text( nudge_y = .35, fontface = "bold", hjust = c(.3, rep(0, 11))) p2

# Add years of terms.p3 <- p2 + geom_text( # use format %Y to extract the year component from a Date aes(label = paste(format(start, "%Y"), "~", format(end, "%Y"))), nudge_y = -.35, hjust = c(.6, rep(0, 11)), size = 3.5) p3

# Draw rectangles to highlight the serving terms and associated parties.p4 <- p3 + geom_rect( aes(xmin = start, xmax = end, ymin = -Inf, ymax = Inf), alpha = .2, linewidth = .2, linetype = "dotted") p4

# Adjust the color scale, aspect ratio, and themes. ## color scale of line segments and texts annotationsmyColors.light <- c("Democratic" = "steelblue2", "Republican" = "firebrick1")## color scale of the backgroundmyColors.dark <- c("Democratic" = "steelblue4", "Republican" = "firebrick4")
p5 <- p4 + # keep a long-narrow dimension coord_fixed(ratio = 2000, clip = "off") + # color / fill scale scale_color_manual(values = myColors.dark ) + scale_fill_manual(values = myColors.light) + theme_void() + theme(plot.margin = margin(rep(10, 4), unit = "pt"), legend.position = "none")p5

# Add plot title with enriched colorslibrary(ggtext)
plot_title <- c( "Presidential Chronicles: A Tale of <span style='color: steelblue3;'>Democrats</span> and <span style='color: red3;'>Republicans</span> from Eisenhower to Trump – Unveiling the Power Shifts in the U.S.")
p6 <- p5 + ggtitle(plot_title)
p6 + theme( plot.title = element_textbox_simple( margin = margin(b = 5, l = 20, r = 20, unit = "pt"), size = 14))

# Load Google font "Anton" to further enhance the title.library(showtext)showtext_auto()font_add_google("Anton", "Anton")
p6 + theme( plot.title = element_textbox_simple( margin = margin(b = 5, l = 20, r = 20, unit = "pt"), size = 14, # use Google font "Anton" family = "Anton"))




Continue Exploring — 🚀 one level up!


Line segments when used properly can become powerful elements to aid in visualization, as demonstrated above. In addition, line segments can be readily updated into arrows to display information about trend of changes. The following article leverages annotated arrows in faceted panels to depict the changes in the proportion of seats held by women in national parliaments from 2000 to 2020.



Line segments can be readily combined with points to create dumbbell plots, useful to highlight items with contrast. In the following article, annotated dumbbell plots in faceted panels are employed to visualize the percentage of votes won by Donald Trump and Hillary Clinton from different population groups at the 2016 United States presidential election.