2014-10-22 2 views
41

У меня есть функция, которая манипулирует объектом ggplot, преобразовывая его в grob и затем изменяя слои. Я хотел бы, чтобы функция возвращала объект ggplot, а не grob. Есть ли простой способ конвертировать grob обратно в gg?Обратный ggplotGrob?

The documentation на 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")` 

UPDATE:

Чтобы ответить на этом вопрос в комментариях, мотивация здесь является изменение цвета фасеточных этикеток программно, на основе значения имени метки в каждая грань. Функции ниже работают хорошо (на основе ввода от крещения в предыдущем вопросе).

Я бы хотел, чтобы возвращаемое значение от colorByGroup было объектом ggplot, а не просто гробом.

Вот код, для тех, кто заинтересован

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 
} 

ответ

8

я бы сказал нет. ggplotGrob - улица с односторонним движением. Объекты grob - это примитивы рисования, определенные сеткой. Вы можете создавать произвольные гномы с нуля. Нет никакого общего способа превратить случайную коллекцию grobs обратно в функцию, которая их генерирует (она не обратима, потому что это не 1: 1). Как только вы пойдете на гроб, вы никогда не вернетесь.

Вы можете обернуть объект ggplot в пользовательский класс и перегрузить команды plot/print, чтобы выполнить некоторые пользовательские манипуляции с grob, но это, вероятно, еще больше hack-ish.

Смежные вопросы