| Top Page | プログラミング | R 自動化 目次 | 索引 | 前へ | 次へ |

R でプログラミング:データの一括処理とグラフ描き

12. 見栄えのよいグラフ(その1):字をきれいに

updated on 2009-03-27

R は細かい指定をしなくともいろいろ「適当」に作図してくれます. データをグラフにして自分で眺めるだけなら,見栄えを気にする必要はありません. デフォルトの設定で描いてくれるグラフでも十分です. けれども論文や学会発表で使う図となると,見た目をよくすることも必要です.

論文用や学会用の図を作れないのでは,R 入門のモチベーションが 下がってしまうことにもなります.また,せっかく作図を自動化しても,そのあと 他のソフトに読み込んで手作業で細工をするのでは効率がよくありません.

この章では,とくに文字の表示・軸の設定を中心に, 特別のパッケージを使うことなく「外むけに使えるグラフ」を描く方法をまとめてみました. すべて,par ないしは作図関数中でのパラメータ設定の範囲の話です. ヘルプを調べれば分かることばかりですが,自分がやりたいことを実現するにはどの パラメータをいじればよいのかを探すのはけっこう手間です. このぐらいのパラメータをいじれば実用上は十分だろうというものを整理ました.

見栄えの設定なしで描いたグラフ () からいろいろ設定したグラフ()へ,徐々に改良しながら説明します. 次の章では,複数のグラフを並べる場合を扱います(). plot関数で描く撒布図を例にして説明していますが, その他のタイプの図にも通用する内容がほとんどです.

注意:作図パラメータの有効期間

作業を始める前の注意をひとつ.見栄えのよいグラフを描くには, par() を 使って作図パラメータを変更することがしばしばあります.すでに5章で説明したように, 画像ファイルや PDF ファイルなどを開いてからパラメータを変更した場合, その設定が有効なのは,作図中のファイル(作図デバイス)への書込みに関してだけです. 他のデバイスには影響しません.dev.off() でファイルを閉じたあとで 描画ウインドウ上でグラフを描く場合には,元どおりの設定が生きています.

また,描画ウインドウもひとつの作図デバイスです.par でいろいろ設定して作業したあと,デフォルトの初期設定に戻したかったら, 一度 dev.off() を実行して描画ウインドウを閉じます. そのあとふたたび描画オブションを設定したり,plot など高水準描画関数を 実行すれば,自動的にあらたな描画ウィンドウが開きますが, これに付随するパラメータは初期設定のものになっています.

初期設定とは異なる状態で描いたグラフがたまたま具合よくできても, あとで描きなおしたら同じように描けずに困惑することもあります. グラフの設定を始める前に,一度 dev.off() しておくとよいでしょう.

素朴な1枚から「実用になるグラフ」へ

素朴な1枚

練習用に,2種類(sp)の樹木,Q. nana と Q. hatena の, 幹の太さ (w) と木の高さ (h) のデータが並んだ架空のデータファイル, w_h_data.txtを使います. データはタブ区切りで,種名は途中に空白を含んでいます. read.table は,特に指定をしないとタブも空白もデータの区切りだと解釈します. これでは種名がちぎれてしまって困ります. sep = "\t" というオプション指定をすれば,タブ (\t)だけが区切りだと解釈してくれます.

まずはこのデータを読み込んで,一枚のグラフに,種類ごとに記号を変えて 太さと高さの関係をプロットしてみます (>グラフ).

d <- read.table ('w_h_data.txt', header = TRUE, sep = "\t")  # データの読み込み
plot(d$w, d$h, pch = c(1, 16)[d$sp], type = 'p')    # 種類によって,記号を変える.

type = 'p' で,線グラフではなく点を打つグラフであることを指定しています. 線グラフの場合は 'l'(エル) を指定します.

第8章の 「因子を添え字として使ってオプション指定」 で,因子で点の色の指定をしたのと同様の技で,記号の種類変えています. 投稿論文など白黒の図が基本の場合にはこちらがふつうですね.

凡例と軸のタイトルを書く

これから順々にお化粧をしていきます. まずは横軸,縦軸,凡例,タイトルをつけてみましょう (>グラフ).

