ggplot2を使用した横並びプロット


338

ggplot2パッケージを使用して2つのプロットを並べて配置したいと思います。つまり、と同等ですpar(mfrow=c(1,2))

たとえば、次の2つのプロットを同じ縮尺で並べて表示したいとします。

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

それらを同じdata.frameに配置する必要がありますか?

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

ラティスでこれができるかもしれないと思います。ggplot2は難しい要件ですか?
JD Long

8
いいえ。しかし、qplotを微調整する時間をすでに取っているので、それはちょうど私の好みの方法でした。:-)そして、私はggplotで遊んでみようとしています。
クリストファーデュボワ


1
素敵な概要については、のためにビネットを参照してください卵のパッケージページ上の複数のプロットのレイアウト
ヘンリック

回答:


504

横並びの任意のggplots(またはグリッド上のn個のプロット)

パッケージgrid.arrange()内の関数はgridExtra複数のプロットを組み合わせます。これは、2つ並べて配置する方法です。

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

これは、2つのプロットが同じデータに基づいていない場合、たとえばreshape()を使用せずに異なる変数をプロットする場合に役立ちます。

これにより、副作用として出力がプロットされます。副作用をファイルに出力するには、デバイスドライバー(などpdfpng)などを指定します。

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

または、使用arrangeGrob()との組み合わせでggsave()

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

これは、を使用して2つの異なるプロットを作成することと同じですpar(mfrow = c(1,2))。これは、データの配置にかかる時間を節約するだけでなく、2つの異なるプロットが必要な場合にも必要です。


付録:ファセットの使用

ファセットは、異なるグループに対して同様のプロットを作成するのに役立ちます。これは、以下の多くの回答で以下に指摘されていますが、上記のプロットと同等の例でこのアプローチを強調したいと思います。

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)

更新

plot_grid関数は、cowplotの代替としてチェックアウトする価値がありgrid.arrangeます。同等のアプローチについては、以下の@ claus-wilkeによる回答このビネットを参照してください。ただし、このビネットに基づいて、この機能により、プロットの位置とサイズをより細かく制御できます。


2
ggplotオブジェクトを使用してコードを実行すると、sidebysideplotがnullになります。出力をファイルに保存する場合は、gridArrangeを使用します。stackoverflow.com/questions/17059099/…を
Jim

@ジムは指摘してくれてありがとう。回答を修正しました。ご不明な点がありましたらお知らせください。
David LeBauer、2013

1
grid.aarangeは今、値下げされていますか?
Atticus29、2014年

?grid.arrangeこの関数は現在、arrangeGrobと呼ばれていると思います。私が実行して欲しかったものを行うことができたa <- arrangeGrob(p1, p2)当時とprint(a)
blakeoft 2014年

@blakeoft例を見ましたか?grid.arrangeは引き続き有効な非推奨の関数です。この機能を使ってみましたか?あなたが期待したことではないにしても、何が起こるか。
David LeBauer、2014年

159

に基づくソリューションの欠点の1つは、grid.arrangeほとんどのジャーナルが必要とするように、プロットに文字(A、Bなど)でラベルを付けることが困難になることです。

私はこの問題(およびその他いくつかの問題)を解決するためにカウプロットパッケージを作成しました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")

ここに画像の説明を入力してください

plot_grid()返されるオブジェクトは別のggplot2オブジェクトでありggsave()、通常どおりに保存できます。

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

または、cowplot関数を使用することもできますsave_plot()。これは、ggsave()結合されたプロットの正しい寸法を簡単に取得できるようにする薄いラッパーです。例:

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

ncol = 2引数はsave_plot()、2つのプロットが並んでいることsave_plot()を示し、保存されたイメージを2倍の幅にします。)

グリッドにプロットを配置する方法の詳細については、このビネットを参照してください凡例を共有してプロットを作成する方法を説明するビネットもあります。

