web-dev-qa-db-de.com

Side-by-Side-Grundstücke mit ggplot2

Ich möchte zwei Diagramme mit dem ggplot2-Paket nebeneinander platzieren, d. H. Das Äquivalent von par(mfrow=c(1,2)) ausführen.

Ich möchte zum Beispiel, dass die folgenden zwei Diagramme nebeneinander mit demselben Maßstab angezeigt werden.

x <- rnorm(100)
eps <- rnorm(100,0,.2)
qplot(x,3*x+eps)
qplot(x,2*x+eps)

Muss ich sie im gleichen data.frame ablegen?

qplot(displ, hwy, data=mpg, facets = . ~ year) + geom_smooth()
302

Beliebige GG-Diagramme nebeneinander (oder n Diagramme in einem Raster)

Die Funktion grid.arrange() im Paket gridExtra kombiniert mehrere Diagramme. So setzen Sie zwei nebeneinander.

require(gridExtra)
plot1 <- qplot(1)
plot2 <- qplot(1)
grid.arrange(plot1, plot2, ncol=2)

Dies ist nützlich, wenn die beiden Diagramme nicht auf denselben Daten basieren, z. B. wenn Sie verschiedene Variablen ohne Verwendung von reshape () zeichnen möchten.

Dies zeichnet die Ausgabe als Nebeneffekt auf. Geben Sie zum Drucken des Nebeneffekts in eine Datei einen Gerätetreiber an (z. B. pdf, png usw.), z.

pdf("foo.pdf")
grid.arrange(plot1, plot2)
dev.off()

oder verwenden Sie arrangeGrob() in Kombination mit ggsave(),

ggsave("foo.pdf", arrangeGrob(plot1, plot2))

Dies entspricht dem Erstellen von zwei unterschiedlichen Plots mit par(mfrow = c(1,2)). Dies spart nicht nur Zeit beim Anordnen von Daten, sondern ist auch dann erforderlich, wenn Sie zwei unterschiedliche Darstellungen wünschen.


Anhang: Verwenden von Facetten

Facetten sind hilfreich, um ähnliche Diagramme für verschiedene Gruppen zu erstellen. Dies wird nachfolgend in vielen Antworten hervorgehoben, aber ich möchte diesen Ansatz mit Beispielen hervorheben, die den obigen Darstellungen entsprechen.

mydata <- data.frame(myGroup = c('a', 'b'), myX = c(1,1))

qplot(data = mydata, 
    x = myX, 
    facets = ~myGroup)

ggplot(data = mydata) + 
    geom_bar(aes(myX)) + 
    facet_wrap(~myGroup)

Aktualisieren

die Funktion plot_grid in cowplot ist eine Alternative zu grid.arrange. Siehe Antwort von @ claus-wilke unten und diese Vignette für eine äquivalente Vorgehensweise; Mit dieser Funktion können Sie jedoch die Position und Größe des Diagramms anhand von diese Vignette genauer steuern.

444
David LeBauer

Ein Nachteil der auf grid.arrange Basierenden Lösungen ist, dass sie es schwierig machen, die Diagramme mit Buchstaben (A, B usw.) zu kennzeichnen, wie es die meisten Journale erfordern.

Ich habe das Paket cowplot geschrieben, um dieses (und einige andere) Probleme zu lösen, insbesondere die Funktion plot_grid():

library(cowplot)

iris1 <- ggplot(iris, aes(x = Species, y = Sepal.Length)) +
  geom_boxplot() + theme_bw()

iris2 <- ggplot(iris, aes(x = Sepal.Length, fill = Species)) +
  geom_density(alpha = 0.7) + theme_bw() +
  theme(legend.position = c(0.8, 0.8))

plot_grid(iris1, iris2, labels = "AUTO")

enter image description here

Das Objekt, das plot_grid() zurückgibt, ist ein anderes ggplot2-Objekt, und Sie können es wie gewohnt mit ggsave() speichern:

p <- plot_grid(iris1, iris2, labels = "AUTO")
ggsave("plot.pdf", p)

Alternativ können Sie die Cowplot-Funktion save_plot() verwenden, bei der es sich um eine dünne Hülle um ggsave() handelt, mit der die richtigen Abmessungen für kombinierte Diagramme leicht ermittelt werden können, z.

