【R】TeX形式の図表をR⇒PDFに直接出力する

# 0. はじめに

この記事は**『R Advent Calendar 2020』**第2日目の記事です。
Advent Calendar自体、今回が初参戦です。お手柔らかにお願いします。

# 1. 趣旨

RはTeX形式と親和性が良いのか、`stargazer`や`texreg`等、TeX形式で図表を出力することが可能であり、数値の転記ミスを防止できるし、Excelで作るより見た目が整っているのが印象的です。
しかし、私は普段はTeXではなくWordを使うので、SVGやPNG等に変換して使用する必要があります。

その際の手順が少々煩雑であり[^1]、

1. Rで出力したコードをtex形式のファイルに貼り付けて、
2. pLaTex、XeLaTeX、Cloud LaTeX等をかませてPDF出力し、
3. InkscapeでPDFをベクター化してから各種画像に変換する

という3ステップを噛ませているのですが、**特に1～2が面倒くさい！**
**どうにか1～2を一発で済ませたい！**

というわけで、今回はTeX形式の図表をRからダイレクトにPDFとして出力する方法を書いておきます。

[^1]: 拙著『[TeX形式の図表をWordで使いたい!!!!](https://qiita.com/zakkiiii/items/d543489676b27712687a)』をご参照ください。

## 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](https://www.tug.org/texlive/acquire-netinstall.html)**
- **XeLaTeX** (TeXLiveを入れれば自動で入っているはず)
- **[ImageMagick](https://imagemagick.org/index.php)**

## 2.2 パッケージ

- `{dplyr}`
- `{kable}`
- `{kableExtra}`
- `{knitr}`
- `{magick}`
- `{pdftools}`
- `{tinytex}`


# 3. 下準備

## 3.1. パッケージの導入

```R
# 未導入の物があれば入れておいてください。
install.packages(c("dplyr","kableExtra","knitr","magick","pdftools","tinytex"))
```

##3.2. {tinytex}の導入

`{tinytex}`はパッケージをダウンロードしただけでは意味がありません。
以下のコードを実行して、初めて導入が完了します。

```R
tinytex::install_tinytex()
```

# 4. コード

```R
# 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`で出力したモノです。

```R:サンプルデータの用意
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))
```
```R:data1
> 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
```
```R:data2
> 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`は出力するファイル名（拡張子除く）のことです。

```R
makepdf(df = data1, filename = "data1")
```

![data1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551476/f94196a5-a151-da7c-a421-eda2fb4c677d.png)

いい感じです。

### 5.2.2. character型データの場合（data2）
続いて、`stargazer`の結果をPDF出力します。
こちらは、行毎にベクトルの要素に分解されているので、全部繋げる必要があります。

```R
library(dplyr)
data2 %>% 
  paste0(collapse = "\n") %>%
  makepdf(filename = "data2")
```
![data2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551476/c37ad8a0-7725-f4fa-5d00-b7e00f149926.png)


# 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