web-dev-qa-db-ja.com

複数の複雑なプロットを1つの図のパネルとして組み合わせる

@backlinによる紹介

layoutまたはpar(mfrow=...)を使用すると、複数の単純なプロットを1つの図のパネルとして組み合わせることができます。ただし、より複雑なプロットは、独自のパネルレイアウトを設定して、パネルとして使用できないようにする傾向があります。ネストされたレイアウトを作成し、複雑なプロットを単一のパネルにカプセル化する方法はありますか?

gridパッケージでこれを実現できると感じています。パネルを別々のビューポートにプロットすることによって、しかしその方法を理解することができませんでした。これは、問題を実証するためのおもちゃの例です。

_my.plot <- function(){
    a <- matrix(rnorm(100), 10, 10)
    plot.new()
    par(mfrow=c(2,2))
    plot(1:10, runif(10))
    plot(hclust(dist(a)))
    barplot(apply(a, 2, mean))
    image(a)
}
layout(matrix(1:4, 2, 2))
for(i in 1:4) my.plot()
# How to avoid reseting the outer layout when calling `my.plot`?
_

@alittleboyによる元の質問

ヒートマップを生成するために、gplotsパッケージの_heatmap.2_関数を使用します。単一のヒートマップのサンプルコードは次のとおりです。

_library(gplots)
row.scaled.expr <- matrix(sample(1:10000),nrow=1000,ncol=10)
heatmap.2(row.scaled.expr, dendrogram ='row',
          Colv=FALSE, col=greenred(800), 
          key=FALSE, keysize=1.0, symkey=FALSE, density.info='none',
          trace='none', colsep=1:10,
          sepcolor='white', sepwidth=0.05,
          scale="none",cexRow=0.2,cexCol=2,
          labCol = colnames(row.scaled.expr),                 
          hclustfun=function(c){hclust(c, method='mcquitty')},
          lmat=rbind( c(0, 3), c(2,1), c(0,4) ), lhei=c(0.25, 4, 0.25 ),                 
)
_

ただし、1つのプロットで複数のヒートマップを比較したいので、par(mfrow=c(2,2))を使用してから、_heatmap.2_を4回呼び出します。

_row.scaled.expr <- matrix(sample(1:10000),nrow=1000,ncol=10)
arr <- array(data=row.scaled.expr, dim=c(dim(row.scaled.expr),4))
par(mfrow=c(2,2))
for (i in 1:4)
heatmap.2(arr[ , ,i], dendrogram ='row',
          Colv=FALSE, col=greenred(800), 
          key=FALSE, keysize=1.0, symkey=FALSE, density.info='none',
          trace='none', colsep=1:10,
          sepcolor='white', sepwidth=0.05,
          scale="none",cexRow=0.2,cexCol=2,
          labCol = colnames(arr[ , ,i]),                 
          hclustfun=function(c){hclust(c, method='mcquitty')},
          lmat=rbind( c(0, 3), c(2,1), c(0,4) ), lhei=c(0.25, 4, 0.25 ),                 
)
_

ただし、結果は1つのプロットに4つのヒートマップではなく、4つの別々のヒートマップになります。つまり、pdf()を使用して結果を出力すると、ファイルは1ページではなく4ページになります。どこかでパラメータを変更する必要がありますか?どうもありがとうございます!

20
alittleboy

はい。この質問は、長い答えを書き留めるのに十分な時間、答えられずに座っていたと思います。

最も難しいグラフィックスの問題に対する答えは、(@ backlinが示唆しているように)「グリッド」パッケージの生の使用です。多くのビルド済みグラフィックパッケージは、現在のすべてのビューポートとプロットデバイス設定を上書きするため、非常に特殊な方法で何かを実行したい場合は、自分でビルドする必要があります。

Paul Murrellの本「RGraphics」を手に取って、「grid」パッケージの章に目を通すことをお勧めします。それはクレイジーで便利な本であり、コピーはいつも私の机の上にあります。

あなたのヒートマップのために、私はあなたがすぐに始めることができる簡単な入門書を書きました。

