2

I'm trying to add a grid on top of a 3D surface created with persp3D (package plot3D), however I can't sort a way of doing it without causing a deformation on the grid.

library(plot3D)
data("volcano")

volcano is a 3D matrix that can be used to create a 3D plot by simply calling:

persp3D(z=volcano)

What I intend to do is create a new grid using the dimensions of the 3D matrix and than add it to the 3D plot.

# new grid
x.seq <- seq(1, dim(volcano)[1], length = 20)
y.seq <- seq(1, dim(volcano)[2], length = 20)

# Visualize grid
plot(x=c(0,length(volcano[,1])), y=c(0,length(volcano[1,])), type='n')
abline(v=x.seq, h=y.seq)

I got close to it by subsetting the matrix volcano by the new sequences created and then plot the new 3D matrix over the original 3D surface.

# New matrix using sequences created
mtx.sub <- volcano[time.seq, freq.seq]

# Plot new matrix on top of original surface
persp3D(z=volcano)
persp3D(z=amp.sub, border="black", facets=NA, add=T, colkey=list(plot=F))

3D plot with overlaid grid

Even though the result is close to what I expected, a closer look will show that the grid is not really on top of the existing surface, it is a whole new surface that do not match the original one (which is quite obvious, given that it is a different matrix).

What I'm looking for is a way to add a 2D grid that will go over the original surface, something similar to abline, but for a 3D plot.

I had a look at plot3D documentation and searched on the web, but none of the solutions apply to persp3D().

Any thoughts on a way around this?

Ian Campbell
  • 23,484
  • 14
  • 36
  • 57
Pedro Rocha
  • 79
  • 1
  • 10

2 Answers2

2

You can add the grid directly within the call to persp3D:

persp3D(z=volcano, border="black", lwd=0.3)

enter image description here

In response to your comment, you could plot at lower resolution to get wider borders, however, the surface will also be at lower resolution (see below). It would be nice to be able to plot the surface at full resolution and then have a sparser net of border lines that still matches the high-resolution surface, for example, by plotting the border lines only on every other facet, but I'm not sure how to do that without hacking persp3D (or one of the functions called by persp3D).

persp3D(z=volcano[seq(1,nrow(volcano),2), seq(1,ncol(volcano),2)], 
        border="black", lwd=0.4)

enter image description here

eipi10
  • 91,525
  • 24
  • 209
  • 285
  • Yes, but that is the grid from the original matrix. I'm looking for a way to plot a subsetted grid, with "larger" cells – Pedro Rocha Feb 02 '18 at 20:08
0

A work around is to use ribbon3D. It requires some more lines of code and messing around with parameters, but it does work reasonable.

example

require(plot3D)

### create data from 3D plotting
###
### x1, x2 a grid
### x the value of a normal distribution
x1 <- seq(-4,4,0.025)
x2 <- seq(-4,4,0.025)
mu = 0
z <- matrix(rep(0,length(x1)*length(x2)),length(x1))
for (i in 1:length(x1)) {
  for(j in 1:length(x2)) {
    z[i,j] <- dnorm(x1[i],mu,1)*dnorm(x2[j],mu,1)
  }
}

### plot 3D
sel = 1+c(1:32)*10  ### selection of the grid lines to plot
persp3D(x1,x2,z, 
        border = NA, facets = TRUE, col = rgb(1,1,1,0.5), 
        theta = 30, phi = 30, 
        zlim = c(0,0.26))
ribbon3D(x1[sel],x2,z[sel,], 
         border = NA, facets  = NA, col = 1, width = 0.02,
         along = "y", space = 0.9, add = TRUE)
ribbon3D(x1[],x2[sel],z[,sel], 
         border = NA, facets  = NA, col = 1, width = 0.02,
         along = "x", space = 0.9, add = TRUE)

Example with the volcano data

example with volcano

require(plot3D)

### create data from 3D plotting
x <- 1:length(volcano[,1])
y <- 1:length(volcano[1,])
z <- volcano

### plot 3D
selx = seq(1,max(x),4)
sely = seq(1,max(y),4)
persp3D(x,y,z, 
        border = NA, facets = TRUE, lwd = 0.03,
        theta = 30, phi = 30)
ribbon3D(x[selx],y,z[selx,], 
         border = 1, facets  = 1, col = 1, width = 0.1,
         along = "y", space = 0.9, add = TRUE)
ribbon3D(x[],y[sely],z[,sely], 
         border = 1, facets  = 1, col = 1, width = 0.1,
         along = "x", space = 0.9, add = TRUE)