Plot berdampingan dengan ggplot2

339

Saya ingin menempatkan dua plot berdampingan menggunakan paket ggplot2 , yaitu melakukan yang setara par(mfrow=c(1,2)).

Sebagai contoh, saya ingin agar dua plot berikut ditampilkan berdampingan dengan skala yang sama.

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

Apakah saya harus meletakkannya di dalam data.frame yang sama?

qplot(displ, hwy, data=mpg, facets = . ~ year) + geom_smooth()
Christopher DuBois
sumber
Saya pikir Anda mungkin dapat melakukan ini dengan kisi. Apakah ggplot2 persyaratan sulit?
JD Long
8
Tidak. Tapi saya sudah mengatur waktu untuk mengutak-atik qplot jadi itu yang saya suka. :-) Dan saya mencoba untuk bermain-main dengan ggplot.
Christopher DuBois
1
Untuk gambaran umum yang bagus, lihat sketsa paket telur : Meletakkan beberapa plot pada halaman
Henrik

Jawaban:

505

Setiap ggplot berdampingan (atau n plot pada grid)

Fungsi grid.arrange()dalam gridExtrapaket akan menggabungkan beberapa plot; ini adalah bagaimana Anda menempatkan dua sisi berdampingan.

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

Ini berguna ketika kedua plot tidak didasarkan pada data yang sama, misalnya jika Anda ingin memplot variabel yang berbeda tanpa menggunakan membentuk kembali ().

Ini akan memplot output sebagai efek samping. Untuk mencetak efek samping ke file, menentukan driver perangkat (seperti pdf, png, dll), misalnya

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

atau, digunakan arrangeGrob()dalam kombinasi dengan ggsave(),

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

Ini setara dengan membuat dua plot berbeda menggunakan par(mfrow = c(1,2)). Ini tidak hanya menghemat waktu dalam mengatur data, tetapi juga diperlukan saat Anda menginginkan dua plot yang berbeda.


Lampiran: Menggunakan Aspek

Segi sangat membantu untuk membuat plot serupa untuk berbagai kelompok. Ini ditunjukkan di bawah ini dalam banyak jawaban di bawah, tetapi saya ingin menyoroti pendekatan ini dengan contoh yang setara dengan plot di atas.

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)

Memperbarui

yang plot_gridfungsi dalam cowplotadalah senilai check-out sebagai alternatif grid.arrange. Lihat jawaban oleh @ claus-wilke di bawah ini dan sketsa ini untuk pendekatan yang setara; tetapi fungsinya memungkinkan kontrol yang lebih baik pada lokasi dan ukuran plot, berdasarkan sketsa ini .

David LeBauer
sumber
2
Ketika saya menjalankan kode Anda menggunakan objek ggplot, sidebysideplot adalah null. Jika Anda ingin menyimpan output ke file, gunakan gridArrange. Lihat stackoverflow.com/questions/17059099/...
Jim
@ Jim, terima kasih sudah menunjukkannya. Saya telah merevisi jawaban saya. Beri tahu saya jika ada pertanyaan.
David LeBauer
1
Apakah grid.aarange sudah tidak digunakan sekarang?
Atticus29
?grid.arrangemembuat saya berpikir bahwa fungsi ini sekarang dinamakan mengaturGrob. Saya dapat melakukan apa yang saya inginkan dengan melakukan a <- arrangeGrob(p1, p2)dan kemudian print(a).
blakeoft
@blakeoft apakah Anda melihat contohnya? grid.arrangemasih merupakan fungsi yang valid dan tidak usang. Apakah Anda mencoba menggunakan fungsinya? Apa yang terjadi, jika tidak seperti yang Anda harapkan.
David LeBauer
159

Salah satu kelemahan dari solusi yang didasarkan pada grid.arrangeadalah bahwa mereka membuat sulit untuk memberi label plot dengan huruf (A, B, dll), karena kebanyakan jurnal membutuhkan.

Saya menulis paket cowplot untuk menyelesaikan masalah ini (dan beberapa lainnya), khususnya fungsinya 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")

masukkan deskripsi gambar di sini

Objek yang plot_grid()kembali adalah objek ggplot2 lain, dan Anda dapat menyimpannya ggsave()seperti biasa:

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

Sebagai alternatif, Anda dapat menggunakan fungsi cowplot save_plot(), yang merupakan pembungkus tipis ggsave()yang memudahkan untuk mendapatkan dimensi yang benar untuk plot gabungan, misalnya:

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

( ncol = 2Argumennya mengatakan save_plot()bahwa ada dua plot berdampingan, dan save_plot()membuat gambar yang disimpan dua kali lebih lebar.)

Untuk deskripsi yang lebih mendalam tentang cara mengatur plot dalam kisi, lihat sketsa ini. Ada juga sketsa yang menjelaskan cara membuat plot dengan legenda bersama.

