7
votes

Using plotly I would like to have each surface to have different colour.

library(plotly)
t1 <- seq(-3, 3, 0.1); t2 <- seq(-3, 3, 0.1)

p1 <- matrix(nrow = length(t1), ncol = length(t2))
p2 <- matrix(nrow = length(t1), ncol = length(t2))

p8a1 <- 1.2
p8a2 <- 1
p8d <- -1
p8b1 <- 0.7
p8b2 <- 0.6

for (i in 1:length(t2)) {
   for (j in 1:length(t1)) {
      p1[i, j] <- 1 / (1 + exp(-1.7 * (p8a1 * t1[j] + p8a2 * t2[i] + p8d)))
      p2[i, j] <- (1 / (1 + exp(-1.7 * p8a1 * (t1[j]- p8b1)))) * 
                  (1 / (1 + exp(-1.7 * p8a2 * (t2[j]- p8b2))))
   }
}

df1 <- list(t1, t2, p1)
df2 <- list(t1, t2, p2)

names(df1) <- c("t1", "t2", "p1")
names(df2) <- c("t1", "t2", "p2")
m <- list(l = 10, r = 10, b = 5, t = 0, pad = 3)

p <- plot_ly(color = c("red", "blue")) %>%
     add_surface(x = df1$t1,
                 y = df1$t2,
                 z = df1$p1,
                 opacity = 0.8) %>%
     add_surface(x = df2$t1,
                 y = df2$t2,
                 z = df2$p2,
                 opacity = 1) %>%
     layout(autosize = F, width = 550, height = 550, margin = m,
            scene = list(xaxis = list(title = "Theta 1"),
                         yaxis = list(title = "Theta 2"),
                         zaxis = list(title = "P")),
            dragmode = "turntable")
p

Unfortunately, I'm not able to change colours of these two surfaces. I tried to add color = I("red") and color = I("blue") arguments into add_surface but this just changed colour scale from red to blue for both surfaces.

I also tried to add color = "red" into plot_ly() and add inherit = F into second add_surface. This changed the first surface only, but only the yellow default color into red. I would love to have one surface red and second one blue.

1

1 Answers

5
votes

Sounds trivial but it's a bit tricky in Plotly. The color of a surface plot is either derived from the z values or from an array with the same dimensions as z. This color array only accepts numerical values, no color strings or RGB values.

So let's define an array for our colors

color <- rep(0, length(df1$p1))
dim(color) <- dim(df1$p1)

Next we need to trick Plotly into ignoring the colorscale.

surfacecolor=color,
             cauto=F,
             cmax=1,
             cmin=0

et voilĂ , we have a uniformely colored plot.

enter image description here


library(plotly)
t1 <- seq(-3, 3, 0.1); t2 <- seq(-3, 3, 0.1)

p1 <- matrix(nrow = length(t1), ncol = length(t2))
p2 <- matrix(nrow = length(t1), ncol = length(t2))

p8a1 <- 1.2
p8a2 <- 1
p8d <- -1
p8b1 <- 0.7
p8b2 <- 0.6

for (i in 1:length(t2)) {
  for (j in 1:length(t1)) {
    p1[i, j] <- 1 / (1 + exp(-1.7 * (p8a1 * t1[j] + p8a2 * t2[i] + p8d)))
    p2[i, j] <- (1 / (1 + exp(-1.7 * p8a1 * (t1[j]- p8b1)))) * 
      (1 / (1 + exp(-1.7 * p8a2 * (t2[j]- p8b2))))
  }
}

df1 <- list(t1, t2, p1)
df2 <- list(t1, t2, p2)

names(df1) <- c("t1", "t2", "p1")
names(df2) <- c("t1", "t2", "p2")
m <- list(l = 10, r = 10, b = 5, t = 0, pad = 3)

color <- rep(0, length(df1$p1))
dim(color) <- dim(df1$p1)
p <- plot_ly(colors = c('red', 'blue')) %>%
  add_surface(x = df1$t1,
              y = df1$t2,
              z = df1$p1,
              opacity = 0.8,
              #surfacecolor=c('red')
              surfacecolor=color,
              cauto=F,
              cmax=1,
              cmin=0
  )
color2 <- rep(1, length(df2$p2))
dim(color2) <- dim(df2$p2 )

p <-  add_surface(p,
              x = df2$t1,
              y = df2$t2,
              z = df2$p2,
              opacity = 1,
              surfacecolor=color2,
              cauto=F,
              cmax=1,
              cmin=0)
p