6
votes

Attempting to overlay color plots (something like below) using ggplot2

Red + Green giving Yellow in the 3rd column

Trying to use geom_tile but ggplot doesnt allow me to add 2 color scales. Here is an example code.

df <- data.frame(expand.grid(1:5,1:5))
df$z1 <- runif(nrow(df))
df$z2 <- runif(nrow(df))
g1 <- ggplot(df,aes(Var1,Var2)) + theme_bw()
#layer 1
g11 <- g1  + geom_tile(aes(fill=z1),alpha=0.5) + scale_fill_gradient(low="white", high="red")
#layer 2
g12 <- g1  + geom_tile(aes(fill=z2),alpha=0.5) + scale_fill_gradient(low="white", high="green")
g11
g12

One way to possible do this is to make the 2 layers as different groups. But the outcome just doesn't look intuitive.

mdf=melt(df,'id'=1:2)
g2 <- ggplot(mdf,aes(Var1,Var2,fill = factor(variable),alpha = value)) + 
     geom_tile() + scale_fill_manual(values = c('red','green')) + theme_bw()
g2

best outcome i could come up with

2

2 Answers

3
votes

You're really close: just don't divide z1 and z2 by 2.

There is another issue to consider though. If z1 and z2 are not on the same scale, should you use a common scale for both, or should you scale them independently? The result is (can be) different, as illustrated below.

gg.overlay <- function(df) {  # produces 2 color channels and the overlay
  require(ggplot2)
  require(gridExtra)
  gg.z1 <- ggplot(df, aes(x,y))+
    geom_tile(fill=rgb(red=df$z1.scale,green=0,blue=0))+
    scale_x_continuous(expand=c(0,0))+
    scale_y_continuous(expand=c(0,0))+
    coord_fixed()

  gg.z2 <- ggplot(df, aes(x,y))+
    geom_tile(fill=rgb(red=0,green=df$z2.scale,blue=0))+
    scale_x_continuous(expand=c(0,0))+
    scale_y_continuous(expand=c(0,0))+
    coord_fixed()

  gg <- ggplot(df, aes(x,y))+
    geom_tile(fill=rgb(red=df$z1.scale,green=df$z2.scale,blue=0))+
    scale_x_continuous(expand=c(0,0))+
    scale_y_continuous(expand=c(0,0))+
    coord_fixed()

  library(gridExtra)
  grid.arrange(gg.z1, gg.z2, gg, ncol=3)
}

Using an example slightly closer to the image in your question:

library(mvtnorm)  # just for this example
df    <- expand.grid(x=seq(-3,3,len=100),y=seq(-3,3,len=100))
df$z1 <- with(df,dmvnorm(cbind(x,y),mean=c(0,0),sigma=matrix(c(1,-1,-1,2),nc=2)))
df$z2 <- with(df,3*dmvnorm(cbind(x,y),mean=c(0,0),sigma=matrix(c(1,0,0,1),nc=2)))

# scale z1 and z2 together
max.z <- with(df,max(z1,z2))
min.z <- with(df,min(z1,z2))
df$z1.scale <- with(df, (z1-min.z)/(max.z-min.z))
df$z2.scale <- with(df, (z2-min.z)/(max.z-min.z))
gg.overlay(df)

# scale z1 and z2 separately
df$z1.scale <- with(df, (z1-min(z1))/diff(range(z1)))
df$z2.scale <- with(df, (z2-min(z2))/diff(range(z2)))
gg.overlay(df)

In the first case the reds are muted because the z1 intensities are lower than the z2 intensities. In the second case we scale them separately, so the reds are more vibrant. It's not clear which is the "correct" method.

0
votes

One possible solution is to manually calculate the color and then pass it to geom_tile. (continuation to the above code)

cols=rgb(red=df$z1/2,green=df$z2/2,blue=rep(0,nrow(df)))
g1 <- ggplot(df,aes(Var1,Var2)) + theme_bw() + geom_tile(fill=cols)
g1

but it is too dark

How do i brighten the colors?