How to recreate WEB DuBois's Panel 51 from the 1900 Paris Exposition using R and ggplot2 (CC341)

February 13, 2025 • PD Schloss • 7 min read

Pat uses R to recreate an iconic figure that WEB DuBois presented at the 1900 Paris Exposition showing the change in the percentage of Blacks who were free in America between 1790 and 1870 using tools from the ggplot2, dplyr, and showtext packages. The functions he uses from these packages include aes, annotate, coord_cartesian, font_add, geom_area, geom_label, geom_text, geom_vline, ggplot, ggsave, if_else, labs, library, mutate, paste0, pivot_longer, scale_fill_manual, scale_x_continuous, select, seq, showtext_auto, showtext_opts, theme, tribble, and unit. Pat’s newsletter describing how he would go about generating the figure can be found here. The book Pat mentions by Whitney Battle-Baptiste and Britt Rusert, titled “W.E.B. Du Bois’s Data Portraits: Visualizing Black America” is available here. A great set of talks about the DuBois data portraits is available on YouTube. The Anthony Starks GitHub repository can be found here. If you have a figure that you would like to see me discuss in a future newsletter and episode of Code Club, email me at pat@riffomonas.org!

Code

library(tidyverse)
library(showtext)

font_add("b52", regular = "OnlineWebFonts_COM_5d6bfe4f38a46ad2c2304bc1f8ea8151/B52-ULC W00 ULC/B52-ULC W00 ULC.ttf")
showtext_auto()
showtext_opts(dpi = 300)

free_slave <- tribble(
  ~year, ~free,
  1790,   8.0,
  1800,  11.0,
  1810,  13.5,
  1820,  13.0,
  1830,  14.0,
  1840,  13.0,
  1850,  12.0,
  1860,  11.0,
  1870, 100.0
) %>%
  mutate(slave = 100 - free,
         label_y = if_else(year == 1870, 90, slave + 0.5))

free_slave %>%
  select(-label_y) %>%
  pivot_longer(-year, names_to = "status", values_to = "percentage") %>%
  ggplot(aes(x = year, y = percentage, fill = status)) +
  geom_area(show.legend = FALSE) +
  geom_vline(xintercept = seq(1790, 1870, 10), linewidth = 0.1) +
  geom_label(data = free_slave %>% filter(year != 1790 & year != 1870), 
            aes(x = year, y = label_y, label = paste0(free, "%")),
            vjust = 0, family = "b52", size = 8, size.unit = "pt",
            label.padding = unit(0, "mm"), fill = "#00aa00", label.size = unit(0, "mm"),
            inherit.aes = FALSE) +
  geom_text(data = free_slave %>% filter(year == 1790 | year == 1870), 
             aes(x = year, y = label_y, label = paste0(free, "%")),
             vjust = 0, family = "b52", size = 8, size.unit = "pt",
             inherit.aes = FALSE) +
  annotate(geom = "text", x = 1830, y = c(55, 95),
           label = c("SLAVES\nESCLAVES", "FREE - LIBRE"),
           color = c("white", "black"), family = "b52",
           size = c(17, 12), size.unit = "pt", lineheight = 0.9) +
  scale_fill_manual(breaks = c("free", "slave"),
                    values = c("#00aa00", "#000000")) +
  scale_x_continuous(breaks = seq(1790, 1870, 10), position = "top") +
  coord_cartesian(expand = FALSE, clip = "off") +
  labs(x = NULL, y = NULL,
       title = "PROPORTION OF FREEMEN AND SLAVES AMONG AMERICAN NEGROES .\nPROPORTION DES NÈGRES LIBRES ET DES ESCLAVES EN AMERIQUE .",
       subtitle = "DONE BY ATLANTA UNIVERSITY ."
       ) +
  theme(
    text = element_text(family = "b52"),
    axis.ticks = element_blank(),
    axis.text.x.top = element_text(color = "black", size = 10,
                               margin = margin(b = -1)),
    axis.text.y = element_blank(),
    plot.title = element_text(size = 10, hjust = 0.5, lineheight = 2),
    plot.subtitle = element_text(size = 8, hjust = 0.5,
                                 margin = margin(t = 20, b = 28)),
    plot.margin = margin(l = 15, r = 15, b = 10, t = 10)
  )

ggsave("panel_51.png", width = 5, height = 6.41, unit = "in")