10

I'm working on improved hillshading for some topographical map plots. The basic hillshade workflow documented in image() is:

require(raster)
alt = getData('alt', country='CHE')
slope = terrain(alt, opt='slope')
aspect = terrain(alt, opt='aspect')
hill = hillShade(slope, aspect, 40, 270)
plot(hill, col=grey(0:100/100), legend=FALSE, main='Switzerland')
plot(alt, col=rainbow(25, alpha=0.35), add=TRUE)

This image shows plot(hill..) before plot(alt..) is applied:

enter image description here

The method creates a solid grey under-layer of hillshades on which other data layers (e.g. elevation shading) are plotted semi-transparently. The problem with this approach is (a) that the neutral colour for flat terrain (RBG (202,202,202), '#CACACA') severely shades the whole model, which (b) prevents multiple shade layering, such as used by the 'Swiss hillshade' approach.

I can imagine an workaround that converts rasters to matrices and applies hillshading as a numerical multiplier to the brightness of other layers, but this doesn't seem very elegant (although I may be wrong). I wonder if anyone has any ideas or (preferably) experience in this area? Thanks in advance.

geotheory
  • 22,624
  • 29
  • 119
  • 196
  • so @geotheory you make any headway on this since posing the question? Feel free to post an answer as well if you've got something slick working. – tim riffe Feb 12 '14 at 19:07
  • Not yet Tim, and I apologise for getting sidetracked. Have accepted your answer. I'll post anything here you guys might find useful. – geotheory Feb 12 '14 at 22:16

1 Answers1

11

No experience with this, but why not give the gray undermap an alpha value that depends on slopes? Here's my try:

# before
require(raster)
alt = getData('alt', country='CHE')
slope = terrain(alt, opt='slope')
aspect = terrain(alt, opt='aspect')
hill = hillShade(slope, aspect, 40, 270)
plot(hill, col=grey(0:100/100), legend=FALSE, main='Switzerland')
plot(alt, col=rainbow(25, alpha=0.35), add=TRUE)

enter image description here

As you say, very dark.

# after
grayalphas <- seq(-1,1,by=.01)^2*100
grayalphas[grayalphas==100] <- 99
plot(hill, col=paste0(grey(0:100/100),sprintf("%.2d",grayalphas)), legend=FALSE, main='Switzerland')

plot(alt, col=rainbow(25, alpha=0.35), add=TRUE)

enter image description here

I set the gray alphas to have a parabolic shape, with minimum where the gray value is .5 and max of 99 at gray values of 0 or 1. If you choose something like this, you'll want to tinker with levels, etc, but it is easy to implement. Plus you'll want to put more effort than I did into the alphas, as mine are strictly numeric and not hex.

[Edit] I found a nifty function for adding alphas, addTrans() here in Sacha Epskamp's answer. This keeps the parabola, but it ranges from 0 in the middle to 255 on the extremes.

grayalphas <- seq(-1,1,length=101)^2*255
plot(hill, col=addTrans(grey(0:100/100),grayalphas), legend=FALSE, main='Switzerland')
plot(alt, col=rainbow(25, alpha=0.35), add=TRUE)

enter image description here

Community
  • 1
  • 1
tim riffe
  • 5,651
  • 1
  • 26
  • 40
  • 1
    As a packaged alternative to `addTrans`, there's `alpha` in the `scales` package. – Gregor Thomas Jan 31 '14 at 22:42
  • @shujaa thanks for the tip, I didn't know that! That's something I need from time to time, will make note – tim riffe Jan 31 '14 at 23:29
  • I've found it very useful. It used to be in `ggplot2`, but then I panicked when I updated and it was missing! Was happy to realize those function were just getting more appropriately grouped. But now I remember that @BenBolker once pointed me to `?adjustcolor`, which is loaded by default and can do the same job (and more). – Gregor Thomas Feb 01 '14 at 00:24