Load required library

library(tidyverse)

col_types_spec <- cols_only(
  id = col_integer(),
  voyage_id = col_integer(),
  voyage_dates__imp_arrival_at_port_of_dis_sparsedate__year = col_double(),
  voyage_slaves_numbers__imp_total_num_slaves_disembarked = col_double(),
  voyage_slaves_numbers__imp_total_num_slaves_embarked = col_double(),
  voyage_dates__length_middle_passage_days = col_double(),
  voyage_dates__imp_length_home_to_disembark = col_double(),
  voyage_crew__crew_first_landing = col_double(),
  voyage_crew__crew_voyage_outset = col_double(),
  voyage_ship__tonnage_mod = col_double(),
  voyage_slaves_numbers__imp_jamaican_cash_price = col_double(),
  voyage_slaves_numbers__imp_mortality_ratio = col_double(),
  voyage_slaves_numbers__percentage_women_among_embarked_slaves = col_double(),
  voyage_outcome__vessel_captured_outcome__name = col_character(),
  voyage_ship__imputed_nationality__name = col_character(),
  voyage_itinerary__imp_region_voyage_begin__name = col_character(),
  voyage_ship__rig_of_vessel__name = col_character(),
  voyage_itinerary__place_voyage_ended__name = col_character(),
  voyage_dates__slave_purchase_began_sparsedate__month = col_double(),
  voyage_slaves_numbers__percentage_men = col_double(),
  voyage_dates__voyage_completed_sparsedate__month = col_double(),
  voyage_itinerary__region_of_return__name = col_character(),
  voyage_slaves_numbers__percentage_boy = col_double(),
  voyage_itinerary__imp_principal_region_slave_dis__name = col_character(),
  voyage_itinerary__imp_principal_region_of_slave_purchase__name = col_character(),
  voyage_dates__date_departed_africa_sparsedate__month = col_double(),
  voyage_dates__voyage_began_sparsedate__month = col_double(),
  voyage_itinerary__imp_port_voyage_begin__name = col_character(),
  voyage_dates__first_dis_of_slaves_sparsedate__month = col_double(),
  voyage_itinerary__imp_broad_region_slave_dis__name = col_character(),
  voyage_slaves_numbers__percentage_girl = col_double(),
  voyage_outcome__particular_outcome__name = col_character(),
  voyage_itinerary__imp_principal_port_slave_dis__name = col_character(),
  voyage_slaves_numbers__percentage_child = col_double(),
  voyage_slaves_numbers__percentage_women = col_double(),
  voyage_dates__departure_last_place_of_landing_sparsedate__month = col_double(),
  voyage_outcome__outcome_owner__name = col_character(),
  voyage_outcome__outcome_slaves__name = col_character(),
  voyage_itinerary__imp_principal_place_of_slave_purchase__name = col_character(),
  voyage_outcome__resistance__name = col_character(),
  voyage_slaves_numbers__percentage_male = col_double(),
  voyage_slaves_numbers__percentage_female = col_double(),
  voyage_itinerary__imp_broad_region_voyage_begin__name = col_character(),
  voyage_itinerary__imp_broad_region_of_slave_purchase__name = col_character(),
  voyage_sources = col_character(),
  enslavers = col_character()
)

Load the datasets

trans <- read_csv(
  "https://raw.githubusercontent.com/imowerman-prog/data-3210/refs/heads/main/Data/trans-atlantic.csv",
  col_types = col_types_spec
)
intra <- read_csv(
  "https://raw.githubusercontent.com/imowerman-prog/data-3210/refs/heads/main/Data/intra-american.csv",
  col_types = col_types_spec
)

Define successful outcomes

successful_outcomes <- c(
  "Sold slaves in Americas - subsequent fate unknown",
  "Voyage completed as intended",
  "Captured by pirates or privateers - after disembarkation",
  "Condemned - Americas after disembarkation",
  "Detained and condemned in the United States after slaves disembarked",
  "Condemned in the Americas by British after slaves disembarked",
  "Captured by pirates - slaves sold in Americas from another ship",
  "Shipwrecked or destroyed, after disembarkation",
  "Privateer captured slaves at sea and delivered for sale in America",
  "Prisoners of war stole slaves during escape and carried to port of sale",
  "Captives seized from vessel by Spanish officials and sold",
  "Captured by Dutch - after disembarkation",
  "Shipwrecked, slaves salvaged",
  "Captured by slaves, recaptured and landed slaves in the Americas"
)