d <- read.table ('w_h_data.txt', header = TRUE, sep = "\t")  # データの読み込み

plot(d$w, d$h, pch = c(1, 16)[d$sp],  type = 'p',
     xlab = "Diameter at breast height (cm)",
     ylab = "Tree height (cm)",
     main = "Height vs DBH relationships in two oak species")

legend ("topleft", legend = levels(d$sp), pch = c(1, 16)) # 凡例

xlab と ylab の指定はすでに説明しました.main は,グラフの上に書かれるメインタイトルです.

凡例を描くlegendでは, 因子が並んだベクトル(この場合は d$sp) から,どんな因子が含まれているかを取り出して配列で 返す関数 levels を使っています. 以下,少々ややこしいですが,上記のプログラムでプロットに使われる記号と凡例との 整合性が取れる(種名と記号の関係が正しい)理屈を説明してみます.

d$sp には Q. nata と Q. hatena のふたつの因子が含まれていますが, R の内部では1番の因子,2番の因子と,順序付けて扱われます. levels はこの順で因子の要素を返します. また plot の記号の設定で pch = c(1, 16)[d$sp] という書き方をしたとき, 因子である d$sp は数値に変換されて c(1, 16) のどちらの要素かを指定するのに 使われましたが,この数値も因子の順序付け情報によるものです

したがって,凡例の最初の行には levels(d$sp) の最初の要素と c(1,16) のうち 1 の記号(すなわち○)とが並んで書かれますし. 2行目には levels(d$sp) の2番めの要素と,16番の記号(すなわち●)が並びます. そしてグラフのほうも同様に種名と記号が対応します.

字を大きくする

さて,上のプログラムで描かれた グラフは 字も記号も小さく,人に見ていただけるものではありません. 記号の大きさ,字の大きさを設定して,もう少し見栄えをよくしてみましょう (>グラフ).

d <- read.table ('w_h_data.txt', header = TRUE, sep = "\t")  # データの読み込み

plot(d$w, d$h, pch = c(1, 16)[d$sp],  type = 'p',
     xlab = "Diameter at breast height (cm)",
     ylab = "Tree height (cm)",
     main = "Height vs DBH relationships in two oak species",
     cex      = 2.5,     #  記号の大きさを設定する(標準は1)
     cex.lab  = 2,       #  軸の説明の字の大きさを設定する
     cex.axis = 1.8,      #  軸の数字等(ラベル)の大きさを設定する
     cex.main = 1.8)      #  メインタイトルの字の大きさを設定する

legend ("topleft", legend = levels(d$sp), pch = c(1, 16),
        cex = 1.5,    #  説明の字の大きさを設定する(標準は 1)
        pt.cex = 2)   #  記号の大きさを設定する(標準では cex と同じ)

たしかに字は大きくなったけどこれではちょっと… ですね. 縦軸の説明やメインタイトルがはみ出していますし,軸の数字がすこし軸にくっつきすぎて 窮屈そうです.でも,さらに改良する前に,まずは新たに付け加えた設定の説明をします.

plot中の cex は記号や文字の大きさを標準サイズの何倍にするかを 指定します.これは以前にも説明しました. この値を変えると,軸の説明も数字(ラベル)も一律に変化します.

きめ細かく,軸の説明,数字,メインタイトルの大きさを変えるには, それぞれ cex.lab, cex.axis, cex.main に値を設定します. 目的に応じて,ちょうどよい大きさになる設定を探します.

legend でも,cex で記号や文字の大きさを設定します. 記号の大きさだけを変えるには pt.cex に値を設定します.上の例では, cex = 1.5, pt.cex = 2 と,文字以上に記号を大きくしています.

余白を広くして字をおさめる

次に,文字がはみ出さないように余白の設定をしてみます (>グラフ).

d <- read.table ('w_h_data.txt', header = TRUE, sep = "\t")  # データの読み込み

par(mar = c(5.5, 6.0, 4.1, 2)) #  余白の広さを行数で指定.下,左,上,右の順.
par(mgp = c(4, 1.2, 0))        #  余白の使い方.説明,ラベル,軸の位置を行で指定.

