16

I am on the lookout for a function that reduces the saturation of a given colour palette by a certain amount. E.g. imagine I have the palette

library(colorRamps)    
col.palette=colorRampPalette(rainbow(13),interpolate ="spline")(1000)
pie(rep(1,1000), col=col.palette,lty=0,labels=NA)

enter image description here

Is there any function out there that could work on this col.palette colour vector, and reduce the saturation by a certain amount, or allow the brightness and contrast to be changed? (I am trying to achieve a rainbow palette with less saturation and smoother transitions than the standard one)

EDIT: also just discovered function muted in package scales that more or less does what I want : http://www.inside-r.org/packages/cran/scales/docs/muted

as well as rainbow_hcl in package colorspace mentioned by Josh O'Brien below, which was the kind of more muted and equal intensity rainbow I was looking for : http://www.inside-r.org/packages/cran/colorspace/docs/rainbow_hcl :

library(colorspace)
pie(rep(1,1000), col=rainbow_hcl(1000,c=100,l=60),lty=0,labels=NA)

enter image description here

Tom Wenseleers
  • 7,535
  • 7
  • 63
  • 103

3 Answers3

20

Here's a function that will desaturate a vector of input colors by a specified proportion:

library(colorspace)   ## hsv colorspace manipulations
library(RColorBrewer) ## For some example colors

## Function for desaturating colors by specified proportion
desat <- function(cols, sat=0.5) {
    X <- diag(c(1, sat, 1)) %*% rgb2hsv(col2rgb(cols))
    hsv(X[1,], X[2,], X[3,])
}

And here's an example of what it looks like in action:

## Utility function for plotting color palettes, 
## (from vignette("hcl-colors"))
pal <- function(col, border = "light gray", ...) {
  n <- length(col)
  plot(0, 0, type="n", xlim = c(0, 1), ylim = c(0, 1),
  axes = FALSE, xlab = "", ylab = "", ...)
  rect(0:(n-1)/n, 0, 1:n/n, 1, col = col, border = border)
}

## Some example colors
cc <- brewer.pal(9, 'Set1')
cc75 <- desat(cc, 0.75)
cc50 <- desat(cc, 0.50)
cc25 <- desat(cc, 0.25)

## Plot 'em
par(mfcol = c(4,1), mar = c(0,0,0,0))
pal(cc)
pal(cc75)
pal(cc50)
pal(cc25)

enter image description here

Josh O'Brien
  • 159,210
  • 26
  • 366
  • 455
  • 1
    Ha many thanks - that's what I was looking for! Seems I will have to manipulate the V component as well though to avoid that the colours will look to washed out... – Tom Wenseleers Oct 12 '14 at 08:37
  • 2
    @TomWenseleers -- Oh, good. Please consider leaving it here as a better answer if you come up with something clever. If you haven't already discovered it, you might find it interesting to run `colortools::choose_palette(rainbow_hcl)`, then set plot type to "Pie" in the resulting GUI and explore some of your options that way. Cheers. – Josh O'Brien Oct 15 '14 at 15:51
  • I really don't think this should be the accepted correct solution. It desaturates colors toward white instead of toward greys, and I don't think this is expected behavior from the perspective of most users. – user1521655 Aug 24 '18 at 19:40
11

This seems to work fine:

col2 <- adjustcolor(col.palette,alpha.f=0.5)
pie(rep(1,1000), col=col2,lty=0,labels=NA)

adjustcolor is a base R function that lets you adjust colors in many ways, but I find the alpha.f knob the most useful.

Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
  • 1
    Thanks for pointing me to this function! In my case I don't want to change the alpha/transparency though, as it's for use in a 3D rgl plot. And although adjustcolor is nice, it doesn't seem to allow easy manipulation of things like brightness, contrast and saturation (unless these would be specified by custom tranformations). – Tom Wenseleers Oct 11 '14 at 13:18
  • Thank you for the hint @TomWenseleers - I needed the color transformation also in a 3D plot (rglwidget). – lambruscoAcido Aug 21 '18 at 12:33
3

Here is another approach. In rainbow(), you can use two more parameters (i.e, s and v). s is for saturation. If you play with these two parameters you would be able to get what you want.

col.palette=colorRampPalette(rainbow(13, s = 1, v = 0.8),interpolate = "spline")(1000)
pie(rep(1,1000), col=col.palette,lty=0,labels=NA)

enter image description here

col.palette=colorRampPalette(rainbow(13, s = 0.6, v = 1),interpolate = "spline")(1000)
pie(rep(1,1000), col=col.palette,lty=0,labels=NA)

enter image description here

jazzurro
  • 23,179
  • 35
  • 66
  • 76
  • Many thanks for that! This would only work for the specific rainbow palette right, and not for any palette? – Tom Wenseleers Oct 11 '14 at 13:14
  • @TomWenseleers I did a bit of search. You may want to have a look of `?hsv`. According to the R documentation, if you use `hsv()` and create colours, the values returned by the function can be used with a col = specification. So, you can control saturation before you draw figures. – jazzurro Oct 11 '14 at 13:23
  • Ha OK I see - so basically convert to HSV and then change the saturation values, right? I just tried with `cols=colorRampPalette(rainbow(13),interpolate ="spline")(1000); cols=apply(sapply(cols,col2rgb),2,rgb2hsv); cols[2,]=cols[2,]/2;cols=apply(cols,2,hsv);pie(rep(1,1000), col=cols,lty=0,labels=NA)` and that doesn't seem to work though - any thoughts what I'm doing wrong? – Tom Wenseleers Oct 11 '14 at 13:29
  • @TomWenseleers I have not dealt with color issues at this level. But, this is what I'm guessing. Once you convert rgb to hsv, you have three rows. The 2nd row is probably for s, I guess. If you change the values in the row, you'd control saturation; no need for hsv. For pie, col takes a vector of colors. Your cols are still in matrix. I am thinking you may have to go from hsv, rgb, to color. I have seen a [post](http://r.789695.n4.nabble.com/hsv2rgb-in-R-td854595.html) saying there is no hsv2rgb function in R. This is the best I can do for now. – jazzurro Oct 11 '14 at 16:34
  • @TomWenseleers One more. I checked other palettes like `heat.colors`, `cm.colors` and `topo.colors`. In these functions, I see `hsv`. If you need to use these functions, you could modify them. – jazzurro Oct 11 '14 at 17:06
  • Ha thanks a lot - yes above I tried to convert colours to rgb with `col2rgb` and then from rgb to hsv with `rgb2hsv`, after which I modified the 2nd row which I thought was saturation, and then converted from hsv to colours with `hsv`. Not sure why that's not working though... But I'll look into `heat.colors` - thanks for the pointer! – Tom Wenseleers Oct 11 '14 at 18:27