Search code examples
r3dplotly

Multi-layer 3D surface with plotly


for the following data I am trying to create a 3D surface plot with x=alpha, y=lambda and z=RMSE. For each gamma I want to have on separate surface in the graph. I tried the following code to create the first layer. However, all I get is a white graph with a z axis limited to [0;1]. I have tried to use several codes that I found online, but none of it worked.

 data <- data.frame(
        RMSE = c(
            19238769.80, 19238769.80, 19238769.80, 19238769.80, 19238769.80,
            19238769.80, 19238769.80, 19238769.80, 19238769.80, 19238769.80,
            1516996.35, 1603109.25, 1701684.26, 1692241.66, 1728254.06,
            1767298.32, 1840967.14, 1873057.87, 1925787.28, 1922243.27,
            1925263.54, 906742.04, 918061.83, 1170369.15, 1030938.54,
            886937.19, 900514.10, 894224.88, 603581.98, 620510.60,
            609132.61, 619806.55, 58965.11, 86155.05, 82149.93, 80818.37,
            82439.19, 71869.52, 71822.20, 62062.51, 40120.85, 39089.10,
            26557.80
        ),
        alpha = c(
            0.96, 0.97, 0.98, 0.99, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06,
            0.98, 0.99, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09,
            0.46, 0.47, 0.48, 0.49, 0.50, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56,
            0.76, 0.77, 0.78, 0.79, 0.80, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86
        ),
        lambda = c(
            0.00, 0.00, 0.00, 0.00, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01,
            0.03, 0.03, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04,
            0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51, 0.51,
            0.81, 0.81, 0.81, 0.81, 0.81, 0.81, 0.81, 0.81, 0.81, 0.81, 0.81
        ),
        gamma = c(rep(2.1, 25),rep(2.0,18))
    )
    
     fig <- plot_ly(x = data$alpha, y = data$lambda, z = data$RMSE,type="surface")
    fig

Solution

  • Polly's surface plot wants a vector of unique x-axis values for x and unique y-axis values for y. The z argument should be a matrix with values that correspond to the combinations of the x and y values. Here's an example:

    alpha <- seq(0,1, by=.01)
    lambda <- seq(0,1,by=.01)
    gamma <- c(1,2)
    z1 <- outer(alpha, lambda, \(x,y)x*y + gamma[1])
    z2 <- outer(alpha, lambda, \(x,y)x*y + gamma[2])
    
    library(plotly)
    plot_ly(x=alpha, y=lambda) %>% 
      add_surface(z=z2, colorscale = "Greens") %>% 
      add_surface(z=z1, colorscale = "Blues") 
    
    

    enter image description here


    Answering Comments

    In the comments, the OP asked if there are other options. wireframe() in the lattice() package takes data of this format, but there's simply not enough data there to generate the plot. Perhaps this is a toy example, but if you made a heat map of where you actually have data, you would see that it's very sparse and unilkely that a 3-D surface plot of just these data would be all that enlightening:

    library(ggplot2)
    ggplot(data, aes(x=alpha, y=lambda, fill=RMSE)) + 
      geom_tile() + 
      facet_wrap(~gamma, ncol=2) +  
      theme_bw()
    

    enter image description here