【问题标题】:ggplot2 inside function with a 2nd aesthetic: scoping issue具有第二美学的 ggplot2 内部函数:范围问题
【发布时间】:2013-01-15 23:22:47
【问题描述】:

我有以下测试数据:

structure(list(r = c(5.44702625911984, 6.3431860464319, 2.89023592667928, 
6.66260769449341, 7.5521021076857, 5.50645078944005, 6.70001850525037, 
7.39615449137166, 5.96032231142622, 7.88929821115731, 9.45119299499902, 
6.13534105776075, 7.79397401855071, 5.24488870603935, 4.53178061905952, 
5.80573244536445, 10.1194252475799, 12.5794215385996, 7.47503723957468, 
7.8682648760597, 15.7540766770233, 14.9800818974568, 14.5672865569748, 
9.5347507057429, 18.6791666362954, 10.4588651710497, 15.2076130678251, 
10.5052588219606, 13.1314628288852, 12.8384811800557, 10.9978569438483, 
10.0197995395016, 10.1479274794689, 12.5864754383382, 10.7985399338233, 
11.1100572430765, 10.756576992292, 9.17309427876051, 10.0441987112265, 
10.0652520950654), f1 = structure(c(2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L), .Label = c("H", "L"), class = "factor"), f2 = structure(c(1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L), class = "factor", .Label = c("Joe", 
"Sally"))), .Names = c("r", "f1", "f2"), row.names = c(NA, -40L
), class = "data.frame")

以下函数应该绘制点(它会)并连接每个组的手段(它不会):

testFunc <- function(formula = NULL, data = NULL) {
    res <- as.character(formula[[2]])
    fac1 <- as.character(formula[[3]][2])
    fac2 <- as.character(formula[[3]][3])

    # Specify the data & aesthetics     
    p <- ggplot(data, aes_string(x = fac1, y = res, color = fac2,
        group = fac2))

    # Now add points
    p <- p + geom_point() # works fine if we stop here

    # Due to a bug in ggplot2_0.9.3, we must calc some quantities
    # and put them in a separate data frame for a new aesthetic
    avg <- aggregate(data[,res] ~ data[,fac1]*data[, fac2], data, FUN = mean)
    names(avg) <- c("factor1", "factor2", "mean")   
    p <- p + geom_line(aes_string(x = 'factor1', y = 'mean', group = 'factor2'), data = avg)
    }

当我运行它时:

ex <- testFunc(formula = r ~ f1*f2, data = td)
print(ex)

我得到这个错误:

Error in eval(expr, envir, enclos) : object 'f2' not found

我似乎总是遇到这些范围界定问题,有什么建议吗?我以为我正在为该错误遵循适当的解决方法。使用aes 而不是aes_string,或者不引用geom_line 中的变量名都不能解决这个问题。谢谢。

【问题讨论】:

    标签: r ggplot2


    【解决方案1】:

    当我在继承美学方面遇到麻烦时,我总是会返回并从主要的 ggplot() 调用中删除不需要的任何内容。试试这个:

    testFunc <- function(formula = NULL, data = NULL) {
        res <- as.character(formula[[2]])
        fac1 <- as.character(formula[[3]][2])
        fac2 <- as.character(formula[[3]][3])
    
        # Now add points
        p <- ggplot() + geom_point(data = data, aes_string(x = fac1, y = res, color = fac2,
            group = fac2)) # works fine if we stop here
    
        # Due to a bug in ggplot2_0.9.3, we must calc some quantities
        # and put them in a separate data frame for a new aesthetic
        avg <- aggregate(data[,res] ~ data[,fac1]*data[, fac2], data, FUN = mean)
        names(avg) <- c("factor1", "factor2", "mean")   
        p <- p + geom_line(aes_string(x = 'factor1', y = 'mean', group = 'factor2'), data = avg)
        }
    

    【讨论】:

    • 谢谢乔兰。当然工作。但为什么?我猜只是单独调用ggplot()/empty 可以将geom_point 美学与geom_line 美学干净地分开,并且不会污染最初的proto 对象-这是思考的方式吗?非常感谢您的洞察力。
    • 基本上,是的。 ggplot() 中包含的任何内容都将向下传递到每一层,除非特别覆盖。我的猜测是,在这种情况下,aes_string 试图消除 ggplot 中 x、y 和 group 的原始设置美学的尝试出了点问题。这可能是一个错误,但也可能只是 aes_string 的限制,这是不可避免的。
    • 您的分析是正确的,但问题是在原始 ggplot 调用中设置的颜色美学,但在使用 avg 数据的geom_line 美学中没有被覆盖(这不t 有一个 f2 变量)。因此,您可以将data, aes_string(x = fac1, y = res, group = fac2) 留在原来的ggplot 调用中,然后将aes_string(color = fac2) 放入geom_point 调用中就足够了。
    • 谢谢布赖恩,明白了。测试函数现在运行良好,但实际函数有许多选项和潜在层(一些离散的,一些连续的)。我在实际功能上收到Discrete value supplied to continuous scale 错误。所以这是下一个任务。不幸的是,要从中做出 MWE 可能很困难。
    • 感谢@BrianDiggs,我完全错过了两层之间的颜色/组美学差异。需要检查我的眼睛。
    【解决方案2】:

    我必须进行两项更改才能使您的功能正常工作。首先,在 ggplot2 0.9.3(及之前)中存在一个错误,aes() 的评估环境默认为全局环境。解决方法:让它在调用环境(例如,你的函数的环境)中进行评估,使用ggplot(..., environment = environment()

    另一个变化是在最后一行,你有p &lt;- p + geom_line(..., data=avg)。关键是您必须从主要的ggplot 调用中关闭美学继承,因为您的avg 数据集没有fac2 列。为此,请使用geom_line(..., inherit.aes=FALSE)

    testFunc <- function(formula = NULL, data = NULL) {
      res <- as.character(formula[[2]])
      fac1 <- as.character(formula[[3]][2])
      fac2 <- as.character(formula[[3]][3])
    
      # Specify the data & aesthetics     
      p <- ggplot(data, aes_string(x = fac1, y = res, color = fac2, group = fac2),
        environment = environment())
    
      # Now add points
      p <- p + geom_point()
    
      # Due to a bug in ggplot2_0.9.3, we must calc some quantities
      # and put them in a separate data frame for a new aesthetic
      avg <- aggregate(data[,res] ~ data[,fac1]*data[, fac2], data, FUN = mean)
      names(avg) <- c("factor1", "factor2", "mean")   
      p + geom_line(aes_string(x = 'factor1', y = 'mean', group = 'factor2'), 
        inherit.aes = FALSE, data = avg)
    }
    
    ex <- testFunc(formula = r ~ f1*f2, data = td)
    print(ex)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-04-26
      • 1970-01-01
      • 2013-06-25
      • 2012-06-20
      • 1970-01-01
      • 2011-07-31
      • 2011-11-13
      相关资源
      最近更新 更多