Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correctly Converting Numbers to Colors in R (in Matrices or Otherwise)

Tags:

r

matrix

I'm in the process of converting number matrices to color matrices; however, the colors aren't displaying correctly, e.g., the color matrix displays the incorrect color relative to the assigned number in the number matrix.

I first assigned colors to a set of numerical values.

cols <- c(
'0' = "#FFFFFF",
'1' = "#9AFC7F",
'2' = "#77F255",
'3' = "#60DF3D",
'4' = "#49C925",
'5' = "#37B215",
'6' = "#219900"
)

Then generated a couple matrices.

Map1 <- read.table(text="
1   1   1   0   0   1   1   0   2   1
1   1   1   1   0   1   1   1   2   1
0   1   1   0   2   2   1   1   1   1
0   1   1   1   1   1   2   1   2   2
1   1   2   1   1   1   1   1   2   2
1   1   1   1   1   2   2   1   2   2
1   2   0   1   1   2   1   2   1   2
0   2   2   0   1   1   1   1   1   1
0   1   1   0   0   1   2   2   1   0
0   1   1   1   1   1   1   1   1   0
")

Map2 <- read.table(text="
1   2   1   1   1   1   1   0   2   1
1   1   1   1   1   1   1   1   1   1
0   2   1   1   1   2   1   1   1   1
0   0   1   2   2   1   2   2   3   2
0   1   2   2   1   1   2   2   2   2
1   1   0   2   1   1   3   2   3   3
1   1   2   2   1   2   2   2   1   2
0   1   2   2   1   2   2   2   1   2
1   1   2   1   1   1   1   2   1   1
1   1   1   1   1   1   1   1   1   1
")

After plotting the matrices, I find the colors don't match up with the value they should have been assigned.

image(1:nrow(Map1), 1:ncol(Map1), t(apply(Map1, 2, rev)), col=cols, xaxt='n', yaxt='n', ann=FALSE, bty='n', asp = 1)

image(1:nrow(Map2), 1:ncol(Map2), t(apply(Map2, 2, rev)), col=cols, xaxt='n', yaxt='n', ann=FALSE, bty='n', asp = 1)

Map 1

Map 2

I've been stumped trying to figure out why the numbers and colors aren't aligning. Plotting the numbers assigned in to cols generates the correct sequence.

d <- read.table(text="0 1 2 3 4 5 6")
image(1:nrow(d), 1:ncol(d), t(apply(d, 2, rev)), col=cols, xaxt='n', yaxt='n', ann=FALSE, bty='n', asp = 1)

Color Sequence

There aren't any 6 values in the first number matrix, so there shouldn't be any dark squares in the first color matrix. It appears as though values of 2 are given the color assigned to 6 in the first matrix, and 3 to 6 in the second.

Adding a 3 into the first number matrix seems to shift the other values down the color scale, i.e., the largest number in the matrix is assigned the darkest color, rather than the color it was assigned in cols.

Map1.2 <- read.table(text="
1   1   1   0   0   1   1   0   2   1
1   1   1   1   0   1   1   1   2   1
3   1   1   0   2   2   1   1   1   1
0   1   1   1   1   1   2   1   2   2
1   1   2   1   1   1   1   1   2   2
1   1   1   1   1   2   2   1   2   2
1   2   0   1   1   2   1   2   1   2
0   2   2   0   1   1   1   1   1   1
0   1   1   0   0   1   2   2   1   0
0   1   1   1   1   1   1   1   1   0
")

image(1:nrow(Map1), 1:ncol(Map1), t(apply(Map1, 2, rev)), col=cols, xaxt='n', yaxt='n', ann=FALSE, bty='n', asp = 1)
image(1:nrow(Map1.2), 1:ncol(Map1.2), t(apply(Map1.2, 2, rev)), col=cols, xaxt='n', yaxt='n', ann=FALSE, bty='n', asp = 1)

Map 1 containing a matrix of <code>0</code> <code>1</code> and <code>2</code>

Map 1 containing a matrix of <code>0</code> <code>1</code> <code>2</code> and <code>3</code>

The only difference between the number matrices which generated these two color matrices is the 0 in the first column, third row was changed to a 3.

like image 857
Cameron Avatar asked Jul 24 '16 22:07

Cameron


2 Answers

I think you're having a problem with mapping of numbers to characters. If x is numeric then cols[x] will reference the vector by number, not by name ...

I changed the first colour to red (instead of white) to make the values a little more obvious.

cols <- c('0' = "#FF0000",'1' = "#9AFC7F",'2' = "#77F255",'3' = "#60DF3D",
    '4' = "#49C925",'5' = "#37B215",'6' = "#219900")

Check colour definitions:

plot(0:6,rep(1,7),col=cols,pch=16,cex=5,ylim=c(0.9,1.1),
     axes=FALSE,ann=FALSE,mar=c(0,0,0,0))

enter image description here

m <- matrix(0:5,ncol=2)
image(m,col=cols[m])  ## index by number 

enter image description here

Now index by name:

image(m,col=cols[as.character(m)])

enter image description here

like image 198
Ben Bolker Avatar answered Nov 14 '22 22:11

Ben Bolker


The problem, as you noted, is that the colours are being determined by the values in the matrix. This is because image() automatically spreads the values in the matrix across the range of colours provided. To spread them as you intended, you need to set the zlim argument to cover the length of your vector. Take a look at the help page (?image) for more details about this.

So, to correct your image, you can do the following:

cols <- c("#FFFFFF", "#9AFC7F", "#77F255", "#60DF3D", "#49C925", "#37B215", "#219900")

Map1 <- read.table(text="
  1   1   1   0   0   1   1   0   2   1
  1   1   1   1   0   1   1   1   2   1
  0   1   1   0   2   2   1   1   1   1
  0   1   1   1   1   1   2   1   2   2
  1   1   2   1   1   1   1   1   2   2
  1   1   1   1   1   2   2   1   2   2
  1   2   0   1   1   2   1   2   1   2
  0   2   2   0   1   1   1   1   1   1
  0   1   1   0   0   1   2   2   1   0
  0   1   1   1   1   1   1   1   1   0
")

image(1:ncol(Map1), 1:nrow(Map1), t(sapply(Map1, rev)),
  zlim = c(0, length(cols) - 1),  # This will spread you numbers properly
  col = cols, xaxt='n', yaxt='n', ann=FALSE, bty='n', asp = 1)

enter image description here

Here's another example:

cols <- c("#FFFFFF", "#9AFC7F", "#77F255", "#60DF3D", "#49C925", "#37B215", "#219900")
set.seed(123)
d <- as.data.frame(matrix(sample(c(0, 1, 5, 6), 20, replace = TRUE), ncol = 4))
image(1:ncol(d), 1:nrow(d), t(sapply(d, rev)), 
  zlim = c(0, length(cols) - 1),
  col = cols, xaxt='n', yaxt='n', ann=FALSE, bty='n', asp = 1)

enter image description here

Some side notes:

  • The color vector (cols) does not require names. The order is sufficient.
  • If you use data starting from 1 instead of 0, set to zlim = c(1, length(cols)).
  • I shortened apply(Map1, 2, rev) with sapply(Map1, rev).
  • I swapped 1:ncol() and 1:nrow(), as the original order did not work with a rectangular table.
like image 40
Simon Jackson Avatar answered Nov 15 '22 00:11

Simon Jackson