Rで解析:ネットワーク図をわかりやすくプロット「netplot」パッケージ
「netplot」パッケージは、ggplot2と同じgridグラフィックスシステムの上に構築されたネットワーク描画エンジンです。最大の特徴は、既定値のまま実行するだけで見栄えのするネットワーク図が得られる点にあります。具体的には、描画領域に合わせて頂点やエッジのサイズを自動でスケーリングし、直線ではなく湾曲したエッジを描き、始点(ego)から終点(alter)へ向けてエッジの色をなめらかに混ぜ合わせる、といった処理が可能です。igraphやnetworkのオブジェクト、隣接行列をそのまま渡せるため、既存の解析フローにも組み込みやすくなっています。さらに、属性に応じた色分け、凡例の追加、グラデーション色の線分、円グラフの重ね描き、クリックした頂点の情報取得など、図表現を補助する関数も一通り揃っています。
パッケージバージョンは0.4-0。Windows 11 x64 (build 26200)のR version 4.6.1で確認しています。
<おすすめのRに関する書籍です>
パッケージのインストール
下記コマンドを実行してください。
# パッケージのインストール
install.packages("netplot")
install.packages("igraph")
install.packages("gridExtra")
install.packages("magrittr")
# パッケージの読み込み
library("netplot")
# ネットワークオブジェクトの生成・操作に使用
library("igraph")
# 複数のプロットを並べて表示するために使用
library("gridExtra")
# パイプ演算子を使用するために読み込み
library("magrittr")コマンド例
詳細はコメント、パッケージのヘルプを確認してください。
まずnplot()でネットワークを描画します。頂点や辺の色は、make_vertex_colors()などのmake_colors()系関数で属性から一括生成でき、エッジの色はego()とalter()を用いた片側式で始点・終点の色を混ぜ合わせられます。nplot_legend()で凡例を追加でき、segments_gradient()でグラデーション色の線分を、piechart()で柔軟な円グラフを重ね描きできます。最後に、作成したプロット上でlocate_vertex()を使うと、クリックした頂点の情報を取得できます。
頂点の色や形状を属性に応じて設定しネットワーク図をプロット:nplotコマンド
| オプション | 意味 | 初期値 |
|---|---|---|
| x | グラフオブジェクト。igraph、network、行列オブジェクトに対応 | |
| layout | 頂点のx/y座標を表す2列の数値行列 | |
| vertex.size | 頂点の絶対サイズ(0〜1)。片側式で数値属性からマッピング可能 | 1 |
| bg.col | 背景色 | “transparent” |
| vertex.nsides | 頂点を描く多角形の辺の数(3で三角形、100で円に近づく) | 10 |
| vertex.color | 頂点の色。片側式で属性から色分け可能 | grDevices::hcl.colors(1) |
| vertex.size.range | 頂点サイズの最小・最大とスケールの曲率 | c(0.01, 0.03, 4) |
| vertex.frame.color | 頂点の枠線の色 | NULL |
| vertex.rot | 頂点多角形の回転角度(ラジアン) | 0 |
| vertex.frame.prop | 枠が頂点に占める割合(0〜1) | 0.2 |
| vertex.label | 頂点ラベルの文字ベクトル | NULL |
| vertex.label.fontsize | ラベルのフォントサイズ(数値ベクトル) | NULL |
| vertex.label.color | ラベルの色(長さvcount(x)のベクトル) | adjustcolor(“black”, alpha.f = 0.8) |
| vertex.label.fontfamily | ラベルのフォントファミリ(長さvcount(x)の文字ベクトル) | “sans” |
| vertex.label.fontface | フォントの字体(grid::gpar参照) | “plain” |
| vertex.label.show | vertex.sizeの上位から表示するラベルの割合 | 0.3 |
| vertex.label.range | ラベルフォントサイズの相対スケール(ポイント、2〜3要素) | c(5, 15) |
| edge.width | 辺の相対的な幅の数値ベクトル。値は正規化されedge.width.rangeの範囲に変換される。~ weightのような片側式でも指定可能 | 1 |
| edge.width.range | 辺幅をマッピングする最小・最大値(ポイント)。NULLならスケーリングしない | c(1, 2) |
| edge.arrow.size | 矢印のサイズ(0〜1) | NULL |
| edge.color | 辺の色のベクトル。HEXや組み込み色を使用可能。NULLのときはegoとalterの頂点色を混ぜて決定する | ~ego(alpha = 0.1, col = “gray”) + alter |
| edge.curvature | 辺の曲率(ラジアン)の数値ベクトル | pi/3 |
| edge.line.lty | 線種のベクトル | “solid” |
| edge.line.breaks | 辺(弧)を近似する頂点数 | 5 |
| sample.edges | サンプリングする辺の割合(0〜1) | 1 |
| skip.vertex | 論理値。TRUEのとき頂点を描画しない | FALSE |
| skip.edges | 論理値。TRUEのとき辺を描画しない | FALSE |
| skip.arrows | 論理値。TRUEのとき矢印を描画しない | skip.edges |
| add | 論理スカラー | FALSE |
| zero.margins | 論理スカラー | TRUE |
| edgelist | エッジリスト | |
| y | 無視される | NULL |
| newpage | 論理値。TRUEのときgrid::grid.newpage()を呼び出す | TRUE |
| legend | 論理値。TRUEのとき凡例を追加する | TRUE |
### データ例の作成#####
# 乱数シードを固定して再現性を確保
set.seed(314)
# 4グループのネットワークを生成
# 各島は15頂点、島内は密(確率0.4)、島どうしは3本の橋で接続
g <- igraph::sample_islands(4, 15, 0.4, 3)
# 各頂点にグループ属性を付与
V(g)$community <- rep(c("A", "B", "C", "D"), each = 15)
# 各頂点の次数を属性として保存
V(g)$deg <- degree(g)
########
### オプションを設定しないでプロット#####
# igraph標準のプロット
#plot(g)
# netplotコマンドでプロット
nplot(g)
########
### 色はグループ、形状はグループ、サイズは次数を片側式でマッピングしてプロット#####
nplot(g, vertex.color = ~ community,
vertex.nsides = ~ community,
vertex.size = ~ deg)
#####・オプションを設定しないでプロット

