R

トップページ

Google
WWWを検索
サイト内を検索

前世紀、1990年代のやり方ですが、ggplot2パッケージが無くてもそこそこ見やすいグラフが描けます。

1 縦横サイズを指定したキャンバスを作る

以下の例では、(0, 0)から(2, 3)までの座標を取るプロット先のキャンバスを作ります。

plot.new()
xlim <- c(0, 2)
ylim <- c(0, 3)
plot.window(xlim=xlim, ylim=ylim)

plotは自動的にキャンバスを作るので普段使う事は無いと思います。

2 描画関数のオプション

ヘルプに大きく書いてあれば助かるのですが、探すのが大変なパラメーターの値です。

2.1 点キャラクター(pch

pointslinesで指定できるpchパラメーターは以下の値を取れます。pch=21からpch=25では内側に色がつき、引数bgで指定できます。

2.2 線種(lty

linesarrowsで指定できるltyパラメーターは以下の値をとれます。

2.3 プロットのタイプ(type

点だけ、線だけ、点と線の組み合わせるなどのプロットの種類を指定するtypeパラメーターは、"p", "l", "o", "b", "c", "n", "h", "s", "S"の値を取れます。

以下はpch=21で描画した例です。

"h", "s", "S"はそんなに知られていないかも知れません。 type="h"は、実質的に棒グラフになります。

type="s"は、区間(x x+1)y(x)になるグラフで、例えばx=0y=0x=1y=0.64のとき、x=0.5y=0になります。 x+1のときはxの値とx+1の値が垂直な線で結ばれ、下図ではx=1のとき、(1, 0.00)(1, 0.64)が結ばれています。

type="S"は、区間(x x+1)y(x+1)になるグラフで、例えばx=0y=0x=1y=0.64のとき、x=0.5y=0.64になります。 x+1のときはx+1の値とx+2の値が垂直な線で結ばれ、下図ではx=1のとき、(1, 0.64)(1, 0.98)が結ばれています。

2.4 色(col,bg

グラフィックス関数の引数colbgには、colors関数でリストされる色の名前を指定するか、rgb関数の戻り値を指定することができます。

colors関数は戻り値の数が多いので、以下のようにgrepで絞って選びましょう。

grep("^red[0-9]*$", colors(), value=TRUE)
[1] "red"  "red1" "red2" "red3" "red4"

今までrgbを使う機会が無かったのですが、"brown"などと同様に入れられます。

par(mar=c(4, 4, 0, 0))
curve(dgamma(x, 2), 0, 10, lwd=10, col=rgb(0.5, 0.5, 0))

3 余白の調整

Rのプロットはデフォルトでは余白が多いです。しかし、TeXの方でタイトルや注釈を入れる場合は、プロット領域を大きく取りたくなるので、この余白を削りたくなります。 par関数のmarmgpオプションで余白を調整できるので覚えておきましょう。

3.1 marオプション

marオプションは、下・左・上・右の余白を指定します。

par(mar=c(5, 4, 4, 2) + 0.1)

3.2 mgpオプション

mgpオプションは軸ラベル・軸メモリ・軸線の位置を指定します。

par(mgp=c(3, 1, 0))

4 グラフ中文字列の上下左右の寄せ

text関数でプロット領域に文字を書き込むことができるわけですが、指定座標と文字位置の関係を示すadjパラメーターの意味を整理してみましょう。 キャンバスの中心に表示座標をとり、adjの値を色々と変えてみた結果が以下です。

  • c(1, 0)だと、文字列の右下に表示座標が来ます。
  • c(0, 0)だと、文字列の左下に表示座標が来ます。
  • c(0, 1)だと、文字列の左上に表示座標が来ます。
  • c(1, 1)だと、文字列の右上に表示座標が来ます。
  • 0.5を入れておくと中央にあわせになります。

つまり、adj=c(x, y)の値はtext関数の第1引数と第2引数が示す座標を左下においたマイナス方向への相対座標で、xは文字列の長さを単位にしており、yは文字列の高さを単位にしています。

mtext関数のadjはベクトルではなく、値一つのスカラー値になるので注意してください。上下寄せを指定できません。

5 調整に必要な情報の取得

par()$usrでプロット可能な座標の範囲を取得できます。par()$usr[1]が横軸の最小値、par()$usr[2]が横軸の最大値、par()$usr[3]が縦軸の最小値、par()$usr[4]が縦軸の最大値です。 strwidth関数で表示したときの文字列の長さ、strheight関数で高さを取得することができます。

6 数式の書き込み

表現式オブジェクトで表される数式をplotmain,xlab,ylablegendtextなどに代入し、プロットすることができます。

例えば、

text((par()$usr[1] + par()$usr[2])/2, 
    (par()$usr[3] + par()$usr[4])/2, 
    expression(f(x) == 
        frac(1, sqrt(2*pi*sigma^2))*
            exp(-frac(x - mu, 2*sigma^2))), 
    cex=3)

とすると、以下のように中央に表示されます。

利用できる記号などは、?plotmathで出せるヘルプか、demo(plotmath)で見られる例を参照してください。

7 見栄えの良い軸のつけ方

以下のプロットの軸の見栄えをよくしてみましょう。

7.1 軸の目盛りを設定する

axes=FALSEオプションをつけてplotを行い、axis関数で軸を書きます。

at <- seq(-2.5, 2.5, 0.5)
labels <- sprintf("%.2f", at)
axis(1, at=at, labels=labels)
axis(2, at=seq(0, 0.6, 0.1))

7.2 軸の目盛りを回転する

縦軸の目盛りの数字が読みづらいのでlas=1を指定して回転させます。横軸のラベルが長くて、目盛りが表示できないときなどにも有効です。

at <- seq(-2.5, 2.5, 0.5)
labels <- sprintf("%.2f", at)
axis(1, at=at, labels=labels)
axis(2, at=seq(0, 0.6, 0.1), las=1)

7.2.1 目盛りの45°回転

axis関数のlabels引数をFALSEにして、text関数に引数xpd=TRUE, srt=-45をつけてラベルを書けば、位置あわせが煩雑ですが、実現できます。

axis(1, at=at, labels=FALSE)
text(x=at + 0.15, par("usr")[3] - 0.1, labels=labels, srt=-45, adj=c(1, 1), xpd=TRUE)
axis(2, at=seq(ylim[1], ylim[2], 0.1), las=1)

7.3 縦軸のラベル位置を、縦軸の上にする

スペースの都合などで縦軸のラベル位置を動かしたいときは、plotの引数にylab=""をつけたあと、text関数に引数xpd=TRUEをつけてラベルを描きます。

表示位置はpar()$usrでとれるキャバスのサイズの左上のさらに1行上にしますが、text関数の引数にxpd=TRUEが無いと、表示可能エリア外になって表示されないので注意してください。

text(par()$usr[1], par()$usr[4], "density", adj=c(0.5, -1), xpd=TRUE)

7.4 縦軸と縦軸の位置を詰める

例のヒストグラムで不要だと思いますが、axis関数の引数posで表示位置を詰めることもできます。

at <- seq(-2.5, 2.5, 0.5)
labels <- sprintf("%.2f", at)
axis(1, at=at, labels=labels, pos=0)
axis(2, at=seq(0, 0.6, 0.1), las=1, pos=at[1])
text(at[1], par()$usr[4], "density", adj=c(0.5, -1), xpd=TRUE)

8 領域に色を塗る

polygon関数で色を塗ります。閉路を指定しないといけないので、やや煩雑です。

# 内側を塗った後に外側(plot)を描くので低水準描画関数のみを使う
par(mar=c(3, 3, 2, 2))
plot.new()
xlim <- c(0, 3)
ylim <- c(0, 1)
plot.window(xlim=xlim, ylim=ylim)

# 閉路をつくる
n <- 100
x <- c(seq(xlim[1], xlim[2], length.out=n), xlim[2], xlim[1])
y <- c(dexp(x[1:n]), 0, 0)

# 内側を塗る
polygon(x, y, density=50, col="gray", border=NA)

# 外側の線を描く
lines(x[1:n], y[1:n], lty=1, lwd=2, col="black")

# 縦軸と横軸を描く
at <- seq(xlim[1], xlim[2], length.out=10)
axis(1, at=at, labels=sprintf("%.2f", at))
at <- seq(ylim[1], ylim[2], length.out=11)
axis(2, at=at, labels=sprintf("%.2f", at), las=1)
text(par()$usr[1], par()$usr[4], "f(x)", 
    adj=c(0.5, 0), xpd=TRUE, cex=1.25)
text(par()$usr[2], par()$usr[3], "x", 
    adj=c(0, 0.5), xpd=TRUE, cex=1.25)

# 確率密度関数を書く
text((par()$usr[1] + par()$usr[2])/2, 
    (par()$usr[3] + par()$usr[4])/2, 
    expression(f(x) == lambda*exp(-lambda*x)), 
    cex=2, adj=c(0, 0.5))

9 日本語フォント

MS-Windowsの場合は、以下のようにフォントを登録してpar時にfamily引数を指定すると、とりあえず文字化けすることは回避できます。

windowsFonts(Meiryo = windowsFont("Meiryo"))
par(family="Meiryo")

10 プロットを重ねる

一つ目をプロットした後、par(new=T)と命令を出し、二つ目をプロットするだけで、プロットを重ねることができます。 ただし、

  • 2つのプロットのxlimをあわせておき、横軸の表示はaxis関数でまとめて行なう
  • 二つ目のプロットの縦軸はaxis関数の第1引数を4にして行なう

などの工夫をする必要があります。

11 複数のグラフを並べる

par(mfrow = c(m, n))の後にm*n回プロットを行なえば、mn列で合計m*n個のグラフを同時にプロットできます。

11.1 変則的な分割を行なう

1行目は1つのプロットで2列を使い、2行目は2つのプロットを表示するような変則的な同時プロットも、split.screen関数で入れ籠構造をつくれば表示できます。

# omaはページ全体の余白の指定
par(mar=c(4, 4, 0, 0), mgp=c(2.5, 1, 0), oma = c(0, 0, 0, 0))
# 2行1列の親領域をまずつくり、スクリーン番号の戻り値を得る
ss_p <- split.screen(c(2, 1)) 
# スクリーン番号を指定して、1行2列の子領域をつくる
ss_c <- split.screen(c(1, 2), ss_p[2])
# 親領域のスクリーン番号を指定して描画
screen(ss_p[1])
curve(dlnorm, 0, 5, xlab="")
# 子領域のスクリーン番号を指定して描画
screen(ss_c[1])
curve(dnorm, -3, 3, xlab="")
# 子領域のスクリーン番号を指定して描画
screen(ss_c[2])
curve(dexp, 0, 3, xlab="")

12 グラフを保存する

pngpostscriptなどでグラフィックスデバイスを開いた後、plotをして、dev.offでグラフィックスデバイスを閉じれば保存できます。

png(filename = "sin.png", 
    width = 800, height = 600, bg="white", type="cairo")
curve(sin(x), -pi, pi)
dev.off()

12.1 グラフィックスデバイスのオープンとプロットを分離

グラフィックスデバイスのオープンとプロットを分離したい場合は、遅延実行を応用します。 プロット部分だけ関数化できるので、同じ描画のコードを、画面確認,Web用PNG,TeX用EPS,R Markdownなどに使いまわしたいときに便利です。

save_as_png <- function(fname, plot_expression){
    png(filename = fname,
        width = 800, height = 600, bg="white", type="cairo")
    plot_expression
    dev.off()
}

save_as_png("sin.png", { curve(sin(x), -pi, pi) })

12.2 ディスプレイに表示した後に保存

plotしてディスプレイに表示した後に保存したくなった場合は、dev.copydev.copy2epsを使います。

curve(sin(x), -pi, pi)
dev.copy(png,
    file = "sin.png", width=600, height=400, type="cairo")
dev.off()

13 終わり

思い出せたところを列挙しました。後で追記するかも知れません。