niszetの日記

アナログCMOS系雑用エンジニアが頑張る備忘録系日記

(R) 階層化RMarkdownとパラメータの話(階層化Rmdの2回目の話)

ggridgesでプロットするよ

(1つの記事に色々盛り込むのでトピックが安定しませんね…。)

さて、RMarkdownには色々な機能がありますが、パラメータ渡すことも出来ます。

rmarkdown.rstudio.com

これによって、テンプレート化したRmdに対して、色々とパラメータを変えてレポートを作成することが可能です。

使用例はこちらの@tomotagworkさんの記事が詳しいです。

R Markdownによるレポート生成

ちょっと実際にやってみましょうか。 下記のコードをiris_child.Rmdとして保存します。例によって/はハイライト対策です。使うときは削除してくださいね。

---
title: "plot iris in RMarkdown with params"
author: "niszet"
date:  "`r Sys.Date()`"
output: html_document
params:
  x: "Sepal.Length"
---

/```{r setup, include=FALSE}
library(tidyverse)
library(ggridges)
/```

## plot of `r params$x`
/```{r}
iris %>% ggplot()+geom_density_ridges(
  aes_string(x=params$x,y="Species", fill= "Species", 
             point_color="Species", point_fill="Species"),
  position="raincloud", jittered_points=TRUE, alpha=0.3, scale=0.4)+
  theme_bw()
/```

これで、

f:id:niszet:20180528114257p:plain

のように表示されます。いい感じですね。これは、YAMLヘッダ部分にparams:x: "Sepal.Length"と書いてあるので、実行時にparams$x"Sepal.Length"に置き換わって実行されます。aes_string()は引数を文字列で受け取るタイプのaes()です。これもid:yutannihilationさんに教えていただきました。

ちなみに、tidyevalは来月リリースのggplot 2.3.0から使用できるようです。備えよう。

なお、tidyevalに対応しているかどうかを知る方法はないようです。helpとか読むしかない。(deprecatedもそうですよね)

こういう方法もあるとのこと。

話がそれました。この、パラメータ部分は実行時に書き換えができます。Knitのボタンの▽を押すと[Knit with Parameters]が出てくるので、

f:id:niszet:20180528115344p:plain

押すとデフォルトのパラメータが入った状態で下記のような入力画面が出ます。これを下記のように書き換えて

f:id:niszet:20180528115357p:plain

knitを押すと

f:id:niszet:20180528115612p:plain

このように。ちゃんと横軸が変わっていますね(しかも、タイトルも変わっているのです。詳しくはコードを眺めてみてください)

階層化の話

さて、これを親から呼んでみます。環境を別に渡しても良いし、そのまま呼んでも良いですが。今回は環境を与えます。

---
title: "plot iris in hierarchical RMarkdown with params"
author: "niszet"
date:  "`r Sys.Date()`"
output: html_document
---

/```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
options(knitr.duplicate.label = 'allow')
/```

/```{r}
envir <- new.env(parent = parent.frame())
params <- NULL
params$x <- "Petal.Length"
envir$params <- params
knitr::asis_output(knitr::knit_child("iris_child.Rmd", envir=envir, quiet=TRUE))
/```

これをknitすると、

f:id:niszet:20180528120138p:plain

こんな感じになります。なお、envir$paramsとして与えていますが、コレは必須です。具体的に書かれているところを確認していませんが、子Rmdとして呼ばれる場合はyamlヘッダ内の宣言は無視されるのだと思います(そうしないとスタイルが統一されないし、まぁそうなのかなーと)

前回、

niszet.hatenablog.com

で階層化して変数のやり取りをする際には環境を与えた方が良いという話をしましたが、子Rmd側では「どの変数が親から与えられる変数かわからない」「子Rmdを単体でKnit出来ない」という問題がありました。今回のように、paramsとして与えることで、単体の場合はYAMLヘッダ内(あるいは実行時オプション)で値を与え、階層化する場合は親からparamsというパラメータのリストを受け取ることでこのあたりのIFを統一し、どの変数が他所から与えられる(と期待している)かが明確になります。

階層化するメリットについては次回書きます。まぁ、上記のようにテンプレート化した子Rmdをパラメータを変えることによってその書式を統一したまま使いまわせるってだけで目新しい内容ではないんですが…

Enjoy!!