2012-11-15 2 views
22

Vorrei rimuovere un layer (in questo caso i risultati di geom_ribbon) da un oggetto griglia creato da ggplot2. C'è un modo per rimuoverlo una volta che fa già parte dell'oggetto?Rimuovere un livello da un grafico ggplot2

library(ggplot2) 
dat <- data.frame(x=1:3, y=1:3, ymin=0:2, ymax=2:4) 
p <- ggplot(dat, aes(x=x, y=y)) + geom_ribbon(aes(ymin=ymin, ymax=ymax), alpha=0.3) 
    + geom_line() 

# This has the geom_ribbon 
p 

# This overlays another ribbon on top 
p + geom_ribbon(aes(ymin=ymin, ymax=ymax, fill=NA)) 

Mi piacerebbe questa funzionalità per permettermi di costruire trame più complicate in aggiunta a quelle meno complicate. Sto usando funzioni che restituiscono un oggetto di griglia e quindi stampano il grafico finale una volta che è completamente assemblato. Il grafico di base ha una riga singola con una barra di errore corrispondente (geom_ribbon) che lo circonda. La trama più complicata avrà più righe e gli oggetti multipli sovrapposti di geom_ribbon non sono interessanti. Mi piacerebbe rimuoverli dai grafici con più righe. Inoltre, sarò in grado di creare rapidamente versioni alternative utilizzando sfaccettature o altre funzionalità di ggplot2.


Edit: Accettare la risposta di @ mnel come funziona. Ora ho bisogno di determinare come accedere dinamicamente al livello geom_ribbon, che viene catturato nella domanda SO here.


Edit 2: Per completezza, questa è la funzione che ho creato per risolvere questo problema:

remove_geom <- function(ggplot2_object, geom_type) { 
    layers <- lapply(ggplot2_object$layers, function(x) if(x$geom$objname == geom_type) NULL else x) 
    layers <- layers[!sapply(layers, is.null)] 

    ggplot2_object$layers <- layers 
    ggplot2_object 
} 
+0

Puoi descrivere un caso d'uso in cui utilizzeresti questo? – Andrie

+0

Trovare il particolare layer all'interno di 'p $ layers' e poi cancellarlo assegnando' NULL' ad esso probabilmente "funzionerebbe" ma non faccio previsioni sull'affidabilità. – joran

+0

Credo di non aver capito bene. Se devi averlo, ma non vuoi vederlo, perché non 'alpha = 0'? – Mikko

risposta

5

Per ggplot2 versione 2.2.1, ho dovuto modificare la proposta di remove_geom funzione come questa:

remove_geom <- function(ggplot2_object, geom_type) { 
    # Delete layers that match the requested type. 
    layers <- lapply(ggplot2_object$layers, function(x) { 
    if (class(x$geom)[1] == geom_type) { 
     NULL 
    } else { 
     x 
    } 
    }) 
    # Delete the unwanted layers. 
    layers <- layers[!sapply(layers, is.null)] 
    ggplot2_object$layers <- layers 
    ggplot2_object 
} 

Ecco un esempio di come usarlo:

library(ggplot2) 

set.seed(3000) 
d <- data.frame(
    x = runif(10), 
    y = runif(10), 
    label = sprintf("label%s", 1:10) 
) 

p <- ggplot(d, aes(x, y, label = label)) + geom_point() + geom_text() 

Facciamo vedere la trama originale:

p 

plot with text labels

Ora rimuoviamo le etichette e mostriamo di nuovo il grafico:

p <- remove_geom(p, "GeomText") 
p 

plot without text labels

16

Se si guarda alla

p$layers 
[[1]] 
mapping: ymin = ymin, ymax = ymax 
geom_ribbon: na.rm = FALSE, alpha = 0.3 
stat_identity: 
position_identity: (width = NULL, height = NULL) 

[[2]] 
geom_line: 
stat_identity: 
position_identity: (width = NULL, height = NULL) 

vedrete che si desidera rimuovere il primo strato

È possibile farlo da rede multare i livelli come solo il secondo componente nell'elenco.

p$layer <- p$layer[2] 

Ora costruire e la trama p

p 

Nota che p$layer[[1]] <- NULL avrebbe funzionato pure. Sono d'accordo con i commenti di @Andrie e @ Joran riguardo a casi in cui questo potrebbe essere utile, e non mi aspetto che questo sia necessariamente affidabile. enter image description here

+0

Anche questo è stato un mio pensiero, ma non l'ho provato in situazioni più complesse in cui il livello che stai cancellando potrebbe avere scale, legende, ecc. Associati – joran

+0

Se si guarda come funziona 'ggplot_build', si basa tutto su il componente 'layers' della trama, quindi dovrebbe essere ragionevolmente robusto (a meno che non stiate usando' qplot', i meccanismi interni di cui non ho investigato.) – mnel

+0

Penso che tu abbia ragione; almeno i miei test iniziali con alcune trame più complicate sembravano andar bene. – joran

1

@Kamil Slowikowski Grazie! Molto utile. Tuttavia non ho potuto impedirmi di creare una nuova variante sullo stesso tema ... speriamo che sia più facile da capire rispetto a quella del post originale o della versione aggiornata di Kamil, evitando anche alcuni incarichi.

remove_geoms <- function(x, geom_type) { 
    # Find layers that match the requested type. 
    selector <- sapply(x$layers, 
        function(y) { 
         class(y$geom)[1] == geom_type 
        }) 
    # Delete the layers. 
    x$layers[selector] <- NULL 
    x 
} 

Questa versione è funzionalmente identica alla funzione di Kamil, quindi l'esempio di utilizzo di cui sopra non deve essere ripetuto qui.

Per inciso, questa funzione può essere facilmente adattata per selezionare i livelli in base alla classe della stat anziché alla classe della geom.

remove_stats <- function(x, stat_type) { 
    # Find layers that match the requested type. 
    selector <- sapply(x$layers, 
        function(y) { 
         class(y$stat)[1] == stat_type 
        }) 
    # Delete the layers. 
    x$layers[selector] <- NULL 
    x 
} 
2

Poiché questo problema sembrava interessante, ho ampliato il mio pacchetto 'ggpmisc' con le funzioni per manipolare i layer di un oggetto ggplot. Le funzioni sono versioni più raffinate dell'esempio nella mia precedente risposta a questa stessa domanda. Tuttavia, tieni presente che nella maggior parte dei casi questo non è il modo migliore di lavorare in quanto viola la grammatica della grafica. Nella maggior parte dei casi è possibile assemblare diverse variazioni della stessa figura in modo normale con l'operatore +, eventualmente "impacchettare" gruppi di livelli in elenchi per disporre di blocchi predefiniti che semplificano l'assemblaggio di figure complesse. In via eccezionale potremmo voler modificare un grafico esistente o un output di trama da una funzione di livello superiore la cui definizione non possiamo modificare. In tali casi queste funzioni di manipolazione degli strati possono essere utili. L'esempio sopra diventa.

library(ggpmisc) 
p1 <- delete_layers(p, match_type = "GeomText") 

Vedere la documentazione del pacchetto per altri esempi e per informazioni sulle funzioni compagno utili per modificare l'ordine di strati, e per inserire nuovi strati in posizioni arbitrarie.