首页 > 解决方案 > ggplot2:如何使用 ggplot_build() 检查绘图的每个元素?

问题描述

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


细节:

我正在寻找一种解决方案来检索 ggplot2_3.0.0 中轴标签的值,早期的答案之一表明,根据ggplot2版本,正确答案很可能包含来自. 所以我开始检查每一步的输出。其中一个步骤类似于下面的输出。$layout$x.labelsggplot_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 paramsx.labels可以找到许多有用的信息,如下所示:

片段 2:

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

并且可以像这样直接引用:

片段 3:

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

输出 3:

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

我尝试更优雅的方法:

我确信我可以capture.output()像你str()所描述的那样做到一点,但据我所知,你也不会在x.labels那里找到。我不会用那个输出来淹没这个问题,因为它大约有 300 行长。

感谢您的任何建议!


标签: rggplot2

解决方案


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

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"
  • 嵌套结构可以包含命名列表、未命名列表、具有另一个类的命名“列表”(因此返回FALSEis.list()环境。必须处理所有这些情况。
  • 特别需要注意的是 aggplot_built包含对全局环境 ( gb$layout$facet_params$plot_env) 的引用,如果处理不当,将导致无限循环。
  • 的结果find_paths()又是一个嵌套列表,但结构可以很容易地用unlist().
  • 最后一步是提取那些包含正在寻找的名称的路径。我使用的正则表达式确保只返回与给定名称完全匹配的元素。例如,find_name(gb, "x")不会返回"gb$layout$panel_params[[1]]$x.labels"

我已经使用ggplot_built示例中的对象和嵌套列表测试了该函数。我不能保证它适用于所有情况。


推荐阅读