R言語による電子カルテデータの二次利用

~R言語初心者がデータ処理を楽しめるように基本的内容中心のサイトです~

DiagrammeR 〜RでGraphvizを使う~

パワポフローチャートや、ネットワーク図を作ると、ノードやエッジの位置が微妙にずれて、面倒だなと感じる人はいませんか。そんな時は、Graphvizを使用しましょう。
Graphvizを使うと、DOT言語で書かれたグラフを画像に出力できます。R言語では、DiagrammeRのgrViz関数で、DOT言語のテキストを画像に出力します。

目次:

DiagrammeR::grViz()

DiagrammeRではgrViz関数をつかって、DOT言語で記述されたグラフ構造を出力します。
簡単なサンプルです。grViz関数の引数部分(ダブルクォーテーションの中)がDOT言語です。

library(DiagrammeR)
grViz("
      digraph test {
        A -> B
      }
      ")

出力はこうなります。
f:id:r_beginner:20180310183017j:plain

Graphviz本家サイトにも沢山のサンプルがありますが、実際思ったとおりのグラフを出力しようと思うと細かい設定で詰まることが多く、結局ググってサンプルコードを探してくることが多いです。ここでは、自分がよく使う設定等を補足しながら、Graphvizの使い方をまとめておきます。

Graphvizサイト: Graphviz - Graph Visualization Software


DOT言語

DOT は、プレーンテキストを用いてデータ構造としてのグラフを表現するための、データ記述言語の一種である。

DOT言語 - Wikipedia

DOTの構造

digraph 名前 {}

digraphの名前は、予約語を指定するとエラーがでます。Rstudioでは.gv/.dot拡張子のファイルは、シンタックスハイライトが使えるので、予約語かどうかが分かりやすくて良いと思います。

graph, node , edgeについてそれぞれ指定していきます。

  • graph [ 属性=値, ...]
  • node [ 属性=値, ...]
  • edge [ 属性=値, ...]

と記載していきます。

digraph test {
  graph[rankdir = LR, label ="fig. 1"]
  node [shape = box] A; B;
  edge[color = red, arrowsize = 1.5, arrowhead = normal] A -> B
}

RstudioでDOT言語

f:id:r_beginner:20180310202320j:plain
上記のようにgrViz関数の引数としてDOT言語のテキストを記述するサンプルがよく書かれていますが、これだとdigraph以下がハイライトされません。長いコードではタイポしやすくなるので、.gvまたは.dot拡張子で外部ファイルとしておいた方がシンタックスハイライトを利用できるので良いかと思います。Rstudioでは、.gv(.dot)ファイルは、sourceペイン右上にプレビューボタンがでて、ボタンを押すとgrViz関数を呼び出して自動でRstudioのviewerペインに出力してくれます。test.dotファイルなら、DiagrammeR::grViz("test.dot")が実行されます。

f:id:r_beginner:20180310184155p:plain


Graphviz Attributes

http://204.178.9.49/content/attrs

Graph属性

サンプル

digraph graph_attribute {
  graph[rankdir = LR, 
        label ="fig. 1",
        labelloc = t # t, b
        fontsize = 10, 
        fontcolor = red,
        bgcolor = darkgreen,
        nodesep = 0.1, 
        ranksep = 0.1]
}

rankdir : グラフ全体の方向をTB(top -> bottom),LR(left -> right)等変更。

label : ラベル名。

labelloc : ラベルの位置指定。t(top), b(bottom)で指定。

bgcolor : バックグラウンドカラー。

nodesep : ノードの間隔。

ranksep : ランクの間隔。

f:id:r_beginner:20180310200309p:plain

Node属性

color属性
digraph node_color {
  node[style = "filled", color = IndianRed] IndianRed;
}

f:id:r_beginner:20180310222947j:plain

  • カラーサンプル

f:id:r_beginner:20180310201041j:plain

shape属性
digraph node_shape {
  node[shape = box] box;
}
  • shapeサンプル

f:id:r_beginner:20180310201209p:plain

style属性
digraph node_style {
  node[shape = box]
  node[style = solid]
  A
  node[style = dashed]
  B
  node[style = dotted]
  D
  node[style = bold]
  E
  node[style = filled]
  F
  node[style = striped, fillcolor = "Yellow1:Yellow2:Yellow3:Yellow4"]
  G
  node[shape = circle , style = "dashed, wedged", fillcolor = "Tomato1:Tomato2:Tomato3:Tomato4"]
  H
}
  • スタイルサンプル

f:id:r_beginner:20180310201411p:plain

rank属性
digraph node_rank {
  groupA -> groupB -> groupC
  A; B; C; D; E; F; G; H; I
  {rank = same; groupA; A; B; C;}
  {rank = same; groupB; D; E; F;}
  {rank = same; groupC; G; H; I}
}

f:id:r_beginner:20180310203055p:plain

label属性

labelの値にはHTMLっぽい記述をすることが出来ます。

digraph test_graph {
  node[shape = rect, color = black, label = <<I>italic</I>>] A 
  node[label = <10<sup>2</sup>>] B
}

ただし、<>で全体を囲む必要があるみたいです。すべてのタグが使えるわけでも無いみたい…難しい。

特殊な文字は、node[label = "&文字列;"]みたいな感じで出力できるものもあります。

digraph test_graph {
  node[shape = box]
  node[label = "&#931; &#928; &#945; &#946; &#947; &#948; &#949;"] A
  node[label = "&#952; &#954; &#955; &#956; &#966; &#969;"] B
  node[label = "&#9824; &#9825; &#9826; &#9827; &#9834; &#12306; "] C
}

f:id:r_beginner:20180310214949j:plain

ギリシャ文字
【みんなの知識 ちょっと便利帳】使いたいときの HTML特殊文字 & 機種依存文字 - ギリシャ文字

image属性

image属性でファイルパスを指定すると画像を出力できるはずだが、僕の環境のDiagrammeR::grviz()では下記の.dotファイルはうまく出力できませんでした。

digraph ramen {
  rankdir = LR
  node[penwidth = 0, 
       fontname = helvetica,
       labelloc = t, 
       fontsize = 30, 
       fontcolor = darkgreen]
  node[image = "img/sio.jpg"] sio;
  node[image = "img/syouyu.jpg"] syouyu;
  sio -> syouyu
}

いつもはUbuntu16.04にRstudio severをインストールして使用しているので、

$ sudo apt install graphviz

Graphvizをインストールして。
.dotファイルを、Terminalからコマンドで出力して対応

$ dot -Tpng ramen.dot  -o ramen.png

f:id:r_beginner:20180310210333p:plain

最近のRstudioはTerminalペインもあり、気軽にコマンド入力もできるので、DOTファイルからそのまま出力して今回はごまかしました。(DiagrammeRからできるひと教えてください…)

Edge属性

arrowhead属性
digraph edge_arrowhead {
  edge[arrowhead = diamond] A -> B;
}

arrowheadサンプル
f:id:r_beginner:20180310203552p:plain

  • arrowhead名の前に"o"をつけると中抜けになります。
  • "r","l"をつけると、左右半分のarrowheadになります。
  • arrowhead名をつづけて書くと、arrowheadを繋げて出力できます。
dir, arrowsize, color, penwidth属性
digraph edge_arrowhead {
  edge[dir= both, arrowsize = 0.5, color = red, penwidth = .5] A -> B;
}

dir, size, color, penwidthサンプル
f:id:r_beginner:20180310203721p:plain

port属性
digraph edge_arrowhead {
  edge[tailport = n] A -> B;
}

portサンプル
f:id:r_beginner:20180310203924p:plain

Subgraph

digraph subgraph_label {
  rankdir = TB
  subgraph cluster0{
    A -> B 
    label = "group0"
    {rank = same; A; B;}
  }
  subgraph Cluster1{
    C -> D -> E
    label = "group1"
    {rank = same; D; E;}
  }
  B -> C
}

subugraphでいくつかのnodeをグループ化できます。subgraph名は、小文字のcから始まるcluster**の場合に枠線がつきますが、その他の名前では枠が消えます。
f:id:r_beginner:20180310225609j:plain

subgraphからnode、nodeからsubgraph、subgraphからsubgraphへもedgeを繋ぐことができます。

digraph G {
  compound=true;
  subgraph cluster0 {
  b -> d;
  c -> d;
  }
  subgraph cluster1 {
  e -> g;
  e -> f;
  }
  b -> f [lhead=cluster1];
  d -> e;
  c -> g [ltail=cluster0, lhead=cluster1];
  c -> e [ltail=cluster0];
}

f:id:r_beginner:20180310230807j:plain
ちなみに、subgraphを重ねることはできないみたいです。


DOT言語で、どんなグラフも作成できるわけではないですが、何度か作り直しながら使用していくようなフローチャートや、ネットワーク図は、パワポで作るより修正が楽だと思います。

Enjoy!

環境

> sessionInfo()

## R version 3.4.3 (2017-11-30)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 16.04.4 LTS
## 
## Matrix products: default
## BLAS: /usr/lib/libblas/libblas.so.3.6.0
## LAPACK: /usr/lib/lapack/liblapack.so.3.6.0
## 
## locale:
##  [1] LC_CTYPE=ja_JP.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=ja_JP.UTF-8        LC_COLLATE=ja_JP.UTF-8    
##  [5] LC_MONETARY=ja_JP.UTF-8    LC_MESSAGES=ja_JP.UTF-8   
##  [7] LC_PAPER=ja_JP.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=ja_JP.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] DiagrammeR_0.9.2
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_0.12.15       pillar_1.1.0       compiler_3.4.3    
##  [4] RColorBrewer_1.1-2 influenceR_0.1.0   plyr_1.8.4        
##  [7] bindr_0.1          viridis_0.5.0      tools_3.4.3       
## [10] digest_0.6.15      jsonlite_1.5       viridisLite_0.3.0 
## [13] gtable_0.2.0       evaluate_0.10.1    tibble_1.4.2      
## [16] rgexf_0.15.3       pkgconfig_2.0.1    rlang_0.1.6       
## [19] igraph_1.1.2       rstudioapi_0.7     yaml_2.1.16       
## [22] bindrcpp_0.2       gridExtra_2.3      downloader_0.4    
## [25] dplyr_0.7.4        stringr_1.2.0      knitr_1.19        
## [28] htmlwidgets_1.0    hms_0.4.1          grid_3.4.3        
## [31] rprojroot_1.3-2    glue_1.2.0         R6_2.2.2          
## [34] Rook_1.1-1         XML_3.98-1.9       rmarkdown_1.9     
## [37] ggplot2_2.2.1      purrr_0.2.4        readr_1.1.1       
## [40] tidyr_0.8.0        magrittr_1.5       backports_1.1.2   
## [43] scales_0.5.0       htmltools_0.3.6    assertthat_0.2.0  
## [46] colorspace_1.3-2   brew_1.0-6         stringi_1.1.6     
## [49] visNetwork_2.0.3   lazyeval_0.2.1     munsell_0.4.3