DuBois Visualization Challenge 2024

Dynamic DuBois Data Visualisation

Author

Jack Davison

Code
library(tidyverse)
library(leaflet)
library(leaflet.extras2)
library(ggplot2)
library(plotly)
library(htmltools)

# dubois palette
dubois_pal <- list(
  "black"   = "#000000",
  "brown"   = "#654321",
  "tan"     = "#d2b48c",
  "gold"    = "#ffd700",
  "pink"    = "#ffc0cb",
  "crimson" = "#dc143c",
  "green"   = "#00aa00",
  "blue"    = "#4682b4",
  "purple"  = "#7e6583"
)

# plotly margins
m <- list(
  l = 125,
  r = 125,
  b = 25,
  t = 25,
  pad = 4
)

This is a showcase for my attempts at the Du Bois Visualization Challenge: 2024. In the past I’ve explored the DuBois style in a few different ways. As part of a TidyTuesday challenge in 2021 I took the challenge literally, and recreated one of the plates as accurately as I could in {ggplot2}.

In 2023, as part of the Posit Tables Contest, I presented Tabulating DuBois - an attempt to create DuBoisian tables (with admittedly mixed success!) using {gt}.

Since I’ve moved from academia to consultancy, increasingly my outputs are interactive rather than static. This year, I’m keen to see if I can re-render the DuBois data using more interactive packages - notably {leaflet} maps and {plotly} graphs, but I’ll see if anything else comes up as I go! The rules I’m setting for myself are not dissimilar to those of Tabulating DuBois:

  1. I’ll try to capture the spirit of the original plates. DuBois played with the medium of static data visualisation (e.g., making bars loop around, flipping axes, etc.) and I want to try to be as playful with the interactive plots where I can.

  2. Where there’s an opportunity to do something off-piste or learn something new, I’ll take it.

  3. I’ll do my best to follow the DuBois style guide, including using the colour palette.

This year the theme for the challenge will be organized around the colours of the Pan African flag: Challenges 1-3: red, Challenges 4-6: black, Challenges 7-9: green, Challenge 10: a combination. This document is a living one, and will be updated week-on-week as the challenge progresses.

Please note that the data used on this website was originally presented by DuBois in 1900, which means it includes the use of now-offensive terms such as “colored” and “negroes” to make reference to black Americans. These terms were used by many of the participants of the 2021 DuBois Challenge as the goal was to recreate DuBois’ original plates as accurately as possible using modern tools.

The aim of this document is not to directly recreate, but be inspired by. As the data is now presented in a new context and in a new medium, it did not feel appropriate to use these outdated terms. Black Americans are now referred to using the terms “Black” or, where relevant, “Black Americans”. DuBois’ original language can still be seen in the images and descriptions of the plates shown on this website, which are displayed unaltered and uncensored.

RED

Challenge 1

“Negro Population of Georgia by County”, is a choropleth map with a alternating left-right pattern, comparing the population of Black Georgians in the years 1870 and 1890. Note the decrease of lightly populated areas, with the heavily populated areas in red shifting west.

This is a map, so I’m naturally going to use {leaflet}. As we’re comparing two maps, I thought it’d be interesting to use {leaflet.extras2} to create a “side-by-side” slider. This is a bit of a departure from the original plate, but it is fun to play with the slider and see how the colours change between decades!

Code
# read shapefile
shapes <-
  sf::read_sf(
    "data/georgia-1880-county-shapefile/DuBoisChallenge - Georgia Counties w 1870 & 1880 data.shp"
  ) |>
  sf::st_transform(crs = 4326) |>
  mutate(County = toupper(NHGISNAM))

# read CSV data
duboisdata <-
  bind_rows(
    `1870` = readr::read_csv(
      "https://raw.githubusercontent.com/ajstarks/dubois-data-portraits/master/challenge/2024/challenge01/data1870.csv"
    ),
    `1880` = readr::read_csv(
      "https://raw.githubusercontent.com/ajstarks/dubois-data-portraits/master/challenge/2024/challenge01/data1880.csv"
    ),
    .id = "year"
  )

# join
shapes_plot <-
  shapes |>
  left_join(duboisdata, join_by(ICPSRNAM == County)) |>
  sf::st_as_sf(crs = 4326)

