Aligner à gauche deux bords du graphique (ggplot)

105

J'utilise ggplot et j'ai deux graphiques que je veux afficher l'un sur l'autre. J'ai utilisé grid.arrangede gridExtra pour les empiler. Le problème est que je veux que les bords gauches des graphiques s'alignent ainsi que les bords droits indépendamment des étiquettes d'axe. (le problème se pose parce que les étiquettes d'un graphique sont courtes tandis que l'autre est longue).

La question:
comment puis-je faire cela? Je ne suis pas marié à grid.arrange mais le ggplot2 est un must.

Ce que j'ai essayé:
j'ai essayé de jouer avec les largeurs et les hauteurs ainsi que ncol et nrow pour créer une grille 2 x 2 et placer les visuels dans les coins opposés, puis jouer avec les largeurs mais je ne pouvais pas obtenir les visuels dans les coins opposés .

require(ggplot2);require(gridExtra)
A <- ggplot(CO2, aes(x=Plant)) + geom_bar() +coord_flip() 
B <- ggplot(CO2, aes(x=Type)) + geom_bar() +coord_flip() 
grid.arrange(A, B, ncol=1)

entrez la description de l'image ici

Tyler Rinker
la source
2
Voici deux options possibles: ici et ici .
joran
@Joran Je cherche les axes de gauche à aligner. Je ne pense pas que cela suffira. J'aimerais bien me tromper.
Tyler Rinker

Réponses:

132

Essaye ça,

 gA <- ggplotGrob(A)
 gB <- ggplotGrob(B)
 maxWidth = grid::unit.pmax(gA$widths[2:5], gB$widths[2:5])
 gA$widths[2:5] <- as.list(maxWidth)
 gB$widths[2:5] <- as.list(maxWidth)
 grid.arrange(gA, gB, ncol=1)

Éditer

Voici une solution plus générale (travaille avec un certain nombre de parcelles) en utilisant une version modifiée de rbind.gtableinclus dansgridExtra

gA <- ggplotGrob(A)
gB <- ggplotGrob(B)
grid::grid.newpage()
grid::grid.draw(rbind(gA, gB))
baptiste
la source
3
Beau et vraiment assez simple. Merci pour la solution.
Tyler Rinker
1
Solution parfaite! Je cherchais quelque chose comme ça pour aligner plusieurs tracés de séries chronologiques séparés que je ne peux pas faire avec des facettes en raison de la personnalisation majeure de chaque tracé.
wahalulu
Auriez-vous l'amabilité de nous indiquer quelle serait la manière de faire correspondre la hauteur si nous avons deux colonnes? gA $ heights [2: 3] ne semble pas fonctionner. Dois-je sélectionner un autre élément du grob que 2: 3? Je vous remercie!
Etienne Low-Décarie
4
Merci pour votre solution Baptiste. Cependant, je ne fais pas fonctionner cela lorsque l'une des parcelles est un tableGrob. Le gtable::cbindme donne une erreur décevante: nrow(x) == nrow(y) is not TRUE. Aucune suggestion?
Gabra du
2
Cette solution a fonctionné pour moi, j'essaie de la comprendre. À quoi sert le [2:5]stand?
Hurlikus
38

Je voulais généraliser cela pour n'importe quel nombre de parcelles. Voici une solution étape par étape utilisant l'approche de Baptiste:

plots <- list(A, B, C, D)
grobs <- list()
widths <- list()

collecter les largeurs pour chaque grain de chaque parcelle

for (i in 1:length(plots)){
    grobs[[i]] <- ggplotGrob(plots[[i]])
    widths[[i]] <- grobs[[i]]$widths[2:5]
}

utilisez do.call pour obtenir la largeur maximale

maxwidth <- do.call(grid::unit.pmax, widths)

attribuer la largeur maximale à chaque grob

for (i in 1:length(grobs)){
     grobs[[i]]$widths[2:5] <- as.list(maxwidth)
}

terrain

do.call("grid.arrange", c(grobs, ncol = 1))
slizb
la source
2
Fonctionne même lorsque les parcelles ont des légendes de largeurs variables - très bien!
Keith Hughitt
30

Utilisation du package cowplot :

A <- ggplot(CO2, aes(x=Plant)) + geom_bar() +coord_flip() 
B <- ggplot(CO2, aes(x=Type)) + geom_bar() +coord_flip() 

library(cowplot)
plot_grid(A, B, ncol=1, align="v")

entrez la description de l'image ici

zx8754
la source
12

Sur http://rpubs.com/MarkusLoew/13295 se trouve une solution vraiment simple disponible (dernier élément) appliquée à ce problème:

