r - ggplot2:如何使用 ggplot_build() 检查绘图的每个元素?
问题描述
有没有办法搜索ggplot_build()
(或任何其他函数)的整个输出,就像搜索文件夹的每个子目录的完整内容一样?
细节:
我正在寻找一种解决方案来检索 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
可以找到许多有用的信息,如下所示:
片段 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 行长。
感谢您的任何建议!
解决方案
这个函数遍历一个嵌套列表结构,并通过该结构找到包含给定字符串的路径:
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()
环境。必须处理所有这些情况。 - 特别需要注意的是 a
ggplot_built
包含对全局环境 (gb$layout$facet_params$plot_env
) 的引用,如果处理不当,将导致无限循环。 - 的结果
find_paths()
又是一个嵌套列表,但结构可以很容易地用unlist()
. - 最后一步是提取那些包含正在寻找的名称的路径。我使用的正则表达式确保只返回与给定名称完全匹配的元素。例如,
find_name(gb, "x")
不会返回"gb$layout$panel_params[[1]]$x.labels"
。
我已经使用ggplot_built
示例中的对象和嵌套列表测试了该函数。我不能保证它适用于所有情况。