最終更新:2022年 2月 20日 (日曜日)
このページはRのグラフィクスについて説明する。
●グラフィックデバイスによって異なる。
中間さんのAI_UCS2.Rをsource()を使うなどして先に実行してからグラフィックデバイスを開き,par(family="Japan1GothicBBB")をしてグラフ出力すべき。はしご高のように,UTF-8では表示できるがEUC-JPでは表示できないような文字も表示できるようになる(参考:2008年6月23日のメモにいただいたコメント)。
●描画が終わったらdev.off()を忘れずに。
windowsFonts(JP1=windowsFont("MS Gothic"), JP2=windowsFont("MS Mincho"), JP3=windowsFont("Meiryo")) par(family="JP3")
を実行してからplot()などのグラフ出力を実行すべき。こうしておけば,拡張メタファイル(emf)をPowerPointやOpenOffice.orgのImpressなどに読み込んでから編集するためにオブジェクト変換しても漢字が文字化けしない。
●描画が終わったらdev.off()を忘れずに。
●RにはHersheyEUCとして約700の日本語フォントが含まれていて,text関数から使えるのだが,フォントの指定が面倒なので使いにくかった。これを簡単に使えるようにする関数jtext(実行例を含むソース)を書いてみた。ただし内部で漢字文字列をJISコード番号文字列に変換するPerlプログラムjiscode.plを呼び出していて,その中でcgiなどで良く使われているjcode.pl(注:リンク先のWikipediaの説明にあるように、既に使うべきではない。Jcode.pmのページでも書かれているように、2022年現在のPerlではEncode.pmを使うべき)を呼び出しているので,それらが実行時に呼び出せるディレクトリに置かれていて,かつActive Perlにパスが通っている必要がある。もっとも,LinuxやFreeBSD環境ならばjiscode.plの先頭にPerlのパスを書けばいいはずである。なお,Perl5.8以降では標準のEncodeライブラリを使う方がスマートな気がするし,それ以上に,単にjisx0208にできればいいのだからCで書いてライブラリ化した方が便利だと思うが,とりあえずPerlで用が足りるので今後の課題ということにする。
実行例を下に示す(上でリンクしているRプログラムを実行してできるpngファイル)。
●なお,pLaTeXと組み合わせて使えば,上のような面倒なことをしなくても,日本語を含むプロットが簡単にできる(ベクトルグラフィックとしてではなく,文字としてのプロットになる)。textで普通に日本語文字列をプロットした後で,dev.copy(pictex,"jtext3.tex"); dev.off()としてpictex形式のファイルjtext3.texを作り,これを
\documentclass{jarticle} \usepackage{pictex} \usepackage[dvipdfm]{graphicx} \begin{document} \begin{figure}[h] \centerline{\input{jtext3.tex}} \caption{3都市の緯度と経度の2次元表示} \end{figure} \end{document}
のようにして読み込むファイルtest.texを作って,platex test,dvipdfm testとすれば,test.pdf (16,518 bytes)ができあがる。こちらの方が使えるフォントが多いし,美しくて実用的である(時折そのままでは通らない文字があるのだが,出力されるpictexファイルを直接エディタで編集すれば問題ない。textだけではなく,xlabとかmainでも日本語が使えた)。
●簡単にやるには,plot関数のpch=に値を与えればよい。例えば,X,Y,Zという3つの村があって,それぞれ身長と体重のデータがあって,その関係を村ごとにマークを変えてプロットしたいとする。
●データは1行目がタブ区切り変数名で2行目以降がタブ区切りデータのテキストファイルからread.delim関数で読む(上述)のが普通だが,プログラム内で与えるには,
hx <- c(161.5, 167.0, 157.5, 160.5, 156.0, 165.0, 157.5, 169.5, 168.5, 178.5) wx <- c(49.2, 72.8, 61.6, 62.6, 73.6, 57.8, 60.8, 92.4, 58.2, 71.8) hy <- c(159.5, 161.5, 148.0, 164.0, 169.5, 164.5, 161.0, 172.0, 168.0, 163.0, 153.5, 165.5, 168.0, 161.0, 160.5, 158.0, 156.0, 155.5) wy <- c(43.6, 65.2, 49.6, 57.4, 67.0, 61.4, 56.2, 66.4, 67.0, 60.2, 44.6, 63.2, 62.4, 53.8, 63.6, 59.0, 59.0, 53.6) hz <- c(171.5, 176.5, 166.0, 175.0, 166.0, 169.0, 175.5, 167.0, 163.5) wz <- c(73.2, 77.8, 58.0, 57.2, 67.0, 73.6, 97.8, 63.0, 67.4)
として村ごとのデータを与え,さらに
x <- data.frame( VG=c(rep('X',NROW(hx)),rep('Y',NROW(hy)),rep('Z',NROW(hz))), HEIGHT=c(hx,hy,hz), WEIGHT=c(wx,wy,wz) )
としてデータフレームにすればよい。
●村名をそれぞれ違う色で身長と体重の座標位置にプロットするには,
plot(x$WEIGHT ~ x$HEIGHT, pch=as.character(x$VG), col=as.single(x$VG), main="Relationship between HEIGHT(cm) and WEIGHT(kg)\n in Solomon Adult Males", xlab="HEIGHT(cm)",ylab="WEIGHT(kg)")
とすればよい。下図が得られる。なお,村ごとに細かく指定したい場合は,
plot(x$WEIGHT[x$VG=='X'] ~ x$HEIGHT[x$VG=='X'], pch='X', col="blue", xlim=c(140,180), ylim=c(40,100))
などとしてから,points関数を使って重ね書きすればよい。なお,この例のようにプログラム内で付値したのであれば下記のようにする。
plot(hx, wx, pch='X', col="blue", xlim=c(140,180), ylim=c(40,100)) points(hy, wy, pch='Y', col="red"); points(hz, wz, pch='Z', col="green")
●もっとも,3種類くらいならいいが,120種類のマークを変えるのは難しい。マークとして使えるのは1文字だけなので,アルファベットや数字では不足してしまう。解決策は3つあって,
●連続した自然数をカテゴリとする度数分布を描きたいけれども,度数がゼロのカテゴリを飛ばしたくない場合がある。例えば,子ども数の分布を描きたいときは,たまたま子ども数7人の母親がいなかったとしても,8人の人がいたら,子ども数7人の母親の度数がゼロであることも,図には表したいだろう。とくに,複数の図を比較する場合は尚更である。ところが,普通に子ども数を代入(付値)した変数をxとすると,barplot(table(x))では,度数がゼロのカテゴリがtableの出力に出てこないので描画されないのである。この解決のために汎用の関数を作ってみたので紹介する。
●関数定義は以下の通り。
sbarplot <- function(freq,xnames,xlabel,title) { maxc <- max(as.single(dimnames(freq)[[1]])) z <- rep(0, NROW(xnames)) for (i in c(1:NROW(freq))) { z[as.single(dimnames(freq)[[1]][i])+1] <- freq[[i]]/sum(freq) } barplot(z, names.arg=xnames, main=title, xlab=xlabel)}
●使い方は,上の関数をRに読み込んだ後で,例えば,y <- c(3,4,2,1,3,4,2,2,3,2,1,2,6,6,7,4,2)というデータがあったときに,0や5も含めた度数分布図を書きたければ,x <- c(0:7)として横軸を定義しておいて,sbarplot(table(y),x,"label for x axis","title of the figure")とするだけで,下図が得られる(なお,解像度を指定してpngファイルを作るには,画面にグラフが描かれている状態で,例えば,dev.copy(png,"sample.png",width=400,height=480); dev.off()とすれば,画面に出ているグラフがsample.pngというファイルに保存される)。縦軸を割合でなくて実数にしたい場合は,sbarplot関数の中から/sum(freq)を削除すればよい。
●forなど使っていてR的ではないコードだし,おそらくもっと簡単な方法があると思うので,改善のご意見がいただければ幸いである。
●群馬大学の青木先生からいただいた2通りの関数(実行の仕方を含む)を掲載する。
x <- c(162, 159, 163, 157, 152, 168, 153, 156, 167, 161, 154, 162, 160, 157, 169, 160, 162, 158, 161, 160, 163, 160, 163, 153, 164, 163, 163, 153, 155, 155, 162, 163, 168, 160, 158, 168, 163, 163, 158, 153, 161, 153, 168, 156, 155, 159, 158, 161, 157, 155, 161, 156, 167, 156, 158, 152, 160, 160, 155, 157, 158, 160, 157, 156, 164, 157, 161, 158, 161, 153, 163, 161, 160, 162, 159, 162, 161, 158, 160, 177)
としてから試されたい。
◎この項,長らく放置していたが,裏RjpWikiさんの記事を見て目からウロコが落ちた。なるほど,tableをとる前にfactor化してlevelsを強制指定すれば,それだけで良かったのだな。つまり,上述のyについて0と5も含んだ度数分布図を描くためには,
barplot(table(factor(y, levels=0:7)))
とすれば良かった。
Package: pyramid Version: 1.1 Date: 2010/1/6 Title: Functions to draw population pyramid Author: Minato Nakazawa <minato-nakazawa@umin.net> Maintainer: Minato Nakazawa <minato-nakazawa@umin.net> Depends: R (>= 2.2.0) Description: Drawing population pyramid using (1) data.frame or (2) vectors. The former is named as pyramid() and the latter pyramids(), as lapper function of pyramid(). License: GPL (>= 2) URL: https://minato.sip21c.org/swtips/R.html#PYRAMID
\name{pyramid} \alias{pyramid} \title{Drawing population pyramid using data.frame} \description{ Drawing population pyramid using data.frame. Detailed explanation is given in Japanese at https://minato.sip21c.org/swtips/R.html#PYRAMID. } \usage{ pyramid(data, Laxis=NULL, Raxis=NULL, Cgap=0.3, Cstep=1, Llab="Males", Rlab="Females", Clab="Ages", GL=TRUE, Cadj=-0.03 Lcol="Cyan", Rcol="Pink", Ldens=-1, Rdens=-1, main="", ...) } \arguments{ \item{data}{A data.frame including left pyramid numbers in the 1st column and and right pyramid numbers in the 2nd column, where the numbers of males in each age-class are usually given to left numbers and those of females are to right numbers. If the data.frame includes 3rd column, it is used as age-class labels, otherwise the row.names(data) is used as age-class labels.} \item{Laxis}{A vector of axis for left pyramid. If missing, automatically given.} \item{Raxis}{A vector of axis for right pyramid. If missing, Laxis is used.} \item{Cgap}{The width of center gap (as ratio to each panel) to draw age-class. Default is 0.3} \item{Cstep}{The interval to write the labels of age classes. Default is 1} \item{Cadj}{The vertical adjustment factor for the labels of age classes. Default is -0.03} \item{Llab}{The label of the left pyramid. Default is "Males".} \item{Rlab}{The label of the right pyramid. Default is "Females".} \item{Clab}{The label of the center age-class. Default is "Ages".} \item{GL}{Logical value to draw the vertical dotted lines. Default is TRUE.} \item{Lcol}{The color of the left pyramid. Default is "Cyan".} \item{Ldens}{The density of hatching lines (/inch) for left pyramid. Default is -1, when the pyramid will be filled.} \item{Rcol}{The color of the right pyramid. Default is "Pink".} \item{Rdens}{The density of hatching lines (/inch) for right pyramid. Default is -1, when the pyramid will be filled.} \item{main}{The main title of the pyramid.} \item{...}{Other options.} } \author{Minato Nakazawa \email{minatonakazawa@gmail.com} \url{https://minato.sip21c.org/}} \examples{ ages <- c('0-9', '10-19', '20-29', '30-39', '40-49', '50-59', '60-') males <- c(34, 19, 11, 11, 8, 7, 5) females <- c(26, 25, 16, 11, 7, 5, 1) data <- data.frame(males, females, ages) pyramid(data) # another example py.Males <- c(80, 40, 30, 20, 10) names(py.Males) <- c('0-9', '10-19', '20-29', '30-39', '40-') py.Females <- c(60, 50, 40, 30, 5) names(py.Females) <- names(py.Males) py.df <- data.frame(py.Females,py.Males) pyramid(py.df, Llab="Females", Rlab="Males", Lcol="navy", Ldens=5, Rcol="red", Rdens=10, GL=FALSE, main="An example of population pyramid\n with auto-axis") # The census 2005 for Gunma prefecture data obtained from # https://www.e-stat.go.jp/stat-search/files?page=1&layout=datalist&toukei=00200521&bunya_l=02&tstat=000001007251&cycle=0&tclass1=000001007252&tclass2=000001007253&tclass3=000001007281&tclass4=000001007282&stat_infid=0000000370C7&result_page=1&tclass5val=0 # as "a00411.xls" GunmaPop2005 <- data.frame( Males=c(8872, 9144, 9528, 9812, 9817, 10049, 10234, 10047, 10222, 10187, 10319, 10420, 10135, 10473, 10219, 10492, 10943, 11243, 10579, 9653, 9941, 10252, 10396, 10649, 11343, 12031, 12420, 13015, 13354, 14132, 14624, 15873, 16013, 15809, 15338, 14876, 14568, 14536, 14580, 10713, 13844, 12911, 12303, 12158, 12086, 12117, 12620, 12331, 12376, 13138, 14144, 13553, 14353, 15194, 16064, 17286, 18561, 18347, 18230, 12001, 11938, 14363, 13684, 14122, 13475, 12241, 10279, 10866, 10939, 10853, 10093, 9996, 9575, 9334, 9147, 8643, 8249, 7760, 7353, 6812, 6170, 5041, 4099, 3206, 2711, 2778, 2113, 1895, 1630, 1431, 1146, 966, 675, 559, 384, 263, 212, 133, 84, 38, 24, 15, 11, 6, 1, 2, 1, 0, 0), Females=c(8323, 8750, 8964, 9359, 9559, 9605, 9511, 9800, 9790, 9848, 9939, 9755, 9696, 9884, 9734, 9767, 10293, 10616, 10040, 9383, 9731, 9748, 10211, 10204, 10500, 11086, 11758, 12248, 12548, 13524, 13907, 14930, 15129, 15057, 14344, 13982, 13942, 13587, 13972, 10359, 13212, 12435, 11934, 11673, 11668, 11583, 12100, 11867, 11917, 12746, 13364, 13170, 13968, 15318, 16251, 17125, 18253, 18042, 17927, 11981, 11773, 14450, 14124, 14438, 13502, 12960, 10729, 11710, 11697, 11884, 11413, 11442, 11087, 11035, 11209, 10646, 10482, 9784, 9777, 9491, 8891, 8188, 7636, 7034, 6123, 6103, 4577, 4415, 3861, 3426, 3035, 2571, 2064, 1683, 1209, 878, 739, 536, 333, 193, 134, 86, 56, 28, 13, 8, 5, 3, 1), Ages=0:108) pyramid(GunmaPop2005, Llab="Males", Rlab="Females", Clab="", Laxis=seq(0, 20000, len=5), Cstep=10, main="Population pyramid of Gunma Prefecture\n (Data: Census 2005, total by gender)") } \keyword{hplot}
Dear Sirs, I have uploaded the package named `pyramid' including two functions to draw population pyramid. It's very simple and small. But, as far as I know, there is no such package ever, so that I submitted. I hope that this package can pass the review process and go to main archive. Thank you very much. With Best Wishes, Minato Nakazawa, Ph.D. Associate Professor, Gunma University Graduate School of Medicine
古い情報だが、EpiInfoによる塗り分け地図は多少役に立つかも。
2022年2月現在、Rで国レベルの塗り分け地図を描くには、mapdataパッケージを使うのが一番簡単だと思う。より低レベルの地域区分データは、GADMのデータを簡単に使えるようにする、GDAMtoolsパッケージ(GitHubのページも参照)を使うと良いように思う。
Correspondence to: minatonakazawa[at]gmail.com.