Use conditional coloring on a plotly surface

烈酒焚心 提交于 2019-12-10 21:53:26

问题


I am using plotly via R for the first time and trying to create a surface from a grid and color it based on a calculation.

For example, I would like to use the surface from data(volcano), as in

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

But instead of color based on the z-value (altitude), let's just say I wanted to color based on distance from my house on the little mesa at (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 ))})

So far I have tried:

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

Which just returns:

The desired result would color the landscape tan in the region of the house and gradually fade to blue in the regions far from the house.

Somewhat related question uses mesh3d code found elsewhere and doesn't explain how to calculate (i, j, k)


回答1:


Your code virtually has everything you need, just use a surface plot and use your distance array as the 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'))




回答2:


In addition to the surface plot (see accepted answer) we can also do a mesh3d plot and avoid the reshaping (back to grid) step that plot requires.

However, the scale bar still isn't right (showing range of z, not d_rel)

plot_ly(df,
        type='mesh3d',
        x = ~x,
        y = ~y,
        z = ~z,
        intensity=~d_rel,
        colors = colorRamp(c("tan", "blue"))
    )

Counter-intuitively, it is intensity= and not color= which seems to control the conditional coloring.

I originally avoided mesh3d because I thought I had to create a triangular mesh (Delaunay something or another) and had no idea how to do that, but it seems to be handled automatically in this case.



来源:https://stackoverflow.com/questions/42963243/use-conditional-coloring-on-a-plotly-surface

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!