解析动态构建的ggplot2代码时出错

时间:2014-09-17 18:01:16

标签: r ggplot2

在下面的可重现的示例中,我试图动态构建一个ggplot2函数调用,以便能够容纳未知数量的混合分布组件。该代码生成此错误消息:Error in parse(text = g) : <text>:8:0: unexpected end of input。代码有什么问题? (我知道预先计算绘图数据的方法,将其存储在数据框中,将其融合并提供给ggplot2。我也想探索下面的选项。)谢谢!

library(ggplot2)
library(scales)
library(RColorBrewer)
library(mixtools)

NUM_COMPONENTS <- 2

set.seed(12345) # for reproducibility

data(diamonds, package='ggplot2')  # use built-in data
myData <- diamonds$price

calc.component <- function(x, lambda, mu, sigma) {
  lambda * dnorm(x, mean = mu, sd = sigma)
}


overlayHistDensity <- function(data, func) {

  # extract 'k' components from mixed distribution 'data'
  mix <- normalmixEM(data, k = NUM_COMPONENTS,
                     maxit = 100, epsilon = 0.01)
  summary(mix)

  DISTRIB_COLORS <- 
    suppressWarnings(brewer.pal(NUM_COMPONENTS, "Set1"))

  # plot histogram, empirical and fitted densities
  g <- "ggplot(data) +\n"

  for (i in seq(length(mix$lambda))) {
    args <- paste0("args.", i)
    assign(args, list(lambda = mix$lambda[i], mu = mix$mu[i],
                 sigma = mix$sigma[i]))
    g <- paste0(g,
                "stat_function(fun = func, args = ",
                args,
                ", aes(color = ",
                DISTRIB_COLORS[i], ")) +\n")
  }

  tailStr <- 
    "geom_line(aes(y = ..density..,colour = 'Empirical'),stat = 'density') +
     geom_histogram(aes(y = ..density..), alpha = 0.4) +
     scale_colour_manual(name = '', values = c('red', 'blue')) +
     theme(legend.position = 'top', legend.direction = 'horizontal')"

  g <- paste0(g, tailStr)
  gr <- eval(parse(text = g))
  return (gr)
}

overlayHistDensity(log10(myData), 'calc.component')

2 个答案:

答案 0 :(得分:3)

只要你意识到你正在努力解决这个问题......

如果在解析之前查看g的值,则为

ggplot(data) +
stat_function(fun = func, args = args.1, aes(color = #E41A1C)) +
stat_function(fun = func, args = args.2, aes(color = #377EB8)) +
geom_line(aes(y = ..density..,colour = 'Empirical'),stat = 'density') +
     geom_histogram(aes(y = ..density..), alpha = 0.4) +
     scale_colour_manual(name = '', values = c('red', 'blue')) +
     theme(legend.position = 'top', legend.direction = 'horizontal')

通常unexpected end of input消息来自不平衡的引号或括号,但你(显然)没有在这里遇到这个问题。问题在于颜色规范。文字十六进制颜色应指定为字符串

ggplot(data) +
stat_function(fun = func, args = args.1, aes(color = "#E41A1C")) +
stat_function(fun = func, args = args.2, aes(color = "#377EB8")) +
geom_line(aes(y = ..density..,colour = 'Empirical'),stat = 'density') +
     geom_histogram(aes(y = ..density..), alpha = 0.4) +
     scale_colour_manual(name = '', values = c('red', 'blue')) +
     theme(legend.position = 'top', legend.direction = 'horizontal')

如果没有引号,散列是注释字符,其余行(特别是右括号)不包括在内,并且给出了错误。 (注意SO在第一个代码片段中突出显示的语法。)

那就是说,我认为如果没有eval(parse())方法,你可以得到你想要的东西。特别是,请查看aes_string,它允许通过字符串变量的值来指定哪个变量用作美学,并添加stat s或geom s的列表(可以具有使用lapply创建的未预先指定的长度。此外,您似乎指定了文字颜色,然后将它们映射到红色和蓝色;你想要scale_colour_identity吗?所有这些(最后一段)是更多的代码审查,而不是你实际问的。

答案 1 :(得分:3)

你有几个问题:

  • ggplot的数据参数必须是data.frame,而不是vector
  • 必须引用以#开头的
  • 十六进制颜色名称,否则它们将被解释为注释
  • 您必须提供aes(x = )映射
  • 常量的颜色定义不会进入aes

这应该有效:

overlayHistDensity <- function(data, func) {
    # extract 'k' components from mixed distribution 'data'
    mix <- normalmixEM(data, k = NUM_COMPONENTS,
                       maxit = 100, epsilon = 0.01)
    summary(mix)

    DISTRIB_COLORS <- 
        suppressWarnings(brewer.pal(NUM_COMPONENTS, "Set1"))

    # plot histogram, empirical and fitted densities
    g <- "ggplot(as.data.frame(data), aes(x = data)) +\n"

    for (i in seq(length(mix$lambda))) {
        args <- paste0("args.", i)
        assign(args, list(lambda = mix$lambda[i], mu = mix$mu[i],
                          sigma = mix$sigma[i]))
        g <- paste0(g,
                    "stat_function(fun = func, args = ",
                    args,
                    ", color = '",
                    DISTRIB_COLORS[i], "') +\n")
    }

    tailStr <- 
        "geom_line(aes(y = ..density..,colour = 'Empirical'),stat = 'density') +
     geom_histogram(aes(y = ..density..), alpha = 0.4) +
     scale_colour_manual(name = '', values = c('red', 'blue')) +
     theme(legend.position = 'top', legend.direction = 'horizontal')"

    g <- paste0(g, tailStr)
    gr <- eval(parse(text = g))
    return (gr)
}

像Brian一样,我将以2条评论结束:

  1. 这是标准调试,您不需要SO帖子。它本质上是几个语法错误和几个小错误。我将您的代码放在函数之外并在最后的g <- paste0行中运行,并将g输出放在代码窗口中并查找问题。尝试编写首先在函数之外工作的代码,然后将其放在函数中。

  2. 借调Brian的评论,更自然的方法是使用eval(parse())以及所有这些粘贴。相反,请使用aes_string,融化您的数据,以便您可以根据分组变量使用一次stat_function调用。