我第一次通过R使用plotly并尝试从网格创建表面并根据计算对其进行着色。
例如,我想使用data(volcano)
中的曲面,如
library(plotly)
plot_ly(z = ~volcano) %>% add_surface()
但是不是基于z值(海拔高度)的颜色,我只想说我想根据我家在(20,60)的小台面上的距离进行着色。
house_loc <- c(20,60,150) # (x,y,z) of my house
dist_to_house <- Vectorize(function(x,y,z){sqrt(sum( (c(x,y,z)-house_loc)^2 ))})
到目前为止,我已经尝试过:
color_me <-function(x){
colorRampPalette(c('tan','blue')
)(24L)[findInterval(x,seq(0,1,length.out=25),
all.inside=TRUE)]
}
library(dplyr)
library(reshape2)
volcano %>%
melt( varnames=c('y','x'),value.name='z' ) %>%
mutate( d = dist_to_house(x, y, z) ,
d_rel = d/max(d),
d_color = color_me(d_rel)
) -> df
plot_ly(df,
type='scatter3d',
mode='none', # no markers, just surface
x=~x,
y=~y,
z=~z,
surfaceaxis=2,
surfacecolor=~d_color) # last argument seems not to work
刚刚回归:
期望的结果将使房屋区域的景观变成棕褐色,并在远离房屋的区域逐渐淡化为蓝色。
有些related question使用其他地方找到的mesh3d
代码,但没有解释如何计算(i,j,k)
答案 0 :(得分:3)
您的代码几乎拥有您需要的一切,只需使用surface
绘图并将距离数组用作color
。
library(plotly)
library(dplyr)
library(reshape2)
house_loc <- c(20,60,150)
dist_to_house <- Vectorize(function(x,y,z){sqrt(sum( (c(x,y,z)-house_loc)^2 ))})
volcano %>%
melt( varnames=c('y','x'),value.name='z' ) %>%
mutate( d = dist_to_house(x, y, z) ,
d_rel = d/max(d)
) -> df
color <- df$d_rel
dim(color) <- dim(volcano)
plot_ly(df,
type='surface',
z=volcano,
surfacecolor=color,
colors=c('tan','blue'))
答案 1 :(得分:0)
除了surface
情节(参见接受的答案)之外,我们还可以制作mesh3d
情节并避免情节所需的重塑(回到网格)步骤。
但是,比例尺仍然不对(显示z
的范围,而不是d_rel
)
plot_ly(df,
type='mesh3d',
x = ~x,
y = ~y,
z = ~z,
intensity=~d_rel,
colors = colorRamp(c("tan", "blue"))
)
与直觉相反,intensity=
而非color=
似乎控制了条件着色。
我最初避免mesh3d
,因为我认为我必须创建一个三角形网格(Delaunay或其他东西)并且不知道如何做到这一点,但在这种情况下似乎会自动处理。