2014-10-22 19 views
41

Ich habe eine Funktion, die ein ggplot-Objekt manipuliert, indem es in ein grob konvertiert und dann die Ebenen verändert. Ich möchte, dass die Funktion ein ggplot-Objekt zurückgibt, kein Grob. Gibt es eine einfache Möglichkeit, einen Grob wieder in gg umzuwandeln?Inverse von ggplotGrob?

The documentation auf ggplotGrob ist furchtbar spärlich.
Einfaches Beispiel:

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:

die Frage im Kommentar zu beantworten, hier die Motivation ist es, die Farben Facette Etiketten programmatisch auf den Wert der Markennamen basiert ändern in jede Facette. Die unten stehenden Funktionen funktionieren gut (basierend auf dem Input von baptise in einer vorherigen Frage).

Ich möchte für den Rückgabewert von colorByGroup ein ggplot-Objekt sein, nicht einfach ein Grob. Hier

ist der Code, für die Interessenten

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 
} 

Antwort

8

würde ich nicht sagen. ggplotGrob ist eine Einbahnstraße. Grob-Objekte sind Zeichnungs-Primitive, die durch Gitter definiert sind. Sie können beliebige Grobs von Grund auf erstellen. Es gibt keine allgemeine Möglichkeit, eine zufällige Sammlung von Grobs in eine Funktion umzuwandeln, die sie erzeugen würde (sie ist nicht invertierbar, weil sie nicht 1: 1 ist). Sobald du grob bist, gehst du nie wieder zurück.

Sie könnten ein ggplot-Objekt in eine benutzerdefinierte Klasse einfügen und die plot/print-Befehle überladen, um eine benutzerdefinierte Grob-Manipulation durchzuführen, aber das ist wahrscheinlich noch hack-ish.