Question: I am working with the R programming language. I found this tutorial/website over here that shows how to fill the volume under the surface in Python/Plotly (https://community.plotly.com/t/fill-volume-under-the-surface/64944/2): import numpy as np import plotly.express as px import plotly.graph_objects as go f = lambda x,y: np.cos(x)+np.sin(y)+4 #surface x, y = np.meshgrid( np.linspace(-5, 5, 100), np.linspace(-5, 5, 100) ) z = f(x,y) #patch of surface lower_x, upper_x = -1, 2 lower_y, upper_y = -2, 4 int_x, int_y = np.meshgrid( np.linspace(lower_x, upper_x, 50), np.linspace(lower_y, upper_y, 70) ) int_z = f(int_x,int_y) fig= go.Figure() fig.add_surface(x=x[0], y=y[:, 0], z=z, showscale=False, colorscale=px.colors.sequential.Pinkyl, opacity=0.6) fig.add_surface(x=int_x[0],y=int_y[:, 0],z=int_z, showscale=False, colorscale=px.colors.sequential.Agsunset, opacity=1) lower_z= 0 upper_z= int_z.max() X, Y, Z = np.mgrid[lower_x:upper_x:50j, lower_y:upper_y:50j, lower_z:upper_z:75j] vals = Z-f(X,Y) fig.add_volume(x=X.flatten(), y=Y.flatten(), z=Z.flatten(), value= vals.flatten(), surface_show=True, surface_count=2, colorscale=[[0, px.colors.sequential.Agsunset[4]],[1.0, px.colors.sequential.Agsunset[4]]], showscale=False, isomin=-upper_z, isomax=0) #isomin=-upper_z corresponds to z=f(x,y)-upper_z, and isomax=0, to z=f(x,y) fig.update_layout(height=600, width=600, scene_zaxis_range=[0, upper_z+0.5], scene_camera_eye=dict(x=1.85, y=1.85, z=0.7))  My Question: I am trying to replicate this code in R. Doing some research into this, I noticed that Plotly within R does not have an add_volume() function as in Python. I tried to attempt to work around this and find a new way to do this: Attempt 1: library(plotly) f <- function(x, y) { cos(x) + sin(y) + 4 } # Surface x <- seq(-5, 5, length.out = 100) y <- seq(-5, 5, length.out = 100) z <- outer(x, y, f) # Patch of surface lower_x <- -1 upper_x <- 2 lower_y <- -2 upper_y <- 4 int_x <- seq(lower_x, upper_x, length.out = 50) int_y <- seq(lower_y, upper_y, length.out = 70) int_z <- outer(int_x, int_y, f) fig <- plot_ly() %>% add_surface(x = ~x, y = ~y, z = ~z, showscale = FALSE, opacity = 0.6, colors = c('#e31a1c', '#fb9a99')) %>% add_surface(x = ~int_x, y = ~int_y, z = ~int_z, showscale = FALSE, opacity = 1, colors = c('#a6cee3', '#1f78b4')) fig <- layout(fig, scene = list(zaxis = list(range = c(0, max(int_z) + 0.5)), camera = list(eye = list(x = 1.85, y = 1.85, z = 0.7)))) fig   Attempt 2: Identify the Area library(plotly) f <- function(x, y) { cos(x) + sin(y) + 2 } # surface x <- seq(-5, 5, length.out = 200) y <- seq(-5, 5, length.out = 200) z <- outer(x, y, f) # patch of surface lower_x <- -1 upper_x <- 2 lower_y <- -2 upper_y <- 4 int_x <- seq(lower_x, upper_x, length.out = 200) int_y <- seq(lower_y, upper_y, length.out = 200) int_z <- outer(int_x, int_y, f) fig <- plot_ly(x = ~x, y = ~y, z = ~z, type = "surface", showscale = FALSE, opacity = 0.4) %>% add_surface(x = ~int_x, y = ~int_y, z = ~int_z, showscale = FALSE, opacity = 1) %>% layout(showlegend = FALSE) fig   But so far, I can't get anything to work. Can someone please show me how to do this? Thanks!

Answer: You can add a volume trace using add_trace(type = "volume"). The input is different from the surface plot though. You need a regular 3D grid of points given as vectors of x, y and z co-ordinates, such as you might create with expand.grid in R. Each of these points must also have a value. Only values above the isomin argument and below the isomax argument get filled. To fill a volume within an enclosed surface, you can simply calculate whether each 3D gridpoint should be filled or not. Taking your own example, the set-up would be: f <- function(x, y) cos(x) + sin(y) + 2 x <- y <- seq(-5, 5, length.out = 200) z <- outer(x, y, f) xmin <- -1 xmax <- 2 ymin <- -2 ymax <- 4 volume_df <- expand.grid(x = seq(xmin, xmax, length.out = 20 * (xmax - xmin)), y = seq(ymin, ymax, length.out = 20 * (ymax - ymin)), z = seq(0, 4, length.out = 80)) volume_df$value <- with(volume_df, ifelse(z > f(x, y), 0, 1))  The plotting code is then straightforward: library(plotly) plot_ly(showscale = FALSE) %>% add_surface(x = x, y = y, z = z, opacity = 0.4) %>% add_trace(type = "volume", data = volume_df, x = ~x, y = ~y, z = ~z, value = ~value, opacity = 0.2, isomin = 0.5, colorscale = list(c(0, 1), c("red", "red")))