How to recreate a historic map in R using the sf and ggplot2 packages (CC347)

March 6, 2025 • PD Schloss • 7 min read

Pat uses R to show how to create a county map of Georgia from 1890 overlaid wit the number of Black Georgians in each county to recreate an iconic bar plot figure that WEB DuBois presented at the 1900 Paris Exposition using the ggplot2, dplyr, showtext, and sf packages. The functions he uses from these packages include aes, coord_sf, cut, filter, font_add, geom_sf, ggplot, ggsave, guide_legend, inner_join, labs, library, list, mutate, read_tsv, read_sf, scale_fill_manual, showtext_auto, showtext_opts, theme, and year. 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 at Amazon. A great set of talks about the DuBois data portraits is available here. 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!

Census data PDF: https://www2.census.gov/prod2/decennial/documents/1890a_v1-13.pdf (my tsv below…) Historic county boundaries: https://digital.newberry.org/ahcb/downloads/states.html

Code

library(tidyverse)
library(showtext)
library(sf)

font_add("b52", "B52-ULC W00 ULC.ttf")
font_add("vasarely", "vasarely-light.otf")
showtext_auto()
showtext_opts(dpi = 300)


populations <- read_tsv("county_count.tsv") %>%
  mutate(size_category = cut(n,
                             breaks = c(0, 1000, 2500, 5000, 10000,
                                        15000, 20000, 30000, max(n))))

read_sf("GA_AtlasHCB/GA_Historical_Counties/GA_Historical_Counties.shp") %>%
  filter(year(START_DATE) < 1890 & year(END_DATE) > 1890) %>%
  inner_join(., populations, by = c("NAME" = "county")) %>%
  ggplot(aes(fill = size_category)) +
  geom_sf(color = "black", linewidth = 0.1, key_glyph = "point") +
  scale_fill_manual(
    name = NULL,
    breaks = c("(3e+04,3.54e+04]", "(2e+04,3e+04]", "(1.5e+04,2e+04]",
               "(1e+04,1.5e+04]", "(5e+03,1e+04]", "(2.5e+03,5e+03]",
               "(1e+03,2.5e+03]", "(0,1e+03]"),
    values = c("#000000", "#7e6583", "#654321", "#d2b48c", "#dc143c",
               "#ffc0cb", "#ffd700", "#00aa00"),
    labels = c("OVER 30,000 NEGROES", "BETWEEN 20,000 AND 30,000",
               "5,000 TO 20,000", "10,000 TO 15,000", "5,000 TO 10,000",
               " 2,500 TO 5,000", "  1,000 TO 2,500", "     UNDER 1,000"),
    guide = guide_legend(ncol = 2,
                         override.aes = list(shape = 21, size = 6,
                                             stroke = 0.2))
  ) +
  labs(
    title = "NEGRO POPULATION OF GEORGIA BY COUNTIES.",
    subtitle = "1890."
  ) +
  coord_sf(expand = FALSE, clip = "off", xlim = c(-86.4, NA)) +
  theme(
    plot.title.position = "plot",
    plot.title = element_text(family = "b52", hjust = 0.5, size = 12,
                              margin = margin(b = 0, t = 20)),
    plot.subtitle = element_text(family = "b52", hjust = 0.5, size = 8,
                                 margin = margin(b = 80)),
    plot.margin = margin(t = 10, b = 20),
    legend.position = "bottom",
    legend.text = element_text(family = "vasarely", size = 8),
    legend.box.spacing = unit(0, "pt"),
    legend.key.spacing.y = unit(15, "pt"),
    legend.key.spacing.x = unit(10, "pt"),
    axis.ticks = element_blank(),
    axis.text = element_blank(),
    panel.grid = element_blank(),
    panel.background = element_blank()
  )

ggsave("plate_05.png", width = 5, height = 6.21, unit = "in")

county_count.tsv

county	n
APPLING	2462
BAKER	4549
BALDWIN	9343
BANKS	1563
BARTOW	6041
BERRIEN	2417
BIBB	23336
BROOKS	7637
BRYAN	2687
BULLOCH	4689
BURKE	22680
BUTTS	5398
CALHOUN	6199
CAMDEN	4137
CAMPBELL (ext)	3493
CARROLL	3851
CATOOSA	636
CHARLTON	870
CHATHAM	34757
CHATTAHOOCHEE	3065
CHATTOOGA	1998
CHEROKEE	1508
CLARKE	8111
CLAY	4815
CLAYTON	3075
CLINCH	2360
COBB	6774
COFFEE	3858
COLQUITT	477
COLUMBIA	8038
COWETA	12612
CRAWFORD	5156
DADE	1093
DAWSON	259
DECATUR	10811
DEKALB	5974
DODGE	5309
DOOLY	8914
DOUGHERTY	10231
DOUGLAS	1801
EARLY	6122
ECHOLS	1020
EFFINGHAM	2210
ELBERT	7884
EMANUEL	5306
FANNIN	112
FAYETTE	3074
FLOYD	10414
FORSYTH	1288
FRANKLIN	3298
FULTON	35397
GILMER	69
GLASCOCK	1168
GLYNN	7741
GORDON	1727
GREENE	11719
GWINNETT	2996
HABERSHAM	1589
HALL	2767
HANCOCK	12410
HARALSON	1117
HARRIS	10797
HART	2957
HEARD	3342
HENRY	7591
HOUSTON	16341
IRWIN	2075
JACKSON	5396
JASPER	8487
JEFFERSON	10763
JOHNSON	1456
JONES	8778
LAURENS	6093
LEE	7642
LIBERTY	8673
LINCOLN	3673
LOWNDES	7974
LUMPKIN	414
McDUFFIE	5522
McINTOSH	5212
MACON	9181
MADISON	3662
MARION	4261
MERIWETHER	11538
MILLER	1574
MILTON (ext)	672
MITCHELL	6106
MONROE	12516
MONTGOMERY	3658
MORGAN	10997
MURRAY	484
MUSCOGEE	15362
NEWTON	7164
OCONEE	3832
OGLETHORPE	11264
PAULDING	1505
PICKENS	349
PIERCE	1983
PIKE	8077
POLK	4654
PULASKI	10001
PUTNAM	10903
QUITMAN	3050
RABUN	166
RANDOLPH	9473
RICHMOND	22818
ROCKDALE	2686
SCHLEY	3205
SCREVEN	7507
SPALDING	7281
STEWART	11484
SUMTER	15098
TALBOT	9239
TALIAFERRO	4827
TATTNALL	3115
TAYLOR	4068
TELFAIR	2335
TERRELL	9169
THOMAS	15028
TOWNS	74
TROUP	13661
TWIGGS	5447
UNION	165
UPSON	6123
WALKER	1932
WALTON	7155
WARE	3619
WARREN	6756
WASHINGTON	14925
WAYNE	2195
WEBSTER	3272
WHITE	662
WHITFIELD	1930
WILCOX	3155
WILKES	12464
WILKINSON	5214
WORTH	4176