plot(d$w, d$h, pch = c(1, 16)[d$sp],  type = 'p',
     xlab = "Diameter at breast height (cm)",
     ylab = "Tree height (cm)",
     main = "Height vs DBH relationships\nin two oak species", # relationships と in の間で改行
     cex      = 2.5,     #  記号の大きさを設定する(標準は1)
     cex.lab  = 2,       #  軸の説明の字の大きさを設定する
     cex.axis = 1.8,      #  軸の数字等(ラベル)の大きさを設定する
     cex.main = 1.8)      #  メインタイトルの字の大きさを設定する

legend ("topleft", legend = levels(d$sp), pch = c(1, 16),
        cex = 1.5,    #  説明の字の大きさを設定する(標準は 1)
        pt.cex = 2)   #  記号の大きさを設定する(標準では cex と同じ)

グラフを描く前に,par で mar と mgp というふたつのパラメータを 設定しています.

mgp は,プロットの周縁から文字列何行分離れたことろに軸のタイトル,数字などのラベル, そして軸(線)を描くかを,3つの要素が並んだベクトルで指定します.初期状態は c(3, 1, 0) です.軸の位置を 0 より大きくすれば,軸が離れたところに描かれますし, タイトルやラベルを離れたところに描くには,3 や 1 より大きな数字を設定します. mgp = c(4, 1.2, 0) としています.

mar は,四方の余白(margin)を文字列何行分とるかを指定します.下,左,上,右の 余白行数を並べたベクトルで指定します.上の例では,それぞれ 5.5行,6.0行,4.1行,2.0行としています.初期状態では 5.1, 4.1, 4.1, 2.1 ですので,下と左,x軸の説明と y軸の説明を書くところが 少し広くなります.mgp の設定で,軸のタイトルやラベルを 軸から少し離して書くようにしましたが, mar を広くすることではみ出さずに表示されます.

また,グラフの上に書く全体のタイトルは,途中で改行して,両端がはみ出さないようにしました. 引用符で囲まれた文字列中に,円記号 \ と n を並べて書いた改行コードを文字列中に入れています. なお,円記号 \ は環境によってはバックスラッシュ,すなわち左上から右下への斜め線に見えている かもしれませんが,文字コードとしては同じもので,うしろに n を続けて書くと改行を意味するのも 同様です.

凡例の見栄え

次に,凡例の見栄えをよくします (>グラフ).

d <- read.table ('w_h_data.txt', header = TRUE, sep = "\t")  # データの読み込み

par(mar = c(5.5, 6.0, 4.1, 2)) #  余白の広さを行数で指定.下,左,上,右の順.
par(mgp = c(4, 1.2, 0))        #  余白の使い方.説明,ラベル,軸の位置を行で指定.

plot(d$w, d$h, pch = c(1, 16)[d$sp], type = 'p',
     xlab = "Diameter at breast height (cm)",
     ylab = "Tree height (cm)",
     main = "Height vs DBH relationships\nin two oak species",
     cex      = 2.5,     #  記号の大きさを設定する(標準は1)
     cex.lab  = 2,       #  軸の説明の字の大きさを設定する
     cex.axis = 1.8,      #  軸の数字等(ラベル)の大きさを設定する
     cex.main = 1.8)      #  メインタイトルの字の大きさを設定する

par(font = 3)  # 字体をイタリックに

legend ("topleft", legend = levels(d$sp), pch = c(1, 16),
        cex = 1.5,    #  説明の字の大きさを設定する(標準は 1)
        pt.cex = 2,   #  記号の大きさを設定する(標準では cex と同じ)
        bty = "n",    #  凡例を書込む箱(box)のタイプ. "n" だと箱を描かない."o"(デフォルト)だと描く 
        inset = c(0.1, 0.05))  # 位置指定の場所からとる余白.全体を1とする相対値で,x,y両方向の値を並べる.
        
par(font = 1)        # イタリックの設定を解除

parlegend のパラメータ設定で, 字体を変える,箱を描かなくする,位置を動かすの3つのことをしています.

