1

我正在尝试ggplot在函数内部使用,但无法生成绘图。具体来说,我想确定绘图是否会facet_grid()从函数调用中使用。这是我的数据:

mydf <- data.frame(
  group = rep(c("g1", "g2"), each = 16, times = 1), 
  cluster = rep(c("c1", "c2"), each = 8, times = 2), 
  score1 = c(rnorm(n = 16, mean = 10, sd = 10), rnorm(n = 16, mean = 18, sd = 10)), 
  score2 = c(rnorm(n = 16, mean = 50, sd = 10), rnorm(n = 16, mean = 33, sd = 10))
  )

这是功能:

myFunc <- function(data, group = NULL, group2, var1, var2) {

  # So we don't need quotation marks in function call
  arguments <- as.list(match.call())
  var1 = eval(arguments$var1, data)
  var2 = eval(arguments$var2, data)
  group2 = eval(arguments$cluster, data)
  grouping = eval(arguments$group, data)

  # Make this graph if no faceting needed
  if (length(grouping) == 0) {

  means <- aggregate(cbind(var1, var2) ~  group2, FUN = mean, data = data)

  ggplot(data, aes(x = var1, y = var2, color = group2, label = group2)) + 
    stat_ellipse(type = "norm", show.legend = FALSE, geom = "polygon", alpha = 0.1) +
    geom_text(alpha = 0.5, show.legend = FALSE) +
    geom_text(data = means, aes(x = var1, y = var2, color = group2)) 


  # Use faceting
  } else if (length(grouping) > 0) {

  means <- aggregate(cbind(var1, var2) ~ grouping + group2, FUN = mean, data = data)

  # Plot 
  ggplot(data, aes(x = var1, y = var2, color = group2, label = group2)) + 
    stat_ellipse(type = "norm", show.legend = FALSE, geom = "polygon", alpha = 0.1) +
    geom_text(alpha = 0.5, show.legend = FALSE) + 
    geom_text(data = means, aes(x = var1, y = var2, color = group2)) +
    facet_grid(. ~ grouping) 

  }

}

我这样调用函数:

myFunc(data = mydf, group = NULL, group2 = cluster, var1 = score1, var2 = score2)
myFunc(data = mydf, group = group, group2 = cluster, var1 = score1, var2 = score2)

两个调用分别给出以下错误:

# Error 1
Error: Aesthetics must be either length 1 or the same as the data (32): x, y, colour, label

# Error 2
Error in combine_vars(data, params$plot_env, cols, drop = params$drop) : 
At least one layer must contain all variables used for facetting

可以通过手动构建图来获得预期的输出:

means <- aggregate(cbind(score1, score2) ~ group + cluster, FUN = mean, data = mydf)

# without facet
ggplot(mydf, aes(x = score1, y = score2, color = cluster, label = cluster)) + 
  stat_ellipse(type = "norm", show.legend = FALSE, geom = "polygon", alpha = 0.1) +
  geom_text(alpha = 0.5, show.legend = FALSE) + 
  geom_text(data = means, aes(x = score1, y = score2, color = cluster)) 

# with facet
ggplot(mydf, aes(x = score1, y = score2, color = cluster, label = cluster)) + 
  stat_ellipse(type = "norm", show.legend = FALSE, geom = "polygon", alpha = 0.1) +
  geom_text(alpha = 0.5, show.legend = FALSE) + 
  geom_text(data = means, aes(x = score1, y = score2, color = cluster)) + 
  facet_grid(. ~ group)
4

2 回答 2

2

这是stat_ellipse使用和不使用的基本图facet_grid。我会让你添加装饰。在这里,列名被保存为字符串,因此aes_string被用来代替aes,并且公式被传递给使用as.formula.

myFunc <- function(df, var1, var2, group2, group1 = NULL) {

  # Make this graph if no faceting needed
  if (is.null(group1)) {

  means_formula <- as.formula(paste(var1, "+", var2, "~", group2))
  means <- aggregate(means_formula, FUN = mean, data = df)

   p <- ggplot(df, 
       aes_string(x = var1, y = var2, color = group2, label = group2)) + 
       stat_ellipse(type = "norm", show.legend = FALSE, 
           geom = "polygon", alpha = 0.1)
    }else{

    means_formula <- as.formula(paste(var1,"+",var2,"~", group2,"+",group1))
    means <- aggregate(means_formula, FUN = mean, data = df)

    p <- ggplot(df, 
        aes_string(x = var1, y = var2, color = group2, label = group2)) + 
        stat_ellipse(type = "norm", show.legend = FALSE, 
            geom = "polygon", alpha = 0.1) + 
        facet_grid(as.formula(paste(".~ ",group1))) 
  }
  print(p)
}

myFunc(df = mydf, var1 = "score1", var2 = "score2", 
    group2 = "cluster", group1 = NULL)

myFunc(df = mydf, var1 = "score1", var2 = "score2", 
    group2 = "cluster", group1 = "group")

统计椭圆图

于 2017-02-11T16:37:34.810 回答
2

First, you are assigning group2 to a nonexistent variable in scope of function, cluster. Replace: group2 = eval(arguments$cluster, data) with group2 = eval(arguments$group2, data).

Second, you need a dynamic facet_grid formula. Currently you are passing grouping which is not an actual field in dataset. However, since you are going without quotes in functional arguments, you will need to retrieve the string literal of function's argument, group, which can be achieved with deparse(substitute(...)) to return "group".

Consider adding at top near list of other function variables:

grpname = deparse(substitute(group))

Then replace you facet_grid with either a dynamic as.formula string concatenation or with reformulate:

facet_grid(as.formula(paste0(". ~ ", grpname)))

facet_grid(reformulate(grpname))

Of course, all can be dynamically run with quoted function args as shown by @P-robot.

于 2017-02-11T18:03:46.357 回答