Satu hal yang sering membingungkan adalah bahwa paket cowplot mengubah tema ggplot2 default. Paket berperilaku seperti itu karena pada awalnya ditulis untuk penggunaan lab internal, dan kami tidak pernah menggunakan tema default. Jika ini menyebabkan masalah, Anda dapat menggunakan salah satu dari tiga pendekatan berikut untuk mengatasinya:

1. Atur tema secara manual untuk setiap plot. Saya pikir itu praktik yang baik untuk selalu menentukan tema tertentu untuk setiap plot, seperti yang saya lakukan + theme_bw()pada contoh di atas. Jika Anda menentukan tema tertentu, tema default tidak masalah.

2. Kembalikan tema default kembali ke default ggplot2. Anda dapat melakukan ini dengan satu baris kode:

theme_set(theme_gray())

3. Panggil fungsi cowplot tanpa melampirkan paket. Anda juga tidak dapat memanggil library(cowplot)atau require(cowplot)memanggil fungsi cowplot dengan menambahkan terlebih dahulu cowplot::. Misalnya, contoh di atas menggunakan tema default ggplot2 akan menjadi:

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

masukkan deskripsi gambar di sini

Pembaruan:

  • Pada cowplot 1.0, tema default ggplot2 tidak berubah lagi.
  • Pada ggplot2 3.0.0, plot dapat diberi label secara langsung, lihat misalnya di sini.
Claus Wilke
sumber
di cowplot output menghapus tema latar belakang, dari kedua plot? apakah ada alternatif?
VAR121
@ VAR121 Ya, ini adalah satu baris kode. Dijelaskan di akhir bagian pertama sketsa pengantar: cran.rstudio.com/web/packages/cowplot/vignettes/…
Claus Wilke
Apakah mungkin untuk memiliki skala y yang sama untuk semua plot dengan paket ini?
Herman Toothrot
Anda harus mengatur skala y secara manual agar sesuai. Atau pertimbangkan faceting.
Claus Wilke
Anda dapat mengatur ggtitle () untuk setiap plot sebelum menggunakan grid.arrange ()?
Seanosapien
49

Anda dapat menggunakan multiplotfungsi berikut dari buku masak Winston Chang's R

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

}
David LeBauer
sumber
24

Menggunakan paket tambal sulam , Anda cukup menggunakan +operator:

library(ggplot2)
library(patchwork)

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


p1 + p2

tambal sulam

Deena
sumber
Hanya untuk kelengkapan, tambal sulam sekarang di CRAN juga. Semoga Anda senang dengan suntingan kecil saya
Tjebo
18

Ya, metode Anda perlu mengatur data Anda dengan tepat. Salah satu caranya adalah ini:

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

Saya yakin ada trik yang lebih baik dalam plyr atau membentuk kembali - saya masih belum benar-benar mempercepat semua paket kuat oleh Hadley.

Dirk Eddelbuettel
sumber
16

Menggunakan paket membentuk kembali Anda dapat melakukan sesuatu seperti ini.

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)
Thierry
sumber
12

Ada juga paket multipanelfigure yang layak untuk disebutkan. Lihat juga jawaban ini .

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

Dibuat pada 2018-07-06 oleh paket reprex (v0.2.0.9000).

Tung
sumber
9

ggplot2 didasarkan pada grafik kotak, yang menyediakan sistem berbeda untuk mengatur plot pada halaman. The par(mfrow...)perintah tidak memiliki setara langsung, grid benda (disebut grobs ) tidak selalu diambil segera, tetapi dapat disimpan dan dimanipulasi sebagai objek R biasa sebelum dikonversi ke output grafis. Ini memungkinkan fleksibilitas yang lebih besar daripada menggambar model grafis dasar yang sekarang ini , tetapi strateginya sedikit berbeda.

Saya menulis grid.arrange()untuk menyediakan antarmuka sederhana sedekat mungkin par(mfrow). Dalam bentuknya yang paling sederhana, kode tersebut akan terlihat seperti:

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)

masukkan deskripsi gambar di sini

Lebih banyak opsi dirinci dalam sketsa ini .

Salah satu keluhan umum adalah bahwa plot tidak perlu disejajarkan misalnya ketika mereka memiliki label sumbu dengan ukuran yang berbeda, tetapi ini dengan desain: grid.arrangetidak berusaha untuk objek kasus ggplot2 khusus, dan memperlakukannya sama dengan grob lain (plot kisi, misalnya ). Ini hanya menempatkan grob dalam tata letak persegi panjang.

Untuk kasus khusus objek ggplot2, saya menulis fungsi lain ggarrange,, dengan antarmuka yang sama, yang mencoba menyelaraskan panel plot (termasuk plot yang difas) dan mencoba untuk menghormati rasio aspek ketika ditentukan oleh pengguna.

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

