9

すでに作成したプロットから特定のgeomを削除する取り組みの一環として(SOリンクはこちら)、ggplot2オブジェクトの各レイヤーのgeomタイプを動的に決定したいと思います。

レイヤーを追加した順序がわからないと仮定して、特定のジオメトリを持つレイヤーを動的に検索する方法はありますか?以下のようにレイヤーを印刷すると、レイヤーがリストに保存されていることがわかりますが、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)

私はプロトオブジェクトに精通しておらず、プロトドキュメントから試したことがうまくいかないようです(例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で示された結果を提供しなくなりました。受け入れられた回答は2つのNULL値を生成し、他の回答は完全なggprotoオブジェクトを生成します。

于 2017-05-15T14:53:41.637 に答える
4

編集:この回答は現在のものではありません。質問があったときに機能し、おそらくかなりの時間が経過しましたが、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 
于 2012-11-19T16:11:28.223 に答える
2

これがプロトオブジェクトを見る1つの方法です。私が理解しているように、これらは環境であるため、を使用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"  
于 2012-11-19T16:17:21.837 に答える