2016-01-14 12 views
6

Da quando mi sono aggiornato a ggplot2 2.0.0, non riesco ad organizzare i diagrammi in modo propizio utilizzando grigliaExtra. Il problema è che i grafici sfaccettati verranno compressi mentre altri si espanderanno. Le larghezze sono sostanzialmente incasinate. Voglio disporli simile al modo in cui questi singoli appezzamenti sfaccettatura sono: left align two graph edges (ggplot)Disporre la larghezza del grafico comune con gplplat 2.0.0 sfaccettato e grigliaExtra

ho messo un codice riproducibili

library(grid) # for unit.pmax() 
library(gridExtra) 

plot.iris <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) + 
    geom_point() + 
    facet_grid(. ~ Species) + 
    stat_smooth(method = "lm") 

plot.mpg <- ggplot(mpg, aes(x = cty, y = hwy, colour = factor(cyl))) + 
    geom_point(size=2.5) 

g.iris <- ggplotGrob(plot.iris) # convert to gtable 
g.mpg <- ggplotGrob(plot.mpg) # convert to gtable 

iris.widths <- g.iris$widths # extract the first three widths, 
mpg.widths <- g.mpg$widths # same for mpg plot 
max.widths <- unit.pmax(iris.widths, mpg.widths) 

g.iris$widths <- max.widths # assign max. widths to iris gtable 
g.mpg$widths <- max.widths # assign max widths to mpg gtable 

grid.arrange(g.iris,g.mpg,ncol=1) 

enter image description here

Come vedrete, il grafico in alto, il primo aspetto è espanso mentre gli altri 2 vengono compressi a destra. Il grafico inferiore non copre tutta la larghezza.

Potrebbe essere che la nuova versione di ggplot2 stia scherzando con le larghezze di gtable?

Qualcuno sa una soluzione?

La ringrazio molto

EDIT: Aggiunto foto di grafico

Sto cercando qualcosa di simile:

enter image description here

+0

g.iris $ larghezze e g.iris $ larghezze sono lunghezze diverse quindi (penso) voi non potete applicare direttamente unità.pmax attraverso di essi. Quindi prova a applicarlo alle larghezze per la parte a sinistra ea destra dei pannelli. 'max.widths <- unit.pmax (iris.widths [1: 3], mpg.widths [1: 3]); g.iris $ width [1: 3] <- max.widths; g.mpg $ width [1: 3] <- max.widths; g.iris $ width [9] <- unit.c (g.mpg $ width [5] + g.mpg $ widths [6]) ' – user20650

+0

Grazie per il suggerimento! Ho anche provato a inserire le larghezze, ma non ha funzionato neanche. l'ultima parte del codice non l'ho vista prima, ma quando lo applico, ottengo un errore da grid.arrange (e grid.draw) 'Errore nell'unità (widths, default.units): (elenco) l'oggetto non può essere forzato a digitare 'double''. Ho anche provato a cercare cosa significa ogni numero in larghezza Gtable, ma non sono riuscito a ottenere quelle informazioni –

+0

Per il tuo esempio sopra, dovrebbe funzionare senza errori - fa per me (se è il modo migliore per farlo è un altro domanda;)). Ho sostituito le tre righe 'max.widths <- unit.pmax (iris.widths, mpg.widths); ; g.iris $ width <- max.widths; g.mpg $ width <- max.widths' con le quattro righe nel commento sopra. – user20650

risposta

0

Decollo queste due linee e mantenendo il resto, ha funzionato bene

g.iris$widths <- max.widths # assign max. widths to iris gtable 
g.mpg$widths <- max.widths # assign max widths to mpg gtable 

enter image description here

Probabilmente era limitare la larghezza di loro.

+0

Grazie per il feedback, ma questo è solo un caso riproducibile. Il mio caso reale è molto più complesso e la rimozione di tali linee rende i grafici non allineati correttamente. In effetti, l'errore riproducibile non produce grafici allineati se togliamo quelle linee –

+0

Cosa vuoi ottenere? Vuoi mettere tutti i grafici di fila? – ldepaula3

+1

La mia configurazione originale è un gruppo di 4 righe e 1 colonne di grafici allineati (1 grafico per riga). Con ggplot2 1.0.1 questo è fatto con il codice sopra, ma con ggplot2 2.0.0 produce l'errore mostrato nei grafici che puoi vedere nel mio primo post. –

0

Questo è brutto, ma se si è sotto una pressione del tempo questo trucco funzionerà (non generalizzabile e dipende dalle dimensioni della finestra del grafico). In pratica, crea le 2 colonne del grafico in alto con un grafico vuoto sulla destra e indovina alle larghezze.

grid.arrange(
    grid.arrange(plot.iris, ggplot() + theme_minimal(),ncol=2, widths = c(.9, .1)), 
    plot.mpg, 
    ncol=1 
) 
1

Non sono sicuro che tu stia ancora cercando una soluzione, ma questo è abbastanza generale. Sto usando ggplot 2.1.0 (ora su CRAN). È basato su this solution. Rompendo il problema in due parti. Innanzitutto, mi occupo del lato sinistro dei grafici, assicurandomi che le larghezze per il materiale dell'asse siano le stesse. Questo è già stato fatto da altri, e ci sono soluzioni su SO. Ma non penso che il risultato appaia buono. Preferirei che i pannelli si allinassero anche sul lato destro. Quindi, in secondo luogo, la procedura assicura che le larghezze delle colonne a destra dei pannelli siano le stesse. Lo fa aggiungendo una colonna di larghezza appropriata alla destra di ciascuno dei grafici. (C'è modi forse più ordinato per farlo c'è -. Vedi soluzione @baptiste.)