・色はグループ、形状はグループ、サイズは次数を片側式でマッピングしてプロット

<おすすめのRに関する書籍です>
各頂点と辺に使用するカラーベクトルを作成:make_vertex_colorsコマンド
| オプション | 意味 | 初期値 |
|---|---|---|
| dat | 色を生成するためのデータベクトル | |
| categorical | 論理値。TRUEにすると色をカテゴリとして扱う | FALSE |
| color_map | パレットを生成する関数 | grDevices::hcl.colors |
| x | networkまたはigraphクラスのグラフ | |
| vattr | 文字列。色の生成に用いる頂点変数名 | |
| eattr | 文字列。色の生成に用いる辺変数名 |
### データ例の作成#####
# 乱数シードを固定
set.seed(1618)
# 50頂点のランダムグラフ(Erdős–Rényiモデル)を生成
g <- igraph::sample_gnp(50, 0.08)
# 各頂点に3つの役割のいずれかを割り当てる
V(g)$role <- sample(c("生産", "物流", "販売"), 50, replace = TRUE)
########
# 役割("生産", "物流", "販売")ごとに色分けしたカラーベクトルを作成
col <- make_vertex_colors(g, "role", categorical = TRUE)
# 作成した色ベクトルを頂点の塗り・枠・エッジに適用して描画
nplot(g) %>%
set_vertex_gpar("core", fill = col, col = col) %>%
set_vertex_gpar("frame", fill = col, col = col, alpha = .7) %>%
set_edge_gpar(col = "gray50", fill = "gray50", alpha = .5)
エッジの色を始点(ego)と終点(alter)の色の混合で指定する:netplot-formulaeコマンド
| オプション | 意味 | 初期値 |
|---|---|---|
| x | netplotオブジェクト | |
| col | 有効な色を指定。単一の色やベクトルでも可 | |
| alpha | アルファレベル(透過度) | |
| env | 内部使用のみ | |
| type | 内部使用のみ | |
| mix | egoとalterの色を混合する割合 | 1 |
| postfix | 内部使用のみ | NULL |
# 6頂点の有向スターグラフ(中心から外向き)を作成
g <- make_star(6, mode = "out")
# 乱数シードを固定して再現性を確保
set.seed(555)
# 頂点ごとに異なる色を付けてネットワークを描画
np <- nplot(g, vertex.color = grDevices::hcl.colors(6), vertex.size.range = c(.1, .1))
# エッジの線幅を太くして色の混ざり方を見やすくする
np <- set_edge_gpar(np, lwd = 4)
# 各パネルの上部に見出しを付けるためのヘルパー関数
# arrangeGrob()のtop引数に文字列を渡すと、そのグロブの上に見出しが描かれる
titled <- function(x, title) {
arrangeGrob(x, top = grid::textGrob(title, gp = grid::gpar(fontsize = 15, col = "red")))
}
# ego(始点)とalter(終点)の色の混ぜ方を変えた6パターンを並べて描画
grid.arrange(
# 既定のエッジ色(始点側は薄いグレー、終点は頂点色)
titled(np, "既定"),
# 始点と終点、それぞれの頂点色を混ぜ合わせる
titled(np %>% set_edge_gpar(col =~ ego + alter), "ego + alter"),
# 始点側を透明にし、終点の色へフェードインさせる
titled(np %>% set_edge_gpar(col =~ ego(alpha = 0) + alter), "ego(alpha=0) + alter"),
# 終点側を透明にし、始点の色からフェードアウトさせる
titled(np %>% set_edge_gpar(col =~ ego + alter(alpha = 0)), "ego + alter(alpha=0)"),
# 混合の重みを終点側に全振りし、ほぼ終点色で描く
titled(np %>% set_edge_gpar(col =~ ego(mix = 0) + alter(mix = 1)), "ego(mix=0) + alter(mix=1)"),
# 混合の重みを始点側に全振りし、ほぼ始点色で描く
titled(np %>% set_edge_gpar(col =~ ego(mix = 1) + alter(mix = 0)), "ego(mix=1) + alter(mix=0)")
)
ネットワーク図に凡例を追加:nplot_legendコマンド
| オプション | 意味 | 初期値 |
|---|---|---|
| g | netplotオブジェクト | |
| labels | ラベルの文字ベクトル | |
| pch | プロット記号(graphics::points()参照) | |
| gp | grid::gparオブジェクト | grid::gpar() |
| packgrob.args | grid::packGrob()に渡す引数のリスト | list(side = “left”) |
| x | netplot_legendオブジェクト | |
| y | 未使用 | NULL |
| newpage | 論理値。TRUEのときgrid::grid.newpage()を呼び出す | TRUE |
### データ例を作成#####
# 乱数シードを固定
set.seed(808)
# 100頂点のランダムグラフを生成
g <- sample_gnp(100, 0.04)
# 各頂点に2種類の形状を割り当て(4は四角形、10は円に近い多角形)
V(g)$shape <- sample(c(4, 10), 100, replace = TRUE)
########
# 形状と色を属性に応じて設定してネットワークを描画
np <- nplot(
g,
vertex.nsides = V(g)$shape,
vertex.color = ifelse(V(g)$shape == 4, "darkorange", "steelblue")
)
# プロットに凡例を追加(既定では左側に配置される)
# labelsは項目名、pchは各項目の記号(22=四角形、21=円、NA=線)
# gpのfill・lwd・colで、記号の塗り色・線の太さ・線の色を項目ごとに指定する
nplot_legend(
np,
labels = c("四角形の頂点", "円形の頂点", "エッジ"),
pch = c(22, 21, NA),
gp = gpar(
fill = c("darkorange", "steelblue", NA),
lwd = c(NA, NA, 1),
col = c(NA, NA, "gray40")
)
)
<おすすめのRに関する書籍です>
辺をカラーグレードで描画し、グラデーション効果を付与:segments_gradientコマンド
| オプション | 意味 | 初期値 |
|---|---|---|
| x | grDevices::xy.coordsに渡される座標 | |
| y | grDevices::xy.coordsに渡される座標 | NULL |
| col | 色のグラデーション関数(grDevices::colorRamp参照) | colorRamp2(c(“transparent”, “black”), TRUE) |
| lend | graphics::segmentsに渡される | 1 |
# 乱数シードを固定
set.seed(999)
# 2次元のランダムウォークの座標を生成
x <- cbind(cumsum(rnorm(400, sd = .25)), cumsum(rnorm(400, sd = .25)))
# 線分の本数(座標点の数より1つ少ない)
n <- nrow(x) - 1
# 始点から終点へ向かって太くなる線幅ベクトルを用意
lwd <- seq(0.5, 6, length.out = n)
# 描画領域だけを準備(線はまだ描かない)
plot(x, type = "n")
# 黄→赤のグラデーションで、色が濃く(赤く)なるほど線を太く描画
# colにcolorRamp2()で作った色関数、lwdは...経由でsegments()へ渡る
segments_gradient(x, col = colorRamp2(c("gold", "firebrick")), lwd = lwd)
円環上に分割された領域を色分けして表示:piechartコマンド
| オプション | 意味 | 初期値 |
|---|---|---|
| x | 各スライスの面積を表す数値ベクトル | |
| labels | 文字ベクトル(graphics::text()に渡される) | names(x) |
| radius | 各スライスの半径(スカラーも可) | 1 |
| doughnut | 内側の円(ドーナツ)の半径 | 0 |
| origin | 原点の座標(長さ2の数値ベクトル) | c(0, 0) |
| edges | スライスの曲線の滑らかさ | 200 |
| slice.off | スライスを原点から離す距離 | 0 |
| init.angle | 描画を開始する角度(度) | 0 |
| last.angle | 描画を終了する角度(度) | 360 |
| tick.len | 目盛りの長さ(半径に対する割合) | 0.1 |
| text.args | graphics::text()に渡す追加引数のリスト | list() |
| segments.args | 目盛り描画時にgraphics::segments()へ渡す引数のリスト | list() |
| skip.plot.slices | 論理スカラー。FALSEのときスライスを描画しない | FALSE |
| add | 論理スカラー。TRUEのとき現在のデバイスに追加する | FALSE |
| rescale | 論理スカラー。TRUEのとき縦横比を保つようy座標をスケーリングする | TRUE |
# 各カテゴリの値
vals <- c(8, 5, 12, 3, 6)
# 一番外側のリング(値をラベルとして表示)
piechart(vals, col = grDevices::hcl.colors(5, "Teal"),
border = NA, doughnut = .5, radius = .8, labels = vals)
# 内側のリング(同じ値を重ねて二重ドーナツにする)
piechart(vals, col = grDevices::hcl.colors(5, "Peach"),
border = NA, doughnut = .25, radius = .5, add = TRUE)
# 各スライスを外側にずらして強調した円グラフ
piechart(c(30, 20, 35, 15),
col = grDevices::hcl.colors(4, "Sunset"),
slice.off = c(.05, 0, .1, 0),
labels = c("東", "西", "南", "北"))
プロット内でクリックされた頂点の情報を取得:locate_vertexコマンド
| オプション | 意味 | 初期値 |
|---|---|---|
| x | netplotオブジェクト | NULL |
# 乱数シードを固定
set.seed(246)
# 60頂点のランダムグラフを生成
g <- sample_gnp(60, 0.07)
# ネットワークを描画
nplot(g)
# クリックした頂点の名前・座標・ビューポートを取得
res <- locate_vertex()
# 取得した情報を表示
print(res)
この記事が誰かの役に立ちますように。