Introduction

The field of data visualization in R has come a long way, especially in the realm of mapping. Modern R packages have significantly simplified the process of creating maps, moving beyond traditional GIS tools. This lesson will explore various packages and techniques for creating static and interactive maps in R, focusing on both US and world maps. We’ll cover a range of tools from basic plotting to advanced interactive visualizations, providing you with a comprehensive toolkit for geographical data representation.

Setting Up

library(tidyverse)  # For data manipulation and visualization
library(ggplot2)    # For creating static maps
library(usmap)      # Specialized for US maps
library(sf)         # For working with spatial data
#library(rnaturalearth)  # For world map data
library(rnaturalearthdata)  # Additional data for rnaturalearth
library(USAboundaries)  # For historical US boundaries
library(statebins)  # For creating state-based tile grid maps
library(leaflet)    # For interactive web maps
library(plotly)     # For interactive plots and maps
library(highcharter) # For highcharts visualizations)

Using the usmap Package

The usmap package is a powerful tool for creating US maps at both state and county levels. It simplifies the process of plotting US maps by handling the map data and providing convenience functions.

Basic State Map

Let’s start with a basic state map:

plot_usmap()
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found

This command creates a blank state map of the United States. Notice how it uses a pleasing projection where the top of the US isn’t a straight line, making it more visually appealing and geographically accurate.

County Map

We can easily switch to a county-level map:

plot_usmap(regions = "counties")
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found

This creates a detailed map showing all US counties. It’s particularly useful when you need to visualize data at a more granular level than states.

Understanding the Data Structure

The usmap package uses FIPS (Federal Information Processing Standards) codes to identify states and counties. Let’s look at how this data is structured:

states_df <- usmap::us_map()
counties_df <- usmap::us_map(regions = "counties")

