Spatial Data Mapping

Choropleth US States’ Population

#install.packages(c("usmap", "ggplot2", "dplyr", "cartogram", "geofacet", "sf", "tigris"))

library(usmap)
library(ggplot2)
library(dplyr)

data("statepop")
head(statepop) #take a look at first 5 rows

#draw choropleth map
plot_usmap(data = statepop, values = "pop_2022", regions = "states") +
  scale_fill_continuous(
    low = "white", high = "blue", name = "Population (2022)", label = scales::comma
  ) +
  theme(legend.position = "right")

However…

Symbol map

library(usmap)
library(dplyr)
library(ggplot2)
library(sf)

# Load population data
data("statepop")

# Calculate centroids for symbol locating
us_states <- us_map(regions = "states")
# Compute centroids for each state
state_centroids <- us_states %>%
  st_as_sf() %>%
  st_centroid() %>%
  st_coordinates() %>%
  as.data.frame() %>%
  rename(long = X, lat = Y) %>%
  bind_cols(us_states %>% select(abbr))

# Join population data
state_data <- statepop %>%
  left_join(state_centroids, by = c("abbr"))

# Plot symbol map
plot_usmap(regions = "states") +
  geom_point(data = state_data, aes(x = long, y = lat, size = pop_2022),
             color = "red", alpha = 0.7) +
  scale_size_continuous(name = "Population (2022)", range = c(1, 12), labels = scales::comma) +
  labs(title = "US State Population (2022)", subtitle = "Dot size represents population") +
  theme(legend.position = "right")

Contiguous Cartogram

# Load libraries
library(cartogram)
library(sf)
library(tigris)

# Get US states shape data (simplified)
us_states <- states(cb = TRUE, resolution = "20m", year = 2022) %>%
  filter(!STUSPS %in% c("PR", "GU", "VI", "AS", "MP", "AK", "HI")) %>% # Exclude territories
  st_transform(crs = 5070)  # Project to Albers Equal Area for US

# Load state population data
state_pop <- data.frame(
  state = datasets::state.name,
  STUSPS = datasets::state.abb,
  population = datasets::state.x77[, "Population"]
)

# Join shape data with population
us_states_pop <- us_states %>%
  left_join(state_pop, by = "STUSPS") %>%
  na.omit()

# Generate contiguous cartogram based on population
us_cartogram <- cartogram_cont(us_states_pop, weight = "population", itermax = 7)

# Plot the cartogram with ggplot
ggplot(us_cartogram) +
  geom_sf(aes(fill = population), color = "white", size = 0.3) +
  scale_fill_gradient(low = "pink", high = "red", name = "Population",
                      labels = scales::comma) +
  labs(title = "US Contiguous Cartogram by State Population",
       subtitle = "State size and color correspond to population") +
  theme_void() +
  theme(legend.position = "right")

Now this map…

# Load libraries
library(cartogram)
library(sf)
library(tigris)
library(ggplot2)
library(dplyr)

# Load US state boundaries
us_states <- states(cb = TRUE, resolution = "20m", year = 2022) %>%
  filter(!STUSPS %in% c("PR", "GU", "VI", "AS", "MP", "AK", "HI")) %>% # exclude territories
  st_transform(crs = 5070)

# Load state population data
state_pop <- data.frame(
  state = datasets::state.name,
  STUSPS = datasets::state.abb,
  population = datasets::state.x77[, "Population"]
)

# Join data
us_states_pop <- us_states %>%
  left_join(state_pop, by = "STUSPS") %>%
  na.omit()

# Create non-contiguous cartogram
us_noncont_cartogram <- cartogram_ncont(us_states_pop, weight = "population")

# Plot non-contiguous cartogram
ggplot(us_noncont_cartogram) +
  geom_sf(aes(fill = population), color = "white", size = 0.3) +
  scale_fill_gradient(low = "pink", high = "red", name = "Population", labels = scales::comma) +
  labs(title = "US Non-Contiguous Cartogram by Population",
       subtitle = "State size and color represent population") +
  theme_void() +
  theme(legend.position = "right")

Grid cartogram

# Load libraries
library(geofacet)
library(ggplot2)
library(dplyr)

# Prepare population data
state_pop <- data.frame(
  state = datasets::state.name,
  state_abb = datasets::state.abb,
  population = datasets::state.x77[, "Population"]
)

# Merge data with geofacet grid
state_pop_grid <- state_pop %>%
  left_join(us_state_grid1, by = c("state_abb" = "code"))

# Draw the grid cartogram
ggplot(state_pop_grid, aes(x = col, y = -row)) +
  geom_tile(aes(fill = population), color = "white") +
  geom_text(aes(label = state_abb), color = "black", size = 3) +
  scale_fill_gradient(low = "pink", high = "red", name = "Population", labels = scales::comma) +
  coord_equal() +
  labs(title = "US Grid Cartogram by Population",
       subtitle = "Grid colored by population with state abbreviations") +
  theme_void() +
  theme(legend.position = "right",
        plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
        plot.subtitle = element_text(hjust = 0.5, size = 12))

What are the pros / cons