【问题标题】:Function that returns an aesthetic mapping返回美学映射的函数
【发布时间】:2013-01-16 07:49:47
【问题描述】:

我想创建一个“就像”ggplot2aes() 函数一样工作的函数。我卑微的尝试以“找不到对象”错误而失败:

library(ggplot2)

data <- data.frame(a=1:5, b=1:5)

# Works
ggplot(data) + geom_point() + aes(x=a, y=b)

my.aes <- function(x, y) { aes(x=x, y=y) }
# Fails with "Error in eval(expr, envir, enclos) : object 'x' not found"
ggplot(data) + geom_point() + my.aes(x=a, y=b)

实现my.aes()的正确方法是什么?这是为了封装和代码重用。

也许这是相关的,我只是还不知道如何: How to write an R function that evaluates an expression within a data-frame.

【问题讨论】:

标签: r function ggplot2


【解决方案1】:

键入 aes 不带任何括号或参数以查看它在做什么:

function (x, y, ...) 
{
    aes <- structure(as.list(match.call()[-1]), class = "uneval")
    rename_aes(aes)
}

它采用其参数的名称而不评估它们。它基本上是保存名称以供以后使用,因此它可以在您尝试绘制的数据框的上下文中评估它们(这就是您的错误消息抱怨eval 的原因)。因此,当您在ggplot 构造中包含my.aes(x=a, y=b) 时,它会在data 中寻找x——因为x 没有在aes(x=x, y=y) 中评估。

另一种思考aes 中发生的事情的方式类似于

my.aes <- function(x, y) {
  ans <- list(x = substitute(x), y = substitute(y))
  class(ans) <- "uneval"
  ans
}

在上面的示例中应该可以工作,但请参阅plyr::. 中的注释(它使用与aes 相同的match.call()[-1] 范例):

类似的技巧可以用替代来执行,但是当函数 可以通过多种方式调用它变得越来越棘手 确保从正确的帧中提取值。 替代技巧也使编程变得困难 使用它们的函数,而引用的类提供 as.quoted.character 将字符串转换为适当的数据 结构。

如果你想让my.aes 自己调用aes,可能是这样的:

my.aes <- function(x,y) {
    do.call(aes, as.list(match.call()[-1]))
} 

Roman Luštrik 指出的aes_string 函数示例:

my.aes <- function(x,y) {
    aes_string(x = x, y = y)
}

但在这种情况下,您需要将呼叫更改为 my.aes("a", "b")

【讨论】:

  • 感谢您的解释。您的建议基本上意味着重新实现aes,我宁愿避免。有没有办法只使用aes 来实现my.aes? (以后还会有my.geom_text,也许还有其他……)
  • 如果不了解my.aes 的行为与aes 的不同之处,我很难给出更具体的答案——在您的示例中,它们做同样的事情。如果您愿意编写 my.aes("a", "b") 而不是 my.aes(a,b),Roman 的 aes_string 建议将起作用,但我不会将其作为这是他的主意。
  • 请随意在您的回答中包含这一点,我不主张这个想法。就像外星人一样,它就在那里! :)
  • 查看我的编辑以获取将调用从my.aes 传递到aes 的版本。但是,不确定这将如何适应您接下来的计划。
  • 我认为您需要引用传递的参数才能使其正常工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-16
  • 2013-08-05
  • 1970-01-01
相关资源
最近更新 更多