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")





























Converting named-colour to RGB 
  
col2rgb("brown")  
              [,1]  
red           165  
green       42  
blue        42  
  

Converting RGB to hexadecimal colour (hex colour)  
  
rgb(165, 42, 42, maxColorValue = 255)  
   
[1] "#A52A2A"  
  


Converting named-colour to hex colour
  
colName <- "purple"  
  
rgb(col2rgb(colName)[1], col2rgb(colName)[2], col2rgb(colName)[3],  maxColorValue = 255)  
  
[1] "#A020F0"  
  
  

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.

col_gradient<-colorRampPalette(c("grey","white"))
COL1<-col_gradient(100)

plot(1:100,1:100,pch=18,xlab="",ylab="",
main="Colour gradient - grey scale",cex.main=1,frame=TRUE,col=COL1)


























The following is for single colour gradient.


col_gradient<-colorRampPalette(c("red","grey"))
COL1<-col_gradient(100)

plot(1:100,1:100,pch=18,xlab="",ylab="",
main="Colour gradient - single colour",cex.main=1,frame=TRUE,col=COL1)


























R can have gradient between 2 colours as shown below.

col_gradient<-colorRampPalette(c("red","blue"))
COL2<-col_gradient(100)

plot(1:100,1:100,pch=18,xlab="",ylab="",
main="Colour gradient - two colours",cex.main=1,frame=TRUE,col=COL2)



























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

col_gradient<-colorRampPalette(c("red","green","blue"))
COL3<-col_gradient(100)

plot(1:100,1:100,pch=18,xlab="",ylab="",
main="Colour gradient - multiple colours",cex.main=1,frame=TRUE,col=COL3)


























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.

col_gradient<-colorRampPalette(c("red","blue"))
COL2<-col_gradient(100)

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",
"with colour gradient function",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=COL2[50],border=COL2[50])










No comments:

Post a Comment