Choropleth map in ggplot with polygons that have holes
This is just an expansion on @Ista's answer, which does not require that one knows which states (Berlin, Bremen) need to be rendered last.
This approach takes advantage of the fact that fortify(...)
generates a column, hole
which identifies whether a group of coordinates are a hole. So this renders all regions (id's) with any holes before (e.g. underneath) the regions without holes.
Many thanks to @Ista, without whose answer I could not have come up with this (believe me, I spent many hours trying...)
ggplot(map.df, aes(x=long, y=lat, group=group)) + geom_polygon(data=map.df[map.df$id %in% map.df[map.df$hole,]$id,],aes(fill=poverty))+ geom_polygon(data=map.df[!map.df$id %in% map.df[map.df$hole,]$id,],aes(fill=poverty))+ geom_path(colour="grey50")+ scale_fill_gradientn(colours=brewer.pal(5,"OrRd"))+ labs(x="",y="")+ theme_bw()+ coord_fixed()
You can plot the island polygons in a separate layer, following the example on the ggplot2 wiki. I've modified your merging steps to make this easier:
mrg.df <- data.frame(id=rownames(map@data),ID_1=map@data$ID_1)mrg.df <- merge(mrg.df,pov, by="ID_1")map.df <- fortify(map)map.df <- merge(map.df,mrg.df, by="id")ggplot(map.df, aes(x=long, y=lat, group=group)) + geom_polygon(aes(fill=poverty), color = "grey50", data =subset(map.df, !Id1 %in% c("Berlin", "Bremen")))+ geom_polygon(aes(fill=poverty), color = "grey50", data =subset(map.df, Id1 %in% c("Berlin", "Bremen")))+ scale_fill_gradientn(colours=brewer.pal(5,"OrRd"))+ labs(x="",y="")+ theme_bw()+ coord_fixed()
As an unsolicited act of evangelism, I encourage you to consider something like
library(ggmap)qmap("germany", zoom = 6) + geom_polygon(aes(x=long, y=lat, group=group, fill=poverty), color = "grey50", alpha = .7, data =subset(map.df, !Id1 %in% c("Berlin", "Bremen")))+ geom_polygon(aes(x=long, y=lat, group=group, fill=poverty), color = "grey50", alpha= .7, data =subset(map.df, Id1 %in% c("Berlin", "Bremen")))+ scale_fill_gradientn(colours=brewer.pal(5,"OrRd"))
to provide context and familiar reference points.
Just to add another small improvement to @Ista's and @jhoward's answers (thanks a lot for your help!).
The modification of @jhoward could be easily wrapped in a small function like this
gghole <- function(fort){ poly <- fort[fort$id %in% fort[fort$hole,]$id,] hole <- fort[!fort$id %in% fort[fort$hole,]$id,] out <- list(poly,hole) names(out) <- c('poly','hole') return(out)} # input has to be a fortified data.frame
Then, one doesn't need to recall every time how to extract holes info. The code would look like
ggplot(map.df, aes(x=long, y=lat, group=group)) + geom_polygon(data=gghole(map.df)[[1]],aes(fill=poverty),colour="grey50")+ geom_polygon(data=gghole(map.df)[[2]],aes(fill=poverty),colour="grey50")+ # (optionally). Call by name # geom_polygon(data=gghole(map.df)$poly,aes(fill=poverty),colour="grey50")+ # geom_polygon(data=gghole(map.df)$hole,aes(fill=poverty),colour="grey50")+ scale_fill_gradientn(colours=brewer.pal(5,"OrRd"))+ labs(x="",y="")+ theme_bw()+ coord_fixed()