简体   繁体   English

ggplot2内部功能具有第二种美感:作用域问题

[英]ggplot2 inside function with a 2nd aesthetic: scoping issue

I have the following test data: 我有以下测试数据:

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")

And the following function which should draw the points (it does) and connect the means of each group (it doesn't): 下面的函数应该绘制点(确实)并连接每个组的平均值(不是):

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)
    }

When I run it: 当我运行它时:

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

I get this error: 我收到此错误:

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

I seem to always have these scoping problems, any advice? 我似乎总是遇到这些范围界定问题,有什么建议吗? I thought I was following the appropriate work-around for the bug. 我以为我正在针对该错误采取适当的解决方法。 Using aes instead of aes_string , or not quoting the variable names in geom_line doesn't fix it. 使用aes代替aes_string ,或者不引用geom_line中的变量名并不能解决问题。 Thanks. 谢谢。

When I run into trouble with inherited aesthetics, I always go back and remove anything from the main ggplot() call that doesn't need to be there. 当我遇到继承的美学问题时,我总是回去并从主ggplot()调用中删除不需要的所有内容。 Try this: 尝试这个:

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)
    }

I had to make two changes to get your function to work. 我必须进行两项更改才能使您的功能正常工作。 First, there's a bug in ggplot2 0.9.3 (and previous) where the evaluation environment of aes() defaults to the global environment. 首先,ggplot2 0.9.3(及更高版本)中存在一个错误,其中aes()的评估环境默认为全局环境。 The workaround: to make it evaluate in the calling environment (for example, your function's environment) use ggplot(..., environment = environment() . 解决方法:使其在调用环境(例如,函数的环境)中进行评估,请使用ggplot(..., environment = environment()

The other change was in the last line, where you have p <- p + geom_line(..., data=avg) . 另一个变化是在最后一行,其中p <- p + geom_line(..., data=avg) The key there is that you must turn off the inheritance of aesthetics from the main ggplot call, because your avg data set doesn't have the fac2 column. 关键还有就是你必须关闭从主美学的继承ggplot通话,因为你的avg数据集不具备fac2列。 To do that, use geom_line(..., inherit.aes=FALSE) . 为此,请使用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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM