Create animated choropleth map [ggplot2, animation]

For my anti-corruption report, let’s first of all demonstrate how severe corruption is in the world. I decided to let the picture say a thousand words. Instead of an interminable paragraph littered with cherry-picked facts, we now have a picture that 1) is pretty, and 2) allows readers to think for themselves, using our (human’s) superb capability of pattern recognition.

world-corruption-1996

But wait — what if we want to visualize the change in pattern over time? Essentially, we just have to create the same map above for each year, and string them all together using the animation package in R.

Stupid wordpress.com does not allow embedded flash, so you will have to take a look at this dropbox link.

Below is the code used to produce the graphs. The corruption data come from World Governance Indicators (WGI), the map data from thematicmapping.org. Here is a link to my cleaned WGI data (.RData — a lot of the grunt work is simply to match the WB country name system with that of the map.

I sincerely wish that all organizations could just go ahead and accomplish simple things like standardized country names before tackling world poverty.


rm(list=ls())
toInstall <- c("ggplot2", "maptools", "animation", "rgdal")
lapply(toInstall, library, character.only=TRUE)
# Load and clean World Governance Indicators (WGI) data
# Can be downloaded here https://dl.dropboxusercontent.com/u/18955935/wgi_final.RData
# Most of the cleaning involving matching World Bank naming system with that of the map
load('./data/wgi_cleaned.RData')
# Load world map shape file (Google "TM_WORLD_BORDERS_SIMPL-0.3")
world.map <- readOGR(dsn="./data", layer="TM_WORLD_BORDERS_SIMPL-0.3")
world.ggmap <- fortify(world.map, region = "NAME")
# Check the country names in WGI and world.ggmap and fix the unmatched
# Plot
saveSWF({ # Output a flash
for (i in c(1996, 1998, 2000, 2002:2011)) {
temp <- subset(na.omit(wgi[, c('year', 'country', 'cc_est')]), year==i)
choro <- merge(world.ggmap, temp, by.x="id", by.y="country")
choro <- choro[order(choro$order), ] # order matters in map data, so we must reorder
p <- ggplot(data=choro, aes(long, lat, fill=cc_est, group=group))
print(
p + geom_polygon() + ylim(c(60,85)) + # Fix the y-axis range for consistency between the years
scale_fill_gradient2("Control of\n corruption\n score", limits=c(2.5,2.5)) + # Use scale_fill_gradient2 for contrast
labs(title=substitute(paste("Severity of corruption in the world, year ", i), list(i=i)))
)
}
}, swf.name="world_corruption.swf", interval=1,
ani.width=1200, ani.height=600,
swftools="C:/Program Files (x86)/SWFTools",
outdir=getwd())
saveLatex({ # Output a pdf that can be embedded in latex documents
for (i in c(1996, 1998, 2000, 2002:2011)) {
temp <- subset(na.omit(wgi[, c('year', 'country', 'cc_est')]), year==i)
choro <- merge(world.ggmap, temp, by.x="id", by.y="country")
choro <- choro[order(choro$order), ]
p <- ggplot(data=choro, aes(long, lat, fill=cc_est, group=group))
print(
p + geom_polygon() + ylim(c(60,85)) +
scale_fill_gradient2("Control of\n corruption\n score", limits=c(2.5,2.5)) +
labs(title=substitute(paste("Severity of corruption in the world, year ", i), list(i=i)))
)
}
}, ani.basename = "world_corruption", interval=1,
ani.width=900, ani.height=450,
ani.opts="autoplay,loop,controls,width=\\linewidth",
latex.filename = "world.corruption.tex",
outdir=getwd())

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: