Links zwei Grafikkanten ausrichten (ggplot)

105

Ich verwende ggplot und habe zwei Diagramme, die ich übereinander anzeigen möchte. Ich habe grid.arrangevon gridExtra verwendet, um sie zu stapeln. Das Problem ist, dass die linken Ränder der Diagramme sowie die rechten Ränder unabhängig von den Achsenbeschriftungen ausgerichtet werden sollen. (Das Problem tritt auf, weil die Beschriftungen eines Diagramms kurz und das andere lang sind.)

Die Frage:
Wie kann ich das machen? Ich bin nicht mit grid.arrange verheiratet, aber der ggplot2 ist ein Muss.

Was ich versucht habe:
Ich habe versucht, mit Breiten und Höhen sowie ncol und nrow zu spielen, um ein 2 x 2-Raster zu erstellen und die Grafiken in gegenüberliegenden Ecken zu platzieren und dann mit den Breiten zu spielen, aber ich konnte die Grafiken nicht in gegenüberliegenden Ecken erhalten .

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)

Geben Sie hier die Bildbeschreibung ein

Tyler Rinker
quelle
2
Hier sind zwei mögliche Optionen: hier und hier .
Joran
@Joran Ich suche nach den linken Achsen, die ausgerichtet werden sollen. Ich glaube nicht, dass diese es schaffen werden. Ich würde mich gerne irren.
Tyler Rinker

Antworten:

132

Versuche dies,

 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)

Bearbeiten

Hier ist eine allgemeinere Lösung (funktioniert mit einer beliebigen Anzahl von Plots) unter Verwendung einer modifizierten Version von rbind.gtableenthalten ingridExtra

gA <- ggplotGrob(A)
gB <- ggplotGrob(B)
grid::grid.newpage()
grid::grid.draw(rbind(gA, gB))
Baptiste
quelle
3
Schön und wirklich ziemlich geradlinig. Vielen Dank für die Lösung.
Tyler Rinker
1
Perfekte Lösung! Ich habe nach so etwas gesucht, um mehrere separate Zeitreihendiagramme auszurichten, die ich aufgrund der großen Anpassung in jedem Diagramm nicht mit Facettieren machen kann.
Wahalulu
Würden Sie so freundlich sein, anzugeben, wie die Höhe erreicht werden kann, wenn wir zwei Spalten haben? gA $ heights [2: 3] scheint nicht zu funktionieren. Muss ich ein anderes Element des Grobs als 2: 3 auswählen? Danke dir!
Etienne Low-Décarie
4
Vielen Dank für Ihre Lösung Baptiste. Ich bekomme dies jedoch nicht zum Laufen, wenn eine der Handlungen eine ist tableGrob. Das gtable::cbindgibt mir einen enttäuschenden Fehler : nrow(x) == nrow(y) is not TRUE. Irgendwelche Vorschläge?
Gabra
2
Diese Lösung hat bei mir funktioniert, ich versuche sie zu verstehen. Wofür steht das [2:5]?
Hurlikus
38

Ich wollte dies für eine beliebige Anzahl von Handlungen verallgemeinern. Hier ist eine schrittweise Lösung unter Verwendung des Ansatzes von Baptiste:

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

Sammeln Sie die Breiten für jeden Grob jedes Grundstücks

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

Verwenden Sie do.call, um die maximale Breite zu erhalten

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

Weisen Sie jedem Grob die maximale Breite zu

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

Handlung

do.call("grid.arrange", c(grobs, ncol = 1))
slizb
quelle
2
Funktioniert auch dann, wenn die Handlungen Legenden unterschiedlicher Breite haben - sehr schön!
Keith Hughitt
30

Mit cowplot Paket:

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

Geben Sie hier die Bildbeschreibung ein

zx8754
quelle
12

Auf http://rpubs.com/MarkusLoew/13295 ist eine wirklich einfache Lösung verfügbar (letzter Punkt). Auf dieses Problem angewendet:

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

Sie können dies auch für Breite und Höhe verwenden:

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
quelle
2
Verwenden size="first"bedeutet, dass die Ausrichtung nicht sehr gut aussieht, wenn die zweite Handlung größer ist als die erste
Baptiste
10

Das eggPaket verpackt ggplot-Objekte in eine standardisierte 3x3gtable und ermöglicht so die Ausrichtung von Plotfeldern zwischen beliebigen ggplots, einschließlich facettierten.

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)

Geben Sie hier die Bildbeschreibung ein

Baptiste
quelle
Für mich konnte dies eine einfache Heatmap ( geom_tile) mit Legende unten und eine facettenreiche Heatmap ( facet_gridmit geom_tile) richtig horizontal anordnen , aber die Höhe des dritten Diagramms, das ein Dendrogramm ( geom_segment) war, konnte nicht ausgerichtet werden. Allerdings Cowplot oder gridExtra::grid.arrangewaren nicht in der Lage, auch die ersteren zu tun, so funktioniert dies am besten bisher
deeenes
8

Hier ist eine weitere mögliche Lösung meltaus dem reshape2-Paket 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)

Geben Sie hier die Bildbeschreibung ein

bdemarest
quelle
Diese Lösung setzt voraus, dass Sie in jeder Spalte die gleiche Anzahl von Zeilen haben. In meinem MRWE ist das wahr, aber nicht in der Realität.
Tyler Rinker
Ich bin mir nicht sicher, ob ich das verstehe: Meinst du, dass CO2 $ Pflanze und CO2 $ Typ zufällig gleich lang sind, aber dass deine tatsächlichen Daten nicht so sind?
bdemarest
Es sind zwei verschiedene Datensätze, die eine Variable gemeinsam nutzen, sodass die Anzahl der Zeilen nicht gleich ist.
Tyler Rinker
2

Das Patchwork- Paket behandelt dies standardmäßig:

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

Erstellt am 08.12.2019 durch das reprex-Paket (v0.3.0)

MSR
quelle
0

Bestenfalls ist dies ein Hack:

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

Es fühlt sich aber wirklich falsch an.

Tyler Rinker
quelle
-1

Ich weiß, dass dies ein alter Beitrag ist und dass er bereits beantwortet wurde, aber ich kann vorschlagen, den Ansatz von @ baptiste mit zu kombinieren purrr , um ihn schöner aussehen zu lassen:

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