Clean

### Common renames used in both tables
rename_keys <- c(
  year = "voyage_dates__imp_arrival_at_port_of_dis_sparsedate__year",
  slaves_embarked = "voyage_slaves_numbers__imp_total_num_slaves_embarked",
  slaves_disembarked = "voyage_slaves_numbers__imp_total_num_slaves_disembarked",
  particular_outcome = "voyage_outcome__particular_outcome__name",
  dis_broad = "voyage_itinerary__imp_broad_region_slave_dis__name",
  dis_port = "voyage_itinerary__imp_principal_port_slave_dis__name",
  embark_broad = "voyage_itinerary__imp_broad_region_of_slave_purchase__name",
  embark_port = "voyage_itinerary__imp_principal_place_of_slave_purchase__name",
  ship_nation = "voyage_ship__imputed_nationality__name"
)

Rename

### Process trans-atlantic data (fixed)
trans <- trans %>%
  dplyr::rename(
    year = voyage_dates__imp_arrival_at_port_of_dis_sparsedate__year,
    slaves_embarked = voyage_slaves_numbers__imp_total_num_slaves_embarked,
    slaves_disembarked = voyage_slaves_numbers__imp_total_num_slaves_disembarked,
    particular_outcome = voyage_outcome__particular_outcome__name,
    dis_broad = voyage_itinerary__imp_broad_region_slave_dis__name,
    dis_port = voyage_itinerary__imp_principal_port_slave_dis__name,
    embark_broad = voyage_itinerary__imp_broad_region_of_slave_purchase__name,
    embark_port = voyage_itinerary__imp_principal_place_of_slave_purchase__name
  ) %>%
  mutate(
    year = as.integer(year),
    slaves_embarked = as.numeric(slaves_embarked),
    slaves_disembarked = as.numeric(slaves_disembarked)
  ) %>%
  filter(
    !is.na(slaves_disembarked),
    slaves_disembarked > 0,
    particular_outcome %in% successful_outcomes
  ) %>%
  mutate(
    decade = floor(year / 10) * 10,
    estimated_deaths = slaves_embarked - slaves_disembarked,
    is_us = dis_broad == "Mainland North America" |
      str_detect(dis_port, regex("United States|Boston|Charleston|New York|Philadelphia|Savannah|New Orleans", ignore_case = TRUE)),
    embark_is_us = embark_broad == "Mainland North America" |
      str_detect(embark_port, regex("United States|New Orleans", ignore_case = TRUE)),
    source_type = "Trans-Atlantic"
  )

Rename

### Process intra-american data
intra <- intra %>%
 dplyr::rename(
    year = voyage_dates__imp_arrival_at_port_of_dis_sparsedate__year,
    slaves_embarked = voyage_slaves_numbers__imp_total_num_slaves_embarked,
    slaves_disembarked = voyage_slaves_numbers__imp_total_num_slaves_disembarked,
    particular_outcome = voyage_outcome__particular_outcome__name,
    dis_broad = voyage_itinerary__imp_broad_region_slave_dis__name,
    dis_port = voyage_itinerary__imp_principal_port_slave_dis__name,
    embark_broad = voyage_itinerary__imp_broad_region_of_slave_purchase__name,
    embark_port = voyage_itinerary__imp_principal_place_of_slave_purchase__name
  ) %>%
  mutate(
    year = as.integer(year),
    slaves_embarked = as.numeric(slaves_embarked),
    slaves_disembarked = as.numeric(slaves_disembarked)
  ) %>%
  filter(
    !is.na(slaves_disembarked),
    slaves_disembarked > 0,
    particular_outcome %in% successful_outcomes
  ) %>%
  mutate(
    decade = (year %/% 10) * 10,
    estimated_deaths = slaves_embarked - slaves_disembarked,
    is_us = dis_broad == "Mainland North America" |
      str_detect(dis_port, regex("United States|Boston|Charleston|New York|Philadelphia|Savannah|Norfolk|Baltimore|New Orleans|Providence|Alexandria", ignore_case = TRUE)),
    embark_is_us = embark_broad == "Mainland North America" |
      str_detect(embark_port, regex("United States|New Orleans|Charleston|New York|Philadelphia", ignore_case = TRUE)),
    source_type = "Intra-American"
  )

