ggplotGrob的反转? [英] Inverse of ggplotGrob?

查看:258
本文介绍了ggplotGrob的反转?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个操作ggplot对象的函数,通过将其转换为grob并修改图层。我希望函数返回一个ggplot对象而不是grob。有没有简单的方法将grob转换回gg?

文档 ggplotGrob 非常稀疏。

简单示例:

  P < -  ggplot(iris)+ geom_bar(aes(x = Species,y = Petal.Width),stat =identity)

G < - ggplotGrob(P)
...对G的一些操作...

## DESIRED:
P2 < - inverse_of_ggplotGrob(G)

这样我们可以继续使用基本的ggplot语法,即
`P2 + ylab(花瓣的宽度)`






更新:



要回答评论中的问题,这里的动机是修改颜色以编程方式基于每个方面中标签名称的值的方面标签。下面的函数很好地工作(基于上一个问题中baptise的输入)。



我希望从 colorByGroup 的返回值成为ggplot对象,而不仅仅是grob。



这里是代码,对于那些感兴趣的人来说, - 函数(G,strips = grep(pattern =strip。*,G $ layout $ name)){

if(继承(G,gg))
G< ; - ggplotGrob(G)
if(!inherits(G,gtable))
stop(G必须是gtable对象或gg对象)

strip .type< - G $ layout [strips,name]
##我知道这适用于简单的
strip.nms< - sapply(strip,function(i){$ b $ (G $ grobs [[i]] $ width $ arg1)$ data [[1]] [[label]]
})

data.table(grob_index = strip,type = strip.type,group = strip.nms)
}


补充< - 函数(strip,color){
strip [[儿童]] [[1]] [[gp]] [[fill]] < - color
return(strip)
}

colorByGroup< ; - 函数(P,colors,showWarnings = TRUE){
##颜色的名字应该与facet中的组相匹配
G < - ggplotGrob(P)
DT.strips< ; - get_grob_strips(G)

组<< - 名称(颜色)
如果(is.null(groups)|| (长度(颜色)<长度(组))
停止(不是(DT)足够的颜色指定)
颜色< - 颜色[seq(groups)]
名称(颜色)< - 组
}


# #'groups'应该匹配DT.strips中的'group',它来自facet_name
matched_groups< - intersect(groups,DT.strips $ group)
if(!length(matched_groups))
stop(no groups match)
if(showWarnings){
if(length(wh < - setdiff(groups,DT.strips $ group)))
warning (分组中的值,但不是分面标签:\ n,paste(wh,colapse =,))
if(length(wh < - setdiff(DT.strips $ group,groups )))
警告(facet标签中的值,但不在'groups'中:\ n,paste(wh,colapse =,))
}

##识别grob和相应颜色的缺陷
DT.strips [,color:= colors [group]]
inds< - DT.strips [!is.na(color),grob_index]
cols< - DT.strips [!is.na(color),color]

##填充适当的颜色,使用refill()
G $ grobs [inds]< - mapply(重新填充,strip = G $ grobs [inds],color = cols,SIMPLIFY = FALSE)




解决方案

没有。 ggplotGrob 是一条单行道。 grob对象正在绘制由网格定义的基元。您可以从头开始创建任意的grobs。没有一种通用的方法可以将随机的grob集合转换回可以生成它们的函数(因为它不是1:1,所以它不是可逆的)。



您可以将ggplot对象封装在自定义类中,并将plot / print命令重载以执行一些自定义grob操作,但是,这可能会更加黑客。


I have a function which manipulates a ggplot object, by converting it to a grob and then modifying the layers. I would like the function to return a ggplot object not a grob. Is there a simple way to convert a grob back to gg?

The documentation on ggplotGrob is awfully sparse.
Simple example:

P <- ggplot(iris) + geom_bar(aes(x=Species, y=Petal.Width), stat="identity")

G <- ggplotGrob(P)
... some manipulation to G ...

## DESIRED: 
P2 <- inverse_of_ggplotGrob(G)

such that, we can continue to use basic ggplot syntax, ie
`P2 + ylab ("The Width of the Petal")`


UPDATE:

To answer the question in the comment, the motivation here is to modify the colors of facet labels programmatically, based on the value of label name in each facet. The functions below work nicely (based on input from baptise in a previous question).

I would like for the return value from colorByGroup to be a ggplot object, not simply a grob.

Here is the code, for those interested

get_grob_strips <- function(G, strips=grep(pattern="strip.*", G$layout$name)) {

  if (inherits(G, "gg"))
    G <- ggplotGrob(G)
  if (!inherits(G, "gtable"))
    stop ("G must be a gtable object or a gg object")

  strip.type <- G$layout[strips, "name"]
  ## I know this works for a simple 
  strip.nms <- sapply(strips, function(i) {
     attributes(G$grobs[[i]]$width$arg1)$data[[1]][["label"]]
  })

  data.table(grob_index=strips, type=strip.type, group=strip.nms)
}


refill <- function(strip, colour){
  strip[["children"]][[1]][["gp"]][["fill"]] <- colour
  return(strip)
}

colorByGroup <- function(P, colors, showWarnings=TRUE) {
## The names of colors should match to the groups in facet
  G <- ggplotGrob(P)
  DT.strips <- get_grob_strips(G)

  groups <- names(colors)
  if (is.null(groups) || !is.character(groups)) {
    groups <- unique(DT.strips$group)
    if (length(colors) < length(groups))
      stop ("not enough colors specified")
    colors <- colors[seq(groups)]
    names(colors) <- groups
  }


  ## 'groups' should match the 'group' in DT.strips, which came from the facet_name
  matched_groups <- intersect(groups, DT.strips$group)
  if (!length(matched_groups))
    stop ("no groups match")
  if (showWarnings) {
      if (length(wh <- setdiff(groups, DT.strips$group)))
        warning ("values in 'groups' but not a facet label: \n", paste(wh, colapse=", "))
      if (length(wh <- setdiff(DT.strips$group, groups)))
        warning ("values in facet label but not in 'groups': \n", paste(wh, colapse=", "))
  }

  ## identify the indecies to the grob and the appropriate color
  DT.strips[, color := colors[group]]
  inds <- DT.strips[!is.na(color), grob_index]
  cols <- DT.strips[!is.na(color), color]

  ## Fill in the appropriate colors, using refill()
  G$grobs[inds] <- mapply(refill, strip = G$grobs[inds], colour = cols, SIMPLIFY = FALSE)

  G
}

解决方案

I would say no. ggplotGrob is a one-way street. grob objects are drawing primitives defined by grid. You can create arbitrary grobs from scratch. There's no general way to turn a random collection of grobs back into a function that would generate them (it's not invertible because it's not 1:1). Once you go grob, you never go back.

You could wrap a ggplot object in a custom class and overload the plot/print commands to do some custom grob manipulation, but that's probably even more hack-ish.

这篇关于ggplotGrob的反转?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