# View a sample of the state data
states_df %>% slice_sample(n=20)
## Simple feature collection with 20 features and 3 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -1816468 ymin: -2246943 xmax: 2442604 ymax: 681361.7
## Projected CRS: NAD27 / US National Atlas Equal Area
## # A tibble: 20 × 4
##    fips  abbr  full                                                         geom
##    <chr> <chr> <chr>                                          <MULTIPOLYGON [m]>
##  1 28    MS    Mississippi    (((800560.5 -1484352, 806059.2 -1484499, 811041.1…
##  2 55    WI    Wisconsin      (((1014189 129105.4, 1021226 133546, 1024195 1298…
##  3 37    NC    North Carolina (((1422743 -954896.9, 1422655 -952556.9, 1427165 …
##  4 45    SC    South Carolina (((1515345 -990910.5, 1517707 -986922.9, 1516774 …
##  5 40    OK    Oklahoma       (((-268365.3 -920075.2, -267456.6 -894091, -26714…
##  6 17    IL    Illinois       (((720446.8 -496527.1, 720702.3 -491071.4, 720813…
##  7 38    ND    North Dakota   (((-295330.9 452190.6, -246259.4 449797.6, -21442…
##  8 49    UT    Utah           (((-1233236 -717745, -1230718 -702225, -1228183 -…
##  9 04    AZ    Arizona        (((-1386064 -1256492, -1386565 -1253758, -1381911…
## 10 10    DE    Delaware       (((2037480 -284625.1, 2038045 -280253.1, 2039915 …
## 11 15    HI    Hawaii         (((-400384.7 -2147655, -396473.3 -2143778, -39393…
## 12 25    MA    Massachusetts  (((2416640 35916.07, 2422790 38715.18, 2431355 42…
## 13 53    WA    Washington     (((-1676250 657164.2, -1664113 655409.9, -1659884…
## 14 46    SD    South Dakota   (((-318844.3 7706.369, -317381.2 7754.452, -31674…
## 15 18    IN    Indiana        (((1045788 -717761.3, 1047032 -714762.5, 1048125 …
## 16 35    NM    New Mexico     (((-858919.5 -1419649, -855899.6 -1387985, -85232…
## 17 19    IA    Iowa           (((275683.8 -241224.8, 279045.8 -235699.3, 282077…
## 18 48    TX    Texas          (((-628450.4 -1427710, -628653.6 -1421349, -62733…
## 19 21    KY    Kentucky       (((933232.5 -877884.8, 939110.1 -878070.1, 945495…
## 20 30    MT    Montana        (((-1161418 562603.4, -1122401 554683.7, -1101540…
# View a sample of the county data
counties_df %>% slice_sample(n=20)
## Simple feature collection with 20 features and 4 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -1377101 ymin: -1518984 xmax: 1725520 ymax: 402733.1
## Projected CRS: NAD27 / US National Atlas Equal Area
## # A tibble: 20 × 5
##    fips  abbr  full         county                                          geom
##    <chr> <chr> <chr>        <chr>                             <MULTIPOLYGON [m]>
##  1 17009 IL    Illinois     Brown County    (((771598.2 -501768.3, 789992.5 -49…
##  2 48475 TX    Texas        Ward County     (((-343952.1 -1473697, -316977.7 -1…
##  3 29181 MO    Missouri     Ripley County   (((790975.6 -866506.3, 831272 -8634…
##  4 30009 MT    Montana      Carbon County   (((-765776.9 65063.24, -757163.3 64…
##  5 47027 TN    Tennessee    Clay County     (((1263666 -824841.9, 1264214 -8234…
##  6 55137 WI    Wisconsin    Waushara County (((825772.8 -30895.22, 855216 -2728…
##  7 53075 WA    Washington   Whitman County  (((-1375878 350274.9, -1372891 3501…
##  8 08011 CO    Colorado     Bent County     (((-297197.7 -742366.4, -239730.9 -…
##  9 47033 TN    Tennessee    Crockett County (((960581.4 -954166.2, 960050.1 -95…
## 10 38051 ND    North Dakota McIntosh County (((9383.724 142652.7, 74016.24 1430…
## 11 47079 TN    Tennessee    Henry County    (((1025337 -873947.6, 1025731 -8738…
## 12 31041 NE    Nebraska     Custer County   (((-20816.59 -362432.5, 26028.46 -3…
## 13 27079 MN    Minnesota    Le Sueur County (((481940.3 -54931.4, 480848.3 -424…
## 14 13049 GA    Georgia      Charlton County (((1674020 -1379570, 1700630 -13742…
## 15 21237 KY    Kentucky     Wolfe County    (((1429142 -656493.8, 1436061 -6555…
## 16 17061 IL    Illinois     Greene County   (((808345.5 -605347.8, 809672 -5988…
## 17 27105 MN    Minnesota    Nobles County   (((316450.6 -120299.2, 363681.8 -11…
## 18 13045 GA    Georgia      Carroll County  (((1355514 -1142499, 1359949 -11418…
## 19 01081 AL    Alabama      Lee County      (((1338487 -1253037, 1339803 -12511…
## 20 40151 OK    Oklahoma     Woods County    (((52821.81 -888701.5, 77529.42 -88…

These dataframes contain the polygon data needed to draw the maps. The FIPS codes are crucial for merging your data with the map data.

Working with FIPS Codes

You can use the fips() function to get FIPS codes:

fips(state = "MA")
## [1] "25"
fips(state = "Massachusetts")
## [1] "25"
state.abb
##  [1] "AL" "AK" "AZ" "AR" "CA" "CO" "CT" "DE" "FL" "GA" "HI" "ID" "IL" "IN" "IA"
## [16] "KS" "KY" "LA" "ME" "MD" "MA" "MI" "MN" "MS" "MO" "MT" "NE" "NV" "NH" "NJ"
## [31] "NM" "NY" "NC" "ND" "OH" "OK" "OR" "PA" "RI" "SC" "SD" "TN" "TX" "UT" "VT"
## [46] "VA" "WA" "WV" "WI" "WY"
fips(state.abb)
##  [1] "01" "02" "04" "05" "06" "08" "09" "10" "12" "13" "15" "16" "17" "18" "19"
## [16] "20" "21" "22" "23" "24" "25" "26" "27" "28" "29" "30" "31" "32" "33" "34"
## [31] "35" "36" "37" "38" "39" "40" "41" "42" "44" "45" "46" "47" "48" "49" "50"
## [46] "51" "53" "54" "55" "56"

Or perform a reverse lookup:

