Administrative Maps and Projections in R

Today I will demonstrate how to create maps of “other countries”, and use map projections, with the choroplethr package in R. I write “other countries” in quotes because, like most things, translating a high level wish into software can be complicated. If you want to skip ahead and play with a web app that lets you explore the Administrative Level 1 maps of every country in the world, and see how they look under various projections, then click here. Here is a screenshot:


The source code for the app is here. You can learn more about Administrative Divisions here and here.

Admininstrative Level 0 Maps

A map that shows countries of the world is frequently called an Administrative Level 0 map. Last year the only Admin 0 map I could find in R listed the USSR as a country, which meant that I couldn’t use it to create choropleth maps of modern data.

I wanted to map World Bank data, so I packaged version 2.0.0 of Natural Earth Data’s Admin 0 map and added it to my choroplethrMaps package.  I did this in the summer of 2014, because I wanted to present this functionality at the 2014 R User Conference. You can see my documentation on making country level choropleths here.  You can see my documentation on mapping World Bank Data here.

Admininstrative Level 1 Maps

A map that shows the borders of states (or state equivalents) is called an Administrative Level 1 map. In December of 2014 I gave a talk at the Japan.R conference, and wanted to include some choropleth maps of Japanese prefecture-level demographic statistics. To do this I packaged Natural Earth Data’s Admin 1 Map  into a new package: choroplethrAdmin1. You can see documentation of that package here.

The app that I link to above uses the choroplethrAdmin1 package to render the Administrative Level 1 map of a country that the user specifies.


At its core choroplethr uses the ggplot2 library to render maps. This means that, by default, maps are rendered with Cartesian coordinates. This results in maps that “look a bit funny”; virtually all published maps have some form of map projection applied to them, and do not use Cartesian coordinates.

To add a projection to a ggplot2 object use the coord_map() function. The app that I link to above lets you apply 16 different projections to the Admin 1 maps of each country in the world. Note that this dropdown does not include the 18 projections in the mapproj package that require additional parameters. This was done for convenience on my part.

Here is an example showing how projections affect a map of continental US counties. Note that at full zooms the Census Bureau uses an Albers projection with lat0=29.5 and lat1=45.5; at smaller zooms they use a Mercator projection.

continental_us = state.regions$region[!state.regions$region %in% c("alaska", "hawaii")]
no_projection = county_choropleth(df_pop_county,
    title      = "No Projection",
    state_zoom = continental_us) + theme(legend.position="none")
albers_projection = county_choropleth(df_pop_county,
    title      = "Albers Projection",
    state_zoom = continental_us) + theme(legend.position="none")
albers_projection = albers_projection +
    coord_map(projection = "albers", lat0 = 29.5, lat1 = 45.5)
mercator_projection = county_choropleth(df_pop_county,
    title      = "Mercator Projection",
    state_zoom = continental_us) + theme(legend.position="none")
mercator_projection = mercator_projection + coord_map(projection = "mercator")
grid.arrange(no_projection, albers_projection, mercator_projection, nrow=3)


Alaska and Hawaii

In the last example the omission of Alaska and Hawaii was deliberate. In fact, when I began creating county choropleths in R I could not find a map that included the counties of Alaska or Hawaii at all. To remedy this I downloaded a map from the Census Bureau myself and put it in the package choroplethrMaps. I needed that map in order to create choropleths of data from the American Community Survey (ACS).

Once I had that map I encountered another problem: what to do with Alaska and Hawaii? For reference, here is how that map looks by default, both with no projection and a Mercator projection

ggplot(, aes(long, lat, group = group)) +
    geom_polygon() +
    ggtitle("US County Map\nNo Insets, Cartesian Coordinates")
ggplot(, aes(long, lat, group = group)) +
    geom_polygon() +
    coord_map() +
    ggtitle("US County Map\nNo Insets, Mercator Projection")


Most people are shocked at just how big Alaska is, and just how far south Hawaii is. More importantly, Alaska’s boroughs are so large that it becomes difficult to extract information from the counties in the contiguous 48 states.

If you google something like “ggplot2 map alaska hawaii” you will see a large number of people struggling with how to “move and resize Alaska and Hawaii so that they look normal”. I originally looked to simply transpose them, but my GIS friends recommend that I instead render Alaska and Hawaii separately, and then “attach” them to the map of the continental US. They told me that this is how map “insets” are normally accomplished in the GIS world. I posted for help with this on the ggplot2 mailing list, and wound up using ggplot2’s annotation_custom function. The result is familiar to most users of choroplethr:

    title="County Population\nInsets, Cartesian Coordinates",



Insets and Projections

The above map, of course “looks a little funny”. That is, it uses Cartesian coordinates. In fact, a technical limitation of annotation_custom is that it does not work with projections. When I first released choroplethr this was not an issue; users were simply happy with what the package could provide. But as the number of users increased, more people wanted “normal looking” maps of the 50 states, with insets.

Originally I was not sure how to do this, so I posted for help on the ggplot2 mailing list. Bob Rudis replied with a solution that I think I can apply to choroplethr. I’m currently preparing for a tutorial I am teaching next week, but I hope to tackle this project soon after.