R Shinyでネットワークグラフを可視化する方法

R Shinyアプリ上でigraphで作成したネットワーク（グラフ）を可視化する方法を自分へのメモもかねて説明します。
誤りや改善点がありましたぜひ教えてください！

【背景】
ネットワーク（つまりノードとエッジでできた下記のようなグラフ）を可視化して、インタラクティブに操作できる簡易なアプリをR Shinyで作りたい。
というのも、すでに行ったRのMarkdownベースで行ったK-popのコラボネットワークの分析レポート（https://dacss.github.io/Social_Networks_Spring_2023/posts/Final_Project_Kpop_network_Erika_Nagai.html#network-overview）をより、見やすくしたかった。
Markdown上でのネットワークのプロットは動的ではないため、ズームができず、大きなネットワークになるとごちゃごちゃしていて視覚的にあまり便利ではないのです。

R Shinyの情報もなかなかネット上に多くないが、R Shiny x ネットワークとなると日本語の情報はほぼ皆無、英語でも情報が古かったり、GitHubのコードが解読できなかったりと、初歩的なことをやるのにも情報の少なさに苦しめられたので、今回自分へのメモもかねて文章にしておこうと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3488941/42f70432-70b5-7dd9-3d3b-31436073130e.png)

ちなみになかなか面白い分析だと思うのでお時間のある方はぜひ分析内容も読んでいただければ... 


【使う言語とパッケージ】
R, RStudio, 
shiny, igraph, vizNetwork, (その他dplyrなど普段のRの作業でも使うようなパッケージたち）

【プロセス】
まずigraphのみでShinyにネットワークグラフの可視化は難しい（ネットを見ていると方法はあるようだがパラメータ設定がややこしそう）ため、`vizNetwork`パッケージを使用します。
`vizNetwork`の使い方は英語だがこちらにも説明があります。https://cran.r-project.org/web/packages/visNetwork/vignettes/Introduction-to-visNetwork.html

Shinyはapp.Rの単独ファイルで作る方法と、ui.R、server.Rの2つのファイルで作る方法がありますが、今回は後者です。


1. 必要パッケージをインストール
```
library(shiny)
library(igraph)
library(vizNetwork)
```


2. **超シンプルなネットワークの可視化**

ui.RはvisNetworkライブラリの`visNetworkOutput`という関数を使う

``` ui.R

shinyUI(fluidPage(
  titlePanel("Network Graph Visualization"),
    mainPanel(
      visNetworkOutput("networkGraph")
    )
  )
))
```

server.Rでは、`visNetwork`でアウトプットが出せる。
パラメータとして必要なのは、
* **重複のないユニークな**nodes(ノード≒点）が一覧となったデータフレーム
* edges（エッジ≒線、リンク）が一覧となったデータフレーム
    * from, to というカラムが必須。from, toにはnodeが入る
    * From, Toなど大文字は不可

``` server.R
shinyServer(function(input, output) {
    output$Network <- renderVisNetwork({
    edges <- read_csv(XXXXX.csv) # edgelistの形のファイル
    
    nodes <- unique(c(edges$from, edges$to))　#重複ないユニークなノードの一覧
    nodes_df <- data.frame(id = nodes)
    
    visNetwork(nodes = nodes_df,
               edges = edges) 
  })
```
とりあえず上記を行うだけで、特に色もついていない一番シンプルな形のネットワークが表示される。


3. **ノードのカテゴリやタイプによって色を変える**

ui.Rはそのまま
server.R
`visNetwork()`内のnodesパラメータに指定されるデータフレームにcolorカラムを加える

```server.R

shinyServer(function(input, output) {
    output$Network <- renderVisNetwork({
    edges <- read_csv(XXXXX.csv) # edgelistの形のファイル
    
    nodes <- unique(c(edges$from, edges$to))　#重複ないユニークなノードの一覧
    nodes_df <- data.frame(id = nodes)
    nodes_df$color <- color_region_category
    
    visNetwork(nodes = nodes_df,
               edges = edges) 
  })



```
上記で各ノードに色がつきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3488941/a868fad2-91fd-6413-b6c8-d63f77fbe162.png)


4. **カーソルをあてると、そのノードの名前が表示されるようにする** 

server.Rの`vizNetwork`のnodesパラメータにいれるデータフレームにtitleカラムを追加し、そこに表示したい内容を入れる。ノードの名前を表示するのでもよいし、ノードの何かの特徴（数字やカテゴリ名などでも◎）

```server.R

shinyServer(function(input, output) {
    output$Network <- renderVisNetwork({
    edges <- read_csv(XXXXX.csv) # edgelistの形のファイル
    
    nodes <- unique(c(edges$from, edges$to))　#重複ないユニークなノードの一覧
    nodes_df <- data.frame(id = nodes)
    nodes_df$color <- XXX
    nodes_df$title <- XXX　#ここに入るのがカーソルを重ねたときに表示される内容
    
    visNetwork(nodes = nodes_df,
               edges = edges) 
  })


```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3488941/4ce3cfcd-376c-a3b6-5f00-c7e25402ea6b.png)
こんな感じでカーソルをノードの上に重ねると名前が表示される。