library(grid) # for pmax 
library(gridExtra) # to arrange the plots 
library(ggplot2) # to construct the plots 
library(gtable) # to add columns to gtables of plots without legends 

mpg$g = "Strip text" 

# Four fairly irregular plots: legends, faceting, strips 
p1 <- ggplot(mpg, aes(displ, 1000*cty)) + 
    geom_point() + 
    facet_grid(. ~ drv) + 
    stat_smooth(method = "lm") 

p2 <- ggplot(mpg, aes(x = hwy, y = cyl, colour = factor(cyl))) + 
    geom_point() + 
    theme(legend.position=c(.8,.6), 
     legend.key.size = unit(.3, "cm")) 

p3 <- ggplot(mpg, aes(displ, cty, colour = factor(drv))) + 
    geom_point() + 
    facet_grid(. ~ drv) 


p4 <- ggplot(mpg, aes(displ, cty, colour = factor(drv))) + 
    geom_point() + 
    facet_grid(g ~ .) 

# Sometimes easier to work with lists, and it generalises nicely 
plots = list(p1, p2, p3, p4) 

# Convert to gtables 
g = lapply(plots, ggplotGrob) 

# Apply the un-exported unit.list function for grid package to each plot 
g.widths = lapply(g, function(x) grid:::unit.list(x$widths)) 


## Part 1: Make sure the widths of left axis materials are the same across the plots 
# Get first three widths from each plot 
g3.widths <- lapply(g.widths, function(x) x[1:3]) 

# Get maximum widths for first three widths across the plots 
g3max.widths <- do.call(unit.pmax, g3.widths) 

# Apply the maximum widths to each plot 
for(i in 1:length(plots)) g[[i]]$widths[1:3] = g3max.widths 

# Draw it 
do.call(grid.arrange, c(g, ncol = 1)) 


## Part 2: Get the right side of the panels aligned 
# Locate the panels 
panels <- lapply(g, function(x) x$layout[grepl("panel", x$layout$name), ]) 

# Get the position of right most panel 
r.panel = lapply(panels, function(x) max(x$r)) # position of right most panel 

# Get the number of columns to the right of the panels 
n.cols = lapply(g.widths, function(x) length(x)) # right most column 

# Get the widths of these columns to the right of the panels 
r.widths <- mapply(function(x,y,z) x[(y+1):z], g.widths, r.panel, n.cols) 

# Get the sum of these widths 
sum.r.widths <- lapply(r.widths, sum) 

# Get the maximum of these widths 
r.width = do.call(unit.pmax, sum.r.widths) 

# Add a column to the right of each gtable of width 
# equal to the difference between the maximum 
# and the width of each gtable's columns to the right of the panel. 
for(i in 1:length(plots)) g[[i]] = gtable_add_cols(g[[i]], r.width - sum.r.widths[[i]], -1) 

# Draw it 
do.call(grid.arrange, c(g, ncol = 1)) 

enter image description here

+1

Mi sono sempre chiesto perché ggplot non mantenga sempre uno spazio vuoto, indipendentemente dal fatto che una legenda sia presente o meno. Le leggende del BTW non sono sempre sul lato destro, il che può diventare un incubo se si mira alla piena generalità. – baptiste

+1

come dividere ogni trama in tre gtables indipendenti corrispondenti ai seguenti gruppi: sinistra, pannelli, destra e allineamento di questi tre separatamente? – baptiste

+0

Ho pensato alle tre regioni. Ci penserò un po ', ma non per un paio di giorni. Se vuoi intervenire con una soluzione, sentiti libero. –

5

una possibilità è quella di massaggiare ogni trama in un gtable 3x3, dove la cella centrale avvolge tutta la trama pannelli.

Utilizzando l'esempio @SandyMuspratt

# devtools::install_github("baptiste/egg") 
grid.draw(egg::ggarrange(plots=plots, ncol=1)) 

enter image description here

il vantaggio è che, una volta in questo formato standardizzato, trame possono essere combinati in vari layout molto più facilmente, indipendentemente dal numero di pannelli, legende , assi, strisce, ecc

grid.newpage() 
grid.draw(ggarrange(plots=list(p1, p4, p2, p3), widths = c(2,1), debug=TRUE)) 

enter image description here

+0

il tuo pacchetto di uova è un gioiello! Allineare ogni elemento è semplicemente fantastico. I grafici sfaccettati e sfaccettati sono quindi allineati in base all'area del grafico. E le etichette degli assi possono avere lunghezze diverse! Ha reso la mia giornata e molti altri a venire di sicuro. Molte grazie! – aurelien

+0

Questa è una soluzione eccezionale! Mi chiedo se è possibile controllare quanto sono diversi i singoli trame all'interno di "egg"? Ad esempio, plot1 è 1/2 della dimensione del grafico combinato mentre plot2 a 4 place nella restante metà. Grazie! – Tung

+1

(supponendo che tu stia parlando dell'ultimo esempio, layout 2x2) è un po 'come le larghezze (dovrebbe fare); c'è un baco anche se IIRC quindi potrebbe essere necessario modificare manualmente le ampiezze/altezze di gtable risultanti in alcuni casi – baptiste

Problemi correlati