fips_info(c("30", "33", "34"))
##   abbr fips          full
## 1   MT   30       Montana
## 2   NH   33 New Hampshire
## 3   NJ   34    New Jersey
fips_info(c("01001", "01003", "01005", "01007"))
##      full abbr         county  fips
## 1 Alabama   AL Autauga County 01001
## 2 Alabama   AL Baldwin County 01003
## 3 Alabama   AL Barbour County 01005
## 4 Alabama   AL    Bibb County 01007

This is particularly useful when working with datasets that use different state identifiers.

Adding Data to Maps

Now, let’s create a map that visualizes data. We’ll use the built-in statepop dataset to create a choropleth map of state populations:

data(statepop)

statepop
## # A tibble: 52 × 4
##    fips  abbr  full                 pop_2022
##    <chr> <chr> <chr>                   <dbl>
##  1 01    AL    Alabama               5074296
##  2 02    AK    Alaska                 733583
##  3 04    AZ    Arizona               7359197
##  4 05    AR    Arkansas              3045637
##  5 06    CA    California           39029342
##  6 08    CO    Colorado              5839926
##  7 09    CT    Connecticut           3626205
##  8 10    DE    Delaware              1018396
##  9 11    DC    District of Columbia   671803
## 10 12    FL    Florida              22244823
## # ℹ 42 more rows
library(scales)
## 
## Attaching package: 'scales'
## The following object is masked from 'package:purrr':
## 
##     discard
## The following object is masked from 'package:readr':
## 
##     col_factor
plot_usmap(data = statepop, values = "pop_2022", color = "red") + 
  scale_fill_continuous(
    low    = "white",
    high   = "red",
    name   = "Population (2022)",
    labels = label_number(scale_cut = cut_short_scale())
  ) + 
  theme(legend.position = "right") +
  labs(
    title    = "US State Populations",
    subtitle = "2022 Estimates"
  )
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found

This map uses color intensity to represent population size, with darker red indicating higher population. The scale_fill_continuous() function allows us to customize the color scale.

Focusing on Specific Regions

You can also focus on specific states or regions:

plot_usmap(
  data = statepop, 
  values = "pop_2022", 
  include = c("CA", "ID", "NV", "OR", "WA"), 
  color = "blue"
) + 
  scale_fill_continuous(
    low = "white", high = "blue", name = "Population (2022)", label = scales::comma
  ) + 
  labs(title = "Western US States", subtitle = "Population Estimates for Pacific States") +
  theme(legend.position = "right")
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found

This map focuses on the Pacific states, using a blue color scheme. The include parameter allows you to specify which states to show.

County-Level Data

We can also visualize county-level data. Let’s use the countypov dataset to map poverty rates:

data(countypov)

countypov
## # A tibble: 3,194 × 4
##    fips  abbr  county          pct_pov_2021
##    <chr> <chr> <chr>                  <dbl>
##  1 01000 AL    Alabama                 16.3
##  2 01001 AL    Autauga County          10.7
##  3 01003 AL    Baldwin County          10.8
##  4 01005 AL    Barbour County          23  
##  5 01007 AL    Bibb County             20.6
##  6 01009 AL    Blount County           12  
##  7 01011 AL    Bullock County          32.1
##  8 01013 AL    Butler County           22.7
##  9 01015 AL    Calhoun County          19.2
## 10 01017 AL    Chambers County         19.7
## # ℹ 3,184 more rows
plot_usmap(data = countypov, values = "pct_pov_2021", 
           include = c("CT", "ME", "MA", "NH", "VT"), color = "purple") + 
  scale_fill_continuous(low = "white", high = "purple", 
                        name = "Poverty Percentage", label = scales::comma) + 
  labs(title = "New England Region", 
       subtitle = "Poverty Percentage Estimates for New England Counties in 2021") +
  theme(legend.position = "right")

This map shows poverty rates across New England counties, demonstrating how usmap can handle detailed county-level data.

Visualizing Census county-level data

library(tidycensus)

