有没有办法搜索ggplot_build()的全部内容?

时间:2018-08-10 17:32:51

标签: r ggplot2

是否有一种从ggplot_build()(或任何其他函数)中搜索整个输出的方法,就像搜索文件夹中每个子目录的完整内容一样?


详细信息:

我一直在寻找Retrieve values for axis labels in ggplot2_3.0.0的解决方案,早期的答案之一表明,根据ggplot2版本,正确答案很可能包含$layout部分和/或$x.labels输出中的ggplot_build(g)。因此,我开始检查ggplot_build()输出的每一步。步骤之一看起来像下面的输出。

代码段1:

ggplot_build(g)$layout

输出1:

<ggproto object: Class Layout, gg>
    coord: <ggproto object: Class CoordCartesian, Coord, gg>
        aspect: function
        clip: on

        [...]

    map_position: function
    panel_params: list
    panel_scales_x: list
    panel_scales_y: list
    render: function

        [...]

    ylabel: function
    super:  <ggproto object: Class Layout, gg>
>

panel params下的x.labels中可以找到ggplot_build(g)$layout$panel_params 以及许多有用的信息,如下所示:

代码段2:

[[1]]
[[1]]$`x.range`
[1]  7.7 36.3

[[1]]$x.labels
[1] "10" "15" "20" "25" "30" "35"

[[1]]$x.major
[1] 0.08041958 0.25524476 0.43006993 0.60489510 0.77972028 0.95454545

输出2:

ggplot_build(g)$layout$panel_params[[1]]$x.labels

它可以像这样直接引用:

代码段3:

[1] "10" "15" "20" "25" "30" "35"

输出3:

capture.output()

我尝试采用更优雅的方法:

我确定我可以像here一样使用str()来完成此操作,但是据我所知,您找不到{{1} }那里。我不会用这个输出来充斥这个问题,因为它大约有300行。

谢谢您的任何建议!


1 个答案:

答案 0 :(得分:3)

此函数遍历嵌套列表结构,并查找通过该结构的包含给定字符串的路径:

find_name <- function(obj, name) {

  # get all named paths through obj
  find_paths <- function(obj, path) {

    if ((!is.list(obj) && is.null(names(obj))) || identical(obj, .GlobalEnv)) {
      return (path)
    } else {
      if (is.null(names(obj))) {
        return(c(path,
                 lapply(seq_along(obj), function(x) find_paths(obj[[x]], paste0(path, "[[", x, "]]")))
              ))
      } else {
        return(c(path,
                 lapply(names(obj), function(x) find_paths(obj[[x]], paste(path, x, sep = "$")))
              ))
      }  
    }

  }

  # get all the paths through the nested structure
  all_paths <- unlist(find_paths(obj, deparse(substitute(obj))))

  # find the requested name
  path_to_name <- grep(paste0("\\$", name, "$"), all_paths, value = TRUE)

  return (path_to_name)
}

以下是将此功能与ggplot_built对象一起使用的示例:

library(ggplot2)
p <- ggplot(mtcars) + geom_point(aes(x = disp, y = mpg, col = as.factor(cyl)))
gb <- ggplot_build(p)
find_name(gb, "x.labels")
## [1] "gb$layout$panel_params[[1]]$x.labels"

您还可以直接获取x.labels的内容:

eval(parse(text = find_name(gb, "x.labels")))
## [1] "100" "200" "300" "400"

有关其工作原理的几点评论:

  • 函数find_paths()遍历嵌套结构,并以类似于"gb$layout$panel_params[[1]]$x.labels"的形式返回通过该结构的所有“路径”。
  • 嵌套结构可以包含具有另一个类的命名列表,未命名列表,命名“列表”(因此对于FALSE和环境返回is.list()。必须照顾所有这些情况。
  • 特别需要注意的是,ggplot_built包含对全局环境(gb$layout$facet_params$plot_env)的引用,如果处理不当,则会导致无限循环。
  • find_paths()的结果再次是一个嵌套列表,但是使用unlist()可以轻松简化结构。
  • 最后一步是提取包含名称的路径。我使用的正则表达式可确保仅返回与给定名称完全匹配的元素。例如,find_name(gb, "x")将不会返回"gb$layout$panel_params[[1]]$x.labels"

我已经用示例中的ggplot_built对象和嵌套列表测试了该功能。我不能保证它在所有情况下都有效。