How to add a contour overlay to a 3D plotly in R?

First time poster here, hopefully i’ve done it right.

I am trying to create a 3D plot with grid over the top of the data (similar to this example: How to add a meshgrid to a plotly 3d surface?) but no matter what i try, it isnt working. Does anyone know what I am doing wrong? Any advice is much appreciated.

Here is the code i am using:

# Response surface (with grid on axes)
x <- plot_ly(PredDat, x = ~est, y = ~Day, z = ~percent,
             intensity = ~percent,
             colorscale = list(c(0,'green'),
                               c(0.05,'yellow'),
                               c(0.1, 'orange'),
                               c(1, 'red')),
             type = 'mesh3d')
x <- x %>% layout(scene = list(xaxis = list(type = "log", title = 'Concentration (ug/L)', showgrid = TRUE, gridcolor = "black"),
                               yaxis = list(title = 'Day', showgrid = TRUE, gridcolor = "black"),
                               zaxis = list(title = 'percent affected', showgrid = TRUE, gridcolor = "black")))
x

Which produces this plot (the surface is correct but i would like to add contour lines):

My data has the following structure:

> summary(sampleData)
>     percent      est                  Day        
>  Min.   : 1.00   Min.   :    0.000   Min.   :  1.00  
>  1st Qu.:23.75   1st Qu.:    0.064   1st Qu.:  9.00  
>  Median :54.50   Median :    0.955   Median : 17.00  
>  Mean   :52.27   Mean   :  225.022   Mean   : 64.51  
>  3rd Qu.:77.00   3rd Qu.:    9.612   3rd Qu.: 50.00  
>  Max.   :99.00   Max.   :16382.540   Max.   :350.00 
> ```

dput in case that is easier:

> dput(sampleData)
> structure(list(percent = c(63L, 85L, 82L, 49L, 88L, 95L, 88L, 
> 84L, 8L, 99L, 41L, 20L, 55L, 51L, 56L, 18L, 45L, 39L, 18L, 78L, 
> 57L, 44L, 20L, 74L, 90L, 7L, 68L, 22L, 94L, 35L, 70L, 1L, 15L, 
> 47L, 78L, 47L, 92L, 14L, 96L, 42L, 23L, 63L, 89L, 58L, 87L, 49L, 
> 38L, 49L, 56L, 73L, 25L, 54L, 97L, 4L, 99L, 56L, 54L, 1L, 4L, 
> 20L, 75L, 92L, 85L, 89L, 22L, 76L, 85L, 75L, 13L, 13L, 77L, 46L, 
> 56L, 11L, 45L, 35L, 84L, 2L, 6L, 6L, 71L, 20L, 15L, 94L, 21L, 
> 79L, 53L, 75L, 57L, 45L, 63L, 72L, 63L, 21L, 74L, 66L, 79L, 98L, 
> 19L, 97L, 72L, 50L, 86L, 69L, 65L, 91L, 88L, 3L, 34L, 9L, 81L, 
> 65L, 45L, 13L, 70L, 37L, 81L, 7L, 71L, 19L, 20L, 23L, 91L, 98L, 
> 49L, 71L, 12L, 63L, 73L, 26L, 20L, 54L, 28L, 64L, 89L, 77L, 51L, 
> 26L, 62L, 63L, 76L, 25L, 73L, 8L, 53L, 10L, 86L, 19L, 46L, 20L, 
> 90L, 77L, 8L, 28L, 79L, 34L, 31L, 15L, 87L, 87L, 77L, 1L, 29L, 
> 53L, 82L, 44L, 8L, 20L, 68L, 85L, 91L, 6L, 77L, 30L, 6L, 22L, 
> 95L, 92L, 65L, 54L, 58L, 61L, 98L, 74L, 49L, 87L, 42L, 46L, 45L, 
> 28L, 32L, 7L, 62L, 35L, 24L, 12L, 74L, 68L, 71L, 58L), est = c(1.04407485232684, 
> 15.9422865186523, 21.8097901217244, 0.624061160609868, 137.758650998872, 
> 1803.87637210633, 0.760192433809832, 0.414478264297407, 0.0452467657381889, 
> 16382.5401402268, 0.00441304252959353, 0.00241295675163572, 0.994838821417042, 
> 1.79258605469963, 0.513004900664426, 0.0770323004997502, 0.025809346390113, 
> 0.0133350482825202, 0.8335392718973, 2.49033296236117, 1.20919695813704, 
> 0.713393261649366, 0.0895658895371724, 9.5887846390835, 38.1734185089705, 
> 0.021467239694851, 1.28768040659316, 0.200309232297262, 3271.45503789688, 
> 3.84465569672239, 3.24711941679096, 0.0111159045915617, 0.0415015162604063, 
> 0.510156595331072, 11.4562721994463, 0.00643459855069155, 1717.3524984109, 
> 0.241532532773892, 2.05002142540291, 1.5143998596384, 0.000270702976191344, 
> 4.22613920026973, 1.00710427067479, 2.9047941635375, 4.89326455569652, 
> 0.659650724858752, 0.952891055604006, 0.00672668982765519, 2.51984332684414, 
> 6.61606524688289, 0.183850270389014, 0.41968794803407, 613.822979083032, 
> 0.00987130162078365, 5.49410642957213, 2.13426353436643, 0.0311582669288472, 
> 2.45704794843697e-05, 0.104871882328571, 0.0240328611419533, 
> 22.6487599991652, 61.7103654408549, 20.8664072256021, 31.109478318259, 
> 0.0013145762931139, 0.276312784742751, 1230.11276833219, 351.332582939509, 
> 0.00735226683287831, 0.0573946550168844, 15.4663524704398, 0.00551333301462274, 
> 75.4733480046846, 0.0541199633388947, 0.450876010909864, 0.0465558377756151, 
> 69.0420619440199, 0.0326080067237438, 2.35817429782289, 0.00205082752760487, 
> 7.13703981774009, 0.00803477701816285, 0.0363879430802282, 160.560674451424, 
> 0.00867054501275599, 64.0940155981017, 1.73344175905959, 7.25339311177785, 
> 1.7196630588627, 0.66737236404782, 2.3969677782588, 5.31938373229231, 
> 5.0674560906683, 0.525345148814841, 4.81678065649555, 2.3231224341502, 
> 23.2040648865511, 1565.31575271191, 7.49798237833499, 15125.2816672554, 
> 3.83716998913727, 0.0158853750584201, 123.544523295717, 3.12852310907506, 
> 0.0983352986516117, 348.246042942081, 43.8366596677592, 0.53311119445624, 
> 0.330365574177749, 0.0984589727560102, 18.9895060704893, 2.25561904124953, 
> 0.00477499031873687, 0.000294567963473975, 11.1248255984764, 
> 0.00100877519812577, 0.386293426910268, 0.0465262379905129, 12.1853067335855, 
> 0.000359636279803776, 0.0010901640739526, 0.252962117322107, 
> 1.5931599419431, 3.11897366350088, 0.00506088115778639, 0.342454771476626, 
> 0.203903549331277, 0.910175855744087, 5.27270018754817, 0.136732557101739, 
> 0.000203375937630994, 0.0642936643751398, 0.000822344867368876, 
> 2.08387043796528, 97.3238032721882, 0.249618461207728, 0.0311505378973044, 
> 0.0126566639447543, 9.6834496873792, 0.192839064290056, 16.453454277487, 
> 0.00378897335137911, 4.44281773980034, 0.000145357666547522, 
> 0.375842504318371, 0.0280639336070094, 17.4902503513962, 0.00056095897156569, 
> 0.630852788108575, 0.0635845223499213, 564.986667712194, 51.1306086562373, 
> 0.0246691360475172, 1.11476326965692, 0.337453194277694, 0.378281449110894, 
> 1.3398790432204, 0.207956166495869, 26.6078879076572, 23.6593931463183, 
> 78.6316938631263, 0.00175420263945739, 0.187032110123746, 0.817631721338736, 
> 15.5886060559813, 0.553472314050031, 0.0730856839941687, 0.957610566174482, 
> 15.554585131796, 8.4071956356968, 62.7594685395332, 6.36145826749089e-05, 
> 18.3728100876976, 0.000514793790291854, 0.0690791969176382, 0.000745771369488229, 
> 142.966809774615, 82.4629194527887, 49.4430010923703, 3.26254308054076, 
> 10.251010970077, 8.9942750877235, 3.85291157047756, 107.184132364844, 
> 4.00244348090398, 2.01400970149377, 0.408075094375508, 1.56682298054436, 
> 0.87718928574718, 0.000428593686118138, 0.157988307382218, 0.511348418441622, 
> 1.7040487465029, 20.513022659987, 0.11394610962745, 0.0346824155021124, 
> 13.3414141457494, 1.89276239553076, 0.196405473851736, 0.614362904839189
> ), Day = c(40L, 19L, 11L, 19L, 6L, 4L, 250L, 350L, 13L, 15L, 
> 200L, 100L, 19L, 9L, 50L, 16L, 100L, 100L, 4L, 50L, 15L, 12L, 
> 16L, 10L, 19L, 17L, 50L, 11L, 2L, 3L, 20L, 13L, 19L, 20L, 12L, 
> 250L, 2L, 7L, 200L, 7L, 350L, 9L, 200L, 9L, 50L, 18L, 8L, 300L, 
> 9L, 12L, 13L, 50L, 18L, 20L, 150L, 10L, 250L, 150L, 6L, 30L, 
> 6L, 19L, 16L, 19L, 150L, 300L, 1L, 1L, 40L, 15L, 9L, 250L, 1L, 
> 14L, 19L, 40L, 6L, 9L, 1L, 50L, 10L, 50L, 20L, 17L, 50L, 4L, 
> 10L, 13L, 12L, 13L, 13L, 13L, 8L, 6L, 16L, 19L, 8L, 18L, 1L, 
> 2L, 19L, 200L, 5L, 18L, 350L, 5L, 14L, 2L, 13L, 9L, 11L, 18L, 
> 250L, 200L, 7L, 350L, 300L, 12L, 7L, 250L, 150L, 10L, 150L, 200L, 
> 350L, 200L, 7L, 50L, 14L, 16L, 350L, 150L, 250L, 18L, 9L, 350L, 
> 150L, 50L, 5L, 200L, 8L, 100L, 18L, 200L, 50L, 18L, 20L, 200L, 
> 14L, 19L, 3L, 4L, 17L, 5L, 300L, 12L, 5L, 8L, 17L, 18L, 3L, 30L, 
> 15L, 16L, 14L, 14L, 10L, 4L, 5L, 30L, 17L, 250L, 8L, 350L, 9L, 
> 200L, 20L, 17L, 2L, 7L, 4L, 5L, 150L, 2L, 5L, 100L, 17L, 8L, 
> 11L, 350L, 19L, 3L, 17L, 1L, 17L, 18L, 8L, 30L, 300L, 50L)), row.names = c(NA, 
> -200L), class = "data.frame")
> >

Hi @CatN welcome to the forums!

The code snippet you provided leads to the figure you posted, so far so good. What did you try to plot the mesh edges on top of your surface?

The showgrid from this snippet refers to the axis grids, just in case you thought that this parameter was for showing the mesh edges.

What they do in the SO post is that they put two scatter plots on top of the surface plot- the figure has a total of three traces.

Hi @AIMPED thank you for replying! I’ve tried many variations of things i’ve found online but they either produce a completely empty plot or exactly the same plot i alrady have. This is the one i thought most likely to work because it should be adding a mesh over the top of the surface (i think?). But the plot is exactly the same as the one in the pic - no contour lines on top.

# Response SSD surface (with grid on surface)
x <- plot_ly(PredDat, x = ~est, y = ~Day, z = ~percent,
             intensity = ~percent,
             colorscale = list(c(0,'green'),
                               c(0.05,'yellow'),
                               c(0.1, 'orange'),
                               c(1, 'red')),
             type = 'mesh3d')

x <- x %>% layout(scene = list(xaxis = list(type = "log", title = 'Concentration', showgrid = TRUE, gridcolor = "black"),
                               yaxis = list(title = 'Day', showgrid = TRUE, gridcolor = "black"),
                               zaxis = list(title = 'percent affected', showgrid = TRUE, gridcolor = "black")))

x <- x %>% add_trace(
  x = PredDat$est,
  y = PredDat$Day,
  z = rep(0, length(PredDat$Day)),
  type = "mesh3d",
  showscale = FALSE,
  opacity = 0)

x

I’m not familiar with R but it seems that you are adding two mesh3d traces to the figure.

What you will have to do is adding scatter plots.

Here a Python example:

import plotly.graph_objs as go
import numpy as np
import pandas as pd

# generate data
xx = np.arange(0, 2*np.pi, 0.4)
yy = np.arange(0, 5, 1)

# generate mesh
x, y = np.meshgrid(xx, yy)

# flatten x and y, create z coordinate
x=x.flatten()
y=y.flatten()
z = np.sin(x)

# create figure (mesh3d trace)
fig = go.Figure(
    data=go.Mesh3d(
        x=x,
        y=y,
        z=z,
        color='black',
        opacity=0.7
    ),
    layout={'width': 800, 'height':800}
)

# create scatter3d traces for the lines
for i in range(-1, 4):
    fig.add_trace(
        go.Scatter3d(
            x=xx, 
            y=np.ones_like(xx)*(i+1), 
            z=z, 
            mode='lines',
            line_width=5,
            line_color='white'
        )
    )
    
# create scatter3d traces for the lines
for i in range(0, 7):
    fig.add_trace(
        go.Scatter3d(
            x=np.ones_like(yy)*i, 
            y=yy, 
            z=np.ones(5)*np.sin(i), 
            mode='lines',
            line_width=5,
            line_color='red'
        )
    )
    
fig.show()


mrep 3D

2 Likes

thank you AIMPED for this solution @AIMPED!

1 Like