England and Wales heat map in R

By Data Tricks, 12 September 2017

Update 02/02/2019: An updated version of this code has been posted here, which is reproducible as of Feb 2019.

There are many ways of plotting maps in R. In this tutorial we’re going to use the ggplot2 package to create a heatmap of England and Wales.

Step 1

First let’s clear our memory, set the working directory and load some important packages.

setwd("H:/R projects/R gallery")

Step 2

A shapefile is a popular file format for geospatial data. Shapefiles are widely available; in the UK one of the most popular resources is the Office for National Statistics. You can find many useful datasets at geoportal.statistics.gov.uk but for the purposes of this exercise we are going to use the LAU Level 1 Full Clipped Boundaries file from here (valid as of 04/08/2017). To download the file, follow the link and click on Download > Shapefile and extract the zip file to your working directory.

In the UK, shapefiles are generally available at five levels of differing resolution as follows:

NUTS Level 1 Regions

NUTS Level 2 Counties

NUTS Level 3 Districts

LAU Level 1 Local authority districts

LAU Level 2 Local authority wards

It is important to note that at the more detailed levels (ie. LAU Levels 1 and 2), the more likely it is for borders to change. For instance, LAU areas correspond to electoral wards, the border of which have shifted in recent years. Depending on the task you are trying to accomplish, it is therefore sometimes better to analyse the higher levels which are less prone to change over time.

Step 3

Now we can load the shapefile into R and structure it in a way that can be easily interpreted by ggplot2.

#Load the shapefile
shapefile <- readOGR(dsn="/Map shapefiles", layer="Local_Administrative_Units_Level_1_December_2015_Full_Clipped_Boundaries_in_England_and_Wales")
#Reshape for ggplot2 using the Broom package
mapdata <- tidy(shapefile, region="lau115nm")

Step 4

The mapdata object now contains coordinates of all the LAU boundaries. Type head(mapdata) to see what this looks like.

> head(mapdata)
      long      lat order  hole piece  group   id
1 515048.8 109605.9     1 FALSE     1 Adur.1 Adur
2 515060.2 109590.8     2 FALSE     1 Adur.1 Adur
3 515128.4 109603.4     3 FALSE     1 Adur.1 Adur
4 515161.3 109610.1     4 FALSE     1 Adur.1 Adur
5 515191.5 109586.9     5 FALSE     1 Adur.1 Adur
6 515245.9 109555.4     6 FALSE     1 Adur.1 Adur

We can straight away plot these boundaries on a ggplot map using the following code:

gg <- ggplot() + geom_polygon(data = mapdata, aes(x = long, y = lat, group = group), color = "#FFFFFF", size = 0.25)
gg <- gg + coord_fixed(1) #This gives the map a nice 1:1 aspect ratio to prevent the map from appearing squashed

ggplot2 map of England and Wales basic

Step 5

Now that our data contains the coordinates of the local authority borders, we can then bring in data from other datasets to turn our basic map into a heat map. For the purposes of this tutorial, we are going to use a Land Registry dataset containing the number of applications for registrations, leases etc. made to the Land Registry in a given month. At the time of writing this was available here. Download the CSV file and save it to your working directory, then run the following code.

data <- read.csv("Number-of-applications-in-England-and-Wales-divided-by-local-authority-2017-06.csv")
colnames(data)[1] <- "id" #rename the first column to mirror column names in mapdata
mapdata$id <- toupper(mapdata$id) #transform values in the id column to uppercase
mapdata <- join(mapdata, data, by="id") #merge the two datasets
mapdata$Total <- scale(mapdata$Total) #standardise the values in the Total column to ensure we get an even spread of colours across the map rather than very light or dark colours for outliers

Running the same code as in Step 4 but adding fill = Total to aes() will create a heat map.

gg <- ggplot() + geom_polygon(data = mapdata, aes(x = long, y = lat, group = group, fill = Total), color = "#FFFFFF", size = 0.25)
gg <- gg + coord_fixed(1)