よくある混乱の1つは、cowplotパッケージがデフォルトのggplot2テーマを変更することです。パッケージは元々内部のラボでの使用を目的として作成されており、デフォルトのテーマを使用することはないため、パッケージはそのように動作します。これにより問題が発生した場合は、次の3つの方法のいずれかを使用して回避できます。

1.プロットごとに手動でテーマを設定します。+ theme_bw()上記の例で行ったように、各プロットには常に特定のテーマを指定することをお勧めします。特定のテーマを指定する場合、デフォルトのテーマは重要ではありません。

2.デフォルトのテーマをggplot2のデフォルトに戻します。これは、1行のコードで実行できます。

theme_set(theme_gray())

3.パッケージを添付せずにカウプロット関数を呼び出します。library(cowplot)またはrequire(cowplot)、代わりに先頭に追加してカウプロット関数を呼び出すこともできませんcowplot::。たとえば、ggplot2のデフォルトのテーマを使用した上記の例は次のようになります。

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

ここに画像の説明を入力してください

アップデート:

  • cowplot 1.0以降、デフォルトのggplot2テーマは変更されていません。
  • ggplot2 3.0.0以降、プロットに直接ラベルを付けることができます。たとえば、こちらを参照してください

出力でカウプロットは両方のプロットの背景テーマを削除していますか?代替手段はありますか?
VAR121 2016年

@ VAR121はい、それは1行のコードです。:入門ビネットの最初のセクションの最後で説明しcran.rstudio.com/web/packages/cowplot/vignettes/...
クラウスウィルケ

このパッケージでは、すべてのプロットで同じyスケールを使用できますか?
Herman Toothrot

一致するように手動でyスケールを設定する必要があります。またはファセットを検討してください。
クラウスウィルク2017

grid.arrange()を使用する前に、各プロットにggtitle()を設定できますか?
Seanosapien 2017年

49

Winston ChangのRクックブックmultiplotから次の関数 を使用できます

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

}

24

パッチワークパッケージを使用すると、+演算子を簡単に使用できます。

library(ggplot2)
library(patchwork)

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


p1 + p2

パッチワーク


完全を期すために、パッチワークもCRANで行われています。私の小さな編集に満足していただければ幸いです
Tjebo

18

はい、データを適切に配置する必要があると考えています。これは1つの方法です。

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

私はplyrまたはreshapeにもっと良いトリックがあると確信しています-私はまだHadleyによるこれらすべての強力なパッケージに本当にスピードアップしていません。


16

reshapeパッケージを使用すると、次のようなことができます。

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)

12

言及する価値のあるmultipanelfigureパッケージもあります。この回答も参照してください。

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

reprexパッケージ(v0.2.0.9000)によって2018-07-06に作成されました。


9

ggplot2はグリッドグラフィックスに基づいており、ページ上にプロットを配置するための別のシステムを提供します。par(mfrow...)コマンドは、グリッドオブジェクト(と呼ばれるように、直接対応していませんgrobsが)必ずしも即座に描かれているわけではないが、グラフィカルな出力に変換される前に格納され、定期的なRオブジェクトとして操作することができます。これにより、現在のベースグラフィックスのモデルを描画するよりも高い柔軟性が得られますが、戦略は必然的に少し異なります。

私はgrid.arrange()、可能な限りシンプルなインターフェースを提供するために書きましたpar(mfrow)。最も単純な形式では、コードは次のようになります。

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)

ここに画像の説明を入力してください

このビネットでは、その他のオプションについて詳しく説明しています。

よくある不満の1つは、異なるサイズの軸ラベルがある場合など、プロットが必ずしも整列していないことですが、これは設計によるgrid.arrangeものです。ggplot2オブジェクトを特殊なケースにしようとせず、それらを他のグロブ(格子プロットなど)と同じように扱います)。それは単に四角形のレイアウトにグロブを配置するだけです。

