Heavy Watal

knitr — Markdownにコード実行結果を編み込む

特殊Markdownファイル (.Rmd, .qmd) に含まれるRコードを実行し、 結果を編み込んで汎用Markdownファイル (.md) に変換する。

一般的には QuartoR Markdown といったパイプラインの中で利用されることが多く、 直接触れる必要性はあまりない。 私はMarkdown→HTML処理をPandocではなくHugoに任せたいので .Rmd |> knitr |> Hugo という流れで使う。

## Heading

Paragraph.

```{r, example-code-chunk}
#| fig.height: 5
#| fig.width: 6
answer = 6 * 7
ggplot(mpg) + aes(displ, height) + geom_point()
```

Answer to the ultimate question is `r answer`.

Options

https://yihui.org/knitr/options/

Format

chunk header {r, tag=value, tag=value} 形式
knitrではこれが基本という扱い。
値はRコードとして評価される。文字列にはquoteが必要。
改行は許されない。
{r 直後の , はあってもなくてもいい。 Yihuiは付けているが、RStudioの新規作成RmdやPosit社のcheatsheetでは付いてない。
先頭のオプションはtag無しquote無しで label 扱いされる。 明示的に label の値を設定してもよい。
chunk内 #| tag=value, tag=value 形式
Rコードも書けるし改行も許される。
改行はカンマの代わりにはならない。
chunk内 #| tag: value 形式
Quartoではこちらを推奨
一行一項目で改行する前提。
区切り文字としてピリオドよりハイフンが好まれる。 ^(fig|out)-\1. に置換された上でheader形式のオプションとmergeされる。
値はYAMLの型である必要がある。
  • 論理値は小文字: true, false
  • 文字列はquote無しでもいいが付けておいたほうがたぶん安全。 “double” では \n が改行扱いされるなどエスケープシーケンスが有効。 ‘single’ ではそういうのが起こらず文字通り。
  • Rコードを渡すにはひと手間: #| message: !expr 'NA'
一括 knitr::opts_chunk$set(tag = value) 形式
文書内、それより後ろのchunkのデフォルトを変更する。

Chunk label

区切りにはなぜかハイフンが推奨。ピリオドやアンダースコアではなく。

figureやcacheの出力先に使われるのでuniqueになるように注意する。 文書内での重複はknitrがチェックして怒ってくれるが、 ディレクトリ内の文書間での重複までは見てくれない。

省略すると unnamed-chunk-%d のような形で自動的に割り振られる。 入力ファイルによって変わるように unnamed.chunk.label オプションを変更しておいたほうが安全。

General

External

Cache

Figure

Package Options knitr::opts_knit

https://yihui.org/knitr/options/#package-options

knitrロード前に options(knitr.package.verbose = TRUE) とするか、 knit() 実行前に knitr::opts_knit$set(verbose = TRUE) とするか。 chunk内からの実行では遅い。 knitr::opts_chunk とは別であることに注意。

Global R Options

https://yihui.org/knitr/options/#global-r-options

なぜ knitr::opts_knit とまた違うくくりがあるのかは謎。歴史的経緯?

Functions

knitr::knit(input, output = NULL, ...)
input: 呼び出し元とは違うディレクトリにあるファイルを指定しても、 chunk内の getwd() はこのファイルが基準となる。
output: 可能な限り NULL のままにしておく。 input とは違うディレクトリに書き出したい場合、 出力先に予め setwd() しておくことが強く推奨されている。 (個人的には作業ディレクトリをinput側に統一するほうが簡単そうに思えるけど。)
  • Dangerous: knit("report.Rmd", "outdir/report.md")
  • Redundant: setwd("outdir"); knit("../report.Rmd", "report.md")
  • Good: setwd("outdir"); knit("../report.Rmd")
knitr::fig_chunk(label, ext, number, ...)
chunk名から図のパスを取得。 離れたところで図を使い回せる。
knitr::current_input()
処理中の入力ファイル名を取得。
knitr::knit_exit()
文書の途中で終了。

Hooks

Chunk hooks

knitr::knit_hooks$set(foo = \(before, options, envir) {
  if (before) {
    # evaluated before chunk code
    options$cache.rebuild = TRUE  # too late!
  } else {
    # evaluated after chunk code
  }
})

Output hooks

knitr::knit_hooks$set(source = \(x, options) {
  message("hook source ", getwd())
  paste0("src: ", x)
})

Option hooks

knitr::opts_hooks$set(fig.square = \(options) {
  stopifnot(is.numeric(fig.square))
  options$fig.width  = options$fig.square
  options$fig.height = options$fig.square
  options
})

Quarto

https://quarto.org/docs/output-formats/hugo.html