Kedua fungsi tersebut kompatibel dengan ggsave(). Untuk tinjauan umum tentang berbagai opsi, dan beberapa konteks historis, sketsa ini menawarkan informasi tambahan .

baptiste
sumber
9

Pembaruan: Jawaban ini sudah sangat lama. gridExtra::grid.arrange()sekarang pendekatan yang direkomendasikan. Saya meninggalkan ini di sini kalau-kalau mungkin berguna.


Stephen Turner memposting arrange()fungsi di blog Getting Genetics Done (lihat posting untuk instruksi aplikasi)

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
  }
 }
}
Jeromy Anglim
sumber
9
itu pada dasarnya versi yang sangat ketinggalan jaman grid.arrange(seandainya saya tidak mempostingnya di milis pada saat itu - tidak ada cara untuk memperbarui sumber daya online ini), versi paket adalah pilihan yang lebih baik jika Anda bertanya kepada saya
baptiste
4

Menggunakan 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

masukkan deskripsi gambar di sini

berkilau
sumber
1

Solusi di atas mungkin tidak efisien jika Anda ingin memplot banyak plot ggplot menggunakan loop (misalnya seperti yang ditanyakan di sini: Membuat banyak plot di ggplot dengan nilai sumbu Y yang berbeda menggunakan loop ), yang merupakan langkah yang diinginkan dalam menganalisis yang tidak diketahui ( atau besar) set data (misalnya, ketika Anda ingin memplot Hitungan semua variabel dalam set data).

Kode di bawah ini menunjukkan cara melakukannya menggunakan 'multiplot ()' yang disebutkan di atas, sumbernya ada di sini: 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)
}

Sekarang jalankan fungsi - untuk mendapatkan Hitungan untuk semua variabel dicetak menggunakan ggplot pada satu halaman

dt = ggplot2::diamonds
plotAllCounts(dt)

Satu hal yang perlu diperhatikan adalah:
menggunakan aes(get(strX)), yang biasanya Anda gunakan dalam loop ketika bekerja dengan ggplot, dalam kode di atas bukannya aes_string(strX)TIDAK akan menggambar plot yang diinginkan. Sebagai gantinya, itu akan memplot plot terakhir berkali-kali. Saya belum tahu mengapa - mungkin harus melakukan aesdan aes_stringdipanggil ggplot.

Kalau tidak, harap Anda akan menemukan fungsi yang bermanfaat.

IVIM
sumber
1
Perhatikan bahwa kode Anda menumbuhkan plotsobjek for-loopyang sangat tidak efisien dan tidak direkomendasikan masuk R. Silakan lihat tulisan-tulisan hebat ini untuk mengetahui cara-cara yang lebih baik untuk melakukannya: Akumulasi yang efisien dalam R , Menerapkan fungsi pada baris bingkai data & Alur kerja berorientasi baris di R dengan tidyverse
Tung
Cara yang lebih efisien untuk mengulang variabel adalah dengan menggunakan tidy evaluationpendekatan yang telah tersedia sejak ggplot2 v.3.0.0 stackoverflow.com/a/52045613/786542
Tung
0

Dalam pengalaman saya, gridExtra: grid.arrange berfungsi dengan baik, jika Anda mencoba membuat plot dalam satu lingkaran.

Cuplikan Kode Pendek:

gridExtra::grid.arrange(plot1, plot2, ncol = 2)
Mayank Agrawal
sumber
Bagaimana jawaban Anda meningkat pada jawaban pembaptis 2 Desember 17 jam 4:20? Jawaban Anda sepertinya duplikat. Lihatlah apa yang membuat jawaban yang dapat diterima di sini Cara Menjawab
Peter
Saya tidak dapat membagi plot sesuai kebutuhan dalam satu lingkaran, dan karenanya saran. Awalnya, saya menulis potongan lengkap for for loop dengan implementasinya tetapi kemudian memutuskan untuk tidak melakukannya untuk sementara waktu. Akan memperbarui kode lengkap dalam seminggu atau lebih.
Mayank Agrawal
Saya mencoba melakukannya dengan menggunakan paket cowplot di tempat pertama itu sendiri tetapi tidak berhasil. Pada pemindaian cepat saya, tidak ada yang menyebutkan beberapa solusi merencanakan dalam loop for dan karenanya komentar saya. Beri saya komentar jika saya salah.
Mayank Agrawal
Jika kode dalam jawaban Anda termasuk untuk loop yang akan berbeda.
Peter
Saya akan memperbaruinya dalam seminggu probs di sini dan seluruh proyek di Kaggle. Bersulang.
Mayank Agrawal
-3

The cowplotpaket memberi Anda cara yang baik untuk melakukan hal ini, dengan cara yang publikasi pakaian.

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

masukkan deskripsi gambar di sini

tim
sumber
3
Lihat juga jawaban dan alasan yang lebih terperinci dari penulis paket di atas stackoverflow.com/a/31223588/199217
David LeBauer