# Color choosing in R made easy

May 21, 2010
By

(This article was first published on My contRibution » R, and kindly contributed to R-bloggers)

I don’t know about you, but when I want to make a graph in R, I handpick the colors, line widths etc… to produce awesome output.

A lot of my time is spent on color choosing, I had to find a more convenient way of doing so. Earl F. Glynn’s “Chart of R colors”  posted on  http://research.stowers-institute.org/efg/R/Color/Chart/ gave me the idea to the following function.

R has an Internal called colors(), it’s output is a 657 long character vector of reserved names for colors.

The names can be used directly as in :

plot(iris,col="orange")

Alternatively, they can be referred to from colors()

plot(iris,col=colors()[503])

The color() function has a two arguments (notice it is not plural… I chose this unreserved name because it’s easy to remember) :

1. plot.it – FALSE by default
2. locate – 0 by default

The call color() is the same as colors().

> color()[555]==colors()[555]
[1] TRUE

Calling color(plot.it=T) or color(T) gives the following output (very similar to Earl F. Glynn’s “Chart of R colors”) :

You can choose and remember the numbers, or print and stick above your working area… but the following makes color() more useful :

Specifying locate = k > 0 will plot the chart above and this time will use the locator() function in a loop to choose colors you want. After choosing k colors the output will be  a k-long character vector of the chosen colors.

> color(T,5)
[1] "firebrick4" "grey9"      "green"      "gray99"     "khaki1"

You can use it directly in a plot function, the palette of colors will plot first, choose your colors, the plot you called for will be followed by it:

plot(iris,col=color(T,5))

The function is given by :

color    <- function (plot.it=F,locate=0)
{
if(!plot.it)
{
return(.Internal(colors())) # so far, not different from colors()
} # close on if
else
{
ytop    <- rep(seq(1/26,1,by=1/26),each=26)[1:657]
ybottom <- rep(seq(0,1-1/26,by=1/26),each=26)[1:657]
xleft   <- rep(seq(0,1-1/26,by=1/26),times=26)[1:657]
xright  <- rep(seq(1/26,1,by=1/26),times=26)[1:657]
pall    <- round(col2rgb(colors())/256)
pall    <- colSums(pall) ; pall2 <- character(0)
pall2[pall>0]   <- "black"
pall2[pall==0]  <- "white"

par(mar=c(0,0,1,0))

plot.new()
title(main="Palette of colors()")
rect(xleft,ybottom,xright,ytop,col=colors())
text(x=xleft+((1/26)/2)
,y=ytop-((1/26)/2)
,labels = 1:657
,cex=0.55
,col=pall2)

} # close on else
if(locate==0) print("Palette of colors()")
else
{
colmat    <- matrix(c(1:657,rep(NA,26^2-657)),byrow=T,ncol=26,nrow=26)
cols        <- NA
i        <- NA
for(i in 1:locate)
{
h    <- locator(1)
if(any(h$x<0,h$y<0,h$x>1,h$y>1)) stop("locator out of bounds!")
else
{
cc        <- floor(h$x/(1/26))+1 rr <- floor(h$y/(1/26))+1
cols[i]    <- .Internal(colors())[colmat[rr,cc]]
} # close on else
} # close on i
return(cols)
} # close on else
} # close on else+function

You can also write it to variable for further use:

> cols<- color(T,5)
> cols
[1] "magenta"        "orange3"        "palevioletred2" "seagreen4"
[5] "seagreen2"

Of course it’s not perfect, I still have not solved issues of working with Devices such as pdf() jpeg() and such…