グラフィックス参考実例集:棒グラフ、ヒストグラムを描く barplot, hist

(グラフィックス参考実例集に戻る。Rのグラフィックスパラメータを参照する。)


単純な棒グラフ

barplot 関数は棒グラフを描きます。棒グラフは、棒の長さにより観測値の大きさや度数を表すものです。数値ベクトルを引数として与えるのが、関数barplotもっとも簡単な使い方です。こうするとベクトルのそれぞれの値が棒の高さになります。 引数が行列ならば各列が一本の棒となり、列の各要素の値により棒をブロックに分けます。

  • 引数angle、density、colはそれぞれ棒を塗り分ける線分の角度、塗り分ける際の線分の本数、塗り分けの色を指定します。colだけを与えればブロックごとに塗りつぶします。
  • 引数legendを指定すると、右上に凡例を描きます。この引数には塗り分けされた各部分につけるラベルのベクトルを指定します。この凡例はいつも右上に描かれますが、他の場所に凡例を描きたければ関数legend を使います。
  • 引数namesには各棒のラベルを定める文字型ベクトル指定することができます。
  • 引数widthは各棒の相対的な幅を定めるベクトルです。spaceの値は棒の間隔で、数が一つであれば全体がその値で等間隔に並び、ベクトルであればそれぞれの値が各棒の手前の間隔となります。
  • 引数besideをTRUEにすると、引数に与えられた行列の列毎でブロック分けぜずに、それぞれの値ごとに棒を描きます。
  • 引数horizをTRUEにすると棒を水平にします。この場合データは下から順に並びます。
  • barplotは各棒の中心位置のx座標を返します。この値とtextなどの低水準作図関数を使って、さらに細かい装飾を行なうこともできます。

似たものにヒストグラムを描く hist 関数がある。見かけは似ているが、棒グラフが類別・尺度(カテゴリー化された)データを扱うのにたいし、hist は間隔・比率尺度(本来の数値)データを適当な区間毎に集計したものを棒グラフ状に表示する。

注意。base パッケージ中の barplot 関数 (hist も?) は対数y軸をサポートしていない。また par(ylog=TRUE) による指定も無効にされる。アドオンパッケージ gregmisc 中には両対数軸をサポートする barplot 関数があるらしい。

とりあえず書いてみる

barplot01 <- function(){
  on.exit(par(old.par <- par(no.readonly = TRUE)))
  on.exit(dev.off())
  png("barplot01.png")
  d <- ceiling(runif(5, 1, 10))	# サンプルデータ
  barplot(d)
}
barplot01()
r_case03_barplot01.png

x軸に名前を表示して、棒の色を変更する

barplot03 <- function(){
  on.exit(par(old.par <- par(no.readonly = TRUE)))
  on.exit(dev.off())
  png("barplot03.png")
  d <- ceiling(runif(5, 1, 10))
  d.names <- paste("gene", 1:5)   # x軸に表示される名前を作る
  barplot(d, names.arg=d.names, col=c("blue", "green", "red", "yellow", "cyan"))
}
barplot03()
r_case03_barplot03.png

誤差範囲を表示する

棒グラフの棒の幅は1になっています(barplotのwidth引数)。棒と棒の間隔は標準で0.2になっています(barplotのspace引数)。この状態で左からn番目の棒の中心は(0.2 + 1) * n - 1/2になっています。ここからarrows関数で矢印を引っぱると誤差範囲が表示できます。
arrowsのangleは矢印の傾きを指定します。今回は直角になるように90にしてあります。

barplot04 <- function(){
  on.exit(par(old.par <- par(no.readonly = TRUE)))
  on.exit(dev.off())
  png("barplot04.png")
  d <- ceiling(runif(5, 1, 10))
  d.names <- paste("gene", 1:5)
  d.error <- runif(5, 0, 1)   # 誤差範囲のデータ
  d.error.x <- (0.2 + 1) * 1:5 - 1/2   # エラーバーを表示する位置(x座標)
  barplot(d, names.arg=d.names, col=c("blue", "green", "red", "yellow", "cyan"))
  arrows(d.error.x, d, d.error.x, d + d.error, angle=90)
  arrows(d.error.x, d, d.error.x, d - d.error, angle=90)
}
barplot04()
r_case03_barplot04.png

