6
votes

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.

2
Good question, but (1) can you please include data that will provide us with a reproducible example ? (2) you should be aware that code snippets don't do anything useful for R code - best to just use indentation for code blocksBen Bolker
All the data needed to reproduce the problem should be in the question. The only data are the number matrices, and the only code I used is on the page here.Cameron
The number matrices are not in a particularly convenient format for reproducing ... (also, would (much) smaller matrices be easier to work with for reproducing the problem?)Ben Bolker

2 Answers

6
votes

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

3
votes

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.