5. **ノードのラベル（表記される名前）を変える**
`vizNetwork`を用いたグラフは実はズームしていくと各ノードのラベルを表記している
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3488941/da40e231-24e8-ac6f-5a49-36ac54029fa2.png)

デフォルトで何も設定していないと、`vizNetwork`のedgesに指定されるデータフレームのfromとtoのカラムに入っている値がラベルとして表示される。でもこの値がidだったり、本当に表記したい値になっているとは限らない。もしfromやtoのカラムの値以外を設定したい場合は下記の通り

```server.R

shinyServer(function(input, output) {
    output$Network <- renderVisNetwork({
    edges <- read_csv(XXXXX.csv) # edgelistの形のファイル
    
    nodes <- unique(c(edges$from, edges$to))　
    nodes_df <- data.frame(id = nodes)
    nodes_df$color <- XXX
    nodes_df$title <- XXX　
    nodes_df$label <- XXX #ここに入るのがグラフをズームしたときにノードの下に表示されるラベル
    visNetwork(nodes = nodes_df,
               edges = edges) 
  })


```


**その他**
ところでこのグラフでの凡例をうまく表記させる方法がわかりません…
今回はその場しのぎだけど下記のように対応しました。

ui.Rで新たな行を追加して、ノードの色と対応するカテゴリを追記しました。
最終的な見た目はこんな感じ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3488941/aca4334c-9ba9-7341-dbda-c3a86e2456cb.png)




```ui.R

shinyUI(fluidPage(
  titlePanel("Network Graph Visualization"),
    mainPanel(
        tabPanel("3. Network by Regime",
                                   fluidRow(
        
                                     column(12, visNetworkOutput("NetworkByRegime")),
                                     column(12,
                                            tags$div(style="margin-top: 10px;font-size: 14px;",
                                                     HTML(paste0("<div>
                                                                   <span style='display:inline-block; width: 20px; height: 20px; margin-right: 5px; background-color: #FFFFE1; border: 1px solid grey;'></span> K-pop &nbsp; 
                                                                 <span style='display:inline-block; width: 20px; height: 20px; margin-right: 5px; background-color: darkgreen; border: 1px solid grey;'></span> Latino &nbsp; 
                                                                 <span style='display:inline-block; width: 20px; height: 20px; margin-right: 5px; background-color: #FDCCCC; border: 1px solid grey;'></span> South East Asia &nbsp; 
                                                                 <span style='display:inline-block; width: 20px; height: 20px; margin-right: 5px; background-color: #920002; border: 1px solid grey;'></span> East Asia &nbsp; 
                                                                 <span style='display:inline-block; width: 20px; height: 20px; margin-right: 5px; background-color: #ABD7E6; border: 1px solid grey;'></span> Europe &nbsp; 
                                                                 <span style='display:inline-block; width: 20px; height: 20px; margin-right: 5px; background-color: #009acd; border: 1px solid grey;'></span> US or Other &nbsp; 
                                                                 <span style='display:inline-block; width: 20px; height: 20px; margin-right: 5px; background-color: darkgrey; border: 1px solid grey;'></span> Unknown &nbsp;
                                                                 </div>"))))
                                            )
                                     )
                                   
                                   
                          )
                          
                        ))
```


後日、GitHubのリンクも共有します。
現時点ではひとまず記憶が新しいうちに記しておくまで...