Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to have only every other border in a persp

Tags:

plot

r

3d

I would like to do the following

set.seed(1)
x <- seq(-10, 10, length= 600)
y <- x
f <- function(x, y) { r <- sqrt(x^2+y^2); 10 * sin(r)/r }
z <- outer(x, y, f)
persp(x, y, z, theta = 30, phi = 30, expand = 0.5, col = "lightblue")

But the grid is too thin so the border dominates (You can confirm it is indeed the border and not the lighting by using border = NA. It turns to blue):

enter image description here

One way to address this is of course to use not so fine of a grid (for example if you change length = 600 to length= 50 it looks very pleasant, and is actually the example in ?persp). But I want the same shape and smooth exactly as this fine grid. I just don't want to draw all of the borders, maybe only 1/5th of them for example (or half which I assume I can customize).

like image 634
Xu Wang Avatar asked Jul 23 '14 18:07

Xu Wang


3 Answers

An issue with plotting the smooth shape and then plotting a grid over top of it is that you can see through the shape to the grid on the other side. To address this, you can start by plotting the course grid on top of a white object, meaning you can't see the back side of the grid, saving the result to a file.

x <- seq(-10, 10, length=50)
y <- x
z <- outer(x, y, f)
png("top.png")
print(persp(x, y, z, theta = 30, phi = 30, expand = 0.5, border="black", col="white"))
dev.off()

enter image description here

Then, you can plot smoothed image followed by the grid with all white colors fully transparent.

x <- seq(-10, 10, length= 600)
y <- x
f <- function(x, y) { r <- sqrt(x^2+y^2); 10 * sin(r)/r }
z <- outer(x, y, f)
png("bottom.png")
print(persp(x, y, z, theta = 30, phi = 30, expand = 0.5, border="lightblue", col="lightblue"))
dev.off()

par(oma=c(0, 0, 0, 0), mar=c(0, 0, 0, 0))
library(png)
top.img <- readPNG("top.png")
top.img[,,4][top.img[,,1] + top.img[,,2] + top.img[,,3] > 2] <- 0

plot.new()
rasterImage(bottom.img, 0, 0, 1, 1)
rasterImage(top.img, 0, 0, 1, 1)

enter image description here

like image 184
josliber Avatar answered Oct 17 '22 07:10

josliber


I have got two solutions, but I think both of them are not exactly what you are searching for. I make a line overlay, but it doesn't get overlapped by the surface.

set.seed(1)
x <- seq(-10, 10, length= 600)
y <- x
f <- function(x, y) { r <- sqrt(x^2+y^2); 10 * sin(r)/r }
z <- outer(x, y, f)
persp(x, y, z, theta = 30, phi = 30, expand = 0.5, col = "lightblue", border=NA, shade=0.75,  ticktype = "detailed")

par(new=T)

set.seed(1)
x <- seq(-10, 10, length=20)
y <- x
f <- function(x, y) { r <- sqrt(x^2+y^2); 10 * sin(r)/r }
z <- outer(x, y, f)
persp(x, y, z, theta = 30, phi = 30, expand = 0.5, col = NA, border="green")

cornered line overlay

set.seed(1)
x <- seq(-10, 10, length= 600)
y <- x
f <- function(x, y) { r <- sqrt(x^2+y^2); 10 * sin(r)/r }
z <- outer(x, y, f)
res <- persp(x, y, z, theta = 30, phi = 30, expand = 0.5, col = "lightblue", border=NA, shade=0.75,  ticktype = "detailed")

library(grDevices)
xlines <- seq(1, length(x), length.out=20)
for(line in xlines){
  lines (trans3d(x=x[line], y = y, z = z[line, ], pmat = res), col = 3, lwd=2)
}

ylines <- seq(1, length(y), length.out=20)
for(line in ylines){
  lines (trans3d(x=x, y = y[line], z = z[,line], pmat = res), col = 3, lwd=2)
}

curved overlay

like image 21
nnn Avatar answered Oct 17 '22 06:10

nnn


Here are two approaches, neither of which are not ideal. You can use NAs to force transparent "lines" onto the surface (Approach 1) or use NAs to get rid of all but the "grid lines" (Approach 2)

Approach 1:

z2 <- z
lin.seq<- seq(10, 600, 10)
z2[lin.seq,] <- NA
z2[,lin.seq] <- NA
persp(x, y, z2, theta = 30, phi = 30, expand = 0.5,
      border=NA, col="lightblue", box=TRUE)

enter image description here

You can then overlay plot above on a solid black surface:

# using original example data
persp(x, y, z, theta = 30, phi = 30, expand = 0.5, col = "black", border=NA)

par(new=TRUE)
z2 <- z
lin.seq<- seq(10, 600, 10)
z2[lin.seq,] <- NA
z2[,lin.seq] <- NA
persp(x, y, z2, theta = 30, phi = 30, expand = 0.5,
      border=NA, col="lightblue", box=FALSE)

enter image description here

Approach 2:

# using original example data
persp(x, y, z, theta = 30, phi = 30, expand = 0.5, col = "lightblue", border=NA)

z3 <- matrix(ncol=600, nrow=600)               # NA matrix
lin.seq <- seq(25, 600, 25)                    # spacing of "grid lines"
lin.seq <- c(lin.seq, lin.seq-1, lin.seq-2)    # to make lines a bit thicker

# replace some NAs on "grid lines" with values from z.    
z3[lin.seq,] <- z[lin.seq,]
z3[,lin.seq] <- z[,lin.seq]

par(new=TRUE)
persp(x, y, z3, theta = 30, phi = 30, expand = 0.5,
      border=NA, col="black", box=FALSE)

enter image description here

like image 8
Jota Avatar answered Oct 17 '22 06:10

Jota