【问题标题】:Error parsing dynamically-built ggplot2 code解析动态构建的 ggplot2 代码时出错
【发布时间】:2014-09-18 03:20:42
【问题描述】:

在下面的可重现示例中,我尝试动态构建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')

【问题讨论】:

    标签: r ggplot2


    【解决方案1】:

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

    如果在解析之前查看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 在第一个代码 sn-p 上给出的语法突出显示。)

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

    【讨论】:

    • 非常感谢您的回答!
    【解决方案2】:

    你有几个问题:

    • ggplot 的数据参数必须是 data.frame,而不是向量
    • 必须引用以# 开头的十六进制颜色名称,否则它们将被解释为 cmets
    • 您必须提供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)
    }
    

    像布赖恩一样,我将以 2 cmets 结束:

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

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

    【讨论】:

    • 非常感谢您的回答!由于从qplot() 转换到ggplot(),data 参数是意外遗留的。关于调试,在发布这个问题之前,我已经做了很多有功能和没有功能的事情。我不想冒犯任何人。
    • 一切都很好;我只注意到与该问题最直接相关的一个。我以类似的方式找到了问题,但在最后一个 g &lt;- paste0(... 之后放置了一个 return(g),因为有时,由于范围界定(修改后的数据集覆盖以前的数据集),结果并不相同。
    • @AleksandrBlekh 谢谢,我希望我没有冒犯(绝对不是故意的!),只是一个评论。
    • 一切都很好,不用担心!再次感谢您和@BrianDiggs!顺便说一句,我尝试这种方法而不是“标准”熔化方法的原因是对数刻度的问题:stackoverflow.com/a/25641112/2872891。我想知道,除了我的错误之外,它是否与stat_function() 问题有关:stackoverflow.com/a/9424028/2872891。这个问题已经解决了吗?您对处理此类情况有什么建议(ggplot2 的日志正常数据可视化)?
    • 我不知道stat_function 的问题。我倾向于完全避免stat_function,并在绘图前进行此类处理,如有必要,使用第二个 data.frame。我不确定这对你的情况有多好。
    猜你喜欢
    • 2020-11-13
    • 1970-01-01
    • 2019-06-03
    • 1970-01-01
    • 2015-11-29
    • 2017-03-24
    • 2016-04-13
    • 2015-10-22
    • 1970-01-01
    相关资源
    最近更新 更多