グラフィックス参考実例集:その他
(グラフィックス参考実例集に戻る。Rのグラフィックスパラメータを参照する。)
両軸上の等間隔なスケール(1cm)で描かれる散布図を描きます。以下の例の上は plot 関数、下は eqscplot 関数を使った例です。
同じ位置に複数のデータがある場合、「花びら」の数でその数を識別する散布図
> data(iris) > sunflowerplot(iris[, 3:4], cex = 0.2, cex.f = 1, size = 0.035, seg.lwd =0.8)
関数starsで星形図を描くことができます。この図は、各データ間の関係を調べるというより、全体の傾向を見たり、サンプルの分類を行なうためのものです。引数にはデータフレームを指定します。この関数は各行に毎に一つずつ星形図を描きます。引数scaleがTRUEであれば[*1]、まず列毎に標準化が行なわれます。 関数starsは、内部で複数図表を用いていますから、複数図表と同時に使うことはできません。
> data(mtcars) > stars(mtcars[, 1:7], key.loc = c(14, 2), main = "Motor Trend Cars : stars(*, full = F)", full = FALSE)
グラフィックスというべきかどうか?度数分布表+ヒストグラムを同時に作成する賢い集計法。もう一つの長所は、簡単なデータの場合、生データがそのまま保存できること。
> data(islands) # 世界の大陸・島の面積 > stem(log10(islands)) # 常用対数値 The decimal point is at the | # | の位置に小数点がある 1 | 1111112222233444 # データ値 1.1 が6個ある 1 | 5555556666667899999 2 | 3344 2 | 59 3 | # データ 3.0,...,3.4 は無い 3 | 5678 # データ 3.5,3.6,3.7,3.8 がそれぞれ一つずつある 4 | 012 # 幹4、葉0 はアフリカの値 4.060924 に対応
二元分割表の独立性からのずれを表示。(i,j) セルに対して d_{ij} = (f_{ij} - e_{ij}) / sqrt(e_{ij}) ( f_{ij} と e_{ij} は観測度数と、独立仮説の下での期待度数)とすると、各長方形の高さは d_{ij} に、幅は sqrt(e_{ij}) に比例し、箱の大きさは観測値と期待値の食い違いに比例。食い違いが正の場合は基準線より上黒色で、負の場合は基準線より下に赤色で描かれる。
assocplot1 <- function () { data(HairEyeColor) ## 男女統合 x <- margin.table(HairEyeColor, c(1, 2)) assocplot(x, main = "Relation between hair and eye color") }
stripchart1 <- function () { x <- round(rnorm(50), 1) stripchart(x) }
関数dotchartはドットチャートを描きます。これは棒グラフと似た情報を図示しますが、値を点でプロットします。dotchartの最も簡単な使い方は、単にデータベクトルを渡すものです。
dotchart(1:10)
引数labelsにデータのラベルを指定することもできます。
dotchart(1:10, labels=paste("sample", 1:10))
引数groupsに類別オブジェクトを指定すると、それに従ってデータをグループ分けして表示します。 dotchartの引数gdataにグループごとの集約値を指定すると、それがグループを表すラベルの位置に追加されます。
つまりは棒の無い棒グラフ(下の棒グラフ版と比較せよ、よりシンプル?)
dotchart1 <- function () { data(VADeaths) dotchart(VADeaths, main = "Death Rates in Virginia - 1940") }
barplot(VADeaths, beside=T, horiz=T)
dotchart2 <- function () { data(VADeaths) op <- par(xaxs="i")# 0 -- 100% dotchart(t(VADeaths), xlim = c(0,100), main = "Death Rates in Virginia - 1940") par(op) }
chull.ex <- function () { old.par <- par(no.readonly = TRUE) on.exit(par(old.par)) png("chull.png") X <- matrix(rnorm(2000), ncol=2) plot(X, cex=0.5) hpts <- chull(X) hpts <- c(hpts, hpts[1]) lines(X[hpts, ]) dev.off() }
つまりは対数正規確率紙。このグラフ上に対数正規分布の分布関数を画くと直線になる。結構複雑。さて、プロットそのものはどうして重ねたら良いのか。
lognormal.CDF.fn <- function(x.axis.title="Nf, Cycles"){ # 対数正規累積分布関数用グリッド # まず、点無しでグリッドを画く # x軸は対数尺度。y軸は確率ラベルを持つが、正規確率尺度 z.min <- -5.5 z.max <- -z.min z.norm <- seq(z.min, z.max, length=101) plot(NA, NA, xlim=c(3, 7), ylim=c(z.min, z.max), type="n", xaxt="n", yaxt="n", frame = FALSE, xlab = "", ylab = "Cumulative Probability (Fraction less than N)") # # x軸を対数尺度で画く axis(side = 1, labels = FALSE, at = c(3, 4, 5, 6, 7), line = 0., tick=TRUE, outer = FALSE) text(x=c(3, 4, 5, 6, 7), y=rep(z.min-1.0, 5), rep("10", 5), xpd = NA, cex=1.) text(x=c(3, 4, 5, 6, 7)+ 0.1, y=rep(z.min-0.8, 5)+0.08, c("3", "4", "5", "6", "7"), xpd = NA, cex=0.8) text(x=5.05, y=z.min-1.6, x.axis.title, xpd=NA, cex=1.) # Draw the interior log tick marks for (i in 3:6){ axis(side=1, at=log10(c(2, 3, 4, 5, 6, 7, 8, 9))+ i, cex=1, labels=NA,, line = 0, tck = -0.01) text(x=log10(c(2, 3, 4, 5, 6, 7, 8))+ i, y=rep(z.min-0.7, 7), c("2", "3", "4", "5", "6", "7", "8"), xpd = NA, cex=0.7) } # # y軸を正規確率プロットで画く probs <- c(1e-7, 1e-6, 1e-5, 1e-4, 0.001, 0.002, 0.005, 0.01, 0.02, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.95, 0.98, 0.99, 0.995, 0.998, 0.999, 0.9999, 0.99999, 0.999999, 0.9999999) z.vals <- qnorm(probs) axis(side=2, at=z.vals , labels=NA, line = 0, tck = -0.01) text(x=rep(3.-0.4, 4), y= -0.1+qnorm(c(1e-7, 1e-6, 1e-5, 1e-4)), cex=0.8, xpd = NA, labels=rep("10", 6)) text(x=rep(3.-0.3 , 4), y= 0.1+qnorm(c(1e-7, 1e-6, 1e-5, 1e-4)), cex=0.6, xpd = NA,labels=c("-7", "-6", "-5", "-4")) text(x=rep(3.-0.25, 6), y= qnorm(c(0.001, 0.01, 0.1, 0.5, 0.9, 0.99, 0.999)), cex=0.7, xpd = NA,labels=c("0.001", "0.01", "0.1", "0.5", "0.9", "0.99", "0.999"), adj=1) text(x=rep(3.-0.4, 4), y= -0.1-qnorm(c(1e-7, 1e-6, 1e-5, 1e-4)), cex=0.8, xpd = NA, labels=rep("1-10", 6)) text(x=rep(3.-0.27 , 4), y= 0.1-qnorm(c(1e-7, 1e-6, 1e-5, 1e-4)), cex=0.6, xpd = NA,labels=c("-7", "-6", "-5", "-4")) box() }
関数textで、図表領域上の任意の位置に文字列を描画することができます。座標値、文字列ともにベクトルで指定することができます。
text(x, y, labels)
によって、各点( x[i] , y[i] )に文字列 labels[i] を描きます。linesやpointsと同様、x、yを別々に指定する代わりに、x、y成分を持ったリスト、または2列の行列を指定しても構いません。 なお、textで文字列を描画する際は、文字列が余白にはみ出しても描かれます。つまり、作図パラメータxpdは常にTRUEとして扱われますので注意して下さい。 グラフ上の任意の場所に文字列を書き込みたい時などには、textを locatorと組み合わせて使うと便利です。以下の例では、locator により座標を一つだけ得て、その位置に文字列を描き込んでいます。
plot(1:10) text(locator(1), labels = "異常値")
余白に文字列を書き込むにはmtextが便利です。
mtext(text, side, line, at)
引数textに書き込む文字列を指定し、 sideには余白のサイド番号、lineには図形領域から何行離すかを指定します。
mtext1 <- function () { old.par <- par(no.readonly = TRUE); on.exit(old.par) # 作図パラメータの退避と終了時復帰 png("mtext1.png") # png デバイスを開く plot(1:10, (-4:5)^2, main="Parabola Points", xlab="xlab") mtext("10 of them") for(s in 1:4) mtext(paste("mtext(..., line= -1, {side, col, font} = ",s, ", cex = ", (1+s)/2, ")"), line = -1, side=s, col=s, font=s, cex= (1+s)/2) mtext("mtext(..., line= -2)", line = -2) mtext("mtext(..., line= -2, adj = 0)", line = -2, adj =0) dev.off() # デバイスを閉じる }
文字列描画に関する作図パラメータには以下のものがあります。これらによって、字の大きさ、文字列の描画方向などを設定することができます。
## プロット記号の右 0.12 インチにラベルを書く ## この例では xinch(0.12) は 0.5295534 に変換される data(mtcars) # 組み込みデータ mtcars 読み込み with(mtcars, { # mtcars の成分を展開した環境中で作図 plot(mpg, disp, pch=19, main= "Motor Trend Cars", text(mpg + xinch(0.12), disp, row.names(mtcars), adj = 0, cex = .7, col = 'blue') })
矩形を描く rect() 関数 をみよ。
layout 関数による画面の4分割とレイアウトの確認
layout1 <- function (n) { oldpar <- par(no.readonly = TRUE); on.exit(par(oldpar)) # 終了時パラメータ復帰 # layout 関数で画面を横に 3:1、縦に1:3 の4画面に分割 # 副画面の番号を [1,1] -> 2, [1,2] -> 0, [2,1] -> 1, [2,2] -> 3 とする nf <- layout(matrix(c(2,0,1,3),2,2,byrow=TRUE), c(3,1), c(1,3), TRUE) layout.show(nf) # レイアウトを確認したければこうする ## なぜか png デバイスは複数画面を一度に表示しないので遠回り pp <- recordPlot() # X11 デバイスへの出力を記録 png("layout1.png") # png デバイスを開く replayPlot(pp) # pp に記録された画像を png デバイスへ出力 dev.off() # デバイスを閉じる }
layout2 <- function (n) { oldpar <- par(no.readonly = TRUE); on.exit(par(oldpar)) # 終了時パラメータ復帰 x <- pmin(3, pmax(-3, rnorm(50))) # 50個の正規乱数. -3以下(3以上を)を-3 (3) に置き換え y <- pmin(3, pmax(-3, rnorm(50))) # 50個の正規乱数. -3以下(3以上を)を-3 (3) に置き換え xhist <- hist(x, breaks=seq(-3,3,0.5), plot=FALSE) # 棒グラフ情報を記録 yhist <- hist(y, breaks=seq(-3,3,0.5), plot=FALSE) # 棒グラフ情報を記録 top <- max(c(xhist$counts, yhist$counts)) xrange <- c(-3,3) yrange <- c(-3,3) # layout 関数で画面を横に 3:1、縦に1:3 の4画面に分割 # 副画面の番号を [1,1] -> 2, [1,2] -> 0, [2,1] -> 1, [2,2] -> 3 とする # 番号 0 の副画面には何も描かない(?) nf <- layout(matrix(c(2,0,1,3),2,2,byrow=TRUE), c(3,1), c(1,3), TRUE) # layout.show(nf) # レイアウトを確認したければこうする par(mar=c(3,3,1,1)) #番号1の副画面の余白指定 plot(x, y, xlim=xrange, ylim=yrange, xlab="", ylab="") # 番号1の副画面にプロット par(mar=c(0,3,1,1)) #番号2の副画面の余白指定 barplot(xhist$counts, axes=FALSE, ylim=c(0, top), space=0) # 番号2の副画面にプロット par(mar=c(3,0,1,1)) #番号3の副画面の余白指定 barplot(yhist$counts, axes=FALSE, xlim=c(0, top), space=0, horiz=TRUE) # 番号3の副画面にプロット ## なぜか png デバイスは複数画面を一度に表示しないので遠回り pp <- recordPlot() # X11 デバイスへの出力を記録 png("layout2.png") # png デバイスを開く replayPlot(pp) # pp に記録された画像を png デバイスへ出力 dev.off() # デバイスを閉じる }
関数split.screenを使って、作図可能領域内にいくつかの異なる大きさの副画面を定義することができます。個々の副画面には通常の方法でグラフを描くことができます。 これは作図パラメータ mfrowやmfcolを用いた複数図表に似ていますが、規則的な画面分割に限らず、自由に副画面を定義することができ、各副画面で座標入力を行なうこともできます。 重なりを持った副画面を定義することも可能です。また、以下の作図パラメータが各々の副画面ごとに独立して管理されます。
adj bty cex col crt err exp font lab las lty lwd mar mex mgp new pch pty smo srt tck usr xaxp xaxs xaxt xpd yaxp yaxs yaxt
なお、split.screenは内部で複数図表を利用しているので、副画面で複数図表を用いることはできません。また、副画面に外周は作れません。
副画面を定義するには、split.screenを使います。 引数には、分割方法を定義する長さ2のベクトルあるいは (定義する副画面の個数) × 4 の行列を与えます。 分割の結果、副画面の縦あるいは横が全画面の半分より小さくなれば,その時定義したすべての副画面について作図パラメータcexとmexが 0.5に設定されます。
split.screenにベクトル c( m , n ) を与えると、作図パラメー タmfrowによる規則的な分割と同じように、縦を m 個、横を n に分割します。例えば、上下二つに分割するには以下のようにします。
split.screen(c(2,1)) [1] 1 2
分割の結果できた各副画面は番号によって管理されます。split.screen は分割の結果できた副画面の番号を返します。上記の例では上側が副画面1、下側が副画面2になります。引数screenに分割する副画面の番号を指定することによって、その副画面をさらに分割することができます。例えば、先ほどの例でできた副画面2をさらに3つに分割するには、
split.screen(c(1,3), screen = 2) [1] 3 4 5
とします。
split.screenに (定義する副画面の個数) × 4 の行列を与えて画面定義を行なうこともできます。この場合は各行が個々の副画面を定義します。各行には、副画面を定義する画面の左下隅を (0, 0),右上隅を (1, 1) とする座標系で、各副画面の大きさと位置を左下隅のx座標、右上隅のx座標、左下隅のy座標、右上隅のy座標 の順で与えます。副画面は互いに重なりがあっても構いません。
screen 関数はディスプレイを幾つかのスクリーンに分割し、それぞれにグラフィックスを書き込む。この例ではスクリーン 3,5 (スクリーン 2 がスクリーン 3,4,5 に分割されている) には書き込みが無い。
screen1 <- function () { par(bg = "white") # 既定の背景色を白にする split.screen(c(2,1)) # ディスプレイを上下二つのスクリーンに分割 split.screen(c(1,3), screen = 2) # スクリーン 2 (下半分)を更に横に三分割 screen(1) # スクリーン 1 への書き込みを始める plot(10:1) screen(4) # スクリーン 4 への書き込みを始める plot(10:1) close.screen(all = TRUE) # スクリーン分割モードを終了 }
screen2 <- function () { split.screen(c(2,1)) # ディスプレイを上下二つのスクリーンに分割 split.screen(c(1,2),2) # 下のスクリーンを更に横に二分割 plot(1:10) # 既定で最後(screen 3)がアクティブ erase.screen() # ラベルを書くのを忘れたので一旦消す plot(1:10, ylab= "ylab 3") screen(1) # スクリーン 1 への書き込みを始める plot(1:10) screen(4) # スクリーン 4 への書き込みを始める plot(1:10, ylab="ylab 4") screen(1, FALSE) # スクリーン 1 へ戻るが、消さない plot(10:1, axes=FALSE, lty=2, ylab="") # 上書き axis(4) # チックマークを右軸に加える title("Plot 1") close.screen(all = TRUE) # スクリーン分割モードを終了 }
par(oma=c(0,0,2,0)) # 総合タイトル用に隙間を設ける split.screen(figs=c(3,4)) # 画面を 3x4 分割(順に番号 1,2,...,12 が付く) [1] 1 2 3 4 5 6 7 8 9 10 11 12 for(i in 1:12) {screen(i); plot(1:10)} # 各スクリーンに作図 close.screen(all=T) # スクリーンへの作図を終了 title(main='TITLE 1', outer=T) # 総合タイトル
frame 関数は plot.new 関数の別名
> par(mfrow=c(2,1)) > plot.new() # 第一分割画面をスキップし、第二画面に作図 > hist(rgamma(100000,6463.7,scale=0.015471),xlim=c(0,120),main="Emergence")
> par(mfrow=c(2,1)) > plot.new() > hist(rgamma(100000,6463.7,scale=0.015471),xlim=c(0,120),main="Emergence")
> par(mfrow=c(2,2)) > hist(rgamma(100000,6463.7,scale=0.015471),xlim=c(0,120),main="Emergence") > plot.new() > plot.new() > hist(rgamma(100000,6463.7,scale=0.015471),xlim=c(0,120),main="Emergence2")
同じ単位のいくつかのデータを一枚の図にプロットするには、 plotと points、linesなどを利用することができます。しかし、異なる単位のデータを一つのグラフに描画する場合など、 いくつかの異なった座標軸を描きたいこともあります。 この場合、高水準作図関数によるプロットを重ね合わせるのが便利です。通常は高水準作図関数は作図の前に画面を消去しますが、par(new=T)とすることによってこれを抑制できます。例えば以下のようにすると2つの時系列プロットを重ね合わせることができます。後で右の余白に軸を書き加えますから、最初に右の余白を少し広げておきましょう。
> par(mar=c(5,4,4,4)+0.1) > plot(1:100,type="l") > par(new=T) > plot(10:1, type="l", axes=F, xlab="", ylab="", lty=2)
このとき、二度めのplotによって軸と軸のラベルが重ね書きされるのを避けるため、 axes=F, xlab="", ylab=""としていることに注意して下さい。二度めのplotに対する軸は、
> axis(side=4)
とすることによって、現在の単位に従った、すなわち二度めのplotが描くはずだったy軸を図の右側の余白に描きます。この軸に対するラベルは、
> mtext(side=4, line=3, text="uwxyz")
として描きます。最後に凡例も付けてみましょう。位置はlocatorで読み込みます。
> legend(locator(1), legend=c("abcde", "uwxyz"), lty=1:2)
par(mai = c(3,1,1,1)) x <- runif(50) plot(x, xlim = c(1, 500), ylim = c( -5, 1), bty = "l") par(mai = c(2,1.5,2,1)) par(new = TRUE) x <- runif(50) plot(x, xlim = c(1, 500), ylim = c( -5, 1), bty = "l") par(mai = c(1,2,3,1)) par(new = TRUE) x <- runif(50) plot(x, xlim = c(1, 500), ylim = c( -5, 1), bty = "l")
> plot(1:10) # まず最初のプロット(x 軸と y 軸(左側)が書かれる) > par("usr") # その時のユーザー座標系 [1] 0.64 10.36 0.64 10.36 > par(usr=c(par("usr")[1:2], 100.8, 105.2)) # ユーザー座標系を変更(x 座標系はそのまま) > points(1:5, 105:101, col="red") # 追加の点を変更座標系に赤色で書く(軸は書かれない) > axis(4) # 変更座標系の(y)軸を右側に書く
カラーチャートをクリックして色を取得
# L: division of RGB space. # N: number of pick-up colors colorPicker<-function(L=8,N=1){ if(L<2){cat("L must be lager than 1\n");return(NULL)} D<-ceiling(L^(3/2)) # 3D->2D v<-seq(0,1,by=1/(L-1));r<-rep(v,L*L);g<-rep(v,L,e=L);b<-rep(v,e=L*L) col<-c(rgb(r,g,b),rep(rgb(1,1,1),D^2-L-3)) # construct color vector x<-rep(0:(D-1),D);y<-rep(0:(D-1),each=D) # plot coord. par.old<-par(mfrow=c(1,1)) plot(0,xlim=c(0,D),ylim=c(0,D),type="o",xaxt="n",yaxt="n",ann=F,col="0") # whiteboard for(y in (D-1):0)for(x in 0:(D-1)) rect(x,y,x+1,y+1,col=col[1+x+(D-1-y)*D],border=NA) # create color chart p<-locator(N);ret<-col[1+floor(p$x)+(D-1-floor(p$y))*D] # click point -> color par(par.old) ret }