skipndipp
skipndipp

Reputation: 33

How to fill in ggplot shapefile map using a variable?

I am trying to fill a US map where each state is filled in by mean salary (In the default colour scale). I have the shapefile, and a dataframe which looks like this (Data falsified):

data <- structure(list(State = c("Arkansas",
                           "Iowa",
                           "California",
                           "Idaho"),
                 MeanSalary = c(50000,60000,62000,55000)),
                 row.names=1:4, class = "data.frame")

Here is my code:

library(tidyverse)
library(rgdal)

map <- readOGR(dsn = ".", layer = "usamap")

PlotData <- merge(map, data, by = "State")

This all works so far. I can also make an empty map:

map_base <- ggplot(data = PlotData, mapping=(aes(x=long, y = lat, group = group)) +
geom_polygon(color = "black", fill = NA)
map_base

However, I can't fill in the map with the values.

map_base <- ggplot(data = PlotData, mapping=(aes(x=long, y = lat, group = group)) +
geom_polygon(color = "black", fill = PlotData$MeanSalary)
map_base

I get this error:

Error: Aesthetics must be either length 1 or the same as the data (2834334): fill

What am I getting wrong?

Upvotes: 3

Views: 5480

Answers (1)

www
www

Reputation: 39154

Here I provided two solutions to plot polygons using ggplot2.

Solution 1: geom_sf

sf class is the next generation spatial data class in R. geom_sf can plot the sf object. To do this, we need to convert the sp object to sf object. Here I used the state spatial polygons from the USAboundaries package as an example.

library(tidyverse)
library(sf)
library(USAboundaries)

# Get the state data
state <- us_states()

# Check the class
class(state)
# [1] "sf"         "data.frame"

# Create example data frame
data <- structure(list(State = c("Arkansas",
                                 "Iowa",
                                 "California",
                                 "Idaho"),
                       MeanSalary = c(50000,60000,62000,55000)),
                  row.names=1:4, class = "data.frame")

# Merge data to state and filter for these records
state_filter <- state %>% 
  left_join(data, by = c("name" = "State")) %>%
  # Remove Hawaii, Alaska, and Puerto Rico to just focus on the rest states
  filter(!name %in% c("Hawaii", "Alaska", "Puerto Rico"))

# Plot the data
ggplot(state_filter) +
  geom_sf(aes(fill = MeanSalary))

enter image description here

Solution 2: ggspatial package

The ggspatial package can plot the sp object. So if you don't want to work with sf object, using ggspatial could be an option.

library(tidyverse)
library(sf)
library(USAboundaries)
library(sp)
library(ggspatial)

# Convert the sf object to sp object
state_filter_sp <- as(state_filter, "Spatial")

# Plot the data
ggplot() +
  annotation_spatial(state_filter_sp) +
  layer_spatial(state_filter_sp, aes(fill = MeanSalary))

enter image description here

Upvotes: 2

Related Questions