I am trying to add a horizontal reference plane to a 3D surface plot using R's persp() function, but the plane acts as an opaque layer that cover the surface beneath it.
I want the plane to be transparent so that parts of the surface above the plane are clearly above it, and parts below are visibly below it.
Here's a minimal reproducible example:
# Create a simple 3D surface
x <- seq(-2, 2, length.out = 30)
y <- seq(-2, 2, length.out = 30)
z <- outer(x, y, function(x, y) {
exp(-(x^2 + y^2)) + 0.5 * sin(2 * x) * cos(2 * y)
})
# Create perspective plot
p <- persp(x, y, z,
xlab = "X", ylab = "Y", zlab = "Z",
theta = 35, phi = 25,
col = "lightblue", shade = 0.5,
main = "Surface with reference plane at z=0.5")
# Add horizontal plane at z = 0.5
z_plane <- 0.5
x_corners <- c(min(x), max(x), max(x), min(x))
y_corners <- c(min(y), min(y), max(y), max(y))
z_corners <- rep(z_plane, 4)
# Convert to 2D projection and draw polygon
corners_2d <- trans3d(x_corners, y_corners, z_corners, pmat = p)
polygon(corners_2d, col = rgb(1, 0, 0, 0.3), border = "red")
The problem: the red plane covers the entire blue surface beneath it.
I want the surface to be visible both above and below the plane, with the plane acting as a transparent reference. In other words, the 3D surface should appear to pass through the reference plane, with portions above z=0.5 clearly above the plane and portions below clearly below it.
Is there a way to achieve this?
Use rgl. For example,
# Create a simple 3D surface
x <- seq(-2, 2, length.out = 30)
y <- seq(-2, 2, length.out = 30)
z <- outer(x, y, function(x, y) {
exp(-(x^2 + y^2)) + 0.5 * sin(2 * x) * cos(2 * y)
})
library(rgl)
# Create perspective plot
p <- persp3d(x, y, z,
xlab = "X", ylab = "Y", zlab = "Z",
theta = 35, phi = 25,
col = "lightblue", shade = 0.5,
main = "Surface with reference plane at z=0.5")
# Add horizontal plane at z = 0.5
planes3d(0, 0, 1, -0.5, col = rgb(1, 0, 0), alpha = 0.3)

Created on 2025-10-24 with reprex v2.1.1