別の方法:関数barplotは各棒グラフの中点座標の配列を返すので,誤差範囲を表示するためにこれを利用できます.

barplot04b <- function(){
  on.exit(par(old.par <- par(no.readonly = TRUE)))
  on.exit(dev.off())
  png("barplot04b.png")
  d <- ceiling(runif(5, 1, 10))
  d.names <- paste("gene", 1:5)
  d.error <- runif(5, 0, 1)   # 誤差範囲のデータ
  # 各棒グラフの中点座標を取得
  d.error.x <- barplot(d, names.arg=d.names, col=c("blue", "green", "red", "yellow", "cyan"))
  arrows(d.error.x, d, d.error.x, d + d.error, angle=90)
  arrows(d.error.x, d, d.error.x, d - d.error, angle=90)
}
barplot04b()

積み重ねの棒グラフ

まずは書いてみる

barplot05 <- function(){
  on.exit(par(old.par <- par(no.readonly = TRUE)))
  on.exit(dev.off())
  png("barplot05.png")
  dm <- matrix(ceiling(runif(12, 1, 10)), ncol=3)	# サンプルデータ
  barplot(dm)
}
barplot05()
r_case03_barplot05.png

棒グラフの間に線を引く

棒グラフの間の線はsegments関数で引きます。segmentsには線分の始点と終点を与えないといけないのでまずそれを計算します。

barplot06 <- function(){
  on.exit(par(old.par <- par(no.readonly = TRUE)))
  on.exit(dev.off())
  png("barplot06.png")
  dm <- matrix(ceiling(runif(12, 1, 10)), ncol=3)
  d.seg.xs <- rep((0.2 + 1) * 1:(ncol(dm) - 1), each=nrow(dm))   # 線分の始点のx座標
  d.seg.xe <- rep((0.2 + 1) * 2:ncol(dm) - 1, each=nrow(dm))     # 線分の終点のx座標
  d.seg.ys <- apply(dm[,1:(ncol(dm) - 1)], 2, cumsum)            # 線分の始点のy座標
  d.seg.ye <- apply(dm[,2:ncol(dm)], 2, cumsum)                  # 線分の終点のy座標
  barplot(dm)
  segments(d.seg.xs, d.seg.ys, d.seg.xe, d.seg.ye)   # 線分を描く
}
barplot06()
r_case03_barplot06.png

凡例を表示する

barplot07 <- function(){
  on.exit(par(old.par <- par(no.readonly = TRUE)))
  on.exit(dev.off())
  png("barplot07.png")
  dm <- matrix(ceiling(runif(12, 1, 10)), ncol=3)
  d.seg.xs <- rep((0.2 + 1) * 1:(ncol(dm) - 1), each=nrow(dm))
  d.seg.xe <- rep((0.2 + 1) * 2:ncol(dm) - 1, each=nrow(dm))
  d.seg.ys <- apply(dm[,1:(ncol(dm) - 1)], 2, cumsum)
  d.seg.ye <- apply(dm[,2:ncol(dm)], 2, cumsum)
  d.names.r <- paste("exp", 1:nrow(dm))    # 凡例に表示する文字列
  d.names.c<-paste("gene",1:ncol(dm))   # 棒グラフのグループごとの名前
  barplot(dm, names.arg=d.names.c, legend.text=d.names.r)
  segments(d.seg.xs, d.seg.ys, d.seg.xe, d.seg.ye)
}
barplot07()
r_case03_barplot07.png

横に並べた棒グラフ

まずは書いてみる

barplot08 <- function(){
  on.exit(par(old.par <- par(no.readonly = TRUE)))
  on.exit(dev.off())
  png("barplot08.png")
  dm <- matrix(ceiling(runif(12, 1, 10)), ncol=3)	# サンプルデータ
  barplot(dm, beside=T)
}
barplot08()
r_case03_barplot08.png

