LoginSignup
4
3

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-12-01

0. はじめに

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

1. 趣旨

RはTeX形式と親和性が良いのか、stargazertexreg等、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.2 搭載を目指す機能

1.2.1. data.frame → TeX形式

とりあえず個人的に「相関分析」のテーブルを作らなくてはならないのですが、元データがdata.frameで出力されるので、まずdata.frameをTeX形式に書き換える機能を搭載しようと思います。
これはパッケージを利用すれば簡単にできるはずです。

1.2.2. character型vectorにも対応させる

data.frameのみの対応だとstargazertexregを利用できないのが勿体ないので、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
> 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
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は出力するファイル名(拡張子除く)のことです。

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

data1.png

いい感じです。

5.2.2. character型データの場合(data2)

続いて、stargazerの結果をPDF出力します。
こちらは、行毎にベクトルの要素に分解されているので、全部繋げる必要があります。

library(dplyr)
data2 %>% 
  paste0(collapse = "\n") %>%
  makepdf(filename = "data2")

data2.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


  1. 拙著『TeX形式の図表をWordで使いたい!!!!』をご参照ください。 

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3