Step 6

We’re almost done! A map doesn’t look very good inside a chart grid so let’s remove the background, gridlines and axes to make it more appealing.

gg <- ggplot() + geom_polygon(data = mapdata, aes(x = long, y = lat, group = group, fill = Total), color = "#FFFFFF", size = 0.25)
gg <- gg + scale_fill_gradient2(low = "blue", mid = "red", high = "yellow", na.value = "white")
gg <- gg + coord_fixed(1)
gg <- gg + theme_minimal()
gg <- gg + theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(), legend.position = 'none')
gg <- gg + theme(axis.title.x=element_blank(), axis.text.x = element_blank(), axis.ticks.x = element_blank())
gg <- gg + theme(axis.title.y=element_blank(), axis.text.y = element_blank(), axis.ticks.y = element_blank())

Heat map England and Wales

And we’re done! You can always play around with the colours by using scale_fill_gradient for example by adding:

gg <- gg + scale_fill_gradient(low = "white", high = "red", na.value = "white")

Tags: , , ,

9 thoughts on “England and Wales heat map in R”

  1. Data Tricks says:

    An update to this code has been posted at https://datatricks.co.uk/creating-maps-in-r-2019 which contains reproducible code as of Feb 2019.

  2. Raphaelle Soffe says:

    fairly basic question, but how do I make the map itself bigger (resize) relative to the scale on the right

  3. Data Tricks says:

    Hi Raphaelle,

    Good question. The answer needed a bit of digging, but I think legend.key.size might work. Try adding the following line before print(gg):

    gg <- gg + theme(legend.key.size = unit(10,"pt"), legend.title = element_text(size=10), legend.text = element_text(size=8)) That should change the size of the legend (legend.key.size) and you'll also need to play around with the size of the legend title and text (legend.title / legend.text). The 'cheat' way of doing it if you're using RStudio is to view the chart in a different window and resize that window. For example, if you click "Save as Image" or "Copy to Clipboard" in the Plots tab, resizing the chart by click-and-dragging the bottom right arrow seems to resize the chart only, keeping the legend and axis titles the same size. Hope this helps. Tom

  4. Anna says:

    I am trying to do step 4, but no plot shows in my R studio when I run the print(gg) code (also doesn’t show anything when I just type gg) – I have followed all the other steps up to step 4 correctly – I was wondering if you knew what might be happening?

    1. Data Tricks says:

      Hi Anna,

      Thanks for your question, and apologies for my late reply. Do you get any warnings or errors when you try to print the chart? If not, try clicking the ‘Show in new window’ icon in the Viewer pane in RStudio, or ‘Export’ and ‘Save as image.’ Please note also that there is an updated version of this code here. Please let me know if that doesn’t fix it.

      Best Regards,

  5. Rhys Jones says:

    This was an incredibly useful step by step guide thank you very much. I used the NUTS Level 1 Shapefile with some population data and produced a map really easily, the code was super transferrable, just the filenames and region=”lau115nm” in step 3 that needed changing to the corresponding information for the new shape file. Thanks!

    1. Data Tricks says:

      Thanks for your comments Rhys. Glad you found the post helpful!


  6. Maria Smielecka says:

    How do you colour in separate local authorities to highlight then, i want to focus on 10, how do i highlight these a different colour?

    1. Data Tricks says:

      Hi Maria,

      Thanks for your question. Unfortunately I don’t think this example is reproducible anymore without the original shapefiles from 2017 which I no longer have, so I can’t try this without rewriting the code. If you’ve managed to get the code working you’ve done well! I think you might find a potential answer here: https://gis.stackexchange.com/questions/234942/keep-customized-colors-with-geom-polygon. You could try creating a vector of colours which has the same length as the mapdata and then use than in the ‘fill=’ in geom_polygon.


Leave a Reply

Your email address will not be published. Required fields are marked *

Please note that your first comment on this site will be moderated, after which you will be able to comment freely.