Search code examples
r3drgl

Plot vertical surface below function


I'm trying to create a very simple 3D plot using the rgl package: I have a function that just maps x values into y values. For a given z (in my example: z = 1), I can plot this function in a 3D plot:

library(rgl)

mycurve <- function(x) { return (1/x)}
myx <- seq(1, 10, by = 0.1)

plot3d(x = NA, xlim = c(0, 10), ylim = c(0, 10), zlim = c(0, 5), 
       xlab = "x", ylab = "y", zlab = "height")
lines3d(x = myx, y = mycurve(myx), z = 1)

2D line in 3D plot

However, even after hours of trying to understand the documentation of ?persp3d and ?surface3d, I still have no idea how to add a surface to my plot that "connects" my line to the x-y plane – like this:

Space curve.

(To generate this image, I cheated by plotting many lines: for (i in seq(0, 1, by = 0.01)) { lines3d(x = myx, y = mycurve(myx), z = i) }.)

I suppose that I need to supply the correct values to surface3d somehow. From ?surface3d:

The surface is defined by the matrix of height values in z, with rows corresponding to the values in x and columns corresponding to the values in y.

Given that my space curve is "vertical", each value of x corresponds to only 1 value of y. Still, I need to specify two z values for each xy pair, which is why I do not know how to proceed.

How can I plot a space curve as shown in the second image?


Solution

  • In persp3d, all 3 arguments can be matrices, so you can plot arbitrary surfaces. For your needs, this works:

    mycurve <- function(x) { return (1/x)}
    myx <- seq(1, 10, by = 0.1)
    
    
    xmat <- matrix(NA, 2, length(myx))
    ymat <- matrix(NA, 2, length(myx))
    zmat <- matrix(NA, 2, length(myx))
    for (i in 0:1) { 
      xmat[i+1,] <- myx
      ymat[i+1,] <- mycurve(myx)
      zmat[i+1,] <- i
    }
    library(rgl)
    persp3d(x = xmat, y = ymat, z = zmat, xlim = c(0, 10), ylim = c(0, 10), zlim = c(0, 5), 
           xlab = "x", ylab = "y", zlab = "height", col = "gray")
    

    The image produced looks like this:

    enter image description here

    If you want z to depend on x or y, you'll likely want a smaller step size, but this works for the surface you're after.