ggplotGrob的反转? [英] Inverse of 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屋!