Help us understand the problem. What is going on with this article?

RMarkdownでの出力結果をアウトプットの種類に応じて変更させる

More than 3 years have passed since last update.

この記事はドキュメンテーションツールAdvent Calendar (http://www.adventar.org/calendars/1196) の12日目です。

@kazutan さんがちまちまとやっているRMarkdown Advent Calendarこんな記事がありました。この記事ではワード形式での出力の話がされているのですが、これを読んで、そういえばこんな記事があったねというのを、既にみなさんご存知かもしれませんが検証がてら紹介します(元記事は1年以上も前に書かれています)。

元記事: rmarkdown: Alter Action Depending on Document | TRinker's R Blog

みなさん、{ggvis}を利用したインタラクティブな可視化もいいですが、PDFとしてファイルは保存しておきたいし印刷する図は{ggplot2}で描画したかったりしますよね。しますよね

💡 要約

ちょっと書きなぐりのようになっているのではじめにこの記事の内容をまとめます。

  • RMarkdownでの出力形式は、必要に応じて切り替えることが可能(いちいち書き換えなくてもよい)
  • チャンク内で実行するRコードはknitr::opts_knit()switch()で自由自在に切り替えられる

この記事もRMarkdownで書いているので、ダウンロードしてお試しできるよう、gistにあげてあります

🔜 複数の形式でのアウトプット

RMarkdownでは、YAMLに記載された形式でアウトプットの種類を決めているわけですが、この時に記述するoutputの項目は何も特定の何か(markdown, html, word, latex)に限っていなくても良い、という話です。RStudioのKnit HTMLボタンを押した時はYAML outputの第一項目に従ってoutputされますが、実際にRMarkdownファイルを各種の異なるファイルに変換するrender()を利用して、YAMLヘッダー部に記載されているアウトプットの種類すべてを出力することが可能です。YAMLヘッダーで宣言したアウトプットの種類すべてでの出力を一度に行う場合は、render()出力形式を決めるoutput_formatにallを指定すれば良いだけです。

output: 
  html_document:
    toc: false
  md_document:
    variant: markdown
  pdf_document:
    toc: false
  word_document:
    toc: false 

上の例では、HTML、markdown、PDF(LaTeX)、ワードのファイルを出力することを宣言しています。先に述べましたが、この状態でRStudioのKnitボタンを押すとHTMLの出力を行います。ではYAMLで宣言したすべてのファイルの種類を出力しましょう。次のコードを実行するするだけです。

rmarkdown::render("input-output.Rmd", "all")

YAMLで宣言したアウトプット形式すべてのファイルを出力するにはLaTeXのプリアンブル設定は、header-includesで行うか、別途styファイルを用意してください(日本語のPDFを出力するのに必要かも)。

👻 アウトプットの種類に応じて出力を変更させる

さて本題です。複数の形式でのアウトプットができるのは素晴らしいですが、RMarkdown (Pandoc) で出力するフォーマットすべてで図などの出力を行う際の互換性を取るのが難しかったりします。

例えば DT::datatable()はHTMLの出力で実行されますが、markdownやPDFなどでは出力できません。

DT::datatable(trees)

を実行すると

Error: Functions that produce HTML output found in document targeting markdown_github output. Please change the output type of this document to HTML.

と怒られます。同様に{ggvis}はHTMLでおk。PDFでNGだったります。

そこで、アウトプットの形式に応じて実行する結果や処理する内容を変更させれたら良いよね、という話になります。やり方は以外と簡単で、あらかじめアウトプットの形式を取得しておいて、結果を変えたい処理を行う際にswitch()で条件分岐を行う、というだけです。このようにします。

上の例では、出力されたファイルごとに異なる結果を出力します。

関数の処理内容を分岐させることも可能です。

switch(out_type,
       markdown_github = trees %>% head(),
       html = DT::datatable(trees),
       docx = trees %>% head() %>% formattable::formattable(),
       latex = trees %>% xtable::xtable())

アウトプットの種類に応じて、データフレームの内容を表示する関数を変えた例です。次は図の変更を行いましょう。

library(ggvis)
pressure %>% ggvis(~temperature, ~pressure, fill = ~temperature) %>% layer_points()

Error: Functions that produce HTML output found in document targeting markdown_github output. Please change the output type of this document to HTML.

実行した{ggvis}の図を埋め込むにも、HTML以外だと怒られます。そこで、HTML以外の出力では {ggplot2}を利用することにします。

library(ggvis)
library(ggplot2)
p_ggplot2 <- mtcars %>% ggplot(aes(mpg, wt, colour = factor(cyl))) + geom_point()
p_ggvis   <- mtcars %>% ggvis(~mpg, ~wt, fill = ~factor(cyl)) %>% layer_points()

switch(out_type,
       markdown_github = p_ggplot2,
       html            = p_ggvis,
       docx            = p_ggplot2,
       latex           = p_ggplot2)

🌱 devオプションの活用

ちょうどSVG形式での図の出力を紹介した記事があったので、需要のなさそうな話ですが、HTMLでSVGを、PDFではSVGの埋め込みが面倒なのでPDFを埋め込みたいという場合の対応例を紹介します。この場合もswitch()を使います。

svglite 1.0.0を使ってみる - Technically, technophobic.

YAMLはこのように宣言します。

output: 
  html_document:
    dev: svg
  pdf_document:
    dev: cairo_pdf

実行するRコードは下記のように。

library(svglite)
switch(out_type,
       html = knitr::opts_chunk$set(dev     = "svglite",
                                    fig.ext = "svg"))
plot(pressure)

コウモリのように生きていきましょう。
Enjoy! :thumbsup:

hoxom
Machine Learning and Data Analysis Company for Your Smiles :)
http://hoxo-m.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした