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

时间:2015-10-21 13:32:37

标签: r function eval readline 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的新手,我越来越迷失。

我希望我在这里解释的内容是有道理的。我感谢您提供的任何帮助。

2 个答案:

答案 0 :(得分:2)

在您的示例中没有任何内容作为文本传递,因此使用parse()似乎没有必要。如果您想延迟评估,最好的方法是使用substitute将参数作为promises获取,然后在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

答案 1 :(得分:0)

如果我正确地解释您的问题,您似乎需要重新定义您的功能。据我所知,您不能将函数定义中的参数定义为另一个参数的函数。你需要在函数体内做到这一点。所以你想要这样的东西:

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语句,用于捕获用户的不当回复。如果他们输入的选项可能会破坏您的代码,它现在会抓住它并要求他们重新输入他们的响应。