まず,par(font = 3) で字体をイタリック(斜体)にしています.Q. hatena と Q. nana は 学名で,イタリックで書く慣習です.font の設定後に legendで凡例を書くと, 凡例中の文字列がイタリックになります.

関数に与えるパラメータで字体を設定できる描画関数もあり,たとえば text では text(0, 0, "TEST", font = 3) といったことが可能です. いっぽう,legendではそれができず, par(font = ...) で標準の字体を変更しないとイタリックにできません. なお,font は 1 が標準,2 はボールド(太字),3 はイタリック,そして 4 は ボールドかつイタリックです.

上の例では凡例を描いたあと,par(font = 1) で字体を標準にもどしていますが, このあとまったく字を書かないならもどす必要はありません.

つぎに,凡例を囲む箱を描かないようにするために,bty = "n" と設定しています. bty は箱(box)のタイプ(type) を決めるパラメータで,設定できる値は "o" (標準.線で囲み,白で塗りつぶす)か "n" (線で囲わず,塗りつぶしもしない)です.

箱はじゃまになることが多いですし,重なった部分を塗りつぶされてしまうと,一部の プロットが消えてしまうこともあります.そんなとき,字を小さくして重なりを避ける かわりに,箱を描いて塗りつぶすのをやめるほうが見やすいグラフになることが多いでしょう.

3つめは凡例の位置の指定です. 凡例の位置は,プロット内の座標系で指定するか,"topleft"などのキーワードで指定するかします. 後者の場合,箱はプロット領域の隅にきっちり押しつけて描かれますが, inset の指定ですこし余白をとることができます. y軸からの余白と x軸からの余白を並べたベクトルで指定します. 値の単位は,プロット全体を1とする相対値です.

上の例の,位置を示すキーワードが "topleft" で,inset = c(0.1, 0.05) という設定では,

ということになります.

線を太くする

最後に,グラフがはっきり見えるように線を太くします. これは,parで lwd を設定するか, 個々の描画関数で lwd および関連パラメータを設定するかで行います. ここでは簡単に,parで設定してみます (>グラフ).

d <- read.table ('w_h_data.txt', header = TRUE, sep = "\t")  # データの読み込み

par(mar = c(5.5, 6.0, 4.1, 2)) #  余白の広さを行数で指定.下,左,上,右の順.
par(mgp = c(4, 1.2, 0))        #  余白の使い方.説明,ラベル,軸の位置を行で指定.

par(lwd = 2)   #  線の太さを指定.

plot(d$w, d$h, pch = c(1, 16)[d$sp], type = 'p',
     xlab = "Diameter at breast height (cm)",
     ylab = "Tree height (cm)",
     main = "Height vs DBH relationships\nin two oak species",
     cex      = 2.5,     #  記号の大きさを設定する(標準は1)
     cex.lab  = 2,       #  軸の説明の字の大きさを設定する
     cex.axis = 1.8,      #  軸の数字等(ラベル)の大きさを設定する
     cex.main = 1.8)      #  メインタイトルの字の大きさを設定する

par(font = 3)  # 字体をイタリックに

legend ("topleft", legend = levels(d$sp), pch = c(1, 16),
        cex = 1.5,    #  説明の字の大きさを設定する(標準は 1)
        pt.cex = 2,   #  記号の大きさを設定する(標準では cex と同じ)
        bty = "n",    #  凡例を書込む箱(box)のタイプ. "n" だと箱を描かない."o"(デフォルト)だと描く 
        inset = c(0.1, 0.05))  # 位置指定の場所からとる余白.全体を1とする相対値で,x,y両方向の値を並べる.

はじめに par(lwd = 2) と指定することで,plot で描く図の軸の太さ,記号の線の太さ, 凡例の記号の線の太さが太くなっています.よりきめ細かく指定するには,個々の描画関数 のなかで lwd ないしその関連パラメータを設定することになります. それぞれの関数のヘルプを見てみてください.

軸のスケールと目盛の入れ方を指定する

