Using R to add custom layers to Google Earth

Google Earth is amazing and with a little bit of effort, it can also be a brilliant platform for 3D data visualisation.

Adding data to Google Earth isn’t too tough, especially now that the Pro version is free. Its KML files provide an XML based format to draw lines and polygons, apply raster images to the earth’s surface, create tours and more.

I fly paragliders and wanted to check out some of my local hills more closely, but doing this just on the default Google Earth layers highlights an issue. When the image is animated or set at the right angle, you can see outline of the terrain, but from a bird’s eye view and in still images everything’s a mass of muddy green and brown. The lack of perspective means it’s hard to spot ridges, spurs, crevasses and sometimes even whole mountains.

On regular maps, this is what contour lines and hill shading are for. Could we add these to Google Earth?

First some data. I live in the UK and the Ordnance Survey has very helpfully open sourced OS Terrain 50 – a 50m resolution dataset of ESRI shapefiles containing contours and ASCII grid terrain elevations.


If you’re following along with this post, you want the first and third files in the drop-down box on the screenshot. They come as big zip files but more on that in a second.

The rgdal package allows us to load shapefiles in R and combining it with the raster package will allow us to draw images of the ASCII height data.

I’d like to visualise an area of Lancashire near Clitheroe that contains Parlick – a fabulous paragliding hill. It’s a large hill (for England), that we run off to start our flight.

Here’s Google Earth’s default view. See what I mean about the muddy green and brown? Even with the view slightly tilted, it’s tough to tell in places where the hill stops and the lower ground begins. Mostly you end up using the scrubby hilltop compared to green fields in the valleys to work it out.

Unpack the two zip files you downloaded from OS Terrain 50 and you’ll see they’re split into grids, denoted by two letters. This page helps to understand which grid goes where and for this exercise, we’re going to need grid “SD“.

The following piece of code will open all of the contour shapefiles in a directory that you specify, convert them to kml files using the fantastic plotKML package and then save them in another directory, from which you’ll be able to open them in Google Earth.


#Set input and output directories
os50_contours_dir <- "where-you-put-your-unzipped-contours/"
output_dir <- "where-you-want-your-kml-files/"

#Load all shapefiles in input directory
shape_files <- tibble(filename = list.files(os50_contours_dir, "*line.shp")) %>%
  mutate(shapefile = map(filename, .f = ~readOGR(paste0(os50_contours_dir, .))))

#Create a palette to shade contours by height
palette <- rev(RColorBrewer::brewer.pal(10, "PuBuGn"))

#Export shapefiles as Google Earth KML files (if you can make purrr do this, please tell me how!)
for(i in 1:nrow(shape_files)){
    size = 2, = shape_files$filename[i], = paste0(output_dir, shape_files$filename[i], ".kml"),
    colour_scale = palette,
    colour = PROP_VALUE,
    alpha = 0.3,
    open.kml = FALSE)


Provided you’ve got Google Earth Pro installed, if you double click to open “SD54_line.shp.kml” and “SD64_line.shp.kml” then zoom in and pan around a bit, you should see something like this. We have contours! (click the image for bigger).

We can do even better than that though and add a layer to shade the terrain by height. For this we’re going to use the ascii files and create raster images.

Raster images are a lot faster to render than contour lines, so rather than creating lots of little files and then opening the ones we need, we can just stitch together the whole “SD” layer into one file.

This code will do that for you, with plotKML again handling the conversion.


#Set input directory
os50_height_dir <- "where-you-put-your-ascii-files/"

#Load all terrain files in input directory
raster_layers <- tibble(filename = list.files(os50_height_dir, "*.asc$")) %>%
  mutate(raster = map(filename, .f = ~raster::raster(readGDAL(paste0(os50_height_dir, .))))) %>%

#Combine raster layers (if you can make purrr do this, again I'd love to know how)
raster_layers$fun <- mean
raster_mosaic <-, raster_layers)

#Create a hill shading palette
palette <- rev(RColorBrewer::brewer.pal(10, "Spectral"))

#Save the hill shading layer in current working directory
kml(raster_mosaic, colour = layer, colour_scale = palette, alpha = 0.4, = "height_layer.kml")


Open the file “height_layer.kml” in Google Earth and you get a semi-transparent shading layer combined with the contours, which I reckon looks pretty cool.Now you can clearly see the outline of Parlick hill and the surrounding terrain.

It looks good if you animate it too.