census_api_key("2c5ba48be91062db570c7fc5fa49dbca03306c33")
## To install your API key for use in future sessions, run this function with `install = TRUE`.
# Download county-level median household income data
county_income <- get_acs(
  geography = "county",
  variables = "B19013_001",
  year = 2019,
  geometry = FALSE
) %>%
  mutate(
    fips = as.character(GEOID),
    income = estimate
  ) %>%
  select(fips, income) %>%
  mutate(fips = str_pad(fips, width = 5, pad = "0")) # Ensure fips is a character vector and has leading zeros where necessary
## Getting data from the 2015-2019 5-year ACS
# Create the choropleth map for Midwest
plot_usmap(
  data = county_income,
  values = "income",
  include = .midwest_region,
  color = "black",
  size = 0.1,
  regions = "counties"
) +
  scale_fill_viridis_c(
    name = "Median Household Income",
    label = scales::dollar
  ) +
  labs(title = "Median Household Income by County in the Midwest",
       subtitle = "2019 5-year ACS estimates") +
  theme(legend.position = "right")
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found

This code creates a detailed county-level choropleth map of the Midwest region, showcasing median household income data. It begins by using the tidycensus package to fetch the latest available county-level income estimates from the American Community Survey. The data is then processed to ensure proper formatting of FIPS codes, which are crucial for accurate mapping. The plot_usmap() function is employed to generate the map, utilizing the built-in .midwest_region parameter to focus specifically on Midwest states. By setting regions = "counties", the map maintains county-level granularity, providing a detailed view of income distribution across the region. The resulting visualization uses a viridis color scale to represent income levels, with darker colors indicating higher median household incomes. This approach leverages the pre-defined regions in the usmap package for streamlined map creation.

Using Predefined Regions

The usmap package also includes predefined regions:

plot_usmap(include = .south_region)
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found

You can combine or exclude regions:

plot_usmap(include = .south_region, exclude = .east_south_central)
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found
## Warning in CPL_transform(x, crs, aoi, pipeline, reverse, desired_accuracy, :
## GDAL Error 1: PROJ: proj_create_from_database: crs not found

These predefined regions make it easy to focus on specific parts of the country without manually specifying states.

Exploring the sf Package

The sf (Simple Features) package provides a modern approach to working with spatial data in R. It integrates seamlessly with the tidyverse and ggplot2, making it a powerful tool for spatial data analysis and visualization.

Creating an SF Object

Let’s create a simple feature object for US states:

us_states <- st_as_sf(maps::map("state", plot = FALSE, fill = TRUE))

ggplot(data = us_states) +
  geom_sf() +
  theme_minimal() +
  ggtitle("US States using sf and ggplot2")

This code converts the state map data into an sf object and then plots it using ggplot2. The geom_sf() function automatically handles the spatial nature of the data.

Historical Boundaries with USAboundaries

The USAboundaries package is invaluable for working with historical US boundaries. This is particularly useful for historical analysis or showing how US state boundaries have changed over time.

states_1840 <- us_states("1840-03-12")

ggplot(data = states_1840) +
  geom_sf() +
  theme_minimal() +
  ggtitle("U.S. State Boundaries on March 12, 1840")

This map shows the state boundaries as they existed in 1840, providing a snapshot of US geography at that time.

Alternative Visualizations with statebins

Sometimes, a traditional map projection isn’t the best way to visualize state-level data. The statebins package offers an alternative by creating a tile grid map where each state is represented by a square.

data("USArrests")
USArrests$state <- rownames(USArrests)