軸のスケール(両端の座標)は,すでに 4章で説明したとおり,plotのパラメータ xlim と ylim で設定します. これに加えて,決められた座標系のどこに目盛を入れるかを指定することができます (>グラフ).

d <- read.table ('w_h_data.txt', header = TRUE, sep = "\t")  # データの読み込み

par(mar = c(5.5, 6.0, 4.1, 2)) #  余白の広さを行数で指定.下,左,上,右の順.
par(mgp = c(4, 1.2, 0))        #  余白の使い方.説明,ラベル,軸の位置を行で指定.

par(lwd = 2)   #  線の太さを指定.

plot(d$w, d$h, pch = c(1, 16)[d$sp], type = 'p',
     xlab = "Diameter at breast height (cm)",
     ylab = "Tree height (cm)",
     main = "Height vs DBH relationships\nin two oak species",
     cex      = 2.5,      #  記号の大きさを設定する(標準は1)
     cex.lab  = 2,        #  軸の説明の字の大きさを設定する
     cex.axis = 1.8,      #  軸の数字等(ラベル)の大きさを設定する
     cex.main = 1.8,      #  メインタイトルの字の大きさを設定する
     xlim = c(0, 30),        # x 軸の両端の値 (座標系を決める)
     xaxp  = c(0, 30, 3),    # x 軸の両端の目盛の座標と,目盛の間隔の数
     ylim = c(0, 1800),      # y 軸の両端の値 (座標系を決める)
     yaxp  = c(0, 1500, 3))  # y 軸の両端の目盛の座標と,目盛の間隔の数

par(font = 3)  # 字体をイタリックに

legend ("topleft", legend = levels(d$sp), pch = c(1, 16),
        cex = 1.5,    #  説明の字の大きさを設定する(標準は 1)
        pt.cex = 2,   #  記号の大きさを設定する(標準では cex と同じ)
        bty = "n",    #  凡例を書込む箱(box)のタイプ. "n" だと箱を描かない."o"(デフォルト)だと描く 
        inset = c(0.1, 0.05))  # 位置指定の場所からとる余白.全体を1とする相対値で,x,y両方向の値を並べる.

xlim,ylim を使って,x軸,y軸ともゼロから始まるように設定しています.

xaxp, yaxp が軸への目盛の入れ方を指定するパラメータで, 3つの数値がならんだベクトルを設定します. それらの意味は,小さい側の端の目盛を軸上のどこに置くか, 大きい側の端の目盛をどこにおくか,そしてこれら二つの端のあいだを何個の区画に区切るか, です.軸上の位置の指定は,論理的な座標です.つまり,x軸が 0 から 100 に対応する場合に 軸の左端に目盛を置きたいなら 0 を指定するし,軸が 500 から 600 の範囲に対応するなら, 左端は 500です.

上の例の xlim = c(0, 30), xaxp = c(0, 30, 3) という指定は,x 軸は 0 から 30までで, 両端の目盛は 0 のところと 30のところ,そしてそのあいだを3つに分けますから, 間隔はちょうど 10となり,10 と 20 のところに目盛が打たれます.

なお,xlog や ylog にTRUE を設定して対数目盛になっているときは,xaxp, yaxp の指定の意味が まったく異なります.詳しくは parのヘルプを参照してください.

フォントの設定

par(family = ...)で,文字を描くときに使用するフォントを 設定することができます. ややこしいのですが,ここで言うフォントは,par(font=...) で言うフォントではなく, 明朝体とかゴチックとかいったフォントの設定です. とくに family を設定しないと,作図デバイスに対応した標準のフォントが使われます. ふつうは "sans", ウロコ(線の端につく三角形の装飾)のない ゴチック系のフォントが使われることが多いかと思いますが, ここらへんは環境依存かもしれません.

ウロコがついた,日本で言うなら明朝系のフォントを par(family = "serif") で指定した例を載せておきます.plot でグラフを描いたあと,凡例を書くまえに 設定して,凡例の文字だけを serif にした例です (>グラフ).


次の章では,複数のグラフを並べて外側に軸の説明を描く方法を紹介します.


| Top Page | プログラミング | R 自動化 目次 | 索引 | 前へ | 次へ |