Use conditional paint on a flat surface

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

For example, I would like to use a surface from data(volcano)

as in

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

      

enter image description here

But instead of a color based on the z (height) value, let's say what I wanted to color based on the distance from my house on a small meza (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

      

What exactly returns:

enter image description here

The desired result would be to dye the landscape tan around the home and fade to blue in areas further away from the home.

A somewhat related question uses code mesh3d

found elsewhere and does not explain how to compute (i, j, k)

+3


source to share


2 answers


Your code is pretty much all you need, just use a graph surface

and use your distance array like 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

+3


source


In addition to the graph surface

(see the accepted answer) we can also make the graph mesh3d

and avoid the rearrangement step (back to grid) that the graph requires.

However, the scale is still incorrect (range is shown 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=

, not color=

, which appears to be driving the conditional coloring.

enter image description here

I initially avoided mesh3d

it because I thought I needed to create a triangular mesh (something or something else) and had no idea how to do it, but in this case it is automatically handled.

0


source







All Articles