M. Beausoleil M. Beausoleil -4 years ago 78
R Question

How can I plot 2 peaks in a 3D graph with different colors in R (using the x-axis, not the Z-axis)?

I want to color two peaks, with different colors, in a 3d plots but it's not working. Most of the help I find is to color by the z-axis, but I want to color just the peaks.

Here is what I got so far:
enter image description here

x <- seq(-10, 10, length = 100)
y <- x

norm <- function(x,y, mean1 = 3, var1 =2,mean2 = -3, var2 =2) {
1/sqrt(2*var1^2*1)*exp(-((y-mean2)^2/(2*var2^2))) *
1/sqrt(2*var2^2*1)*exp(-((x-mean2)^2/(2*var1^2)))+
1/sqrt(2*var2^2*1)*exp(-((y-mean1)^2/(2*var2^2))) *
1/sqrt(2*var1^2*1)*exp(-((x-mean1)^2/(2*var1^2))) }



z <- outer(x, y, norm)
z[is.na(z)] <- 1

rbPal <- colorRampPalette(c('red','blue'))
Col <- rbPal(10)[as.numeric(cut(x = x,breaks = 2))]

persp(x, y, z, col = "blue",
xlab = "",
ylab = "", zlab = "",
theta = 60,
phi = 15,d = 10,
border = border,
shade = 0.6,
zlim=c(0,.2))


Other try, this is closer to what I want, but as you can see, not optimal since the "floor" is overlapping the other peak!
enter image description here

norm1 <- function(x,y, mean1 = 3, var1 =2,mean2 = -3, var2 =2) {
1/sqrt(2*var1^2*1)*exp(-((y-mean2)^2/(2*var2^2))) *
1/sqrt(2*var2^2*1)*exp(-((x-mean2)^2/(2*var1^2)))
}
norm2 <- function(x,y, mean1 = 3, var1 =2,mean2 = -3, var2 =2) {
1/sqrt(2*var2^2*1)*exp(-((y-mean1)^2/(2*var2^2))) *
1/sqrt(2*var1^2*1)*exp(-((x-mean1)^2/(2*var1^2))) }

z1 <- outer(x, y, norm1)
z1[is.na(z1)] <- 1

z2 <- outer(x, y, norm2)
z2[is.na(z1)] <- 1

persp(x, y, z1, col ="red",
xlab = "",
ylab = "", zlab = "",
theta = 60,
phi = 15,d = 10,
border = border,
shade = 0.6,
zlim=c(0,.2))

par(new=TRUE)
red.a = adjustcolor( "blue", alpha.f = .70)
persp(x, y, z2, col ="blue",
xlab = "",
ylab = "", zlab = "",
theta = 60,
phi = 15,d = 10,
border = border,
shade = 0.6,
zlim=c(0,.2))

Answer Source

One approach is to make the full plot as a collage of different pieces. In the code below, I split the plot along the diagonal (in the x-y plane) to give the two peaks different colors. But I think there's nothing stopping you from getting fancier here with different colors for multiple regions of the x-y plane.

x <- seq(-10, 10, length = 100)
y <- x

norm <- function(x,y, mean1 = 3, var1 =2,mean2 = -3, var2 =2) {
  1/sqrt(2*var1^2*1)*exp(-((y-mean2)^2/(2*var2^2))) * 
    1/sqrt(2*var2^2*1)*exp(-((x-mean2)^2/(2*var1^2)))+
    1/sqrt(2*var2^2*1)*exp(-((y-mean1)^2/(2*var2^2))) * 
    1/sqrt(2*var1^2*1)*exp(-((x-mean1)^2/(2*var1^2)))      }

z <- outer(x, y, norm)
z[is.na(z)] <- 1

rbPal <- colorRampPalette(c('red','blue'))
Col <- rbPal(10)[as.numeric(cut(x = x,breaks = 2))]

persp(x, y, z, col = "blue", 
      xlab = "", 
      ylab = "", zlab = "", 
      theta = 60,
      phi = 15,d = 10,
    #  border = border,
      shade = 0.6,
      zlim=c(0,.2))

z2 <- z
for(i in 1:100){
  for(j in 1:(100-i)){
    z2[i,j] <- NA
  }
}



par(new=T)
graphics::persp(x, y, z2, col = "red", 
      xlab = "", 
      ylab = "", zlab = "", 
      theta = 60,
      phi = 15,d = 10,
    #  border = border,
      shade = 0.6,
      zlim=c(0,.2))

Or if you just want the peaks colored (and everything else gray, for example), you could do

z3 <- z
z3[z3<.03] <- NA
z4 <- z2
z4[z4<.03] <- NA

persp(x, y, z, col = "gray90", 
      xlab = "", 
      ylab = "", zlab = "", 
      theta = 60,
      phi = 15,d = 10,
      #  border = border,
      shade = 0.6,
      zlim=c(0,.2))

par(new=T)
persp(x, y, z3, col = "skyblue1", 
      xlab = "", 
      ylab = "", zlab = "", 
      theta = 60,
      phi = 15,d = 10,
      #  border = border,
      shade = 0.6,
      zlim=c(0,.2))

par(new=T)
persp(x, y, z4, col = "indianred1", 
      xlab = "", 
      ylab = "", zlab = "", 
      theta = 60,
      phi = 15,d = 10,
      #  border = border,
      shade = 0.6,
      zlim=c(0,.2))
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download