【发布时间】:2018-09-06 19:55:10
【问题描述】:
我有一个函数r(x),我想围绕x 轴旋转以获得一个solid of revolution,我想使用add_surface 将其添加到现有的plot_ly 图中(由x 着色) .
这是一个例子:
library(dplyr)
library(plotly)
# radius depends on x
r <- function(x) x^2
# interval of interest
int <- c(1, 3)
# number of points along the x-axis
nx <- 20
# number of points along the rotation
ntheta <- 36
# set x points and get corresponding radii
coords <- data_frame(x = seq(int[1], int[2], length.out = nx), r = r(x))
# for each x: rotate r to get y and z coordinates
# edit: ensure 0 and pi are both amongst the angles used
coords %<>%
rowwise() %>%
do(data_frame(x = .$x, r = .$r,
theta = seq(0, pi, length.out = ntheta / 2 + 1) %>%
c(pi + .[-c(1, length(.))]))) %>%
ungroup %>%
mutate(y = r * cos(theta), z = r * sin(theta))
# plot points to make sure the coordinates define the desired shape
coords %>%
plot_ly(x = ~x, y = ~y, z = ~z, color = ~x) %>%
add_markers()
如何将上述点指示的形状生成为plotly 表面(理想情况下两端都是开放的)?
编辑(1):
这是我迄今为止最好的尝试:
# get all x & y values used (sort to connect halves on the side)
xs <-
unique(coords$x) %>%
sort
ys <-
unique(coords$y) %>%
sort
# for each possible x/y pair: get z^2 value
coords <-
expand.grid(x = xs, y = ys) %>%
as_data_frame %>%
mutate(r = r(x), z2 = r^2 - y^2)
# format z coordinates above x/y plane as matrix where columns
# represent x and rows y
zs <- matrix(sqrt(coords$z2), ncol = length(xs), byrow = TRUE)
# format x coordiantes as matrix as above (for color gradient)
gradient <-
rep(xs, length(ys)) %>%
matrix(ncol = length(xs), byrow = TRUE)
# plot upper half of shape as surface
p <- plot_ly(x = xs, y = ys, z = zs, surfacecolor = gradient,
type = "surface", colorbar = list(title = 'x'))
# plot lower have of shape as second surface
p %>%
add_surface(z = -zs, showscale = FALSE)
虽然这给出了所需的形状,
- 它在
x/y平面附近有“锋利的牙齿”。 -
半部分不接触。(通过在theta向量中包含0和pi解决) -
我不知道如何用(由x代替z给它上色(尽管到目前为止我并没有对此进行过多研究)。gradient矩阵解决)
编辑(2):
这是使用单个表面的尝试:
# close circle in y-direction
ys <- c(ys, rev(ys), ys[1])
# get corresponding z-values
zs <- rbind(zs, -zs[nrow(zs):1, ], zs[1, ])
# as above, but for color gradient
gradient <-
rbind(gradient, gradient[nrow(gradient):1, ], gradient[1, ])
# plot single surface
plot_ly(x = xs, y = ys, z = zs, surfacecolor = gradient,
type = "surface", colorbar = list(title = 'x'))
令人惊讶的是,虽然这应该连接与x / y 平面正交的两半以创建完整的形状,
它仍然遭受与上述解决方案相同的“剃刀齿”效果:
编辑(3):
原来缺少部分是由于z-values 在接近 0 时为 NaN:
# color points 'outside' the solid purple
gradient[is.nan(zs)] <- -1
# show those previously hidden points
zs[is.nan(zs)] <- 0
# plot exactly as before
plot_ly(x = xs, y = ys, z = zs, surfacecolor = gradient,
type = "surface", colorbar = list(title = 'x'))
这可能是由于 r^2 和 y 太接近时减法的数值不稳定导致的,导致 sqrt 的负输入,而实际输入仍然是非负的。
这与数值问题无关,因为即使考虑到 +-4“接近”为零,也无法完全避免“剃刀齿”效应:
# re-calculate z-values rounding to zero if 'close'
eps <- 4
zs <- with(coords, ifelse(abs(z2) < eps, 0, sqrt(z2))) %>%
matrix(ncol = length(xs), byrow = TRUE) %>%
rbind(-.[nrow(.):1, ], .[1, ])
# plot exactly as before
plot_ly(x = xs, y = ys, z = zs, surfacecolor = gradient,
type = "surface", colorbar = list(title = 'x'))
【问题讨论】:
-
有趣的是,我可以“看到”所有这些图表直到我将 Chrome 设置为同时启用 webGL 和硬件加速。现在我看不到他们了。但我现在可以在代码生成的浏览器页面上看到示例。非常可能的 kewl 旋转效果。去搞清楚! (在具有相当古老硬件的 Mac El Cap 上。显然允许硬件加速会破坏这些 png 的显示。)