使用 visNetwork 绘制可交互的关系网络图
·
3067字
·
7分钟
本文使用的 R 包版本分别是:visNetwork 2.1.4。
假设这里有四个节点分别名为 A、B、C、D,对应的唯一 id 分别是1、2、3、4。节点之间有两条线来连接,分别是A->B和B->C。如果把这个简单的例子看做流程图,我们可以使用 DiagrammeR 包,但这里我们将其看做关系图,使用 visNetwork 包来实现,后者的优势在于可以批量导入节点和线的数据。
visNetwork 包最重要的函数就是 visNetwork(),此函数必须填入的是两个数据框,即 nodes(节点数据)和 edges(线的数据)。在这个例子中,数据框的内容如下所示。
- nodes(节点数据)
- id:每个节点的唯一id,不能重复。
- label:每个节点的标签。
- edges(线的数据)
- from:线的起点的节点id。
- to:线的终点的节点id。
- label:线的标签。
- arrows:线的方向,取值有四种”to”、“from”、“middle”、“middle;to”。
| from |
to |
label |
arrows |
| 1 |
2 |
‘A->B’ |
‘to’ |
| 2 |
3 |
‘B->C’ |
‘to’ |
library(visNetwork)
nodes <-
data.frame(
id = c(1:4),
label = c('A', 'B', 'C', 'D')
)
edges <-
data.frame(
from = c(1, 2),
to = c(2, 3),
label = c('A->B', 'B->C'),
arrows = rep('to', 2)
)
visNetwork(
nodes,
edges,
# 图形容器的宽度
width = '80%',
# 图形容器的高度
height = 400,
# 图形容器的背景颜色
background = 'lightgray'
)
1.样式 🔗
一般,自定义的样式有三类,分别是图形容器、节点、线。
- 图形容器(函数
visNetwork())
- 主标题(
visNetwork(..., main = NULL))
- 副标题(
visNetwork(..., submain = NULL))
- 脚注(
visNetwork(..., footer = NULL))
- 图例(函数
visLegend())
对于图形容器的主标题、副标题、脚注和图例标题等四处文本,对应的写法都是如main = list(text = '文本内容', style = 'css样式'),其中 css 样式可以修改的有四种,即font-family(字体)、font-weight(字体粗细)、font-size(字体大小)、text-align(文字对齐,只有 left、right、center)。
另外,图例必须基于节点分组的情况下才能正常显示,所以下面的节点数据增加了一列 group 作为分组的结果。
# 增加节点分组信息
nodes$group <- c('grp1', rep('grp2', 3))
visNetwork(
nodes,
edges,
width = '80%',
height = 350,
background = 'lightgray' ,
main = list(text = '这是主标题',
style = 'font-family:Georgia, Times New Roman, Times, serif;font-weight:bold;font-size:20px;text-align:center;'),
submain = list(text = '这是副标题',
style = 'font-weight:bolder;font-size:20px;text-align:left;'),
footer = list(text = '这是脚注',
style = 'font-size:20px;text-align:right;')
) %>%
visLegend(
# 图例位置
position = 'right',
# 图标之间纵向空间
stepY = 50,
# 图标的列数,默认为1
ncol = 1,
main = list(text = '节点分组的\n图例标题',
style = 'font-size:20px;text-align:center;')
)
参照官方文档,节点的样式、线的样式可配置的参数非常多。整体上讲,自定义节点或线的样式的方法有以下几种。
- 将自定义样式的值写入 nodes、edges 这两张表中。
- nodes 表中增加 group (分组)的列,然后将自定义节点样式通过
visGroups()引入。
- 将自定义的样式通过
visNodes()、visEdges()这两个函数引入。
- 通过
visSetOptions()引入。
对比这几种方法,有这样几点注意事项:其一,visGroups()、visNodes()、visEdges()可以分别为节点和线设定全局样式,如果要为每个节点单独设置样式需要添加到 nodes、edges 表中;其二,四种方法的优先级是 nodes、edges >> visGroups() >> visNodes()、visEdges() >> visSetOptions()。
# 添加节点的提示信息
nodes$title <- c( "这是 A 的提示信息", "这是 B 的提示信息", "这是 C 的提示信息", "这是 D 的提示信息" )
# 添加线的提示信息
edges$color <- c('red', '#5a8d96')
edges$title <- rep('线的悬停提示信息', 2)
visNetwork(nodes, edges, background = 'lightgray') %>%
visNodes(title = '看能不能覆盖?', color = 'blue') %>%
visGroups(
# 指定节点所属分组的名称
groupname = 'grp1',
# 节点颜色
color = 'red',
# 节点大小,默认25
size = 30,
# 节点形状
shape = 'diamond',
# 节点透明度
opacity = 0.8
) %>% visEdges(
# 线的颜色
color = '#5a8d96',
# 线的长度
length = 200,
# 线的宽度
width = 2
)
2.导出 🔗
visNetwork 包将可视化图形导出的方式有以下几种。
- 函数
visExport()
展示的图形容器中增加一个“导出按钮”,在浏览器中打开后点击按钮可导出为静态文件,可选文件类型有 png(默认)、jpeg、pdf。
visNetwork(nodes, edges) %>% visExport(type = 'pdf',
name = '导出文件名称',
label = '导出按钮名称')
- 函数
visSave()
导出为指定目录下的 html 文件。
visNetwork(nodes, edges) %>% visSave(file = '/文件路径/文件名称.html', selfcontained = TRUE)
- htmlwidgets 包的函数
saveWidget()
由于 visNetwork 本质是通过 htmlwidgets 框架来封装 vis.js,也可使用 htmlwidgets 包来导出。
visNetwork(nodes, edges) %>% htmlwidgets::saveWidget('/文件路径/文件名称.html', selfcontained = TRUE)
3.聚合 🔗
当节点数量较多时,展示全部节点数据会难以迅速找到重点,因此需要聚合节点便于分析。visNetwork 支持不同的聚合方式:其一,用于展示机器学习算法的图形结果,比如使用 visTree()展示 rpart 包生成的分类树或回归树,以及使用visHclust()展示层次聚类的结果;其二,在关系网络的基础上按不同目的将节点聚合后展示,然后用鼠标单击查看具体的节点。
指定按照一种或多种颜色聚合。
nodes$color <- c(rep('red', 2), rep('blue', 2))
visNetwork(nodes, edges) %>%
visClusteringByColor(colors = c("red", "blue"))
指定按照一个或多个分组类别聚合。
# 去掉上段代码中的颜色,改用 visLegend 默认的
nodes$color <- NULL
visNetwork(nodes, edges) %>%
visClusteringByGroup(groups = c('grp2'))%>%
visLegend()
指定按照一个或多个节点 id 及其直接连接的相邻节点聚合。
visNetwork(nodes, edges) %>%
visClusteringByConnection(nodes = 3)
指定size = n,等同于size >= n,即大于等于 n 条线能互相连通的节点都聚合起来展示。
visNetwork(nodes, edges) %>%
visClusteringByHubsize(size = 2)
在动态图形放大缩小的过程中,自动展开或聚合。clusterFactor 参数取值在0到1之间,取值为0时,无论如何缩小都不会聚合。
visNetwork(nodes, edges) %>%
visClusteringOutliers(clusterFactor = 1)
4.布局 🔗
节点数量较多时,若是随机排列,可能会显得很乱,通过设置visLayout()函数中的一些参数可以改善布局结果。
- randomSeed:数值型,设定布局的随机种子,方便复现结果。
- improvedLayout:默认取值为 TRUE,当节点数量超过100时,自动聚合并进行初始布局。
- clusterThreshold:设置聚类阈值,默认150,当节点数量超过阈值时,自动聚合并进行初始布局。
- hierarchical:默认取值为 FALSE,从上到下排列。
# 从上到下
visNetwork(nodes, edges) %>%
visLayout(hierarchical = TRUE)
# 从左到右
# visNetwork(nodes, edges) %>%
# visHierarchicalLayout(direction = "LR")
5.动态交互 🔗
visNetwork 包中还有一些函数可以设置动态交互的参数,比如visPhysics()、visInteraction()、visOptions()等,不过一般默认值就算合用,所以这几个函数只是匆匆看过。
visInteraction()
- dragNodes: 默认取 TRUE,允许拖动未固定的节点。
- dragView: 默认取 TRUE,允许拖动整个视图。
- hover: 默认取 FALSE,取 TRUE 时鼠标悬停节点时,启用设置的颜色。
- selectConnectedEdges: 默认取 TRUE,允许悬停节点时高亮与节点相连的线。
- zoomView: 默认取 TRUE,允许缩放。
- zoomSpeed:默认取1,代表缩放的速度。
- navigationButtons:默认取 FALSE,取 TRUE 时添加导航按钮。
下面以设置悬停颜色为例,这里需要先去掉 nodes 中的 title、group 等信息,否则visNodes()优先级不够高,悬停颜色会不生效。
nodes$title <- NULL
nodes$group <- NULL
# 设置节点悬停颜色
visNetwork(nodes, edges) %>%
visNodes(color = list(hover = "green")) %>%
visInteraction(hover = TRUE, navigationButtons = TRUE)
visOptions()
- highlightNearest:取 TRUE 时,被选中的节点及相连节点高亮显示,其他节点变灰。
- nodesIdSelection:取 TRUE 时允许按照节点 id(标签)进行筛选。
visNetwork(nodes, edges) %>%
visOptions(highlightNearest = TRUE, nodesIdSelection = TRUE)