Reputation: 33
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
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))
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))
Upvotes: 2