Elio Campitelli

How to make a shaded relief in R

While trying to build a circular colour scale to plot angles and wind direction, I stumbled upon an easy way to make shaded reliefs in R. You known, when you look at cool maps of mountain areas where peaks and valleys are easily distinguishable from their shadows like this:

What I accidentally discovered is that one way of approximating this look is by taking the directional derivatives of height and then plotting the cosine of its angle from the sun. After some further research I learned that this is actually done in cartography and is called aspect-based shading. I also learned that it’s not the best method, and I’m itching to try others. But for now, let’s keep things simple and get stuff actually done.

Just as an example, I will be using our old friend, the volcano database. I will be also using data.table syntax because that how I roll. Deal with it, dplyr lovers 😎.

So then I take the derivative (this is a function I made in my personal package, but bear with me 🙏) and take the angle. The minus sign are there… well, because it works –I’m not sure about the exact maths here.

But hey, don’t leave, there’s more. What if you want to use this gorgeous shading as a background to map other data? For example, let’s say you had surface temperature readings, or sulphur concentration data. Since our scale_fill is being taken by the shading and ggplot2 does not allow for more than one scale per aesthetic, you couldn’t use another geom_raster() to “paint” the data over this background.

One solution is to take the plot we made above, extract the raster grob (GRaphical OBject) and put it over another plot as an annotation. This is akin to a plot transplant and –just as organ transplants– it’s an ugly mess that will become a forgotten practice of a less civilized age once we master 3D printing of organs. But it works and is the best we’ve got so far.

Lucky for us, at least for this kind of plot transplant, there’s already a better way: just make a geom! Once we are inside the guts of ggplot2 we are no longer bound by the tyranny of scales can do the craziest things. In this case, we use a modified version of geom_tile() that performs all the calculations we need and builds the grayscale pattern (modifiable by the user via the light and dark aesthetics). It allows changing sun.angle and decide whether to use raster or rect and whether to interpolate for a smoother finish. I give to you geom_relief():

For a while now I’ve been thinking that, yes, ggplot2 is awesome and offers a lot of geoms and stats, but it would be great if it could be extended with new user-generated geoms and stats. Then I learnt that ggplot2 actually has a pretty great extension system so I could create my own geoms I needed for my work or just for fun. But still, creating a geom from scratch is an involved process that doesn’t lend itself to simple transformations.

Spanish version of this post
While trying to build a circular colour scale to plot angles and wind direction, I stumbled upon an easy way to make shaded reliefs in R. You known, when you look at cool maps of mountain areas where peaks and valleys are easily distinguishable from their shadows like this:
What I accidentally discovered is that one way of approximating this look is by taking the directional derivatives of height and then plotting the cosine of its angle from the sun.