知っておくべき関数

  • grid.newpage()これはプロットデバイスを初期化します。パラメータなしで使用してください。
  • grid.rect()これは長方形を描画します。ヒートマップは基本的に色付きの長方形の巨大なセットであるため、これはグラフィックの大部分になります。これは次のように機能します。grid.rect(x=x_Position, y=y_Position, width=width_Value, height=height_Value, gp=gpar(col=section_Color, fill=section_Color), just=c("left", "bottom"), default.units="native")'just '引数は、長方形のどの点が指定された(x、y)座標上にあるかを指定します。
  • grid.text()これはテキストを描画します。それは次のように機能します:grid.text("Label Text", x_Value, y_Value, gp=gpar(col=color_Value, cex=font_Size), just=c("right","center"), rot=rot_Degrees, default.units="native")
  • grid.lines()これは線を引きます。それは次のように機能します:grid.lines(c(x_Start,x_End), c(y_Start, y_End), gp=gpar(col=color_Value), default.units="native")
  • dataViewport()これは、プロットウィンドウの属性を定義します。これは「グリッド」が「ビューポート」と呼びます。次のように使用します。pushViewport(dataViewport(xData=x_Data, yData=y_Data, xscale=c(x_Min, x_Max), yscale=c(y_Min, y_Max), x=x_Value, y=y_Value, width=width_Value, height=height_Value, just=c("left","center")))ここで覚えておくべきことがいくつかあります...ビューポートのより詳細な説明を参照してください。
  • pushViewport()これはveiwportを初期化するために使用されます。 pushViewport(dataViewport([stuff in here]))のように、これをビューポート定義にラップして、実際にビューポートを実行します。
  • popViewport()これにより、ビューポートが完成し、ビューポートの階層の1つ上のレベルに移動します。ビューポートの詳細な説明を参照してください。

一言で言えばビューポート

ビューポートは、「グリッド」オブジェクトが描画される場所と方法を定義する一時的な描画スペースです。ビューポート内のすべてがビューポートに対して相対描画されます。ビューポートを回転させると、内部のすべてが回転します。ビューポートはネストすることができ、オーバーラップすることができ、1つの例外を除いて、ほぼ無限に柔軟性があります。ビューポートは常に長方形です。

最初に多くの人を混乱させるのは座標系です。最初の 'grid.newpage()'ビューポートを含むすべてのビューポートは、x軸とy軸の両方で0から1になります。原点(0,0)は左下隅で、最大値(1,1)は右上隅です。これは「npc」単位系であり、単位のセットが指定されていないものはすべて、このシステムに従って描画される可能性があります。これはあなたにとって2つのことを意味します:

  1. ビューポートのサイズと場所を指定するときは、「npc」システムを使用してください。ビューポートが「npc」座標を使用する必要があると仮定するだけで、多くの手間を省くことができます。つまり、2つのプロットを並べて描画する場合、2つのビューポートの定義は次のようになります。
    • viewport(x=0, y=0, width=0.5, height=1, just=c("left","lower"))および
    • viewport(x=0.5, y=0, width=0.5, height=1, just=c("left","lower"))
  2. ビューポートの座標系が異なる場合(たとえば、グラフをプロットするためのビューポート)、描画するすべての「グリッド」オブジェクトに対して「default.units」引数を指定する必要があります。たとえば、(2,4)でポイントをプロットしようとすると、画面から大きく外れるため、ポイントが表示されません。 default.units="native"を指定すると、そのポイントにビューポート独自の座標系を使用するように指示され、ポイントが正しく描画されます。

ビューポートはナビゲートして直接書き込むことができますが、非常に自動化された操作を行わない限り、ビューポートを指定して内部に描画し、ビューポートを「ポップ」(ファイナライズ)する方が簡単です。これにより、親ビューポートに戻り、次のビューポートから開始できます。各ビューポートをポップすることは、すっきりとしたアプローチであり、ほとんどの目的に適しています(そして、デバッグが容易になります!)。

