55

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

的文档ggplotGrob非常稀疏。
简单的例子:

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")`

更新:

为了回答评论中的问题,这里的动机是根据每个构面中标签名称的值以编程方式修改构面标签的颜色。下面的函数运行良好(基于上一个问题中 baptise 的输入)。

我希望 from 的返回值colorByGroup是一个 ggplot 对象,而不仅仅是一个 grob。

代码如下,有兴趣的可以看看

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
}
4

3 回答 3

15

我会说不。ggplotGrob是一条单行道。grob 对象是由网格定义的绘图图元。您可以从头开始创建任意 grobs。没有通用的方法可以将随机的 grobs 集合转换回生成它们的函数(它不可逆,因为它不是 1:1)。一旦你去 grob,你就再也回不去了。

您可以将 ggplot 对象包装在自定义类中,并重载绘图/打印命令以进行一些自定义 grob 操作,但这可能更加hack-ish。

于 2017-09-11T17:26:52.760 回答
6

您可以尝试以下方法:

p = ggplotify::as.ggplot(g)

有关更多信息,请参阅https://cran.r-project.org/web/packages/ggplotify/vignettes/ggplotify.html

它涉及一点点作弊annotation_custom(as.grob(plot),...),因此它可能不适用于所有情况:https ://github.com/GuangchuangYu/ggplotify/blob/master/R/as-ggplot.R

于 2018-11-09T23:37:56.820 回答
3

看看ggpubr包:它有一个函数as_ggplot(). 如果您的 grob 不是太复杂,它可能是一个解决方案!

我还建议您查看完美结合 ggplots 的patchwork 包……它可能不是您要找的东西,但是……看看。

于 2019-09-05T13:53:55.927 回答