USArrests
##                Murder Assault UrbanPop Rape          state
## Alabama          13.2     236       58 21.2        Alabama
## Alaska           10.0     263       48 44.5         Alaska
## Arizona           8.1     294       80 31.0        Arizona
## Arkansas          8.8     190       50 19.5       Arkansas
## California        9.0     276       91 40.6     California
## Colorado          7.9     204       78 38.7       Colorado
## Connecticut       3.3     110       77 11.1    Connecticut
## Delaware          5.9     238       72 15.8       Delaware
## Florida          15.4     335       80 31.9        Florida
## Georgia          17.4     211       60 25.8        Georgia
## Hawaii            5.3      46       83 20.2         Hawaii
## Idaho             2.6     120       54 14.2          Idaho
## Illinois         10.4     249       83 24.0       Illinois
## Indiana           7.2     113       65 21.0        Indiana
## Iowa              2.2      56       57 11.3           Iowa
## Kansas            6.0     115       66 18.0         Kansas
## Kentucky          9.7     109       52 16.3       Kentucky
## Louisiana        15.4     249       66 22.2      Louisiana
## Maine             2.1      83       51  7.8          Maine
## Maryland         11.3     300       67 27.8       Maryland
## Massachusetts     4.4     149       85 16.3  Massachusetts
## Michigan         12.1     255       74 35.1       Michigan
## Minnesota         2.7      72       66 14.9      Minnesota
## Mississippi      16.1     259       44 17.1    Mississippi
## Missouri          9.0     178       70 28.2       Missouri
## Montana           6.0     109       53 16.4        Montana
## Nebraska          4.3     102       62 16.5       Nebraska
## Nevada           12.2     252       81 46.0         Nevada
## New Hampshire     2.1      57       56  9.5  New Hampshire
## New Jersey        7.4     159       89 18.8     New Jersey
## New Mexico       11.4     285       70 32.1     New Mexico
## New York         11.1     254       86 26.1       New York
## North Carolina   13.0     337       45 16.1 North Carolina
## North Dakota      0.8      45       44  7.3   North Dakota
## Ohio              7.3     120       75 21.4           Ohio
## Oklahoma          6.6     151       68 20.0       Oklahoma
## Oregon            4.9     159       67 29.3         Oregon
## Pennsylvania      6.3     106       72 14.9   Pennsylvania
## Rhode Island      3.4     174       87  8.3   Rhode Island
## South Carolina   14.4     279       48 22.5 South Carolina
## South Dakota      3.8      86       45 12.8   South Dakota
## Tennessee        13.2     188       59 26.9      Tennessee
## Texas            12.7     201       80 25.5          Texas
## Utah              3.2     120       80 22.9           Utah
## Vermont           2.2      48       32 11.2        Vermont
## Virginia          8.5     156       63 20.7       Virginia
## Washington        4.0     145       73 26.2     Washington
## West Virginia     5.7      81       39  9.3  West Virginia
## Wisconsin         2.6      53       66 10.8      Wisconsin
## Wyoming           6.8     161       60 15.6        Wyoming
statebins(USArrests, value_col = "Assault", name = "Assault", round = TRUE) +
  theme_statebins(legend_position = "right") +
  ggtitle("Assault Arrests by State")

This visualization represents each state as a square, colored by the number of assault arrests. It’s particularly useful when you want to give equal visual weight to each state, regardless of its geographic size.

Interactive Maps with leaflet and plotly

While static maps are useful, interactive maps can provide a more engaging user experience and allow for exploration of the data.

Leaflet for Interactive Web Maps

Leaflet is a popular JavaScript library for interactive maps, and the R package makes it easy to use in R:

leaflet() %>%
  addTiles() %>%
  addMarkers(lng = -95.307, lat = 29.7601, 
             popup = "Houston")

This creates an interactive map centered on Houston. Users can zoom, pan, and click on the marker to see the popup.

Plotly for Interactive Choropleth Maps

We can create a more detailed interactive choropleth map of the US using Plotly:

data(statepop, package = "usmap")

# Create an interactive choropleth map directly with plotly
fig <- plot_ly(
  data = statepop,
  type = 'choropleth',
  locations = ~abbr, # Use state abbreviations for locations
  locationmode = 'USA-states',
  z = ~pop_2022, # The variable to color by (population)
  colorscale = 'Viridis',
  # Custom hover text. We use the 'full' column for state names
  # and format the population with commas.
  text = ~paste(full, '<br>Population:', scales::comma(pop_2022)),
  hoverinfo = 'text',
  # Customize the color bar (legend)
  colorbar = list(title = 'Population')
)

# Customize the map's layout, such as the title and geographic projection
fig <- fig %>% layout(
  title = 'US State Population (Interactive)',
  geo = list(
    scope = 'usa', # Focus the map on the USA
    showlakes = TRUE,
    lakecolor = toRGB('white')
  )
)

# Display the final interactive figure
fig

Highchart

hcmap("countries/us/us-all")|>
  hc_title(text = "United States")
hcmap("countries/ua/ua-all")|>
  hc_title(text = "Ukraine")