Now that we know how to make some more dynamic maps, let’s look at another cool mapping tool: gganimate. This will allow us to make dynamic maps that change over time. You can use the same methods on regular ggplots as well - gganimate is a really cool package for dynamically visualizing your data.
library(sf)
library(dplyr)
library(spData)
library(urbnmapr)
library(ggplot2)
#load in unemployment data
setwd("~/Binghamton/geog380")
Warning: The working directory was changed to C:/Users/mhaller/Documents/Binghamton/geog380 inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
unemploy <- read.csv("unemploy_nys.csv", check.names = F)
unemploy <- unemploy[complete.cases(unemploy),]
#reshape the data!
library(tidyr)
unemploy <- unemploy %>%
pivot_longer(!county_name, names_to = "year", values_to = "unemploy_rate")
Next, we’ll load in our base map and merge the data (as always)
counties <- get_urbn_map("counties", sf = TRUE)
#filter the data to get just NYS
counties <- counties %>%
filter(state_abbv == "NY") %>%
st_transform("EPSG:32116")
old-style crs object detected; please recreate object with a recent sf::st_crs()
#separate the county name so that we can merge the dataframes
counties1 <- counties %>%
separate(county_name, c("county_name", "county"), sep = " County") %>%
select(-county)
#Now merge it!!
county_data_full <- counties1 %>%
left_join(unemploy,by = c("county_name" = "county_name"))
Warning: Each row in `x` is expected to match at most 1 row in `y`.
#plot the data to make sure it merged correctly -
#Does the unemployment data work?
plot(county_data_full)
#Let's make an animated map!The only real difference here is that we'll add a transition layer
library(gganimate)
Attaching package: 'gganimate'
The following object is masked from 'package:terra':
animate
library(transformr)
Attaching package: 'transformr'
The following object is masked from 'package:sf':
st_normalize
library(gifski)
county_data_full <- county_data_full %>% mutate(year = as.numeric(year))
map <- ggplot()+
geom_sf(county_data_full, mapping = aes(fill = unemploy_rate))+
scale_fill_gradient(
# Make legend title more readable
name = "Percent \nUnemployment",
#set the color gradient
low = "lightblue",
high = "purple") +
theme_minimal()+
labs(title = "Unemployment in NYS",
subtitle = "2012-2018")+
theme(legend.title.align = 0.5)
map_with_animation <- map +
#set the transition variable
transition_time(year) +
ggtitle('Year: {frame_time}',
subtitle = 'Frame {frame} of {nframes}')
num_years <- max(county_data_full$year) - min(county_data_full$year) + 1
gganimate::animate(map_with_animation,
#7 years - we want 7 frames
nframes = num_years,
#This tell it how fast to go
fps = 2)
Inserting image 1 at 0.00s (14%)...
Inserting image 2 at 0.50s (28%)...
Inserting image 3 at 1.00s (42%)...
Inserting image 4 at 1.50s (57%)...
Inserting image 5 at 2.00s (71%)...
Inserting image 6 at 2.50s (85%)...
Inserting image 7 at 3.00s (100%)...
Encoding to gif... done!
What if we wanted to compare a few counties? This is surprisingly easy to do!
small_county <- county_data_full %>%
filter(county_name %in% c("Broome", "Erie", "Monroe", "Onondaga"))
map <- ggplot()+
geom_sf(small_county, mapping = aes(fill = unemploy_rate))+
scale_fill_gradient(
# Make legend title more readable
name = "Percent \nUnemployment",
#set the color gradient
low = "lightblue",
high = "purple") +
theme_minimal()+
#this will put each county in a new pane so we can compare side-by-side
facet_wrap(~county_name)+
labs(title = "Unemployment in NYS",
subtitle = "2012-2018")+
theme(legend.title.align = 0.5)+
transition_time(year) +
ggtitle('Year: {frame_time}',
subtitle = 'Frame {frame} of {nframes}')
#tell the map to animate!
gganimate::animate(map,
#7 years - we want 7 frames
nframes = num_years,
#This tells it how fast to go
fps = 2)
Inserting image 1 at 0.00s (14%)...
Inserting image 2 at 0.50s (28%)...
Inserting image 3 at 1.00s (42%)...
Inserting image 4 at 1.50s (57%)...
Inserting image 5 at 2.00s (71%)...
Inserting image 6 at 2.50s (85%)...
Inserting image 7 at 3.00s (100%)...
Encoding to gif... done!
Clearly, this would be nicer if we could compare different states or larger geographic areas, but it’s good to know how to do this.
This same animation works well for regular ggplots, too! I won’t demo this right now, but you could easily build an animated plot in the same way: first, add the transition_time and ggtitle layers to the bottom, then use the animate command to display the map.
To save the map, open it in a new tab and right-click > save image as.
Resources
Lilja, D. J. (2021). How to Plot and Animate Data on Maps Using the R Programming Language. Retrieved from: https://conservancy.umn.edu/bitstream/handle/11299/220339/time-maps-tutorial-v2.html?sequence=3&isAllowed=y.
Pederson, T.L. & Robinson, D. (N.D.) gganimate. Retrieved from: https://gganimate.com/.
Rockefeller Institute of Government (2022). New York Statistical Yearbook. [Data Set]. Retrieved from: https://rockinst.org/data-hub/new-york-data-sets/.