0

I am working with the R programming language. I have the following function :

#function

my_function_b <- function(input_1, input_2, input_3, input_4) {

final_value = sin(input_1) + cos(input_2) + input_3 + input_4
 
}

Question:

  • For "my_function_b", I am trying to evaluate "final_value" for different values of "input_1", "input_2", "input_3" and "input_4" . E.g. input_1, input_2, input_3, input_4 from 1 to 100 at increments of 0.1.

  • Then, I want to make a 3 Dimensional plot with "input_1", "input_2" and "input_3".

  • Next, I want to a fit a 3 Dimensional surface over this plot

  • Finally, I want to "color" this 3 Dimensional surface according to the values of "final_input"

What I tried so far:

I figured out how to make a "grid frame" for the second function and then evaluate "final_value" using this "grid frame", e.g.

#create grid and evaluate function
input_1 <- seq(0,100,0.1)
input_2 <- seq(0,100,0.1)
input_3 <- seq(0,100,0.1)
input_4 <- seq(0,100,0.1)

my_grid <- data.frame(input_1, input_2, input_3, input_4)
my_grid$final_value = sin(input_1) + cos(input_2) + input_3 + input_4

But I am not sure if this is the best way to solve this question. This is now creating problems when I try to plot the results, e.g.

#make a 3d plot for two of the inputs and the output, and fit surface over the plot

persp(my_grid$input_1, my_grid$input_2, my_grid$final_value)

Error in persp.default(my_grid$input_1, my_grid$input_2, my_grid$final_value) : 
  invalid 'z' argument

Alternative #2: Does Not Work

library(plotly)

a = my_grid[,c(1,2,5)]
fig <- plot_ly(a = ~as.matrix(a))
fig <- fig %>% add_surface()

Error: Must supply `z` attribute

Alternative #3 : Does Not Work - Creates an Empty Plot

plot_ly() %>% 
    add_trace(data = my_grid,  x=my_grid$input_1, y=my_grid$input_2, z=my_grid$final_value, type="mesh3d" ) 

Problem: Can someone please show me how to do this? Can this be done using the "lattice" or "rsm" libraries? Or can it be done using the ways I suggested?

Thanks

stats_noob
  • 5,401
  • 4
  • 27
  • 83

1 Answers1

1

If you want to get your plotly approach going, you need to configure your z as a matrix, i.e. an object with defined row and col dimensions!

Plotly does not require a dataframe. You can safely supply the variables (objects) directly.

library(plotly)

x <- my_grid$input_1
y <- my_grid$input_2
z <- matrix(my_grid$final_value, nrow = length(x), ncol = length(y)) # proper matrix & dimensions

plot_ly(x = x, y = y, z = z) %>% add_surface()

and voila:

enter image description here

amended answer based on question in comment - how to set on colorscale

This is a bit hidden in the documentation. In principle, you can define your own colorscale with endpoints/colours for the gradient you prefer, and ensure it is scaled in accordance with your surface data. Surface data must be again a well-defined matrix, i.e. having nrow/ncol dimensions check this SO post.

Typically, a colorscale is defined for the interval c(0,1). The plotly documentation speaks about a mapping for the lowest (0) and highest (1) values. The 2nd element of colorscale is the definition of the spectrum end-colours! As an alternative, you use one of the accepted colour palettes.
This SO post provides an example:

colorscale = list(c(0, 1), c("tan", "blue"))     

So for the mapping you can use your min and max values.

# --- define coordinate vectors
x = input_1
y = input_2
z = matrix(input_3, nrow = length(x), ncol = length(y)) # z must be well-dimensioned matrix

# --- define a scale for your colour setting
my_colorscale = list(
    c(min(final_value),max(final_value))    # set min/max value, or use c(0,1)
  , c("tan", "blue")                        # define desired grad. colours
)

# --- plot
plot_ly(x = x, y = y, z = z) %>% 
   add_surface(
       surfacecolor = matrix(final_value, nrow = length(x), ncol = length(y))   # your surface data points 
      ,colorscale = my_colorscale)    # scale for your surface 

enter image description here

Ray
  • 2,008
  • 14
  • 21
  • Thank you for your answer! Is it possible to make the color of the surface represent "final_value"? I.e. a surface between "input_1", "input_2", input_3"....and the color according to "final_value"? thank you so much for all your help! – stats_noob Jul 24 '21 at 19:59
  • @Noob I amended my answer for setting the surface points and colorscale. Keep on rocking! – Ray Jul 26 '21 at 07:18
  • Thank you so much for your answer! I was able to figure out another way of doing some slightly different! – stats_noob Jul 26 '21 at 18:47
  • X <- seq(0,100,1); Y <- seq(0,100,1); DF <- expand.grid(X,Y); DF$Z <- sin(DF$Var1) + cos(DF$Var2); Z <- matrix(DF$Z, nrow = 100); plot_ly(y = ~Y, x = ~X, z=~Z) %>% add_surface() – stats_noob Jul 26 '21 at 18:48
  • excellent. as mentioned, you do not need to work with data frames with plotly, but you can. Just make sure to use the "tilde" notation when you do. It cost me hours of my life chasing errors ... :). .... The important thing to keep in mind that you have to well-format your z-variable as a matrix with clear dimensions. Here your nrow is sufficient. Well spotted, Noob. – Ray Jul 27 '21 at 17:09