Download as pdf or txt
Download as pdf or txt
You are on page 1of 2

Animated Range Maps

Nicholas M. Caruso
June 12, 2016

The Data
I am using range maps from IUCN, they can be found here. First, read in the range and county map data,
and provide the same projection for both.
library(maptools)
library(ggplot2)
library(maps)
library(sp)
library(raster)
library(tidyr)
library(dplyr)
caudates <- readShapePoly('you_range_maps.shp')
albers.proj <- CRS("+proj=aea +lat_1=29.5 +lat_2=45.5 +lat_0=37.5 +lon_0=-96
+x_0=0 +y_0=0 +datum=NAD83 +units=m +no_defs")
usa <- map("county", fill=TRUE, plot=FALSE)
IDs <- usa$names
usa <- map2SpatialPolygons(usa, IDs=IDs, proj4string=albers.proj)
projection(caudates) <- albers.proj

Spatial Overlay
I could not think of a faster/better approach than to use a for loop, where I am looping over each family
level (or genus, or any other level), such that the spatial locations of the counties are receiving the attributes
(species) from the range map polygons. Lastly, I used sapply() to get the length of the list of species (number
of species found in that county).
counts.list <- list()
for(sp in unique(caudates@data$family_nam)){
counts.list[[sp]] <- sapply(over(usa, geometry(caudates[caudates@data$family_nam==sp,]),
returnList = TRUE), length)
}

Combine into a dataframe


The next steps involve converting the list, which has each family as an element, into a dataframe, and then
joining this dataframe with the original county data.
# List to dataframe
counts.df2 <- as.data.frame(counts.list)
counts.df2$id <- rownames(counts.df2)
rownames(counts.df2) <- NULL

# Convert us map to dataframe


states.df <- fortify(usa, region = "ID")
# Join the two datasets
states.df2 <- left_join(states.df, counts.df2, by='id')
# Gather the columns into rows
fam.counts.df <- states.df2 %>%
gather(family, number, SALAMANDRIDAE:SIRENIDAE)
# Which families are in reference maps
sum.fam <- fam.counts.df %>%
group_by(family) %>%
summarise(num=sum(number)) %>%
filter(num>0)
# Filter the main dataset by only US families
fam.counts.us <- fam.counts.df %>%
filter(family %in% sum.fam$family)

Make a gif
To create a gif, youll need other drivers install on your computer, see the gganimate package and animation
package for more details on this. The code, however, for making a gif, is relatively easy and only requires
adding frame to the aesthetics for the layer that you want animated (here is family).
library(gganimate)
p <- ggplot() +
geom_polygon(data = fam.counts.us,
aes(x = long, y = lat, group = group, fill = number, frame=factor(family)),
color = "black", size = 0.25) +
coord_equal() +
scale_fill_gradient2(name="Number of\nSpecies", low="white", high='navyblue') +
theme_bw() +
theme(legend.position=c(0.92, 0.27),
legend.background=element_rect('transparent')) +
scale_x_continuous(breaks=c(-120,-100,-80),
labels=c(120,100,80),
expression(paste('Longitude (', degree,
'W)'))) +
ylab(expression(paste('Latitude (', degree, 'N)')))
gg_animate(p, 'your_file.gif')

You might also like