Soothing Pastel Colours in R

by Richard in 
r graphics

While writing a report recently, I made a series of bar charts like the following one.

dat <- rep(1:5, 2)
barplot(dat, col=rep(c("red", "blue"), each=5))

Upon review, the colours looked rather harsh, so I decided to convert them to something more soothing and professional-looking. I needed a pastellize function, but a search on the internet didn’t turn up anything. This led me to read about pastel colours which Wikipedia describes as

the family of colors which, when described in the HSV color space, have high value and low to intermediate saturation.

I had vaguely heard of the HSV colour space, but this was my first attempt to use it. I usually work with rgb values, in which a colour is described by a triple of red, green and blue, with the values of each running from 0 to 1. In HSV, colours are arranged on a cylinder as in the following picture from the Wikiepdia page.

It seems that pastellizing a colour will be a simple task. First, convert from rgb to HSV. Second, decrease the saturation. Third, convert back.

R features a handy rgb2hsv function which converts rgb values into HSV values. Unfortunately, in typical R fashion, there is no hsv2rgb function. However, the algorithm for this conversion is described on the Wikipedia page as well, so it can be implemented in R.

hsv2rgb <- function(x){  
  # convert an hsv colour to rgb  
  # input:  a 3 x 1 matrix (same as output of rgb2hsv() function)  
  # output: vector of length 3 with values in [0,1]    

  # recover h, s, v values  
  h <- x[1,1]  
  s <- x[2,1]  
  v <- x[3,1]    

  # follow the algorithm from Wikipedia  
  C <- s*v   

  # in R, h takes values in [0,1] rather than [0, 360], so dividing by  
  # 60 degrees is the same as multiplying by six  
  hdash <- h*6  
  X <- C * (1 - abs(hdash %% 2 -1))
  
   if (0 <= hdash & hdash <=1) RGB1 <- c(C, X, 0)  
   if (1 <= hdash & hdash <=2) RGB1 <- c(X, C, 0)  
   if (2 <= hdash & hdash <=3) RGB1 <- c(0, C, X)  
   if (3 <= hdash & hdash <=4) RGB1 <- c(0, X, C)  
   if (4 <= hdash & hdash <=5) RGB1 <- c(X, 0, C)  
   if (5 <= hdash & hdash <=6) RGB1 <- c(C, 0, X)    
 
   # the output is a vector of length 3. This is the most convenient  
   # format for using as the col argument in an R plotting function  
   RGB1 + (v-C)
}

This function is not as fast or versatile as rgb2hsv since it is not vectorized, but it is good enough for now.

Now here is the pastellizer function.

pastellize <- function(x, p){
  
  # x is a colour
  # p is a number in [0,1]
  # p = 1 will give no pastellization
  
  # convert hex or letter names to rgb
  if (is.character(x)) x <- col2rgb(x)/255
  
  # convert vector to rgb
  if (is.numeric(x)) x <- matrix(x, nr=3)
  
  col <- rgb2hsv(x, maxColorValue=1)
  col[2,1] <- col[2,1]*p
  col <- hsv2rgb(col)
  
  # return in convenient format for plots
  rgb(col[1], col[2], col[3])
}

A quick demo, showing what happens when the parameter p is varied.

demo <- function(){
  plot(0,0, xlim=c(0,10), ylim=c(0,10), type="n", xaxt="n", yaxt="n", bty="n", xlab="", ylab="")
  for (i in 0:9){
    for (j in 10:0){
      rect(i,j-1,i+1,j, col=pastellize(rainbow(10)[i+1], j/10), border=NA)
    }
  }
}

demo()

And finally, here is how to use it in a plot. Much more restful!

pastel_red <- pastellize("red", 0.3)
pastel_blue <- pastellize("blue", 0.3)

dat <- rep(1:5, 2)
barplot(dat, col=rep(c(pastel_red, pastel_blue), each=5), border=NA)
# border=NA removes black borders from the bars

Happy pastellizing!

© Data Science Confidential 2017 All rights reserved.