2013-04-27 9 views
39

Ho alcune categorie diverse che voglio tracciare. Queste sono diverse categorie, ciascuna con il proprio set di etichette, ma che ha senso raggrupparsi nel documento. Di seguito fornisce alcuni semplici barre in pila grafico esempi:Come posso creare grafici a larghezza costante in ggplot (con legende)?

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 diverse etichette, le leggende hanno diverse larghezze, il che significa che le trame hanno diverse larghezze, che porta alle cose cercando un po 'goffo se faccio un tabella o elementi \subfigure. Come posso risolvere questo?

C'è un modo per impostare in modo esplicito la larghezza (assoluta o relativa) del grafico o della legenda?

Chart 1 based on x (wider) Chart 2 based on y (narrower)

+2

un'altra alternativa: si potrebbe forse mettere le leggende in alto/in basso/dentro la trama? – Arun

+4

'+ theme (legend.position =" top ")' (o "bottom") (o) '+ theme (legend.position = c (1,0), legend.justification = c (1,0))' – Arun

risposta

30

Edit: molto facile con egg pacchetto disponibile presso 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) 

originale Udated a ggplot2 2.2.1

Ecco una soluzione che utilizza le funzioni da il pacchetto gtable e si concentra su le larghezze delle scatole delle legende. (Una soluzione più generale può essere trovato here.)

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 leggenda hanno bisogno di essere giustificato a sinistra, e prendendo in prestito un po 'di codice scritto da here @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) 

enter image description here

soluzioni alternative ci sono rbind e cbind funzioni nel pacchetto gtable per combinare gro bs in un grob. Per i grafici qui, le larghezze dovrebbero essere impostate utilizzando size = "max", ma la versione CRAN di gtable genera un errore.

Un'opzione: dovrebbe essere ovvio che la legenda nella seconda trama è più ampia. Pertanto, utilizzare 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 allineato 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 è da usare rbind dal pacchetto di Baptiste gridExtra

# 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 allineato 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) 
+1

È eccellente! Queste funzioni e variabili sono documentate ovunque o hai semplicemente guardato attraverso la sorgente 'ggplot'? –

+0

@ jamie.f.olson C'è il [manuale di Gtable] (http://cran.r-project.org/web/packages/gtable/index.html) su CRAN, ma a parte questo, si tratta di prendere prendere nota degli esempi di altri su SO e talvolta sulla [mailing list ggplot] (https://groups.google.com/forum/?hl=it&fromgroups#!forum/ggplot2). –

+1

Hai provato 'rbind()' a inserire i grafici? Dovrebbe funzionare, ma non ricordo se abbiamo finito quel codice. – hadley

8

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

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

tuttavia, le larghezze di layout dovrebbe essere idealmente size="max", che doesn't cope well con alcuni tipi di unità di griglia.

+0

Is: 'Errore in mmm

+0

è necessario eseguire il codice di esempio per vederlo – baptiste

1

Solo per 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 suggerito di spostare la legenda in fondo superiore o:

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") 

enter image description here enter image description here

Ora, le trame hanno la stessa larghezza come richiesto. Inoltre, l'area di stampa è ugualmente dimensionata in entrambi i casi.

Se ci sono più fattori o etichette ancora più lunghe, potrebbe essere necessario giocare con la legenda, ad es., 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.

5

Il pacchetto cowplot ha anche la funzione align_plots per questo scopo (uscita non mostrata),

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 le trame allo stesso file.

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

enter image description here

Problemi correlati