【问题标题】:How to determine the geom type of each layer of a ggplot2 object?如何确定ggplot2对象每一层的geom类型?
【发布时间】:2018-04-14 06:25:06
【问题描述】:

作为从我已经创建的绘图中删除特定几何图形的一部分(SO 链接here),我想动态确定 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)

我不熟悉原型对象,我从原型documentation 尝试过的东西似乎不起作用(例如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
}

【问题讨论】:

  • 为了方便起见,您能否提供一个小的可重现数据集以及您的代码?
  • 哎呀,复制粘贴失败。谢谢,@Dason

标签: r ggplot2 layer proto ggproto


【解决方案1】:

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

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

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

[1] "GeomRibbon" "GeomLine" 

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

【讨论】:

  • 任何想法哪个版本破坏了我的答案中的代码?
  • 我不确定,但 2015 年 12 月的第 2 版引入了一系列重大变化,也许是这样? blog.rstudio.org/2015/12/21/ggplot2-2-0-0
  • 大概就是这样。无论哪种方式,我都在帖子顶部添加了一个编辑,以重定向到您的答案,因为它似乎是最新的。
  • 鉴于这些变化,我现在将其作为公认的答案。
【解决方案2】:

编辑:这个答案不再是最新的。当这个问题被问到并且大概在很长一段时间后它起作用了,但是对于一个适用于 ggplot2 >= 2.2.0 的答案,请参阅https://stackoverflow.com/a/43982598/1003565


如果我们只是想获取每个项目的 geom 名称,这似乎位于每个层的 $geom$objname 部分。

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

作为补充说明 - 您无法使用 p$layers[[1]]$str() 语法的原因(可能)是因为您没有显式加载 proto 包。 ggplot2 在内部使用它,但它导入它而不是使用 Depends。注意区别:

> 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 

【讨论】:

  • 感谢您解释为什么 $str() 不可用。
  • (五年后,这不再适用于当前的 ggplot 版本;发布了一个新答案)
【解决方案3】:

这是查看 proto 对象的一种方式。据我了解,它们是环境,因此使用 ls 可以为您提供名称(显然,即使是从作为绘图对象的父环境中提取的项目,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-attributes 内部更深的一层:

 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"  

【讨论】:

  • 您的 sapply 调用仍会返回 proto 对象,但这并不适合使用。如果你抓住你返回的 objname 部分,那么你会得到一个很好的字符串。
  • 修复了这个缺陷。
猜你喜欢
  • 2020-10-16
  • 2021-01-12
  • 2012-05-02
  • 2016-09-06
  • 2011-01-14
  • 1970-01-01
  • 1970-01-01
  • 2020-11-08
相关资源
最近更新 更多