require(ggplot2);require(gridExtra)
A <- ggplot(CO2, aes(x=Plant)) + geom_bar() +coord_flip() 
B <- ggplot(CO2, aes(x=Type)) + geom_bar() +coord_flip() 
grid.draw(rbind(ggplotGrob(A), ggplotGrob(B), size="first"))

vous pouvez également l'utiliser pour la largeur et la hauteur:

require(ggplot2);require(gridExtra)
A <- ggplot(CO2, aes(x=Plant)) + geom_bar() +coord_flip() 
B <- ggplot(CO2, aes(x=Type)) + geom_bar() +coord_flip() 
C <- ggplot(CO2, aes(x=conc)) + geom_bar() +coord_flip()
D <- ggplot(CO2, aes(x=uptake)) + geom_bar() +coord_flip() 
grid.draw(cbind(
            rbind(ggplotGrob(A), ggplotGrob(B), size="first"),
            rbind(ggplotGrob(C), ggplotGrob(D), size="first"),
            size='first'))
Wilbert
la source
2
l'utilisation size="first"signifie que l'alignement ne sera pas très bon si la deuxième parcelle est plus grande que la première
baptiste
10

Le eggpackage enveloppe les objets ggplot dans un 3x3gtable standardisé , permettant l'alignement des panneaux de tracé entre les ggplots arbitraires, y compris ceux à facettes.

library(egg) # devtools::install_github('baptiste/egg')
library(ggplot2)

p1 <- ggplot(mtcars, aes(mpg, wt, colour = factor(cyl))) +
  geom_point() 

p2 <- ggplot(mtcars, aes(mpg, wt, colour = factor(cyl))) +
  geom_point() + facet_wrap( ~ cyl, ncol=2, scales = "free") +
  guides(colour="none") +
  theme()

ggarrange(p1, p2)

entrez la description de l'image ici

baptiste
la source
pour moi, cela pourrait correctement organiser horizontalement une simple carte thermique ( geom_tile) avec une légende en bas et une carte thermique à plusieurs facettes ( facet_gridavec geom_tile), mais n'a pas réussi à aligner la hauteur du troisième graphique, qui était un dendrogramme ( geom_segment). cependant, cowplot ou gridExtra::grid.arrangen'étant pas en mesure de faire même le premier, cela fonctionne donc le mieux jusqu'à présent
deeenes
8

Voici une autre solution possible à l'aide meltdu package reshape2, et facet_wrap:

library(ggplot2)
library(reshape2)

dat = CO2[, c(1, 2)]
dat$id = seq(nrow(dat))
mdat = melt(dat, id.vars="id")

head(mdat)
#   id variable value
# 1  1    Plant   Qn1
# 2  2    Plant   Qn1
# 3  3    Plant   Qn1
# 4  4    Plant   Qn1
# 5  5    Plant   Qn1
# 6  6    Plant   Qn1

plot_1 = ggplot(mdat, aes(x=value)) + 
         geom_bar() + 
         coord_flip() +
         facet_wrap(~ variable, nrow=2, scales="free", drop=TRUE)

ggsave(plot=plot_1, filename="plot_1.png", height=4, width=6)

entrez la description de l'image ici

bdemarest
la source
Cette solution suppose que vous disposez d'un nombre égal de lignes dans chaque colonne. Dans mon MRWE c'est vrai mais pas en réalité.
Tyler Rinker
Je ne suis pas sûr de comprendre: voulez-vous dire que l'usine CO2 $ et le type CO2 $ ont la même longueur, mais que vos données réelles ne sont pas comme ça?
bdemarest
Ce sont deux ensembles de données différents qui partagent une variable, donc le nombre de lignes n'est pas le même.
Tyler Rinker
2

Le package patchwork gère cela par défaut:

library(ggplot2)
library(patchwork)

A <- ggplot(CO2, aes(x = Plant)) + geom_bar() + coord_flip() 
B <- ggplot(CO2, aes(x = Type)) + geom_bar() + coord_flip() 

A / B

Créé le 08/12/2019 par le package reprex (v0.3.0)

MSR
la source
0

Au mieux, c'est un hack:

library(wq)
layOut(list(A, 1, 2:16),  list(B, 2:3, 1:16))

Cela semble vraiment faux.

Tyler Rinker
la source
-1

Je sais que c'est un ancien post, et qu'il a déjà été répondu, mais puis-je suggérer de combiner l'approche de @ baptiste avec purrrpour le rendre plus joli:

library(purrr)
list(A, B) %>% 
  map(ggplotGrob) %>% 
  do.call(gridExtra::gtable_rbind, .) %>% 
  grid::grid.draw()
Felipe Gerard
la source