Wednesday, 15 October 2014

Plot - Colours and Plotting Characters

When plotting scatterplot graphs 'pch' determines the shape of the plots used. Usually, there are 25 symbols used for plotting in general, but depending on your R session locale settings, you can have more options. You can use sessionInfo() or Sys.getlocale() to check your locale settings, and change it with Sys..setlocale().

For  LC_CTYPE="English_Australia", there are 247 characters you can choose from pch parameter. The below will plot these options in the graphic device. Note, pch 26 to 31 inclusive are often left blank.

plot(rep(c(1:20),times=13),rep(seq(2,26,by=2),each=20),
pch=1:260,yaxt="n",xaxt="n",xlab="",ylab="",
main="pch values and corresponding displays",cex.main=1,frame=FALSE)
text(rep(c(1:20),times=13),rep(seq(2.7,26.7,by=2),each=20),
label=c(1:260),cex=0.8,col="darkgrey")

R has 657 predefined colours that is included in the base package. These can be listed by colours(). The below chart shows the names and colours available.

par(mai=c(0,0,0.5,0))
plot(rep(seq(0,9,by=1),each=66),rep(seq(1,66,by=1),times=10),pch=15,
col=colours(),cex=1.5,yaxt="n",xaxt="n",xlab="",ylab="",
main="colour options",cex.main=1,frame=FALSE,xlim=c(0,10.5))
text(rep(seq(0.5,9.5,by=1),each=66),rep(seq(1,66,by=1),times=10),
label=colours(),cex=0.7,col="darkgrey")

Colour gradient is often useful for beautifying graphs and visualising values of continuous variables. The following shows grey scale colour gradient, set at 100 units.

