ggplot2 maps with insets

August 22, 2012 Comments
Tags: ggplot2 map gridExtra inset R



UPDATE: changed data source so that the entire example can be run by anone on their own machine. Also, per Joachim's suggestion, I put a box around the blown up area of the map. Thoughts?


Here's a quick demo of creating a map with an inset within it using ggplot. The inset is achieved using the gridExtra package.


Install libraries

1 library(ggplot2)
2 library(maps)
3 library(maptools)
4 library(gridExtra)
5 library(rgeos)

Create a data frame

1 dat <- data.frame(ecosystem = rep(c("oak", "steppe", "prairie"), each = 8), 
2     lat = rnorm(24, mean = 51, sd = 1), lon = rnorm(24, mean = -113, sd = 5))
3 head(dat)
  ecosystem   lat    lon
1       oak 51.81 -109.1
2       oak 50.41 -115.0
3       oak 52.20 -112.5
4       oak 51.67 -114.8
5       oak 49.75 -105.4
6       oak 51.42 -114.6

Get maps using the maps library

 1 # Get a map of Canada
 2 canadamap <- data.frame(map("world", "Canada", plot = FALSE)[c("x", "y")])
 3 
 4 # Get a map of smaller extent
 5 canadamapsmall <- canadamap[canadamap$x < -90 & canadamap$y < 54, ]
 6 
 7 # Make inset rectangle to show area of zoom
 8 canadamapsmall_ <- na.omit(canadamapsmall)  # omit NA's
 9 
10 # This should get your corner points for the box, picking min and max of
11 # lat and lon
12 insetrect <- data.frame(xmin = min(canadamapsmall_$x), xmax = max(canadamapsmall_$x), 
13     ymin = min(canadamapsmall_$y), ymax = max(canadamapsmall_$y))
14 insetrect
    xmin   xmax  ymin ymax
1 -133.1 -90.39 48.05   54

Make the maps

 1 # The inset map, all of Canada
 2 a <- ggplot(canadamap) + 
 3  theme_bw(base_size = 22) +
 4  geom_path(data = canadamap, aes(x, y), colour = "black", fill = "white") +
 5  geom_rect(data = insetrect, aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax), alpha=0, colour="blue", size = 1, linetype=1) +
 6  opts(panel.border = theme_rect(colour = 'black', size = 1, linetype=1),
 7           panel.grid.major = theme_blank(), panel.grid.minor=theme_blank(),
 8           panel.background = theme_rect( fill = 'white'),
 9           legend.position = c(0.15,0.80), legend.key = theme_blank(),
10           axis.ticks = theme_blank(), axis.text.x=theme_blank(),
11           axis.text.y=theme_blank()) +
12  labs(x = '', y = '')
13 
14 # The larger map, zoomed in, with the data
15 b <- ggplot(dat, aes(lon, lat, colour=ecosystem)) +
16  theme_bw(base_size = 22) +
17  geom_jitter(size=4, alpha=0.6) +
18  geom_path(data = canadamapsmall, aes(x, y), colour = "black", fill = "white") +
19  scale_size(guide="none") +
20  opts(panel.border = theme_rect(colour = 'black', size = 1, linetype=1),
21           panel.grid.major = theme_blank(), panel.grid.minor=theme_blank(),
22           panel.background = theme_rect( fill = 'white'),
23           legend.position = c(0.1,0.20), legend.text=theme_text(size=12, face='bold'), 
24           legend.title=theme_text(size=12, face='bold'), legend.key = theme_blank(),
25           axis.ticks = theme_segment(size = 2)) +
26  labs(x = '', y = '')

Print the two maps together, one an inset of the other

This approach uses the gridExtra package for flexible alignment, etc. of ggplot graphs

1 grid.newpage()
2 vpb_ <- viewport(width = 1, height = 1, x = 0.5, y = 0.5)  # the larger map
3 vpa_ <- viewport(width = 0.4, height = 0.4, x = 0.8, y = 0.8)  # the inset in upper right
4 print(b, vp = vpb_)
5 print(a, vp = vpa_)

center


Get the .Rmd file used to create this post at my github account.


Written in Markdown, with help from knitr, and nice knitr highlighting/etc. in in RStudio.