ggplot2オブジェクトの特殊なケースでggarrangeは、同様のインターフェイスを使用して、プロットパネル(ファセットプロットを含む)を整列させ、ユーザーが定義したアスペクト比を尊重しようとする別の関数を作成しました。

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

どちらの機能もと互換性がありggsave()ます。さまざまなオプションの概要といくつかの歴史的背景について、このビネットは追加情報を提供します


9

更新:この回答は非常に古いものです。gridExtra::grid.arrange()これが推奨されるアプローチです。役に立つかもしれないので、ここに置いておきます。


Stephen Turner が、このarrange()関数をGetting Genetics Doneブログに投稿しました(アプリケーションの手順については、投稿を参照してください)。

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

9
それは基本的には非常に古いバージョンだgrid.arrange(私は一度にメーリングリスト上でそれを掲示していなかった希望-これらのオンラインリソースを更新する方法はありません)、パッケージ版あなたは私に言わせればより良い選択である
バティスト

4

使用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

ここに画像の説明を入力してください


1

上記の解決策は、ループを使用して複数のggplotプロットをプロットする場合(たとえば、ここで尋ねられるように、ループを使用して異なるY軸値で複数のプロットをggplotに作成する)は効率的でない可能性があります。これは、未知の(または大きい)データセット(たとえば、データセット内のすべての変数のカウントをプロットする場合)。

以下のコードは、上記の 'multiplot()'を使用してそれを行う方法を示しています。そのソースはここにあります: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)
}

次に、関数を実行します-1ページにggplotを使用して出力されたすべての変数のカウントを取得します

dt = ggplot2::diamonds
plotAllCounts(dt)

注意すべき事柄は、次のとおりです。
使用 aes(get(strX))を取り扱う際には、通常のループで使用しており、ggplot代わりに上記のコードでは、aes_string(strX)希望のプロットを描画しません。代わりに、最後のプロットを何度もプロットします。理由はわかりません。実行する必要がaesありaes_string、呼び出されggplotます。

それ以外の場合は、関数が役立つことを願っています。


1
コードによってplotsオブジェクトが大きくなることに注意してください。オブジェクトfor-loopは非常に非効率的であり、では推奨されませんR。それを行うためのより良い方法を見つけるために、これらの素晴らしい投稿をご覧ください:Rでの 効率的な蓄積、データフレームの行への関数の適用tidyverseを使用したRでの行指向のワークフロー
Tung

変数をループするより効率的な方法はtidy evaluationggplot2 v.3.0.0 stackoverflow.com
Tung

0

私の経験では、グリッドでプロットを生成しようとしている場合、gridExtra:grid.arrangeは完全に機能します。

短いコードスニペット:

gridExtra::grid.arrange(plot1, plot2, ncol = 2)

あなたの答えは、17年12月2日のバプテストの答えの4:20をどのように改善しますか あなたの答えは重複しているようです。許容できる答えをここで確認してください。回答方法
Peter

ループ内で必要に応じてプロットを分割できなかったため、提案。最初は、自分のforループの完全なスニペットをその実装とともに作成しましたが、当面はこれに反対しました。1週間程度で完全なコードを更新します。
Mayank Agrawal

デビッド・ルバウアーが承認した回答をチェック
ピーター

私はそもそもカウプロットパッケージを使用してそれを実行しようとしましたが、失敗しました。私のクイックスキャンでは、誰もがforループ内で複数のプロットソリューションについて言及していないため、私のコメントもありませんでした。私が間違っている場合は、コメントを参照してください。
Mayank Agrawal

回答のコードにforループが含まれている場合は異なります。
ピーター

-3

cowplotパッケージには、方法そのスーツの出版物で、あなたにこれを行うには良い方法を提供します。

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

ここに画像の説明を入力してください


3
また、パッケージの作成者のより詳細な回答と上記の理論的根拠を参照してくださいstackoverflow.com/a/31223588/199217
デヴィッドLeBauer
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.