plot(1:100,1:100,pch=18,xlab="",ylab="",

The following is for single colour gradient.

plot(1:100,1:100,pch=18,xlab="",ylab="",

R can have gradient between 2 colours as shown below.

plot(1:100,1:100,pch=18,xlab="",ylab="",

You can also have gradient between multiple colours. This example has 3 colours.

plot(1:100,1:100,pch=18,xlab="",ylab="",

The colours can be converted to rgb code by using col2rgb() function as shown below.

col2rgb("red")

[,1]
red    255
green    0
blue     0

col2rgb("blue")

[,1]
red      0
green    0
blue   255

More than one colour can be converted at the same time as shown below which produces output as a matrix.

col2rgb(c("red","blue"))

[,1]         [,2]
red      255        0
green    0          0
blue      0        255

Mixing colour is not so straight forward but is not so complex neither. However, logical outcome of a colour mix is not always same in R as it is normally understood in practice. For example, mixing blue and red should produce purple, but rgb of respective colours show that purple has a hint of green in the mix.

rbp<-col2rgb(c("red","blue","purple"))
colnames(rbp)<-c("red","blue","purple")
rbp

red    blue    purple
red     255      0       160
green   0        0        32
blue     0      255     240

If you follow the simplistic approach and take a mean of rgb values between source colours (red and blue), you have the following colour that is compared with predefined purple colour.

Colrgb<-col2rgb(c("red","blue"))
p<-apply(Colrgb,1,mean)

plot(1:2,rep(1,2),col=c("purple",rgb(p[1],p[2],p[3],max=255)),pch=16,cex=10,
yaxt="n",xaxt="n",xlab="",ylab="",frame=TRUE,xlim=c(0,3),ylim=c(0,2))
text(1:2,rep(1.5,2),label=c("purple","rgb mean"),cex=1,col="darkgrey")

Alternatively, we can use colorRampPalette() as seen above and pick the mid-point between 2 colours.

plot(1:3,rep(1,3),col=c("purple",rgb(p[1],p[2],p[3],max=255),COL2[50]),pch=16,
cex=10,yaxt="n",xaxt="n",xlab="",ylab="",frame=TRUE,xlim=c(0,4),ylim=c(0,2))
text(1:3,rep(1.5,3),label=c("purple","rgb mean","palette"),cex=1,col="darkgrey")

There is a minor difference between these colours and they can be seen from rgb values shown below.

purple     average     palette
red          160        127.5         128
green       32            0               0
blue        240        127.5         126

The practical application is when you have overlapping regions in the shaded areas of the graph.

The below is when you do not assign colour to the overlapping region, but use lighter density to display he overlap. In other graph functions, this would be equivalent to alpha parameter.

plot(sin(seq(-pi,pi,length=100)),cos(seq(-pi,pi,length=100)),type="l",
col=rgb(255,0,0,max=255),xlim=c(-1,3),yaxt="n",xaxt="n",xlab="",ylab="",frame=FALSE,
main="Shaded Region between Red and Blue Circles without colouring",cex.main=1)

polygon(sin(seq(-pi,pi,length=100)),cos(seq(-pi,pi,length=100)),density=60,angle=90,
col=rgb(255,0,0,max=255),fillOddEven=FALSE,border=NA)

lines(sin(seq(-pi,pi,length=100))+1.5,cos(seq(-pi,pi,length=100)),type="l",
col=rgb(0,0,255,max=255),yaxt="n",xaxt="n",xlab="",ylab="")

polygon(sin(seq(-pi,pi,length=100))+1.5,cos(seq(-pi,pi,length=100)),density=60,angle=0,
col=rgb(0,0,255,max=255),fillOddEven=FALSE,border=NA)

The below compares the use of purple, average rgb and palette for the overlapping region. You can decide which one looks more natural and suit the purpose.

A<-data.frame(theta=seq(-pi,pi,length=100),
cbind(sin(seq(-pi,pi,length=100)),rev(sin(seq(-pi,pi,length=100))+1.5)))
A\$ind<-A\$X1-A\$X2
A<-A[which(A\$ind>0),]
A\$Y<-cos(A\$theta)

B<-data.frame(theta=seq(-pi,pi,length=100),
cbind(rev(sin(seq(-pi,pi,length=100))),sin(seq(-pi,pi,length=100))+1.5))
B\$ind<-B\$X1-B\$X2
B<-B[which(B\$ind>0),]
B\$Y<-cos(B\$theta)

par(mfrow=c(3,1))

plot(sin(seq(-pi,pi,length=100)),cos(seq(-pi,pi,length=100)),type="l",col="red",
xlim=c(-1,3),yaxt="n",xaxt="n",xlab="",ylab="",frame=FALSE,
main=paste("Shaded Region between Red and Blue Circles",
"with purple colour",sep="\n"),cex.main=1)
polygon(sin(seq(-pi,pi,length=100)),cos(seq(-pi,pi,length=100)),col="red",
fillOddEven=FALSE,border=NA)
lines(sin(seq(-pi,pi,length=100))+1.5,cos(seq(-pi,pi,length=100)),type="l",col="blue")
polygon(sin(seq(-pi,pi,length=100))+1.5,cos(seq(-pi,pi,length=100)),col="blue",
fillOddEven=FALSE,border=NA)
polygon(c(A\$X1,B\$X2),c(A\$Y,B\$Y),col="purple",border="purple")

plot(sin(seq(-pi,pi,length=100)),cos(seq(-pi,pi,length=100)),type="l",col="red",
xlim=c(-1,3),yaxt="n",xaxt="n",xlab="",ylab="",frame=FALSE,
main=paste("Shaded Region between Red and Blue Circles",
"with average rgb of red and blue",sep="\n"),cex.main=1)
polygon(sin(seq(-pi,pi,length=100)),cos(seq(-pi,pi,length=100)),col="red",
fillOddEven=FALSE,border=NA)
lines(sin(seq(-pi,pi,length=100))+1.5,cos(seq(-pi,pi,length=100)),type="l",col="blue")
polygon(sin(seq(-pi,pi,length=100))+1.5,cos(seq(-pi,pi,length=100)),col="blue",
fillOddEven=FALSE,border=NA)
polygon(c(A\$X1,B\$X2),c(A\$Y,B\$Y),col=rgb(p[1],p[2],p[3],max=255),
border=rgb(p[1],p[2],p[3],max=255))

plot(sin(seq(-pi,pi,length=100)),cos(seq(-pi,pi,length=100)),type="l",col="red",
xlim=c(-1,3),yaxt="n",xaxt="n",xlab="",ylab="",frame=FALSE,
main=paste("Shaded Region between Red and Blue Circles",
polygon(sin(seq(-pi,pi,length=100)),cos(seq(-pi,pi,length=100)),col="red",
fillOddEven=FALSE,border=NA)
lines(sin(seq(-pi,pi,length=100))+1.5,cos(seq(-pi,pi,length=100)),type="l",col="blue")
polygon(sin(seq(-pi,pi,length=100))+1.5,cos(seq(-pi,pi,length=100)),col="blue",
fillOddEven=FALSE,border=NA)
polygon(c(A\$X1,B\$X2),c(A\$Y,B\$Y),col=COL2[50],border=COL2[50])