白黒印刷用に図を書く

barplot09 <- function(){
  on.exit(par(old.par <- par(no.readonly = TRUE)))
  on.exit(dev.off())
  png("barplot09.png")
  dm <- matrix(ceiling(runif(12, 1, 10)), ncol=3)
  d.names.r <- paste("exp", 1:nrow(dm))
  d.names.c<-paste("gene",1:ncol(dm))
  d.angle <- c(20,-20) * 1:nrow(dm)
  barplot(dm, beside=T, angle=d.angle, density=10, col="black",
          names.arg=d.names.c, legend.text=d.names.r)
}
barplot09()
r_case03_barplot09.png

誤差範囲を表示する

標準では棒の幅1、グループ内の棒の間隔0、グループの間隔1で作成されています。このときm番目のグループのn番目の棒(d[n,m]に相当)の中心は(1+1*N)*(m-1)+1*n+1/2になります(ああ、ややこしい)。
arrowsのlengthは矢印の矢じりの部分の長さを指定します。棒の数が多い場合はこの値を小さくしないときれいな図になりません(標準で0.25)。

barplot10 <- function(){
  on.exit(par(old.par <- par(no.readonly = TRUE)))
  on.exit(dev.off())
  png("barplot10.png")
  dm <- matrix(ceiling(runif(12, 1, 10)), ncol=3)
  d.names.r <- paste("exp", 1:nrow(dm))
  d.names.c<-paste("gene",1:ncol(dm))
  dm.error <- runif(length(dm), 0,1)
  dm.error.x <- rep((nrow(dm)+1) * (1:ncol(dm) - 1), each = nrow(dm))	# (1+1*N)*(m-1)まで
  dm.error.x <- dm.error.x + rep(1:nrow(dm) + 1/2, ncol(dm))	# +1*n+1/2 の部分
  barplot(dm, ylim=c(0, max(dm + dm.error)), beside=T, names.arg=d.names.c,
          legend.text=d.names.r)
  arrows(d.error.x, dm, d.error.x, dm + dm.error, angle=90, length=0.1)
  arrows(d.error.x, dm, d.error.x, dm - dm.error, angle=90, length=0.1)
}
barplot10()
r_case03_barplot10.png

別の方法:関数barplotは各棒グラフの中点座標の配列を返すので,誤差範囲を表示するためにこれを利用できます.

barplot10 <- function(){
  on.exit(par(old.par <- par(no.readonly = TRUE)))
  on.exit(dev.off())
  png("barplot10.png")
  dm <- matrix(ceiling(runif(12, 1, 10)), ncol=3)
  d.names.r <- paste("exp", 1:nrow(dm))
  d.names.c<-paste("gene",1:ncol(dm))
  dm.error <- runif(length(dm), 0,1)
 # 各棒グラフの中点座標を取得
  dm.error.x <-   barplot(dm, ylim=c(0, max(dm + dm.error)), beside=T, names.arg=d.names.c,
               legend.text=d.names.r)
  arrows(dm.error.x, dm, dm.error.x, dm + dm.error, angle=90, length=0.1)
  arrows(dm.error.x, dm, dm.error.x, dm - dm.error, angle=90, length=0.1)
}
barplot10()

ヒストグラム

 ヒストグラムにより、データの分布の仕方を大雑把に知ることができます。このグラフは関数histで描きます。引数には数値ベクトルを指定します。他に細かなことを設定する引数がいくつかありますが、基本的にはこの引数を指定するだけでヒストグラムを描くことができます。例えば、

> hist(rnorm(100))

で、ヒストグラムが描かれます。 特に何も指定せずデータのみを与えた場合は、データの範囲を log2n + 1 ( n はデータの個数)個の階級に分割し、各階級に属すデータの数を棒グラフとして作図します。通常は絶対度数を使いますが、probability=Tと指定することによって相対度数で作図することもできます。また、引数nclassで階級数を明示的に指定することもできます。