Combine the datasets

# Combine to the name you actually use later
slave_trades <- bind_rows(trans, intra)

2) Analyses to answer questions

### Question 1: Net slaves imported to the US (gross imports minus re-exports)
gross_us <- slave_trades %>%
  filter(is_us == TRUE) %>%
  summarise(gross_us = sum(slaves_disembarked, na.rm = TRUE)) %>%
  pull(gross_us)

re_exports <- slave_trades %>%
  filter(source_type == "Intra-American", embark_is_us == TRUE, is_us == FALSE) %>%
  summarise(re_exports = sum(slaves_embarked, na.rm = TRUE)) %>%
  pull(re_exports)

net_us <- gross_us - re_exports

cat("Gross slaves imported to the US:", gross_us, "\n")
## Gross slaves imported to the US: 396325
cat("Slaves re-exported from the US:", re_exports, "\n")
## Slaves re-exported from the US: 7548
cat("Net slaves retained in the US:", net_us, "\n")
## Net slaves retained in the US: 388777
### Q2: Proportion of all slaves taken from Africa that went to the US 
trans_total_embarked <- trans %>%
  summarize(total_embarked = sum(slaves_embarked, na.rm = TRUE)) %>%
  pull(total_embarked)

proportion <- net_us / trans_total_embarked

cat("Proportion of all slaves taken from Africa (net US):", proportion, "\n")
## Proportion of all slaves taken from Africa (net US): 0.05114323

Q3: Graph US imports by decade (bar)

library(ggplot2)

us_by_decade <- slave_trades %>%
  filter(is_us) %>%
  mutate(decade = (year %/% 10) * 10) %>%
  group_by(decade) %>%
  summarise(total_imports = sum(slaves_disembarked, na.rm = TRUE))

ggplot(us_by_decade, aes(x = decade, y = total_imports)) +
  geom_col(fill = "steelblue") +
  labs(
    title = "Slave Imports to the US by Decade",
    x = "Decade",
    y = "Total Slaves Disembarked"
  )

Q4: US imports by decade and region/port/state (table + faceted bar)

### Simplify ports into rough states
slave_trades <- slave_trades %>%
  mutate(us_state = case_when(
    str_detect(dis_port, "New Orleans") ~ "Louisiana",
    str_detect(dis_port, "Charleston") ~ "South Carolina",
    str_detect(dis_port, "Savannah") ~ "Georgia",
    str_detect(dis_port, "Virginia") ~ "Virginia",
    str_detect(dis_port, "Maryland") ~ "Maryland",
    str_detect(dis_port, "New York") ~ "New York",
    str_detect(dis_port, "Philadelphia") ~ "Pennsylvania",
    TRUE ~ "Other/Unknown"
  ))

us_by_region <- slave_trades %>%
  filter(is_us) %>%
  mutate(decade = (year %/% 10) * 10) %>%
  group_by(decade, dis_broad, dis_port, us_state) %>%
  summarize(total_imports = sum(slaves_disembarked, na.rm = TRUE)) %>%
  ungroup() 

### Table
us_by_region
## # A tibble: 278 × 5
##    decade dis_broad              dis_port                 us_state total_imports
##     <dbl> <chr>                  <chr>                    <chr>            <dbl>
##  1   1610 Mainland North America Hampton                  Other/U…            29
##  2   1620 Mainland North America Virginia, port unspecif… Virginia             3
##  3   1630 Caribbean              Providence Island        Other/U…            14
##  4   1630 Mainland North America Boston                   Other/U…             7
##  5   1630 Mainland North America New York                 New York            53
##  6   1630 Mainland North America Virginia, port unspecif… Virginia            13
##  7   1640 Mainland North America New York                 New York            69
##  8   1640 Mainland North America Virginia, port unspecif… Virginia            12
##  9   1650 Mainland North America Maryland, port unspecif… Maryland             5
## 10   1650 Mainland North America New York                 New York           477
## # ℹ 268 more rows
### Faceted plot
ggplot(us_by_region, aes(x = decade, y = total_imports, fill = us_state)) +
  geom_col() +
  facet_wrap(~ us_state, scales = "free_y") +
  labs(
    title = "US Slave Imports by Decade and Region/State",
    x = "Decade",
    y = "Total Slaves Disembarked"
  )

