R 中的函数 - 使用 eval() 和 parse() 绘制 rgl 中的表达式

Functions in R - using eval() and parse() to plot expressions in rgl

我是 R 的新手。我正在尝试创建一个函数,用户可以在其中将表达式输入参数。然后通过 rgl 包在 plot3d 中使用这些输入。我到目前为止的功能是:

flight_sim <- function(xval, yval, zval)
{
# Evaluate arguments and convert them into expressions 
eval(parse(text = zval))
z <- data.frame(zval)
eval(parse(text = xval))
x <- data.frame(xval)
eval(parse(text = yval))
y <- data.frame(yval)
flight_path <- as.data.frame(cbind(x,y,z))
}

我有一个 readline() 和 switch() 命令:

cat('Select the flight path you wish to plot from the list below : 
1. Helix
2. Conical
3. Spherical
4. Define your own flight path...')

userplot <- readline('Enter number here : ') # Allow user to enter choice from above

switch(userplot,"1"=flight_sim( sin(z), 1-cos(z), seq(0,20, pi/32) ),
                "2"=flight_sim( z*cos(6*z), z*sin(6*z), seq(0,10, pi/64) ),
                "3"=flight_sim( sin(z)*cos(20*z), sin(z)*sin(20*z), seq(0,pi,pi/399)), 
                "4"=custom())

其中 custom() 只是通过 readline() 提示用户输入 x、y 和 z 值,然后是 eval() 和 parse(),它工作正常。

我一直遇到的问题是 x 和 y 需要是 z 的函数,这会导致错误:

Error in parse(text = xval) : object 'z' not found

我想通过让 flight_sim 函数首先评估 zval 参数来修复它,但是因为我是 R 的新手,所以我越来越迷路了。

我希望我在这里的解释有些道理。我很感激能提供的任何帮助。

如果我正确地解释了你的问题,那么你似乎需要重新定义你的函数。据我所知,您不能将函数定义中的参数定义为另一个参数的函数。您需要在函数体内执行此操作。所以你想要这样的东西:

flight_sim <- function(userplot) {
  if (userplot == "1") {
    z <- seq(0, 20, pi / 32)
    x <- sin(z)
    y <- 1 - cos(z)
  } else if (userplot == "2") {
    z <- seq(0, 10, pi / 64)
    x <- z * cos(6 * z)
    y <- z * sin(6 * z)
  } else if (userplot == "3") {
    z <- seq(0, pi, pi / 399)
    x <- sin(z) * cos(20 * z)
    y <- sin(z) * sin(20 * z)
  } else if (userplot == "4") {
    x <- readline("Please enter a function for the x-value: ")
    y <- readline("Please enter a function for the y-value: ")
    z <- readline("Please enter a function for the z-value: ")
    eval(parse(text = z)) # have to evaluate z first since x and y are functions of z
    eval(parse(text = x))
    eval(parse(text = y))
  } else {
    valid_response <- FALSE
    while (!valid_response) {
      userplot <- readline("Please enter a valid response (1-4): ")
      if (userplot %in% 1:4) {
        valid_response <- TRUE
        flight_sim(userplot)
      }
    }
  }
  dat <- data.frame(x, y, z)
  return(dat)
}

cat('Select the flight path you wish to plot from the list below : 
1. Helix
    2. Conical
    3. Spherical
    4. Define your own flight path...')

userplot <- readline('Enter number here : ') # Allow user to enter choice from above

dat <- flight_sim(userplot)

head(dat)
                     x                    y                    z
1 0.000000000000000000 0.000000000000000000 0.000000000000000000
2 0.046973698885313400 0.014249315773629733 0.049087385212340517
3 0.081629338302900922 0.054542980081485989 0.098174770424681035
4 0.093422122547587999 0.113835185692147969 0.147262155637021552
5 0.075139716235543288 0.181403322008714424 0.196349540849362070
6 0.024057025623845932 0.244255080177979672 0.245436926061702587

在上面的代码中,我还添加了最后一个 else 语句来捕获用户的不当响应。如果他们输入的选择可能会破坏您的密码,它现在会捕捉到并要求他们重新输入他们的回复。

在您的示例中没有任何内容作为文本传递,因此似乎没有必要使用 parse()。如果你想延迟评估,最好的方法是使用 substitute 获取参数作为承诺,然后在你的 fliht_sim 函数的上下文中评估它们。这就是它的样子

flight_sim <- function(xval, yval, zval) {
    z <- eval(substitute(zval))
    x <- eval(substitute(xval))
    y <- eval(substitute(yval))
    data.frame(x,y,z)
}


userplot="2"

x <- switch(userplot,"1"=flight_sim( sin(z), 1-cos(z), seq(0,20, pi/32) ),
                "2"=flight_sim( z*cos(6*z), z*sin(6*z), seq(0,10, pi/64) ),
                "3"=flight_sim( sin(z)*cos(20*z), sin(z)*sin(20*z), seq(0,pi,pi/399)), 
                "4"=custom())
head(x)
#            x          y          z
# 1 0.00000000 0.00000000 0.00000000
# 2 0.04697370 0.01424932 0.04908739
# 3 0.08162934 0.05454298 0.09817477
# 4 0.09342212 0.11383519 0.14726216
# 5 0.07513972 0.18140332 0.19634954
# 6 0.02405703 0.24425508 0.24543693