p <- plot_grid(iris1, iris2, labels = "AUTO")
save_plot("plot.pdf", p, ncol = 2)

(Das Argument ncol = 2 Teilt save_plot() mit, dass zwei Diagramme nebeneinander vorliegen, und save_plot() macht das gespeicherte Bild doppelt so breit.)

Eine ausführlichere Beschreibung zum Anordnen von Diagrammen in einem Raster finden Sie in dieser Vignette . Es gibt auch eine Vignette, in der erklärt wird, wie Sie Diagramme mit einem erstellen. geteilte Legende.

Ein häufiger Punkt der Verwirrung ist, dass das Cowplot-Paket das Standard-Thema ggplot2 ändert. Das Paket verhält sich so, weil es ursprünglich für interne Laborbedingungen geschrieben wurde und wir niemals das Standarddesign verwenden. Wenn dies zu Problemen führt, können Sie sie mithilfe einer der folgenden drei Methoden umgehen:

1. Stellen Sie das Thema manuell für jeden Plot ein. Ich denke, es ist eine gute Praxis, immer ein bestimmtes Thema für jeden Plot anzugeben, so wie ich es im obigen Beispiel mit + theme_bw() getan habe. Wenn Sie ein bestimmtes Thema angeben, spielt das Standardthema keine Rolle.

2. Setzen Sie das Standarddesign auf den Standardwert von ggplot2 zurück. Sie können dies mit einer Codezeile tun:

theme_set(theme_gray())

3. Rufen Sie Cowplot-Funktionen auf, ohne das Paket anzuhängen. Sie können auch nicht library(cowplot) oder require(cowplot) aufrufen und stattdessen Cowplot-Funktionen aufrufen, indem Sie cowplot:: Voranstellen. Zum Beispiel würde das obige Beispiel unter Verwendung des Standardthemas ggplot2 wie folgt aussehen:

## Commented out, we don't call this
# library(cowplot)

iris1 <- ggplot(iris, aes(x = Species, y = Sepal.Length)) +
  geom_boxplot()

iris2 <- ggplot(iris, aes(x = Sepal.Length, fill = Species)) +
  geom_density(alpha = 0.7) +
  theme(legend.position = c(0.8, 0.8))

cowplot::plot_grid(iris1, iris2, labels = "AUTO")

enter image description here

Updates:

  • Ab Cowplot 1.0 wird das Standarddesign von ggplot2 nicht mehr geändert.
  • Ab ggplot2 3.0.0 können Diagramme direkt beschriftet werden, siehe z. hier.
130
Claus Wilke

Sie können die folgende multiplot -Funktion aus Winston Changs R-Kochbuch verwenden

multiplot(plot1, plot2, cols=2)

multiplot <- function(..., plotlist=NULL, cols) {
    require(grid)

    # Make a list from the ... arguments and plotlist
    plots <- c(list(...), plotlist)

    numPlots = length(plots)

    # Make the panel
    plotCols = cols                          # Number of columns of plots
    plotRows = ceiling(numPlots/plotCols) # Number of rows needed, calculated from # of cols

    # Set up the page
    grid.newpage()
    pushViewport(viewport(layout = grid.layout(plotRows, plotCols)))
    vplayout <- function(x, y)
        viewport(layout.pos.row = x, layout.pos.col = y)

    # Make each plot, in the correct location
    for (i in 1:numPlots) {
        curRow = ceiling(i/plotCols)
        curCol = (i-1) %% plotCols + 1
        print(plots[[i]], vp = vplayout(curRow, curCol ))
    }

}
46
David LeBauer

Mit dem Patchwork Paket können Sie einfach + Operator:

# install.packages("devtools")
devtools::install_github("thomasp85/patchwork")

library(ggplot2)
p1 <- ggplot(mtcars) + geom_point(aes(mpg, disp))
p2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear))

library(patchwork)
p1 + p2

patchwork

18
Deena

Ja, denken Sie, Sie müssen Ihre Daten entsprechend arrangieren. Ein Weg wäre dies:

X <- data.frame(x=rep(x,2),
                y=c(3*x+eps, 2*x+eps),
                case=rep(c("first","second"), each=100))

qplot(x, y, data=X, facets = . ~ case) + geom_smooth()

Ich bin mir sicher, dass es bessere Tricks in Sachen Plyr oder Reshape gibt - ich bin mit all diesen leistungsstarken Paketen von Hadley immer noch nicht wirklich auf dem neuesten Stand.