Question 5: Countries participating in export from Africa

trans <- slave_trades %>%
  mutate(
    decade = (year %/% 10) * 10
  ) %>%
  group_by(decade, slaves_disembarked) %>%
  summarize(
    voyages = n_distinct(voyage_id),
    total_embarked = sum(slaves_embarked, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  arrange(decade, desc(total_embarked))

trans
## # A tibble: 9,365 × 4
##    decade slaves_disembarked voyages total_embarked
##     <dbl>              <dbl>   <int>          <dbl>
##  1   1510                125       1            150
##  2   1510                 62       1             83
##  3   1510                 11       2             27
##  4   1510                 23       1             27
##  5   1510                  8       2             20
##  6   1510                 15       1             18
##  7   1510                  7       1             10
##  8   1510                  6       1              8
##  9   1510                  4       1              6
## 10   1510                  5       1              6
## # ℹ 9,355 more rows

Part 3: Visualizations and publications

Plot 1: U.S. imports by decade

us_by_decade <- slave_trades %>%
  filter(is_us) %>%
  mutate(decade = (year %/% 10) * 10) %>%
  group_by(decade) %>%
  summarize(total_imports = sum(slaves_disembarked, na.rm = TRUE), .groups = "drop") %>%
  arrange(decade)

# Build pretty decade breaks
dec_min <- min(us_by_decade$decade, na.rm = TRUE)
dec_max <- max(us_by_decade$decade, na.rm = TRUE)
dec_breaks <- seq(dec_min, dec_max, by = 10)

library(ggplot2)

ggplot(us_by_decade, aes(x = decade, y = total_imports)) +
  geom_col() +
  labs(
    title = "Slaves Imported to the US by Decade",
    x = "Decade",
    y = "Slaves Disembarked"
  ) +
  scale_x_continuous(breaks = dec_breaks) +
  theme_minimal()

Plot 2: U.S. imports by decade & port (faceted)

us_by_state <- slave_trades %>%
  filter(is_us) %>%
  mutate(
    decade = (year %/% 10) * 10
  ) %>%
  group_by(decade, us_state) %>%
  summarize(total_imports = sum(slaves_disembarked, na.rm = TRUE), .groups = "drop")

# Plot
ggplot(us_by_state, aes(x = decade, y = total_imports, fill = us_state)) +
  geom_col() +
  facet_wrap(~ us_state, scales = "free_y") +
  labs(
    title = "US Slave Imports by Decade and State (Approx. from Ports/Regions)",
    x = "Decade",
    y = "Slaves Disembarked"
  ) +
  theme_minimal() +
  theme(legend.position = "none")

2) Summary

Using the Trans-Atlantic and Intra-American voyage records, I estimated total enslaved people disembarked in the United States by filtering completed landings and summing slaves_disembarked across both datasets. The US total represents a small fraction of the total number of people embarked from Africa in the Trans-Atlantic records; my proportion metric divides the US total by the Trans-Atlantic embarked total to approximate the US share of the African diaspora through the Middle Passage. The decade-level bar chart shows that imports to the US were highly uneven across time, with identifiable peaks corresponding to periods of intense trans-Atlantic activity and policy changes. Breaking results down by state (approximated from ports/regions) highlights historical hubs—e.g., New Orleans (Louisiana) and Charleston (South Carolina)—that together account for a large share of US disembarkations. Finally, grouping by ship nationality in the Trans-Atlantic dataset illustrates which European powers were most active over time; this varies by decade, reflecting geopolitical shifts, wars, and changes in enforcement. Overall, the results reinforce that (1) the US received a smaller proportion of those trafficked from Africa relative to the wider Americas, (2) specific ports dominated US arrivals, and (3) national participation changed materially across decades.