例1 example(hist.default) 中の例 (2003.12.7)

histmisc1 <- function() {
    data(islands)
    op <- par(mfrow=c(2, 2))
    hist(islands)
    str(hist(islands, col="gray", labels = TRUE))

    hist(sqrt(islands), br = 12, col="lightblue", border="pink")
    ##-- For non-equidistant breaks, counts should NOT be graphed unscaled:
    r <- hist(sqrt(islands), br = c(4*0:5, 10*3:5, 70, 100, 140), col='blue1')
    text(r$mids, r$density, r$counts, adj=c(.5, -.5), col='blue3')
    sapply(r[2:3], sum)
    sum(r$density * diff(r$breaks)) # == 1
    lines(r, lty = 3, border = "purple") # -> lines.histogram(*)
    par(op)
}
 left

例2 ヒストグラムの色々 (2003.12.10)

既定の Sturges の方法は単に伝統があり、有名と言うだけで実際は使わない方が良さそう。 Q&Aコーナーの関連質問参照。

> x <- rnorm(1000)^2
> hist(x)                               
> hist(x, breaks="Sturges")  # 既定の hist(x) と同一 (古典的な Sturges の方法による分割点決定)
> hist(x, breaks="scott")      # Scott の方法による分割点決定
> hist(x, breaks="FD")          # Frieman-Daiconis の方法による分割点決定
 left

棒グラフの枠線を消す(本体色と同じ色の枠線を描く 2004.01.14)

ついでに棒の間の隙間を色々変えてみる。

> par(mfrow=c(2,2))
> barplot(1:5, space=0, col="red", border="red")
> barplot(1:5, space=0.1, col="red", border="red")
> barplot(1:5, space=0.5, col="red", border="red")
> barplot(1:5, space=1, col="red", border="red")
> pp=recordPlot(); png("histnoborder.png"); replayPlot(pp); dev.off()
 left

この例では塗りつぶしと枠を同じ色にすることで解決しているが、 そもそも枠を描きたくないという場合はオプションで「border=NA」を指定する。hist()でも同じ。

MASS ライブラリ中の truehist は基準化相対度数でヒストグラムを描く (2004.3.2)

truehist は総面積が1となるヒストグラム(度数を区間幅で割る)を書く

library(MASS)
data(islands)
par(mfrow=c(1,2))
hist(islands)
truehist(islands)
 left

各棒の面積が等しくなるヒストグラム (from r-help, 2005.01.10)

quantile 関数を用い各棒の面積(標本確率)が等しくなるように分割点を定める

x <- rnorm(400)
nbin <- 10          # 区間の数を10にする
hist(x,breaks=quantile(x,prob=seq(0,1,length=nbin+1)))
 left
  • この方法はあまりおすすめできませんね。上の例は 400 個の正規乱数だから上図のようになっているのかと思いましたが,40000個のデータのヒストグラムを描いても,下図のようにしかなりません。この図が母分布を表しているとはとてもいえません。
    bad.png

添付ファイル: filehistmisc1.png 1973件 [詳細] filer_case03_barplot07.png 2728件 [詳細] filetruehist.jpg 1838件 [詳細] filebad.png 1629件 [詳細] filer_case03_barplot05.png 2348件 [詳細] filer_case03_barplot09.png 2467件 [詳細] filer_case03_barplot02.png 835件 [詳細] filehist.equalarea.png 1812件 [詳細] filer_case03_barplot01.png 3055件 [詳細] filer_case03_barplot08.png 2488件 [詳細] filehistnoborder.png 1778件 [詳細] filer_case03_barplot06.png 1931件 [詳細] filer_case03_barplot03.png 4119件 [詳細] filehistgram2.png 1844件 [詳細] filer_case03_barplot04.png 2442件 [詳細] filer_case03_barplot10.png 3123件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Google
WWW を検索 OKADAJP.ORG を検索
Last-modified: 2015-03-01 (日) 01:15:59 (761d)