'dataViewport'関数は、グラフをプロットするときにすべて重要です。これは、使用しているデータを指定する限り、すべての座標とスケールを処理する特別なタイプのビューポートです。これは、私がプロット領域に使用するものです。 「grid」パッケージを最初に使い始めたとき、「npc」座標系に合うようにすべての値を調整しましたが、それは間違いでした。 'dataViewport'関数を使用すると、各図面アイテムに「ネイティブ」単位を使用することを覚えている限り、すべて簡単になります。

免責事項

データの視覚化は私の得意分野であり、優れたビジュアルを作成するために半日を費やしてもかまいません。 「グリッド」パッケージを使用すると、他のどのパッケージよりも高速に非常に洗練されたビジュアルを作成できます。ビジュアルを関数としてスクリプト化するので、さまざまなデータをすばやく読み込むことができます。私はこれ以上幸せになることはできませんでした。

ただし、スクリプトを作成したくない場合は、「グリッド」が敵になります。また、半日をビジュアルにするには時間がかかりすぎると考える場合、「グリッド」はあまり役に立ちません。 (不)有名な「ggplot2」パッケージは、ほとんどの人が決めているものであり、個人的には役に立たないと思いますが、心からお勧めします。

誰かが「グリッド」グラフィックスの学習を手伝いたいのなら、私は喜んで教えます。これは、高速でインテリジェントで見栄えの良いデータビジュアルを作成する私の能力に完全に革命をもたらしました。

19
Dinre

gridGraphicsパッケージが役立つかもしれませんが、

enter image description here

library(gridGraphics)
library(grid)

grab_grob <- function(){
  grid.echo()
  grid.grab()
}

arr <- replicate(4, matrix(sample(1:100),nrow=10,ncol=10), simplify = FALSE)

library(gplots)
gl <- lapply(1:4, function(i){
  heatmap.2(arr[[i]], dendrogram ='row',
            Colv=FALSE, col=greenred(800), 
            key=FALSE, keysize=1.0, symkey=FALSE, density.info='none',
            trace='none', colsep=1:10,
            sepcolor='white', sepwidth=0.05,
            scale="none",cexRow=0.2,cexCol=2,
            labCol = colnames(arr[[i]]),                 
            hclustfun=function(c){hclust(c, method='mcquitty')},
            lmat=rbind( c(0, 3), c(2,1), c(0,4) ), lhei=c(0.25, 4, 0.25 ),                 
  )
  grab_grob()
})

grid.newpage()
library(gridExtra)
grid.arrange(grobs=gl, ncol=2, clip=TRUE)
8
baptiste

Dinreが言ったように、「グリッド」パッケージはすべての複雑なプロットを処理できます。 @alittleboyによる元の質問については、Bionconductorのパッケージ「ComplexHeatmap」(これもグリッドに基づいています)が優れたソリューションになると思います( http://www.bioconductor.org/packages/release/bioc /vignettes/ComplexHeatmap/inst/doc/ComplexHeatmap.html

2
japrin

私は同様の問題に苦労し、非常に簡単ですが、imagemagickをインストールする必要がある解決策を思いつきました。アイデアは、ヒートマップを別々のファイルにプロットしてから、それらをモンタージュコマンドと組み合わせるというものです。

library(gplots)
row.scaled.expr <- matrix(sample(1:10000),nrow=1000,ncol=10)
arr <- array(data=row.scaled.expr, dim=c(dim(row.scaled.expr),4))
par(mfrow=c(2,2))
for (i in 1:4) {
    ifile <- paste0(i,'_heatmap.pdf')
    pdf(ifile)
    heatmap.2(arr[ , ,i], dendrogram ='row',
                        Colv=FALSE, col=greenred(800), 
                        key=FALSE, keysize=1.0, symkey=FALSE, density.info='none',
                        trace='none', colsep=1:10,
                        sepcolor='white', sepwidth=0.05,
                        scale="none",cexRow=0.2,cexCol=2,
                        labCol = colnames(arr[ , ,i]),                 
                        hclustfun=function(c){hclust(c, method='mcquitty')},
                        lmat=rbind( c(0, 3), c(2,1), c(0,4) ), lhei=c(0.25, 4, 0.25 ),                 
    )
    dev.off()
}
system('montage -geometry 100% -tile 2x2 ./*_heatmap.pdf outfile.pdf')
2
chakalakka