Rでメタアナリシス:DiagrammeRパッケージでPRISMAフローチャートを作る
1. 始めに
1.1. この記事の趣旨
こんにちは、nekometaと申します。「Rでメタアナリシス」では、GNU R(以下、R)で要約データを用いたランダム化比較試験のメタアナリシスを行い、代表的な図表を作成する方法を説明します。今回はRの DiagrammeR
パッケージを利用してPRISMAフローチャートを作ります。
1.2. 背景
メタアナリシスの論文では、PRISMAガイドラインにしたがい、解析に使用した臨床試験をどのように選択したのか、所定の形式を備えたフローチャート(PRISMAフローチャート)で示す必要があります。InkscapeなどのドローソフトやMicrosoft PowerPointで描画してもよいのですが、Rで出力できたら手作業を減らせて楽ですね。そこで、Rの DiagrammeR
パッケージを利用します。
DiagrammeR
はRからViz.jsやMermaid.jsといったJavaScriptのグラフ生成ライブラリを使用することで、テキストからグラフを生成できるパッケージです。今回はViz.jsを使用してフローチャートを生成します。
PRISMAフローチャートを生成することに特化したパッケージとして PRISMA2020
があります。このパッケージは適切に整形したデータフレームを渡すとPRISMAフローチャートを生成することができ、対話的UIでPRISMAフローチャートを生成することもできます。ただ、個人的にはデータフレームを用意するよりDOT言語で構造を記述するほうが性に合うことと、他の作図にも応用できそうなパッケージを使いたいことから、DiagrammeR
を紹介します。
1.3. 目標
The PRISMA 2020 statementのフローチャートと同レベルのものをRで出力します。
1.4. 環境
- OS:Windows 10 Pro(バージョン:21H2、OSビルド19044.1645)
- WSL2-Ubuntu 20.04.4 TLS
- Docker Desktop 4.7.1(WSL2バックエンド)
- Docker Engine version 20.10.14
- Docker Compose version v2.4.1
- rocker/rstudio:4.2.0
- installed R packages:
checkpoint
,pacman
,rmarkdown
- checkpoint date: 2022-04-21
この記事で使用した解析プロジェクトの構成は以下の通りです。Quartoを使用することを想定して説明しますが、R Scriptで書く場合もコードの中身は同じです。
【解析プロジェクトのテンプレート】
【主要な設定ファイルの説明】
2. 解析コード
2.1. セットアップチャンク
2.1.1. コードの例
analysis.qmdというファイルに解析コードを記載します。冒頭に記載する一連のコード(通称:セットアップチャンク)の例を示します。
```{r}
#| label: setup
#| code-fold: false
# set working directory
setwd("~/project/codes")
# attach the package 'checkpoint'
library(checkpoint)
# set checkpoint date
checkpoint("2022-04-21", checkpoint_location = "../", scan_now = FALSE)
# attach packages
library(pacman)
p_load(DiagrammeR, DiagrammeRsvg)
```
2.1.2. コードの説明
# set working directory
setwd("~/project/codes")
analysis.qmdを配置した ~/project/codes
ディレクトリをワーキングディレクトリに設定しています。
# attach the package 'checkpoint'
library(checkpoint)
# set checkpoint date
checkpoint("2022-04-21", checkpoint_location = "../", scan_now = FALSE)
checkpoint
パッケージをアタッチしてチェックポイント日を指定し、以後呼び出すパッケージのバージョンを固定します。
# attach packages
library(pacman)
p_load(DiagrammeR, DiagrammeRsvg)
pacman
パッケージをアタッチし、p_load()
で解析に使用するパッケージを読み込みます(パッケージがインストールされていない場合は、インストールされます)。
-
DiagrammeR
:RでViz.js(≒Graphviz)を使用します。 -
DiagrammeRsvg
:生成したフローチャートをsvg形式に変換します。
2.2. フローチャートの出力と保存
2.2.1. コードの例
R側のコードはたったこれだけです。
```{r}
#| label: flowchart
#| fig-cap: "Figure 1. Flowchart of study selection."
# create a PRISMA flowchart on Graphviz
fc <- grViz(diagram = "flowchart.gv", width = 795)
fc
# save the flowchart as a SVG file
export_svg(fc) |>
writeLines("figures/analysis_files/figure-html/flowchart.svg")
```
2.2.2. コードの説明
#| label: flowchart
#| fig-cap: "Figure 1. Flowchart of study selection."
Quartoのチャンクオプション fig-cap
に、図のタイトルを記述します。既定値ではタイトルの位置は図の下ですが、QuartoのYAMLヘッダーで fig-cap-location
の値を指定することで変更可能です。
# create a PRISMA flowchart on Graphviz
fc <- grViz(diagram = "flowchart.gv", width = 795)
fc
flowchart.gvというファイルにDOT言語でグラフ構造を記述しておき、DiagrammeR
パッケージの grViz()
関数で読み込みます。width
はQuartoで出力するHTMLレポートのメインカラムの幅に合わせて適当に設定しています(出力されるグラフ自体には影響しません)。
# save the flowchart as a SVG file
export_svg(fc) |>
writeLines("figures/analysis_files/figure-html/flowchart.svg")
DiagrammeRsvg
パッケージの export_svg()
関数で文字列として出力し、baseパッケージの writeLines()
関数でSVGファイルとして書きだします。なお、書きだした flowchart.svg
はInkscapeなどのドローソフトで編集できます。
出力結果
出力したフローチャートを示しました。シンプルに作りましたが、必要な要素はすべて含まれています。
2.3. DOT言語によるグラフ構造の記述
2.3.1. グラフ構造の記述例
flowchart.gvというファイルにグラフ構造を記述します。グラフ構造の記述例を示します(長くなるので、記述例のコードは折りたたみます)。
flowchart.gv
digraph PRISMA_flowchart {
# general Settings
graph [
newrank = true,
ranksep = "0.4",
nodesep = "0.4",
splines = ortho];
node [
shape = rectangle,
style = "filled, rounded",
fillcolor = gray95,
fontsize = 10,
width = 2.2];
edge [
penwidth = 2,
arrowsize = 0.7];
# node relationships between clusters
{rank = same; c1_1; c2_1; c3_1; c4_1};
{rank = same; c2_2; c3_2};
{rank = same; c2_3; c3_3; c4_3; c5_3};
{rank = same; c2_4; c3_4; c4_4; c5_4};
{rank = same; c2_5};
# edges between clusters
c1_1 -> res;
c2_5 -> res;
c2_1 -> c3_1;
c2_2 -> c3_2;
c2_3 -> c3_3;
c2_4 -> c3_4;
c4_3 -> c5_3;
c4_4 -> c2_5;
c4_4 -> c5_4;
res [
width = 3,
style = "filled, rounded",
fillcolor = white,
fontname="times-bold",
label = "Total studies included in review (n = )\l\lReports of total included studies (n = )\l" ];
subgraph cluster_A {
label = "Previous studies";
fontsize = 12;
c1_1 [
height = 1.2,
label = "Studies included in previous \lversion of review (n = )\l\lReports of studies included in\lprevious version of review (n = )\l"]
}
subgraph cluster_B {
label = "Identification of new studies via databases and registers";
fontsize = 12;
subgraph column_3 {
label= "";
c3_1 [
height = 1.2,
label = "Records removed before screening:\l - Records marked as ineligible\l by automation tools (n = )\l\l - Records removed for\l other reasons(n = )\l"];
c3_2 [label = "Records excluded\l(n = )\l"];
c3_3 [label = "Reports not retrieved\l(n = )\l"];
c3_4 [label = "Reports excluded:\l - Reason 1 (n = )\l - Reason 2 (n = )\l"];
}
subgraph column_2 {
label = "";
c2_1 [label = "Records identified from:\l - Databases (n = )\l - Registers (n = )\l"]
c2_2 [label = "Records screened\l(n = )\l"];
c2_3 [label = "Reports sought for retrieval\l(n = )\l"];
c2_4 [label = "Reports assessed for eligibility\l(n = )\l"];
c2_5 [label = "New studies included in review\l(n = )\l\lReports of new included studies\l(n = )\l"];
# edges
c2_1 -> c2_2 -> c2_3 -> c2_4 -> c2_5
}
}
subgraph cluster_C {
label = "Identification of new studies via other methods";
fontsize = 12;
subgraph column_5 {
label = "";
c5_3 [label = "Reports not retrieved\l(n = )\l"];
c5_4 [label = "Reports excluded:\l - Reason 1 (n = )\l - Reason 2 (n = )\l"]
}
subgraph column_4 {
label = "";
c4_1 [
height = 1.2,
label = "Records identified from:\l - Websites (n = )\l - Organisations (n = )\l - Citation searching (n = )\l"];
c4_3 [label = "Reports sought for retrieval\l(n = )\l"];
c4_4 [label = "Reports assessed for eligibility\l(n = )\l"];
# edges
c4_1 -> c4_3 -> c4_4
}
}
}
}
2.3.2. 記述の説明
DOT言語自体はかなりシンプルに書けるので、先人の記事(日本語)を一読のうえで、必要に応じて公式ドキュメントを検索すれば良いものと思います。
Graphvizは、データドリブンなグラフ生成が本分なので、縦横を揃えたフローチャートを生成するためには、ある程度レイアウトをコントロールする必要があります。ここでは、レイアウト上悩みがちなポイント、もとい、私が悩んだポイントを説明します。
縦方向のレイアウトを制限する
- ノードの幅を統一する(例:
node [width = 2.2]
) - 列単位でノードをまとめる(例:
subgraph cluster{}
またはsubgraph{}
) - 各列の最初のノードの高さを揃える(例:
c1_1 [height = 1.2]
) -
subgraph
をネストする場合は記載順に気を付ける
横方向のレイアウトを制限する
- 行単位でノードをまとめる(例:
{rank = same; c1_1; c2_1; c3_1; c4_1}
) - 異なる
subgraph
のノード間でrank
を設定するときはgraph [newrank = true]
とする
エッジをコントロールする
- エッジを直線にする:(例:
graph [splines = ortho]
)
ノードのlabel(文字)の体裁を調整する
-
\n
で中央寄せ改行、\l
で左寄せ改行、\r
で右寄せ改行できる - HTML様のタグを使用することができる
まとめ
今回は DiagrammeR
パッケージを使用して、The PRISMA 2020 statementのフローチャートと同レベルのものをRで出力しました。これで面倒な描画作業とおさらばです。
Discussion