0. はじめに
この記事は**『R Advent Calendar 2020』**第2日目の記事です。
Advent Calendar自体、今回が初参戦です。お手柔らかにお願いします。
1. 趣旨
RはTeX形式と親和性が良いのか、stargazer
やtexreg
等、TeX形式で図表を出力することが可能であり、数値の転記ミスを防止できるし、Excelで作るより見た目が整っているのが印象的です。
しかし、私は普段はTeXではなくWordを使うので、SVGやPNG等に変換して使用する必要があります。
その際の手順が少々煩雑であり1、
- Rで出力したコードをtex形式のファイルに貼り付けて、
- pLaTex、XeLaTeX、Cloud LaTeX等をかませてPDF出力し、
- InkscapeでPDFをベクター化してから各種画像に変換する
という3ステップを噛ませているのですが、特に1~2が面倒くさい!
どうにか1~2を一発で済ませたい!
というわけで、今回はTeX形式の図表をRからダイレクトにPDFとして出力する方法を書いておきます。
1.2 搭載を目指す機能
1.2.1. data.frame → TeX形式
とりあえず個人的に「相関分析」のテーブルを作らなくてはならないのですが、元データがdata.frame
で出力されるので、まずdata.frame
をTeX形式に書き換える機能を搭載しようと思います。
これはパッケージを利用すれば簡単にできるはずです。
1.2.2. character型vectorにも対応させる
data.frame
のみの対応だとstargazer
やtexreg
を利用できないのが勿体ないので、TeXコード(character
型ベクトル)の入力にも対応させます。
1.2.3. 四捨五入
上記の元データをそのまま利用すると桁数が多すぎるので、四捨五入する機能を載せておきます。(入力がdata.frame
の場合のみ)
1.2.4. プレビュー機能
PDF出力後、RStudioのビューアーにPDFをプレビューさせようと思います。
この辺もパッケージを利用すれば手軽に実装できます。
2. 必要な道具
網羅的に書いたつもりですが、元々入れているもの等見落としがあるかもしれません。
2.1. ソフトウェア
- R
- RStudio
- TeXLive
- XeLaTeX (TeXLiveを入れれば自動で入っているはず)
- ImageMagick
2.2 パッケージ
{dplyr}
{kable}
{kableExtra}
{knitr}
{magick}
{pdftools}
{tinytex}
3. 下準備
3.1. パッケージの導入
# 未導入の物があれば入れておいてください。
install.packages(c("dplyr","kableExtra","knitr","magick","pdftools","tinytex"))
##3.2. {tinytex}の導入
{tinytex}
はパッケージをダウンロードしただけでは意味がありません。
以下のコードを実行して、初めて導入が完了します。
tinytex::install_tinytex()
4. コード
# data.frameの四捨五入
shisha <- function(df, digits = 3, convert = T) {
df.new <- df
for(x in 1: nrow(df)){
for(y in 1: ncol(df)){
p <- try(as.numeric(df[x,y]))
if(!is.na(p)){
if(convert == T){
df.new[x,y] <- as.character(signif(p, digits = digits))
}else{
df.new[x,y] <- signif(p, digits = digits)
}
}
}
}
return(df.new)
}
# TeX形式の文書を作成する
texmaker <- function(x = NA){
if(is.na(x)) {
x <- as.character("")
}
header <- paste0("\\documentclass{article}\n",
"\\usepackage{fontspec}",
"\\usepackage{zxjatype}",
"\\setjamainfont{MS Mincho} ",
"\\usepackage[dvipdfmx]{graphicx}\n",
"\\usepackage{caption}\n",
"\\usepackage[pass,letterpaper]{geometry}\n",
"\\usepackage {scalefnt}\n",
"\\usepackage {graphicx}\n",
"\\usepackage {booktabs}\n")
body <- paste0("\\begin{document}\n",
"\\thispagestyle{empty}\n")
content <- paste0(x)
footer <- paste0("\\end{document}")
code <- paste0(header, body, content, footer)
return(code)
}
# 作成した文書を外部ファイルに出力する
maketex <- function(texdoc, filename){
sink(file(filename, encoding = "UTF-8"))
cat(texdoc)
sink()
}
# 完成品 (上記のWrapper関数)
makepdf <- function(df, filename = "result", preview = T) {
if (is.data.frame(df)){
p <- texmaker(kableExtra::kbl(shisha(df), booktabs = T, format = "latex"))
} else {
if (is.character(df)){
message('Process "df" as tex document.')
p <- texmaker(df)
} else {
stop('Argument "df" must be data.frame of character.')
}
}
maketex(p, filename = paste0(filename, ".tex"))
tinytex::xelatex(paste0(filename, ".tex"))
knitr::plot_crop(paste0(filename, ".pdf"))
if (preview == T) {
magick::image_read_pdf(paste0(filename, ".pdf"))
}
}
5. 動作
5.1. サンプルデータ
今回は二種類用意しました。
Data1が相関分析表(架空のデータ)、Data2がiris
の回帰結果をstargazer
で出力したモノです。
data1 <- data.frame(c("1","","","",""), c("0.7892401","1","","",""), c("0.7124973", "0.9673863","1","",""), c("0.4897329","0.8834619","0.9287465","1",""), c ("0.4680764","0.6982260","0.7143392","0.8676399","1"))
colnames(data1) <- c("20代", "30代", "40代", "50代", "60代")
rownames(data1) <- colnames(data1)
data2 <- stargazer(lm (Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width , data=iris))
> data1
20代 30代 40代 50代 60代
20代 1 0.7892401 0.7124973 0.4897329 0.4680764
30代 1 0.9673863 0.8834619 0.6982260
40代 1 0.9287465 0.7143392
50代 1 0.8676399
60代 1
> head(data2)
[1] ""
[2] "% Table created by stargazer v.5.2.2 by Marek Hlavac, Harvard University. E-mail: hlavac at fas.harvard.edu"
[3] "% Date and time: 日, 11 22, 2020 - 15:55:30"
[4] "\\begin{table}[!htbp] \\centering "
[5] " \\caption{} "
[6] " \\label{} "
# 以下略
5.2. 実際に動かしてみる
5.2.1. データフレームの場合(data1)
まずはデータフレームから。作成したmakepdf()
関数に代入します。なお、filename
は出力するファイル名(拡張子除く)のことです。
makepdf(df = data1, filename = "data1")
いい感じです。
5.2.2. character型データの場合(data2)
続いて、stargazer
の結果をPDF出力します。
こちらは、行毎にベクトルの要素に分解されているので、全部繋げる必要があります。
library(dplyr)
data2 %>%
paste0(collapse = "\n") %>%
makepdf(filename = "data2")
6. 補足
6.1. なぜ「XeLaTeX」なのか。
理由は簡単です。日本語に対応しているTeXエンジンで一番楽だったからです。
最初はずっと「pLaTeX」でやろうと考えていたのですが、丸二日試行錯誤した末無理だったので、XeLaTeXに切り替えました。XeLaTeXに関してはRパッケージもある程度充実していたこともあり、あっさりできました。
6.2. OSX・Linuxであれば…
どうやらR上でPDFとSVGの相互変換が可能のようです。そこまで可能であればさらにワンステップ自動化できるので、超理想ですね。いいなぁ。Windowsなもんで。
https://sjp.co.nz/projects/grconvert/
7. おわりに
ということで、何とか実装できました。
「TeX⇒PDF出力」まで自動化できれば、そこそこ便利じゃないでしょうか。
是非お試しください。
おしまい。
8. 参考
https://qiita.com/nozma/items/1c6b000b674225fd40d7
https://cran.r-project.org/web/packages/magick/index.html
https://texwiki.texjp.org/?TeX%E3%81%A8%E3%83%95%E3%82%A9%E3%83%B3%E3%83%88
https://yyhhyy.hatenablog.com/entry/2015/10/17/203000
-
拙著『TeX形式の図表をWordで使いたい!!!!』をご参照ください。 ↩