9

作为从我已经创建的绘图中删除特定几何图形的一部分(此处链接),我想动态确定 ggplot2 对象的每一层的几何图形类型。

假设我不知道添加图层的顺序,有没有办法动态查找具有特定几何图形的图层?如果我像下面那样打印出图层,我可以看到这些图层存储在一个列表中,但我似乎无法访问 geom 类型。

library(ggplot2)
dat <- data.frame(x=1:3, y=1:3, ymin=0:2, ymax=2:4)
p <- ggplot(dat, aes(x=x, y=y)) + geom_ribbon(aes(ymin=ymin, ymax=ymax), alpha=0.3) + geom_line()
p$layers

[[1]]
mapping: ymin = ymin, ymax = ymax 
geom_ribbon: na.rm = FALSE, alpha = 0.3 
stat_identity:  
position_identity: (width = NULL, height = NULL)

[[2]]
geom_line:  
stat_identity:  
position_identity: (width = NULL, height = NULL)

我不熟悉 proto 对象,而且我从 proto文档中尝试过的东西似乎不起作用(例如p$layers[[1]]$str())。


感谢下面的答案,我能够想出一个动态删除图层的函数:

remove_geom <- function(ggplot2_object, geom_type) {
  layers <- lapply(ggplot2_object$layers, function(x) if(x$geom$objname == geom_type) NULL else x)
  layers <- layers[!sapply(layers, is.null)]

  ggplot2_object$layers <- layers
  ggplot2_object
}
4

3 回答 3

10

ggplot 2.2更新: 如果你想要的是一个命名geom类型的字符串,你可以使用:

sapply(p$layers, function(x) class(x$geom)[1])

它为每一层的 geom 对象产生第一个类名。在 OP 的示例中:

[1] "GeomRibbon" "GeomLine" 

上面答案中的代码不再给出 2.2 版显示的结果 接受的答案产生两个 NULL 值,另一个答案产生完整的ggproto对象。

于 2017-05-15T14:53:41.637 回答
4

Edit: This answer is no longer current. It worked when the question was asked and presumably for quite some time after but for an answer that works with ggplot2 >= 2.2.0 see https://stackoverflow.com/a/43982598/1003565


If we're just looking to get the geom name for each item this appears to be in the $geom$objname part of each layer.

p$layers[[1]]$geom$objname
#[1] "ribbon"
lapply(p$layers, function(x){x$geom$objname})
#[[1]]
#[1] "ribbon"
#
#[[2]]
#[1] "line"

As an added note - the reason you couldn't use the p$layers[[1]]$str() syntax is (probably) because you didn't explicitly load the proto package. ggplot2 uses it internally but it imports it instead of using Depends. Notice the difference:

> library(ggplot2)
> dat <- data.frame(x=1:3, y=1:3, ymin=0:2, ymax=2:4)
> p <- ggplot(dat, aes(x=x, y=y)) + geom_ribbon(aes(ymin=ymin, ymax=ymax), alpha=0.3) + geom_line()
> p$layers
[[1]]
mapping: ymin = ymin, ymax = ymax 
geom_ribbon: na.rm = FALSE, alpha = 0.3 
stat_identity:  
position_identity: (width = NULL, height = NULL)

[[2]]
geom_line:  
stat_identity:  
position_identity: (width = NULL, height = NULL)

> p$layers[[1]]$str()
Error: attempt to apply non-function
> library(proto)
> p$layers[[1]]$str()
proto object 
 $ geom_params:List of 2 
 $ mapping    :List of 2 
 $ stat_params: Named list() 
 $ stat       :proto object  
  ..parent: proto object  
 .. .. parent: proto object  
 $ inherit.aes: logi TRUE 
 $ geom       :proto object  
  ..parent: proto object  
 .. .. parent: proto object  
 $ position   :proto object  
  ..parent: proto object  
 .. .. parent: proto object  
 .. .. .. parent: proto object  
 $ subset     : NULL 
 $ data       : list() 
  ..- attr(*, "class")= chr "waiver" 
 $ show_guide : logi NA 
于 2012-11-19T16:11:28.223 回答
2

这是查看原型对象的一种方式。据我了解,它们是环境,因此 usingls为您提供了名称(显然,即使是从作为绘图对象的父环境中提取的项目,p.):

 ls(p$layers[[1]])
# [1] "data"        "geom"        "geom_params" "inherit.aes" "mapping"    
# [6] "position"    "show_guide"  "stat"        "stat_params" "subset" 

 p$layers[[1]][["geom"]]
#geom_ribbon: 

 sapply( p$layers, "[[", "geom")
#---------------
[[1]]
geom_ribbon: 

[[2]]
geom_line: 

@Dason 指出您可能因此需要一个字符向量,因此再次使用 sapply 和 "[[" 应该可以满足这种可能的需求:

 sapply( sapply( p$layers, "[[", "geom"), "[[", 'objname')
#[1] "ribbon" "line"

ggproto 设计中的更改包括使名称位于 - 属性内部更深的一层class

 lapply( sapply( p$layers, "[[", "geom"), function(x) attributes(x) )
#----------------
[[1]]
[[1]]$class
[1] "GeomRibbon" "Geom"       "ggproto"   


[[2]]
[[2]]$class
[1] "GeomLine" "GeomPath" "Geom"     "ggproto" 

sapply( sapply( p$layers, "[[", "geom"), function(x) class(x)[[1]][1] )
[1] "GeomRibbon" "GeomLine"  
于 2012-11-19T16:17:21.837 回答