# get color pal
pal_df <-
  tribble(
    ~Population, ~Colour,
    "> 1000", dubois_pal$green,
    "1000 - 2500", dubois_pal$gold,
    "2500 - 5000", dubois_pal$pink,
    "5000 - 10000", dubois_pal$crimson,
    "10000 - 15000", dubois_pal$tan,
    "15000 - 20000", dubois_pal$brown,
    "20000 - 30000", dubois_pal$purple
  )

# join
shapes_plot <- left_join(shapes_plot, pal_df, join_by(Population))

# get border
sf::sf_use_s2(FALSE)
border <- summarise(shapes_plot)

# define a nice binned legend pal
breaks_pal <-
  scales::col_bin(
    palette = pal_df$Colour,
    bins = c(0, 1000, 2500, 5000, 10000, 15000, 20000, 30000)
  )

# make map
challenge1 <-
  leaflet() %>%
  addMapPane("left", zIndex = 0) %>%
  addMapPane("right", zIndex = 0) %>%
  addProviderTiles(providers$CartoDB.Positron,
                   layerId = "light",
                   options = pathOptions(pane = "left")
  ) |>
  addProviderTiles(providers$CartoDB.Voyager,
                   layerId = "colour",
                   options = pathOptions(pane = "right")
  ) |>
  addPolygons(
    data = border,
    opacity = 1,
    fillOpacity = 0,
    color = "black", fillColor = "white"
  ) |>
  addPolygons(
    data = filter(shapes_plot, year == 1870),
    fillColor = ~Colour,
    opacity = 1,
    fillOpacity = 3 / 4,
    weight = 0.5,
    color = "black",
    options = pathOptions(pane = "left")
  ) |>
  addPolygons(
    data = filter(shapes_plot, year == 1880),
    fillColor = ~Colour,
    opacity = 1,
    fillOpacity = 3 / 4,
    weight = 0.5,
    color = "black",
    options = pathOptions(pane = "right")
  ) |>
  addSidebyside(
    layerId = "sidecontrols",
    rightId = "colour",
    leftId = "light"
  ) |>
  addControl(html = "<b>1870</b>", position = "bottomleft") |>
  addControl(html = "<b>1880</b>", position = "bottomright") |>
  addLegend(
    pal = breaks_pal,
    values = c(0, 30000),
    opacity = 1,
    title = toupper("Black Population<br>of Georgia<br>by Counties .")
  )
Figure 1: A comparison between the black population of Georgia between the years 1870 (left) and 1880 (right). Move the central bar to move between the two years.

Challenge 2

“Slave and Free Negroes” is a vertical bar/area chart with a strong red/black color scheme that compares the population of free and enslaved Black people from 1790 to 1890. The chart depicts the rise of slavery, peaking in 1850, and a sudden burst of freedom at emancipation 1865.

DuBois always seems to do something subversive when he finds himself in a situation where one observation is radically different than the others. The original plate has a “torn” effect to concatenate the x-axis, but in my reimagining I use a rangeslider() with default parameters, so users can expand it to see the plot in full.

Code
data <-
  readr::read_csv("https://raw.githubusercontent.com/ajstarks/dubois-data-portraits/master/challenge/2024/challenge02/data.csv")

plt <- plot_ly()

for (i in 1:9) {
  data_i <- data[i:(i + 1), ]
  if (nrow(data_i) == 2) {
    plt <-
      plt |>
      add_polygons(
        x = c(data_i$Free[1], data_i$Free[2], 100, 100),
        y = c(data_i$Year[1], data_i$Year[2], data_i$Year[2], data_i$Year[1]),
        color = I(dubois_pal$black),
        opacity = 100,
        name = "ENSLAVED",
        legendgroup = "ENSLAVED",
        showlegend = i == 1,
        line = list(color = "white", size = 2),
        hoverinfo = "none"
      ) |>
      add_polygons(
        x = c(data_i$Free[1], data_i$Free[2], 0, 0),
        y = c(data_i$Year[1], data_i$Year[2], data_i$Year[2], data_i$Year[1]),
        color = I(dubois_pal$crimson),
        opacity = 100,
        name = "FREE",
        legendgroup = "FREE",
        showlegend = i == 1,
        line = list(color = "white"),
        hoverinfo = "none"
      ) |>
      add_lines(
        hovertemplate = "%{x}<extra></extra> FREE IN %{y} .",
        x = I(data_i$Free), y = I(data_i$Year), color = I("white"), showlegend = FALSE
      )
  }
}