17

Mit dem Reshape-Paket können Sie so etwas tun.

library(ggplot2)
wide <- data.frame(x = rnorm(100), eps = rnorm(100, 0, .2))
wide$first <- with(wide, 3 * x + eps)
wide$second <- with(wide, 2 * x + eps)
long <- melt(wide, id.vars = c("x", "eps"))
ggplot(long, aes(x = x, y = value)) + geom_smooth() + geom_point() + facet_grid(.~ variable)
15
Thierry

Update: Diese Antwort ist sehr alt. gridExtra::grid.arrange() ist jetzt der empfohlene Ansatz. Ich lasse dies hier, falls es nützlich sein könnte.


Stephen Turner hat die Funktion arrange() am gepostet Genetik fertigstellen Blog (siehe Beitrag für Anweisungen zur Bewerbung)

vp.layout <- function(x, y) viewport(layout.pos.row=x, layout.pos.col=y)
arrange <- function(..., nrow=NULL, ncol=NULL, as.table=FALSE) {
 dots <- list(...)
 n <- length(dots)
 if(is.null(nrow) & is.null(ncol)) { nrow = floor(n/2) ; ncol = ceiling(n/nrow)}
 if(is.null(nrow)) { nrow = ceiling(n/ncol)}
 if(is.null(ncol)) { ncol = ceiling(n/nrow)}
        ## NOTE see n2mfrow in grDevices for possible alternative
grid.newpage()
pushViewport(viewport(layout=grid.layout(nrow,ncol) ) )
 ii.p <- 1
 for(ii.row in seq(1, nrow)){
 ii.table.row <- ii.row 
 if(as.table) {ii.table.row <- nrow - ii.table.row + 1}
  for(ii.col in seq(1, ncol)){
   ii.table <- ii.p
   if(ii.p > n) break
   print(dots[[ii.table]], vp=vp.layout(ii.table.row, ii.col))
   ii.p <- ii.p + 1
  }
 }
}
10
Jeromy Anglim

ggplot2 basiert auf Gittergrafiken, die ein anderes System zum Anordnen von Plots auf einer Seite bieten. Der Befehl par(mfrow...) hat keine direkte Entsprechung, da Rasterobjekte (genannt Grobs ) nicht unbedingt sofort gezeichnet werden, sondern können als reguläre R-Objekte gespeichert und bearbeitet werden, bevor sie in eine grafische Ausgabe umgewandelt werden. Dies ermöglicht eine größere Flexibilität als das Zeichnen dieses jetzt Modells von Basisgrafiken, aber die Strategie ist notwendigerweise ein wenig anders.

Ich habe grid.arrange() geschrieben, um eine einfache Schnittstelle bereitzustellen, die der von par(mfrow) möglichst nahe kommt. In seiner einfachsten Form würde der Code so aussehen:

library(ggplot2)
x <- rnorm(100)
eps <- rnorm(100,0,.2)
p1 <- qplot(x,3*x+eps)
p2 <- qplot(x,2*x+eps)

library(gridExtra)
grid.arrange(p1, p2, ncol = 2)

enter image description here

Weitere Optionen finden Sie in diese Vignette .

Eine häufige Beschwerde ist, dass Parzellen nicht unbedingt aufeinander abgestimmt sind, z. Wenn sie Achsenbeschriftungen unterschiedlicher Größe haben, ist dies jedoch beabsichtigt: grid.arrange unternimmt keinen Versuch, ggplot2-Objekte in Sonderfällen zuzuordnen, und behandelt sie gleichermaßen für andere Gruppen (z. B. Gitterdiagramme). Es werden lediglich Grobs in einem rechteckigen Layout platziert.

Für den Spezialfall von ggplot2-Objekten habe ich eine andere Funktion, ggarrange, mit einer ähnlichen Schnittstelle geschrieben, die versucht, Diagrammfelder (einschließlich facettierter Diagramme) auszurichten und die Seitenverhältnisse zu berücksichtigen, wenn dies vom Benutzer definiert wird.

library(Egg)
ggarrange(p1, p2, ncol = 2)

Beide Funktionen sind kompatibel mit ggsave(). Um einen allgemeinen Überblick über die verschiedenen Optionen und einen historischen Kontext zu erhalten, diese Vignette enthält zusätzliche Informationen .

