R语言网络关系数据可视化
知识点总览
- 节点链接图 (Node-Link Diagram):最经典的网络图,节点代表实体,边代表关系
- 弧线图 (Arc Diagram):节点排列在直线上,用弧线表示连接
- 蜂巢图 (Hive Plot):节点分布在径向轴上,边按规则连接
- 和弦图 (Chord Diagram):圆形布局,用弦的宽度表示流量大小
- 边绑定图 (Edge Bundling Diagram):将相似的边聚合成束,减少视觉杂乱
1. 节点链接图 (Node-Link Diagram)
语法知识点
节点链接图是最经典的网络可视化方式。常用包:
networkD3: 基于D3.js的交互式网络图igraph: 强大的网络分析包,支持多种布局算法ggraph: ggplot2扩展,基于图形布局
核心概念:
- 节点 (Node): 网络中的实体,可设置大小、颜色
- 边 (Edge): 节点间的连接关系,可设置粗细、颜色
- 布局算法: 力导向布局、圆形布局、层次布局等
案例代码
1.1 使用igraph包创建静态网络图
r
# 安装并加载igraph包
if(!require(igraph)) install.packages("igraph")
library(igraph)
# 创建示例数据:社交网络关系
# 方法1:通过边列表创建图
edges <- data.frame(
from = c("张三", "张三", "李四", "李四", "王五", "赵六", "赵六", "钱七"),
to = c("李四", "王五", "王五", "赵六", "赵六", "钱七", "张三", "李四"),
weight = c(5, 3, 4, 2, 6, 3, 1, 4) # 边的强度
)
# 创建图对象
g <- graph_from_data_frame(edges, directed = FALSE) # 无向图
# 查看图的基本信息
print(g) # 显示图的节点数和边数
summary(g)
# 添加节点属性
V(g)$name <- c("张三", "李四", "王五", "赵六", "钱七") # 节点名称
V(g)$department <- c("销售部", "市场部", "技术部", "技术部", "销售部") # 部门
V(g)$importance <- c(10, 8, 9, 7, 6) # 重要性评分
# 设置节点颜色(根据部门)
V(g)$color <- ifelse(V(g)$department == "销售部", "lightblue",
ifelse(V(g)$department == "市场部", "lightgreen", "lightcoral"))
# 设置节点大小(根据重要性)
V(g)$size <- V(g)$importance * 3
# 设置边的宽度(根据权重)
E(g)$width <- E(g)$weight
# 选择布局算法
# 力导向布局(FR算法)适合大多数网络
layout_fr <- layout_with_fr(g)
# 绘制网络图
plot(g,
layout = layout_fr, # 布局算法
vertex.label = V(g)$name, # 节点标签
vertex.label.cex = 1.2, # 标签字体大小
vertex.label.color = "black", # 标签颜色
vertex.size = V(g)$size, # 节点大小
vertex.color = V(g)$color, # 节点颜色
vertex.frame.color = "gray", # 节点边框颜色
edge.width = E(g)$width, # 边宽度
edge.color = "gray50", # 边颜色
edge.curved = 0.2, # 边的弯曲度
main = "节点链接图:公司社交网络",
cex.main = 1.5)
# 添加图例
legend("topright",
legend = c("销售部", "市场部", "技术部"),
fill = c("lightblue", "lightgreen", "lightcoral"),
title = "部门")
# 计算网络统计指标并标注
# 计算度中心性(连接数)
degree_centrality <- degree(g)
cat("度中心性:\n")
print(degree_centrality)
# 计算介数中心性(桥梁作用)
betweenness_centrality <- betweenness(g)
cat("\n介数中心性:\n")
print(betweenness_centrality)
# 在图上标注度中心性
plot(g,
layout = layout_fr,
vertex.label = paste(V(g)$name, "\ndeg:", degree_centrality),
vertex.label.cex = 0.9,
vertex.size = V(g)$size,
vertex.color = V(g)$color,
edge.width = E(g)$width,
main = "节点链接图(带度中心性标注)")
1.2 使用networkD3创建交互式网络图
r
# 安装并加载networkD3包
if(!require(networkD3)) install.packages("networkD3")
library(networkD3)
# 准备数据:网络D3要求特定的数据格式
# 边数据框:source和target使用从0开始的索引
links_d3 <- data.frame(
source = c(0, 0, 1, 1, 2, 3, 3, 4), # 起始节点索引
target = c(1, 2, 2, 3, 3, 4, 0, 1), # 目标节点索引
value = c(5, 3, 4, 2, 6, 3, 1, 4) # 连接强度
)
# 节点数据框:包含节点名称和分组信息
nodes_d3 <- data.frame(
name = c("节点A", "节点B", "节点C", "节点D", "节点E"),
group = c("group1", "group1", "group2", "group2", "group3"),
size = c(20, 15, 25, 18, 12) # 节点大小
)
# 创建力导向网络图
force_network <- forceNetwork(
Links = links_d3, # 边数据框
Nodes = nodes_d3, # 节点数据框
Source = "source", # 源节点列名
Target = "target", # 目标节点列名
Value = "value", # 边权重列名
NodeID = "name", # 节点标签列名
Group = "group", # 节点分组列名(用于颜色)
Nodesize = "size", # 节点大小列名
# 视觉设置
radius = 10, # 节点半径
opacity = 0.8, # 不透明度
zoom = TRUE, # 允许缩放
legend = TRUE, # 显示图例
bounded = TRUE, # 限制在框内
# 交互设置
fontSize = 14, # 字体大小
fontFamily = "Arial", # 字体
linkColour = "#666", # 边的颜色
colourScale = JS('d3.scaleOrdinal(d3.schemeCategory10);') # 颜色方案
)
# 显示交互式网络图
force_network
# 使用igraph创建图并转换为networkD3格式
if(!require(igraph)) install.packages("igraph")
library(igraph)
# 创建Zachary空手道俱乐部网络(经典社会网络数据集)
karate <- make_graph("Zachary")
# 计算社区结构
wc <- cluster_walktrap(karate)
members <- membership(wc)
# 转换为networkD3格式
karate_d3 <- igraph_to_networkD3(karate, group = members)
# 绘制力导向网络图
forceNetwork(
Links = karate_d3$links,
Nodes = karate_d3$nodes,
Source = 'source',
Target = 'target',
NodeID = 'name',
Group = 'group',
opacity = 0.9,
zoom = TRUE,
legend = TRUE,
fontSize = 12,
linkColour = "#aaa",
colourScale = JS('d3.scaleOrdinal(d3.schemeSet3);')
)
# 使用rD3plot包创建增强型网络图
if(!require(rD3plot)) install.packages("rD3plot")
library(rD3plot)
# 使用内置数据
data("crannetworkdata")
links <- crannetworkdata$links
nodes <- crannetworkdata$nodes
# 创建自定义网络
net <- network_rd3(
links = links,
nodes = nodes,
lcolor = "Type", # 边颜色映射
size = "downloadsyear", # 节点大小映射
info = "info", # 节点信息
color = "downloads", # 节点颜色映射
dir = "CRANnetwork"
)
# 绘制网络图
plot(net)
2. 弧线图 (Arc Diagram)
语法知识点
弧线图将节点排列在一条直线上,用弧线(半圆)表示节点间的连接。特点:
- 适合展示线性顺序中的关系(如时间序列、基因组数据)
- 可以有效避免视觉杂乱
- 弧线的高度可编码边的权重
常用包:
ggraph+geom_edge_arcigraph+ 自定义布局
案例代码
r
# 安装并加载必要的包
if(!require(ggraph)) install.packages("ggraph")
if(!require(igraph)) install.packages("igraph")
if(!require(tidygraph)) install.packages("tidygraph")
library(ggraph)
library(igraph)
library(tidygraph)
# 创建示例数据:时间序列上的事件关联
# 创建节点:按时间顺序排列的事件
events <- data.frame(
id = 1:10,
name = c("事件A", "事件B", "事件C", "事件D", "事件E",
"事件F", "事件G", "事件H", "事件I", "事件J"),
time = c(1, 3, 5, 7, 9, 11, 13, 15, 17, 19), # 时间顺序
importance = c(5, 3, 8, 4, 6, 7, 5, 9, 4, 6)
)
# 创建边:事件之间的关联
edges_arc <- data.frame(
from = c(1, 1, 2, 3, 3, 4, 5, 6, 7, 8, 8, 9),
to = c(3, 5, 4, 5, 7, 6, 8, 9, 10, 9, 10, 10),
weight = c(2, 1, 3, 2, 4, 1, 2, 3, 2, 1, 2, 3)
)
# 创建图对象
g_arc <- graph_from_data_frame(edges_arc, vertices = events, directed = FALSE)
# 方法1:使用ggraph绘制弧线图
# 创建线性布局(按时间顺序排列)
linear_layout <- create_layout(g_arc, layout = "linear",
sort.by = time) # 按时间排序
# 绘制弧线图
ggraph(linear_layout) +
# 绘制弧线边
geom_edge_arc(aes(alpha = weight, width = weight), # 弧线透明度/宽度映射权重
strength = 0.5, # 弧的弯曲程度
colour = "steelblue") +
# 绘制节点
geom_node_point(aes(size = importance), # 节点大小映射重要性
colour = "darkred", alpha = 0.8) +
# 添加节点标签
geom_node_text(aes(label = name),
repel = TRUE, # 避免标签重叠
size = 4, vjust = -1) +
# 主题设置
theme_void() +
labs(title = "弧线图:事件时间序列关联",
subtitle = "节点按时间顺序排列,弧线表示事件间的关联") +
theme(plot.title = element_text(hjust = 0.5, face = "bold"),
plot.subtitle = element_text(hjust = 0.5))
# 方法2:手动创建弧线图(使用ggplot2绘制基础弧线)
if(!require(ggplot2)) install.packages("ggplot2")
library(ggplot2)
# 准备节点位置:x坐标为时间顺序,y坐标均为0
node_positions <- data.frame(
id = events$id,
name = events$name,
x = events$time,
y = 0
)
# 准备弧线数据:计算每条弧线的控制点
# 弧线方程为半圆:y = sqrt(r^2 - (x - center)^2)
arc_data <- data.frame()
for(i in 1:nrow(edges_arc)) {
from_id <- edges_arc$from[i]
to_id <- edges_arc$to[i]
weight <- edges_arc$weight[i]
# 获取起止点的x坐标
x1 <- node_positions$x[node_positions$id == from_id]
x2 <- node_positions$x[node_positions$id == to_id]
# 计算弧的参数
center_x <- (x1 + x2) / 2 # 圆心x坐标
radius <- abs(x2 - x1) / 2 # 半径
max_height <- radius * (weight / max(edges_arc$weight)) # 弧高与权重成正比
# 生成弧线上的点
t <- seq(0, pi, length.out = 50) # 角度序列(半圆)
arc_x <- center_x + radius * cos(t)
arc_y <- max_height * sin(t)
arc_data <- rbind(arc_data,
data.frame(x = arc_x, y = arc_y,
weight = weight,
edge_id = i))
}
# 绘制手动弧线图
ggplot() +
# 绘制弧线
geom_path(data = arc_data,
aes(x = x, y = y, group = edge_id, alpha = weight),
colour = "steelblue", size = 1) +
# 绘制节点
geom_point(data = node_positions,
aes(x = x, y = y, size = events$importance),
colour = "darkred", alpha = 0.8) +
# 节点标签
geom_text(data = node_positions,
aes(x = x, y = y - 0.5, label = name),
size = 4, vjust = 1) +
# 主题
theme_minimal() +
labs(title = "弧线图(手动版)",
x = "时间", y = "弧线高度") +
theme(axis.text.y = element_blank(),
panel.grid.minor = element_blank())
3. 蜂巢图 (Hive Plot)
语法知识点
蜂巢图将节点分布在几条径向轴上,边按照规则连接。特点:
- 节点按属性分配到不同轴
- 轴上的位置反映节点的某种度量
- 有效避免视觉杂乱,适合大型网络
常用包:
HiveR: 专门绘制蜂巢图的包ggforce: 提供径向布局支持
核心概念:
- 轴 (Axis): 每条轴代表一类节点
- 节点位置: 沿轴的距离反映节点属性值
- 边: 用曲线连接不同轴或同轴上的节点
案例代码
r
# 安装并加载HiveR包
if(!require(HiveR)) install.packages("HiveR")
library(HiveR)
# 创建示例数据:组织通信网络
# 节点按部门分配到3条轴:销售部、市场部、技术部
set.seed(456)
# 创建节点数据
nodes_hive <- data.frame(
id = 1:30,
name = paste0("员工", 1:30),
department = sample(c("销售部", "市场部", "技术部"), 30, replace = TRUE,
prob = c(0.3, 0.3, 0.4)),
# 在轴上的位置(基于工作年限或绩效)
position = runif(30, 0, 100)
)
# 创建边数据(通信关系)
edges_hive <- data.frame()
for(i in 1:50) {
from <- sample(1:30, 1)
to <- sample(1:30, 1)
if(from != to) {
edges_hive <- rbind(edges_hive,
data.frame(from = from, to = to,
weight = runif(1, 1, 10)))
}
}
edges_hive <- unique(edges_hive) # 去重
# 准备HiveR所需的数据格式
# 为每个节点分配轴编号
nodes_hive$axis <- ifelse(nodes_hive$department == "销售部", 1,
ifelse(nodes_hive$department == "市场部", 2, 3))
# 创建蜂巢图数据对象
hive_data <- list()
hive_data$nodes <- data.frame(
id = nodes_hive$id,
axis = nodes_hive$axis,
radius = nodes_hive$position / 100, # 归一化到[0,1]
size = 1,
color = ifelse(nodes_hive$axis == 1, "#2E86AB",
ifelse(nodes_hive$axis == 2, "#A23B72", "#F18F01"))
)
# 创建边数据
hive_data$edges <- data.frame(
id1 = edges_hive$from,
id2 = edges_hive$to,
weight = edges_hive$weight / max(edges_hive$weight) # 归一化权重
)
# 绘制蜂巢图
# 注意:HiveR包的绘图函数需要特定的数据对象结构
# 这里展示使用HiveR包的标准方法
# 方法2:使用ggplot2手动创建蜂巢图
if(!require(ggplot2)) install.packages("ggplot2")
library(ggplot2)
# 定义三条轴的角度
axis_angles <- c(0, 120, 240) * pi / 180 # 转换为弧度
# 计算每个节点的笛卡尔坐标
nodes_hive$x <- nodes_hive$position * cos(axis_angles[nodes_hive$axis])
nodes_hive$y <- nodes_hive$position * sin(axis_angles[nodes_hive$axis])
# 计算边的曲线控制点
edge_curves <- data.frame()
for(i in 1:nrow(edges_hive)) {
from_node <- nodes_hive[nodes_hive$id == edges_hive$from[i], ]
to_node <- nodes_hive[nodes_hive$id == edges_hive$to[i], ]
weight <- edges_hive$weight[i]
# 使用贝塞尔曲线连接两点
# 控制点取两点连线的中垂线方向
mid_x <- (from_node$x + to_node$x) / 2
mid_y <- (from_node$y + to_node$y) / 2
# 垂直方向偏移(与边权重成正比)
perp_x <- -(to_node$y - from_node$y)
perp_y <- to_node$x - from_node$x
norm <- sqrt(perp_x^2 + perp_y^2)
if(norm > 0) {
perp_x <- perp_x / norm
perp_y <- perp_y / norm
}
ctrl_x <- mid_x + perp_x * weight * 20
ctrl_y <- mid_y + perp_y * weight * 20
# 生成贝塞尔曲线上的点
t <- seq(0, 1, length.out = 30)
curve_x <- (1-t)^2 * from_node$x + 2*(1-t)*t * ctrl_x + t^2 * to_node$x
curve_y <- (1-t)^2 * from_node$y + 2*(1-t)*t * ctrl_y + t^2 * to_node$y
edge_curves <- rbind(edge_curves,
data.frame(x = curve_x, y = curve_y,
weight = weight, edge_id = i))
}
# 绘制蜂巢图
ggplot() +
# 绘制边曲线
geom_path(data = edge_curves,
aes(x = x, y = y, group = edge_id, alpha = weight),
colour = "gray50", size = 0.5) +
# 绘制轴(虚线)
geom_abline(data = data.frame(slope = tan(axis_angles), axis = 1:3),
aes(slope = slope, intercept = 0),
linetype = "dashed", colour = "gray70") +
# 绘制节点
geom_point(data = nodes_hive,
aes(x = x, y = y, color = department, size = position),
alpha = 0.8) +
# 节点标签
geom_text_repel(data = nodes_hive,
aes(x = x, y = y, label = name),
size = 3) +
# 颜色方案
scale_color_manual(values = c("销售部" = "#2E86AB",
"市场部" = "#A23B72",
"技术部" = "#F18F01")) +
# 主题
theme_void() +
coord_equal() +
labs(title = "蜂巢图:部门通信网络",
subtitle = "节点分布在三条轴上,位置反映工作年限,曲线表示通信频率",
color = "部门", size = "轴位置(工作年限)") +
theme(plot.title = element_text(hjust = 0.5, face = "bold"),
legend.position = "bottom")
4. 和弦图 (Chord Diagram)
语法知识点
和弦图以圆形布局展示节点间的流动关系。特点:
- 节点沿圆周排列
- 弦的宽度表示流量大小
- 适合展示转移矩阵、贸易流等
常用包:
circlize: 功能最全面的和弦图包chorddiag: 基于D3.js的交互式弦图edgebundleR: 支持边绑定的圆形图
案例代码
r
# 安装并加载circlize包
if(!require(circlize)) install.packages("circlize")
library(circlize)
# 创建示例数据:国际贸易流量
# 定义国家/地区
regions <- c("中国", "美国", "日本", "德国", "英国", "法国", "韩国", "澳大利亚")
# 创建贸易流量矩阵(随机生成)
set.seed(789)
trade_matrix <- matrix(runif(64, 0, 100), nrow = 8, ncol = 8)
diag(trade_matrix) <- 0 # 对角线设为0(无自贸易)
# 设置行列名
rownames(trade_matrix) <- regions
colnames(trade_matrix) <- regions
# 使矩阵不对称(出口≠进口)
trade_matrix <- round(trade_matrix, 1)
# 查看矩阵
print("贸易流量矩阵(百万美元):")
print(trade_matrix)
# 方法1:使用circlize包绘制和弦图
# 设置颜色
region_colors <- c("#2E86AB", "#A23B72", "#F18F01", "#C73E1D",
"#6A994E", "#BC4A3C", "#8B8C89", "#3A6EA5")
# 初始化圆形布局
circos.clear()
circos.par(start.degree = 90, gap.degree = 5) # 起始角度和间隙
# 创建和弦图
chordDiagram(
trade_matrix,
# 基本设置
grid.col = setNames(region_colors, regions), # 每个扇区的颜色
transparency = 0.3, # 透明度
# 方向设置
directional = 1, # 有向图(1表示有方向)
direction.type = c("diffHeight", "arrows"), # 箭头表示方向
diffHeight = 0.04, # 箭头高度差异
# 标签设置
annotationTrack = c("name", "grid"), # 显示名称和网格
annotationTrackHeight = c(0.03, 0.05), # 轨道高度
# 链接设置
link.sort = TRUE, # 排序链接
link.decreasing = TRUE, # 降序排列
# 缩放
scale = TRUE
)
# 添加标题
title("和弦图:国际贸易流量(百万美元)")
# 添加图例
legend("topright",
legend = regions,
fill = region_colors,
title = "国家/地区",
cex = 0.8)
# 方法2:使用chorddiag包创建交互式弦图
if(!require(chorddiag)) install.packages("chorddiag")
library(chorddiag)
# 创建更丰富的贸易数据
# 不同商品类别的贸易
sectors <- c("电子产品", "汽车", "农产品", "纺织品", "机械设备", "化学品")
# 创建转移矩阵(行业间流动)
flow_matrix <- matrix(c(
0, 120, 45, 30, 80, 25, # 电子产品 -> 各行业
80, 0, 35, 25, 110, 30, # 汽车 -> 各行业
40, 25, 0, 55, 30, 15, # 农产品 -> 各行业
25, 20, 45, 0, 35, 20, # 纺织品 -> 各行业
90, 100, 40, 35, 0, 45, # 机械设备 -> 各行业
30, 25, 20, 15, 40, 0 # 化学品 -> 各行业
), nrow = 6, byrow = TRUE)
rownames(flow_matrix) <- sectors
colnames(flow_matrix) <- sectors
# 创建交互式弦图
chorddiag(
flow_matrix,
# 类型设置
type = "bipartite", # 二分图类型
# 视觉设置
groupnameFontsize = 14, # 组名大小
groupPadding = 5, # 组间距
margin = 90, # 边距
# 颜色
showTicks = FALSE, # 不显示刻度
# 交互设置
tooltipGroupConnector = " → " # 悬停提示格式
)
# 方法3:使用edgebundleR创建圆形边绑定图
if(!require(edgebundleR)) install.packages("edgebundleR")
if(!require(igraph)) install.packages("igraph")
library(edgebundleR)
library(igraph)
# 创建小世界网络示例
ws_graph <- watts.strogatz.game(1, 50, 4, 0.05)
# 绘制圆形边绑定图
edgebundle(
ws_graph,
tension = 0.5, # 边张力(0-1之间)
fontsize = 12, # 字体大小
padding = 100, # 内边距
nodesize = c(5, 20) # 节点大小范围
)
# 方法4:使用ggplot2手动创建和弦图
# 准备节点位置(圆周上的点)
angles <- seq(0, 2*pi - 2*pi/8, length.out = 8)
node_pos_circle <- data.frame(
name = regions,
x = cos(angles),
y = sin(angles),
color = region_colors
)
# 准备弦数据
chord_data <- data.frame()
for(i in 1:nrow(trade_matrix)) {
for(j in 1:ncol(trade_matrix)) {
if(trade_matrix[i,j] > 0) {
# 起点和终点的角度
start_angle <- angles[i]
end_angle <- angles[j]
# 计算弦的控制点
# 使用贝塞尔曲线绘制弦
t <- seq(0, 1, length.out = 100)
# 弦的曲线参数
# 起点和终点在圆周上
start_x <- cos(start_angle)
start_y <- sin(start_angle)
end_x <- cos(end_angle)
end_y <- sin(end_angle)
# 控制点:沿圆周方向偏移
# 使用三次贝塞尔曲线
ctrl1_x <- cos(start_angle + (end_angle - start_angle) * 0.3) * 1.2
ctrl1_y <- sin(start_angle + (end_angle - start_angle) * 0.3) * 1.2
ctrl2_x <- cos(start_angle + (end_angle - start_angle) * 0.7) * 1.2
ctrl2_y <- sin(start_angle + (end_angle - start_angle) * 0.7) * 1.2
# 贝塞尔曲线公式
curve_x <- (1-t)^3 * start_x + 3*(1-t)^2*t * ctrl1_x +
3*(1-t)*t^2 * ctrl2_x + t^3 * end_x
curve_y <- (1-t)^3 * start_y + 3*(1-t)^2*t * ctrl1_y +
3*(1-t)*t^2 * ctrl2_y + t^3 * end_y
chord_data <- rbind(chord_data,
data.frame(x = curve_x, y = curve_y,
value = trade_matrix[i,j],
from = regions[i], to = regions[j]))
}
}
}
# 绘制基础和弦图
ggplot() +
# 绘制弦
geom_path(data = chord_data,
aes(x = x, y = y, group = interaction(from, to),
color = value, alpha = value),
size = 0.8) +
# 绘制圆周上的节点
geom_point(data = node_pos_circle,
aes(x = x, y = y, fill = name),
size = 10, shape = 21, color = "white") +
# 节点标签
geom_text(data = node_pos_circle,
aes(x = x * 1.2, y = y * 1.2, label = name),
size = 4) +
# 颜色映射
scale_color_gradient(low = "lightblue", high = "darkred", name = "贸易额") +
scale_alpha_continuous(range = c(0.3, 0.8), guide = "none") +
scale_fill_manual(values = setNames(region_colors, regions), guide = "none") +
# 主题
theme_void() +
coord_equal() +
labs(title = "和弦图(手动版):国际贸易流量",
color = "贸易额\n(百万美元)") +
theme(plot.title = element_text(hjust = 0.5, face = "bold"),
legend.position = "right")
5. 边绑定图 (Edge Bundling Diagram)
语法知识点
边绑定图通过将相似的边聚合成束来减少视觉杂乱。特点:
- 基于层次结构引导边的走向
- 有效减少大型网络中的"毛球"效应
- 突出显示整体模式而非单个连接
常用包:
ggraph::geom_conn_bundle: 层次边绑定edgebundleR: 圆形布局边绑定geom_edge_bundle(ggraph扩展)
核心概念:
- 层次结构: 边的绑定基于隐含的树状结构
- 张力参数: 控制边的弯曲程度和绑定强度
- 捆绑路径: 多条边沿着相似的路径走向
案例代码
r
# 安装并加载必要的包
if(!require(ggraph)) install.packages("ggraph")
if(!require(tidygraph)) install.packages("tidygraph")
if(!require(igraph)) install.packages("igraph")
library(ggraph)
library(tidygraph)
library(igraph)
# 案例:软件包依赖关系网络
# 使用flare数据集(类层次结构和导入关系)
# 创建示例层次数据:文件系统的目录结构
# 创建节点:目录和文件
dir_nodes <- data.frame(
id = 1:20,
name = c("root", "src", "docs", "tests", "R", "man", "vignettes",
"utils.R", "stats.R", "plot.R", "intro.Rmd", "advanced.Rmd",
"test1.R", "test2.R", "test_utils.R", "README.md", "LICENSE",
"DESCRIPTION", "NAMESPACE", "NEWS.md"),
type = c("dir", "dir", "dir", "dir", "dir", "dir", "dir",
rep("file", 13)),
level = c(0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1)
)
# 创建层次边(目录结构)
dir_edges <- data.frame(
from = c(1, 1, 1, 2, 2, 2, 3, 4, 5, 6, # 目录结构
2, 2, 2, 4, 4, 5, 5), # 文件位置
to = c(2, 3, 4, 5, 6, 7, 16, 17, 8, 9,
10, 11, 12, 13, 14, 15, 18),
type = c(rep("hierarchy", 10), rep("import", 7))
)
# 创建导入关系(用于边绑定)
import_edges <- data.frame(
from = c(8, 9, 10, 11, 12, 13, 14, 15, 18, 19),
to = c(9, 10, 8, 12, 11, 14, 15, 13, 20, 18),
weight = runif(10, 0.5, 2)
)
# 创建完整的图对象
graph <- tbl_graph(
nodes = dir_nodes,
edges = rbind(dir_edges[, c("from", "to")], import_edges[, c("from", "to")]),
directed = TRUE
)
# 方法1:使用ggraph的层次边绑定
# 创建树状布局(基于层次结构)
ggraph(graph, layout = 'dendrogram', circular = TRUE) +
# 绘制绑定的边(使用导入关系)
geom_conn_bundle(
data = get_con(import_edges$from, import_edges$to), # 获取连接数据
aes(colour = after_stat(index)), # 颜色映射
edge_alpha = 0.3, # 边透明度
tension = 0.8, # 张力(绑定强度)
width = 1 # 边宽度
) +
# 绘制节点
geom_node_point(
aes(filter = type == "file", colour = level), # 只显示文件节点
size = 3
) +
# 添加节点标签
geom_node_text(
aes(filter = type == "file", label = name,
angle = node_angle(x, y)), # 标签角度适应圆形布局
size = 3, hjust = "outside"
) +
# 颜色方案
scale_edge_colour_distiller('方向', direction = 1, guide = 'edge_direction') +
scale_colour_viridis_c(option = "plasma") +
# 主题
coord_fixed() +
theme_void() +
labs(title = "边绑定图:软件包依赖关系",
subtitle = "边绑定减少视觉杂乱,突出依赖模式")
# 方法2:使用edgebundleR创建圆形边绑定图
if(!require(edgebundleR)) install.packages("edgebundleR")
library(edgebundleR)
# 创建相关矩阵作为输入
# 生成一个对称的相关矩阵
set.seed(123)
cor_matrix <- matrix(runif(400, -0.5, 0.8), nrow = 20)
cor_matrix <- (cor_matrix + t(cor_matrix)) / 2 # 对称化
diag(cor_matrix) <- 1
# 设置行名列名
var_names <- paste0("Var", 1:20)
rownames(cor_matrix) <- var_names
colnames(cor_matrix) <- var_names
# 只保留显著相关的连接(|r| > 0.3)
cor_matrix[abs(cor_matrix) < 0.3] <- 0
# 使用edgebundle绘制
edgebundle(
cor_matrix,
tension = 0.3, # 张力(值越小绑定越紧)
cutoff = 0.3, # 连接阈值
fontsize = 12, # 字体大小
padding = 80, # 内边距
nodesize = c(3, 15) # 节点大小范围
)
# 方法3:使用igraph创建层次边绑定的基础结构
if(!require(igraph)) install.packages("igraph")
library(igraph)
# 创建更复杂的网络:学术引用网络
# 生成论文节点(按主题聚类)
n_papers <- 40
topics <- sample(c("ML", "Stats", "Bioinfo", "Physics"), n_papers, replace = TRUE)
# 创建引用关系(同一主题内引用更多)
citation_matrix <- matrix(0, n_papers, n_papers)
for(i in 1:n_papers) {
for(j in 1:n_papers) {
if(i != j) {
# 同主题引用概率高,不同主题概率低
if(topics[i] == topics[j]) {
citation_matrix[i,j] <- rbinom(1, 1, 0.3)
} else {
citation_matrix[i,j] <- rbinom(1, 1, 0.05)
}
}
}
}
# 创建图
citation_graph <- graph_from_adjacency_matrix(citation_matrix, mode = "directed")
# 添加节点属性
V(citation_graph)$topic <- topics
V(citation_graph)$size <- runif(n_papers, 5, 15)
# 计算社区结构(作为层次绑定的基础)
communities <- cluster_louvain(citation_graph)
V(citation_graph)$community <- membership(communities)
# 使用Kamada-Kawai布局(力导向布局)
layout_kk <- layout_with_kk(citation_graph)
# 绘制基础网络(无边绑定)
par(mfrow = c(1, 2), mar = c(1, 1, 3, 1))
plot(citation_graph,
layout = layout_kk,
vertex.color = as.numeric(factor(topics)),
vertex.size = V(citation_graph)$size / 2,
vertex.label = NA,
edge.arrow.size = 0.2,
edge.color = rgb(0.5, 0.5, 0.5, 0.3),
main = "标准网络图(杂乱)")
# 简化网络:按社区分组后绘制边绑定效果
# 计算社区间的关系强度
community_edges <- matrix(0, max(communities), max(communities))
for(e in 1:ecount(citation_graph)) {
from_comm <- V(citation_graph)$community[head_of(citation_graph, e)]
to_comm <- V(citation_graph)$community[tail_of(citation_graph, e)]
community_edges[from_comm, to_comm] <- community_edges[from_comm, to_comm] + 1
}
# 绘制简化后的社区级网络
community_graph <- graph_from_adjacency_matrix(community_edges, weighted = TRUE)
plot(community_graph,
edge.width = E(community_graph)$weight / 2,
vertex.size = 20,
vertex.label = 1:max(communities),
main = "边绑定简化效果\n(社区级聚合)")
# 添加图例
legend("topright",
legend = unique(topics),
fill = 1:4,
title = "主题")
par(mfrow = c(1, 1))
# 方法4:使用geom_edge_bundle_path(ggraph的路径边绑定)
# 创建具有层次结构的网络
hierarchy_nodes <- data.frame(
id = 1:15,
name = c("Root", "A", "B", "C", "A1", "A2", "B1", "B2", "C1", "C2",
"A1a", "A1b", "B1a", "B1b", "C1a"),
level = c(0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3)
)
# 层次边(树结构)
hierarchy_edges <- data.frame(
from = c(1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7),
to = c(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 10)
)
# 额外连接(用于边绑定)
extra_edges <- data.frame(
from = c(11, 12, 13, 14, 15, 11, 12, 8),
to = c(13, 14, 15, 11, 12, 15, 13, 15)
)
# 合并所有边
all_edges <- rbind(
cbind(hierarchy_edges, type = "hierarchy"),
cbind(extra_edges, type = "bundle")
)
# 创建图对象
bundle_graph <- tbl_graph(
nodes = hierarchy_nodes,
edges = all_edges
)
# 绘制带路径边绑定的网络
ggraph(bundle_graph, layout = "dendrogram", circular = FALSE) +
# 层次边(灰色背景)
geom_edge_link(aes(filter = type == "hierarchy"),
colour = "gray80", width = 0.5) +
# 绑定边(彩色,沿层次路径弯曲)
geom_edge_bundle_path(
aes(filter = type == "bundle", colour = after_stat(index)),
tension = 0.6, # 张力
edge_width = 1,
edge_alpha = 0.7
) +
# 节点
geom_node_point(aes(size = level), colour = "steelblue", alpha = 0.8) +
geom_node_text(aes(label = name), size = 3, vjust = -1, hjust = 0) +
# 颜色
scale_edge_colour_viridis_c(option = "inferno", guide = "none") +
# 主题
theme_graph() +
labs(title = "边绑定图:层次结构中的额外连接",
subtitle = "额外连接沿层次路径弯曲,形成自然束")
本章小结
| 图表类型 | 主要用途 | 关键函数/包 | 适用场景 |
|---|---|---|---|
| 节点链接图 | 通用网络可视化 | igraph::plot, networkD3::forceNetwork |
社交网络、知识图谱 |
| 弧线图 | 线性顺序中的关系 | ggraph::geom_edge_arc |
时间序列关联、基因组数据 |
| 蜂巢图 | 避免视觉杂乱的网络 | HiveR |
大型网络、多属性节点 |
| 和弦图 | 流动/转移关系 | circlize::chordDiagram |
贸易流、迁移数据 |
| 边绑定图 | 减少"毛球"效应 | ggraph::geom_conn_bundle |
大型层次网络、依赖关系 |
选择建议
- 节点链接图:最直观,适合中小型网络(<100节点)
- 弧线图:适合有时间或线性顺序的网络
- 蜂巢图:当节点有明确分类属性时使用,可处理较大网络
- 和弦图:适合展示流量/转移矩阵,强调节点间的流动量
- 边绑定图:适合大型层次网络,通过绑定相似边减少杂乱
性能考虑
- 对于大型网络(>1000节点),推荐使用
networkD3或edgebundleR的交互式版本 - 静态绘图建议使用
ggraph,可与ggplot2语法无缝集成 - 边绑定图的计算量较大,大型网络可能需要调整
tension参数以获得合理的渲染时间
所有代码均可直接复制到R环境中运行(需联网安装缺失包)。建议根据实际数据规模选择合适的图表类型和包。