challenge2 <-
  plt |>
  layout(
    yaxis = list(autorange = "reversed"),
    xaxis = list(ticksuffix = '%', title = "PERCENT OF FREE BLACK AMERICANS .", showgrid = FALSE),
    legend = list(orientation = "h", y = 0.95, x = 0.5, xanchor = "center"), 
    title = toupper("Slaves and Free Black Americans ."),
    margin = m
  ) |>
  rangeslider(start = 0, end = 3)
Figure 2: The rise of slavery leading to emancipation. The rangeslider at the bottom can be used to expand the x-axis scale.

Challenge 3

“Acres of Land Owned by Negroes in Georgia” is a conventional bar chart with a twist. The chart shows the increase of land owned between 1874 (338,769 acres) and 1899 (1,023,741), with the red shape of the data echoing the map of Georgia.

This is indeed a conventional bar chart and, like Figure 2, has been recreated in {plotly} relatively accurately. Users can hover over the bars to read the exact values, however.

Code
dat <-
  readr::read_csv(
    "https://raw.githubusercontent.com/ajstarks/dubois-data-portraits/master/challenge/2024/challenge03/data.csv",
    col_names = c("year", "acres"),
    skip = 1
  ) |>
  # data doesn't match the plate (10/02/24)
  filter(year != 1899) |>
  mutate(year = 1874 + (row_number() - 1)) |>
  mutate(year = factor(paste(year, " ")))

ylabs <- dat$acres
ylabs <- scales::label_comma()(ylabs)
ylabs[-c(1, length(ylabs))] <- ""
ylabs <- glue::glue("<b>{ylabs}</b>")

challenge3 <-
  plot_ly(dat, x = ~acres, y = ~year) |>
  add_bars(y = ~year, 
           x = ~acres, 
           textposition = 'auto',
           text = ylabs,
           hovertemplate = "%{x}<extra></extra>",
           marker = list(line = list(color = dubois_pal$black, width = 1),
                         color = dubois_pal$crimson),
           textfont = list(color = dubois_pal$black)
  ) |>
  layout(xaxis = list(showticklabels = FALSE,
                      title = "",
                      showgrid = FALSE,
                      zeroline = FALSE,
                      fixedrange = TRUE),
         yaxis = list(showgrid = FALSE,
                      zeroline = FALSE,
                      title = "",
                      autorange = "reversed",
                      fixedrange = TRUE),
         title = toupper("Acres of Land Owned by Black Georgians ."),
         margin = m)
Figure 3: The acres of land owned by plack people in Georgia from 1874 to 1897. This is a conventional bar chart, but specific values can be read by hovering over each bar.

BLACK

Challenge 4

“The Georgia Negro, A Social Study” shows the transatlantic slave trade, with routes from Europe, Africa, the Americas and the Caribbean, highlighting Georgia. This visual contains Du Bois’ famous assertion: “The problem of the 20th century is the problem of the color line”

Coming soon.

Challenge 5

“Race Amalgamation in Georgia” is a single bold monolith of a stacked bar chart, showing the ethnic make-up of people of color in Georgia, using literal colors to describe them (Black, Brown, and Yellow).

Coming soon.

Challenge 6

Continuing the theme from last week, “The Amalgamation of the White and Black Elements of population in the United States”, the mountain-like area chart shows how the gradient of racial identities changed between 1800 and 1890.

Coming soon.

GREEN

Challenge 7

Comparing the state of Black Americans with the larger world, “Illiteracy of American Negroes compared with that of other nations” shows Black American’s illiteracy in red, in the middle of a sea of green, higher than countries like France, but better than others like Russia.

Coming soon.

Challenge 8

“The Rise of Negroes from Slavery to Freedom in One Generation”, uses two stacked bars to show how a group of people, largely enslaved in 1860, transformed into a group where nearly one-fifth owned their own farms and homes in the face of discrimination, and without state aid.

Coming soon.

Challenge 9

With the green waters of Freedom plunging down a waterfall set on the dark base of slavery, “Proportion of Freeman and Slaves Among American Negroes” shows number of enslaved and free from 1790 to 1870.

Coming soon.

FINAL

Challenge 10

Serving as the introductory display, this chart shows the full Du Bois color palette. The chart includes bi-lingual text, a map of the Black population in the US, and a familiar pie chart showing professions in the population.

Coming soon.