Come posso creare grafici a larghezza consistente in ggplot (con legende)?

Ho alcune diverse categorie che voglio tracciare. Si tratta di categorie diverse , ciascuna con il proprio set di etichette, ma che ha senso raggrupparsi nel documento. Di seguito sono riportati alcuni semplici esempi di grafici a barre in pila:

df <- data.frame(x=c("a", "b", "c"), y=c("happy", "sad", "ambivalent about life")) ggplot(df, aes(x=factor(0), fill=x)) + geom_bar() ggplot(df, aes(x=factor(0), fill=y)) + geom_bar() 

Il problema è che con etichette diverse, le legende hanno larghezze diverse, il che significa che i grafici hanno larghezze diverse, il che porta a cose un po ‘sciocche se \subfigure una tabella o \subfigure elementi. Come posso risolvere questo?

C’è un modo per impostare in modo esplicito la larghezza (assoluta o relativa) della trama o della legenda?

Grafico 1 basato su x (più ampio) Grafico 2 basato su y (più stretto)

Modifica: molto facile con il pacchetto di egg disponibile su github

 # install.package(devtools) # devtools::install_github("baptiste/egg") library(egg) p1 <- ggplot(data.frame(x=c("a","b","c"), y=c("happy","sad","ambivalent about life")), aes(x=factor(0),fill=x)) + geom_bar() p2 <- ggplot(data.frame(x=c("a","b","c"), y=c("happy","sad","ambivalent about life")), aes(x=factor(0),fill=y)) + geom_bar() ggarrange(p1,p2, ncol = 1) 

Udated originale su ggplot2 2.2.1

Ecco una soluzione che utilizza le funzioni del pacchetto gtable e si concentra sulle larghezze delle caselle della legenda. (Una soluzione più generale può essere trovata qui .)

 library(ggplot2) library(gtable) library(grid) library(gridExtra) # Your plots p1 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=x)) + geom_bar() p2 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=y)) + geom_bar() # Get the gtables gA <- ggplotGrob(p1) gB <- ggplotGrob(p2) # Set the widths gA$widths <- gB$widths # Arrange the two charts. # The legend boxes are centered grid.newpage() grid.arrange(gA, gB, nrow = 2) 

Se in aggiunta, le caselle della legenda devono essere lasciate giustificate e prendere in prestito un codice da qui scritto da @Julius

 p1 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=x)) + geom_bar() p2 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=y)) + geom_bar() # Get the widths gA <- ggplotGrob(p1) gB <- ggplotGrob(p2) # The parts that differs in width leg1 <- convertX(sum(with(gA$grobs[[15]], grobs[[1]]$widths)), "mm") leg2 <- convertX(sum(with(gB$grobs[[15]], grobs[[1]]$widths)), "mm") # Set the widths gA$widths <- gB$widths # Add an empty column of "abs(diff(widths)) mm" width on the right of # legend box for gA (the smaller legend box) gA$grobs[[15]] <- gtable_add_cols(gA$grobs[[15]], unit(abs(diff(c(leg1, leg2))), "mm")) # Arrange the two charts grid.newpage() grid.arrange(gA, gB, nrow = 2) 

inserisci la descrizione dell'immagine qui

Soluzioni alternative Ci sono funzioni rbind e cbind nel pacchetto gtable per combinare i grobs in un grob. Per i grafici qui, le larghezze dovrebbero essere impostate usando size = "max" , ma la versione CRAN del gtable genera un errore.

Una possibilità: dovrebbe essere ovvio che la leggenda nella seconda trama è più ampia. Pertanto, utilizza l'opzione size = "last" .

 # Get the grobs gA <- ggplotGrob(p1) gB <- ggplotGrob(p2) # Combine the plots g = rbind(gA, gB, size = "last") # Draw it grid.newpage() grid.draw(g) 

Leggende allineate a sinistra:

 # Get the grobs gA <- ggplotGrob(p1) gB <- ggplotGrob(p2) # The parts that differs in width leg1 <- convertX(sum(with(gA$grobs[[15]], grobs[[1]]$widths)), "mm") leg2 <- convertX(sum(with(gB$grobs[[15]], grobs[[1]]$widths)), "mm") # Add an empty column of "abs(diff(widths)) mm" width on the right of # legend box for gA (the smaller legend box) gA$grobs[[15]] <- gtable_add_cols(gA$grobs[[15]], unit(abs(diff(c(leg1, leg2))), "mm")) # Combine the plots g = rbind(gA, gB, size = "last") # Draw it grid.newpage() grid.draw(g) 

Una seconda opzione è quella di utilizzare rbind dal pacchetto gridExtra di Baptiste

 # Get the grobs gA <- ggplotGrob(p1) gB <- ggplotGrob(p2) # Combine the plots g = gridExtra::rbind.gtable(gA, gB, size = "max") # Draw it grid.newpage() grid.draw(g) 

Leggende allineate a sinistra:

 # Get the grobs gA <- ggplotGrob(p1) gB <- ggplotGrob(p2) # The parts that differs in width leg1 <- convertX(sum(with(gA$grobs[[15]], grobs[[1]]$widths)), "mm") leg2 <- convertX(sum(with(gB$grobs[[15]], grobs[[1]]$widths)), "mm") # Add an empty column of "abs(diff(widths)) mm" width on the right of # legend box for gA (the smaller legend box) gA$grobs[[15]] <- gtable_add_cols(gA$grobs[[15]], unit(abs(diff(c(leg1, leg2))), "mm")) # Combine the plots g = gridExtra::rbind.gtable(gA, gB, size = "max") # Draw it grid.newpage() grid.draw(g) 

Come suggerisce @hadley, rbind.gtable dovrebbe essere in grado di gestirlo,

  grid.draw(rbind(ggplotGrob(p1), ggplotGrob(p2), size="last")) 

tuttavia, le larghezze del layout dovrebbero idealmente essere size="max" , che non risponde bene con alcuni tipi di unità di griglia.

Il pacchetto cowplot ha anche la funzione align_plots per questo scopo (output non mostrato),

 both2 <- align_plots(p1, p2, align="hv", axis="tblr") p1x <- ggdraw(both2[[1]]) p2x <- ggdraw(both2[[2]]) save_plot("cow1.png", p1x) save_plot("cow2.png", p2x) 

e anche plot_grid che salva i grafici nello stesso file.

 library(cowplot) both <- plot_grid(p1, p2, ncol=1, labels = c("A", "B"), align = "v") save_plot("cow.png", both) 

inserisci la descrizione dell'immagine qui

Per puro caso, ho notato che la soluzione di Arun che aveva suggerito nei suoi commenti non è stata rilevata. Sento che il suo approccio semplice ed efficace merita davvero di essere illustrato.

Arun suggerì di spostare la legenda in alto o in basso:

 ggplot(df, aes(x=factor(0), fill=x)) + geom_bar() + theme(legend.position = "bottom") ggplot(df, aes(x=factor(0), fill=y)) + geom_bar() + theme(legend.position = "bottom") 

inserisci la descrizione dell'immagine qui inserisci la descrizione dell'immagine qui

Ora i grafici hanno la stessa larghezza richiesta. Inoltre, l’area del tracciato è ugualmente dimensionata in entrambi i casi.

Se ci sono più fattori o etichette ancora più lunghe, potrebbe essere necessario giocare con la legenda, ad esempio, per visualizzare la legenda in due o più righe. theme() e guide_legend() hanno diversi parametri per controllare la posizione e l’aspetto delle legende in ggplot2 .