Инверсия ggplotGrob?
У меня есть функция, которая манипулирует объектом 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")`
ОБНОВЛЕНИЕ:
Чтобы ответить на вопрос в комментарии, мотивация здесь заключается в том, чтобы программно изменить цвета этикеток на основе значения имени метки в каждой грани. Функции ниже работают хорошо (на основе ввода от крещения в предыдущем вопросе).
Я хочу, чтобы возвращаемое значение из 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
}
Ответы
Ответ 1
Я бы сказал, нет. ggplotGrob
- улица с односторонним движением. Объекты grob - это примитивы рисования, определенные сеткой. Вы можете создавать произвольные гномы с нуля. Нет никакого общего способа превратить случайный набор гномов обратно в функцию, которая будет генерировать их (она не обратима, потому что она не 1:1). Как только вы пойдете на гроб, вы никогда не вернетесь.
Вы можете обернуть объект ggplot в пользовательский класс и перегрузить команды plot/print, чтобы выполнить некоторые пользовательские манипуляции с grob, но это, вероятно, еще больше hack-ish.
Ответ 2
Вы можете попробовать следующее:
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
Ответ 3
Посмотрите на пакет ggpubr: он имеет функцию as_ggplot()
. Если ваш гроб не слишком сложен, это может быть решением!
Я бы также посоветовал взглянуть на пакет лоскутков, который прекрасно сочетает в себе ggplots... скорее всего, это не то, что вы ищете, но... посмотрите.