9
baptiste

Es gibt auch multipanelfigure package das es wert ist erwähnt zu werden. Siehe auch diese Antwort .

library(ggplot2)
theme_set(theme_bw())

q1 <- ggplot(mtcars) + geom_point(aes(mpg, disp))
q2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear))
q3 <- ggplot(mtcars) + geom_smooth(aes(disp, qsec))
q4 <- ggplot(mtcars) + geom_bar(aes(carb))

library(magrittr)
library(multipanelfigure)
figure1 <- multi_panel_figure(columns = 2, rows = 2, panel_label_type = "none")
# show the layout
figure1

figure1 %<>%
  fill_panel(q1, column = 1, row = 1) %<>%
  fill_panel(q2, column = 2, row = 1) %<>%
  fill_panel(q3, column = 1, row = 2) %<>%
  fill_panel(q4, column = 2, row = 2)
figure1

# complex layout
figure2 <- multi_panel_figure(columns = 3, rows = 3, panel_label_type = "upper-roman")
figure2

figure2 %<>%
  fill_panel(q1, column = 1:2, row = 1) %<>%
  fill_panel(q2, column = 3, row = 1) %<>%
  fill_panel(q3, column = 1, row = 2) %<>%
  fill_panel(q4, column = 2:3, row = 2:3)
figure2

Erstellt am 06.07.2018 von reprex package (v0.2.0.9000).

9
Tung

Mit tidyverse:

x <- rnorm(100)
eps <- rnorm(100,0,.2)
df <- data.frame(x, eps) %>% 
  mutate(p1 = 3*x+eps, p2 = 2*x+eps) %>% 
  tidyr::gather("plot", "value", 3:4) %>% 
  ggplot(aes(x = x , y = value)) + 
    geom_point() + 
    geom_smooth() + 
    facet_wrap(~plot, ncol =2)

df

enter image description here

4
aelwan

Die obigen Lösungen sind möglicherweise nicht effizient, wenn Sie mehrere ggplot-Diagramme mit einer Schleife zeichnen möchten (z. B. wie hier gefragt: Erstellen mehrerer Diagramme in ggplot mit verschiedenen Y-Achsenwerten mit einer Schleife ). Dies ist a gewünschter Schritt bei der Analyse der unbekannten (oder großen) Datensätze (z. B. wenn Sie die Anzahl aller Variablen in einem Datensatz zeichnen möchten).

Der folgende Code zeigt, wie dies mit dem oben erwähnten 'multiplot ()' gemacht wird, dessen Quelle hier ist: http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_ (ggplot2) :

plotAllCounts <- function (dt){   
  plots <- list();
  for(i in 1:ncol(dt)) {
    strX = names(dt)[i]
    print(sprintf("%i: strX = %s", i, strX))
    plots[[i]] <- ggplot(dt) + xlab(strX) +
      geom_point(aes_string(strX),stat="count")
  }

  columnsToPlot <- floor(sqrt(ncol(dt)))
  multiplot(plotlist = plots, cols = columnsToPlot)
}

Führen Sie nun die Funktion aus, um die Anzahl aller Variablen, die mit ggplot gedruckt wurden, auf einer Seite anzuzeigen

dt = ggplot2::diamonds
plotAllCounts(dt)

Folgendes ist zu beachten:
Mit aes(get(strX)), das Sie normalerweise in Schleifen verwenden würden, wenn Sie mit ggplot arbeiten, werden im obigen Code anstelle von aes_string(strX) NICHT die gewünschten Diagramme gezeichnet . Stattdessen wird der letzte Plot viele Male geplottet. Ich habe nicht herausgefunden, warum - es kann sein, dass aes und aes_string In ggplot aufgerufen werden müssen.

Ansonsten hoffe ich, dass Sie die Funktion nützlich finden.

1
IVIM

Das cowplot -Paket bietet Ihnen eine gute Möglichkeit, dies auf eine Weise zu tun, die zur Veröffentlichung passt.

x <- rnorm(100)
eps <- rnorm(100,0,.2)
A = qplot(x,3*x+eps, geom = c("point", "smooth"))+theme_gray()
B = qplot(x,2*x+eps, geom = c("point", "smooth"))+theme_gray()
cowplot::plot_grid(A, B, labels = c("A", "B"), align = "v")

enter image description here

0
tim