在Plotly表面上使用条件着色

4

我是第一次使用R中的Plotly,并且尝试从网格创建一个表面,并根据计算结果进行着色。

例如,我想使用data(volcano)中的表面,如下所示:

library(plotly)
plot_ly(z = ~volcano) %>% add_surface()

enter image description here

但是,如果不是基于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

只返回如下结果:

enter image description here

期望的结果是在房子周围的地区将景观涂成棕色,并逐渐向远离房子的地区褪色为蓝色。

一个有关问题的相关问题使用了从其他地方找到的mesh3d代码,但没有解释如何计算(i, j, k)。

2个回答

4

你的代码几乎包含了所有你需要的东西,只需使用一个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'))

enter image description here


谢谢你提醒我关于颜色的问题!我已经把它加到答案里了。 - Maximilian Peters
嗨,我一直在尝试做类似的事情,这是我目前离解决方案最接近的地方,但它在我的实现中仍然不起作用。我正在尝试将一个颜色矩阵映射到一个FLAT的3D表面上(即一个平面板,本质上是一个浮在3D平面中的2D热图)。一旦我使用一个所有z矩阵为1的代码与可变颜色矩阵作为表面颜色,我就得到了一个单一颜色的表面。你有什么想法我做错了什么? - renegademonkey
@renegademonkey:请将您的代码作为单独的问题发布,我相信会有人可以帮助您。 - Maximilian Peters

0
除了表面图(参见接受的答案)之外,我们还可以进行mesh3d绘图,并避免plot需要的重塑(返回网格)步骤。
然而,比例尺仍然不正确(显示z的范围,而不是d_rel)。
plot_ly(df,
        type='mesh3d',
        x = ~x,
        y = ~y,
        z = ~z,
        intensity=~d_rel,
        colors = colorRamp(c("tan", "blue"))
    )

有点出乎意料的是,似乎控制条件着色的是 intensity= 而不是 color=

enter image description here

我最初避免使用mesh3d,因为我认为我必须创建一个三角形网格(Delaunay什么的),而我不知道如何做,但在这种情况下似乎自动处理。


如果有人知道如何修复比例尺,请在评论或回答中提出。 - C8H10N4O2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接