如何在R语言中为最小生成树的边标注距离矩阵的距离值?
问题:使用ggplot绘制最小生成树时,无法在边上标注对应距离值
我尝试用ggplot绘制最小生成树(MST),希望借助ggplot2和ggnetwork的geom_edgelabel()等功能生成可精细修改的树状图,但始终无法将支撑MST的距离矩阵中的距离值标注到边上。
我的操作步骤:
- 基于整数矩阵生成距离矩阵:
set.seed(1) matrix <- matrix(sample(1:20, 10 * 20, replace = TRUE), nrow = 10, ncol = 20) dist <- dist(matrix)
- 用
ape::mst()生成最小生成树:
if (!require(ape)) install.packages('ape') library(ape) ape_mst <- ape::mst(dist)
- 转换为igraph对象以便ggplot使用:
if (!require(igraph)) install.packages('igraph') library(igraph) gr_adj <- graph.adjacency(ape_mst, "undirected")
- 用ggnetwork转换为ggplot可用的数据框并绘图:
if (!require(ggnetwork)) install.packages('ggnetwork') library(ggnetwork) gg <- ggnetwork(gr_adj, arrow.gap = 0, layout = layout_with_fr(gr_adj)) ggplot(gg, aes(x = x, y = y, xend = xend, yend = yend)) + geom_edges() + geom_nodelabel(aes(label = name)) + geom_edgelabel(aes(label = name), size = 2)
问题在于,转换后的gg数据框没有保存边的距离信息,无法标注所需的距离值。虽然用Claddis包的find_minimum_spanning_edges(dist)可以轻松获取MST各边对应的距离,但受之前创建的对象结构限制,无法完成标注。
后续尝试(仍未解决):
参考建议修改代码后,使用ape::mst而非igraph::mst时,边标注的长度仍与预期不符:
set.seed(1) dist <- dist(matrix(sample(1:20, 10 * 20, replace = TRUE), nrow = 10, ncol = 20)) ape_mst <- ape::mst(dist) gr_adj <- graph.adjacency(ape_mst, weighted = TRUE) ggraph(gr_adj, layout = "igraph", algorithm = "nicely") + geom_edge_link(aes(label = round(weight, 3)), angle_calc = "along", vjust = -0.5) + geom_node_label(aes(label = name), size = 2) + scale_edge_width_continuous(range = c(0.5, 1.5), guide = "none") + theme_graph() find_minimum_spanning_edges(dist)
我希望边标注能和目标图中的边长度对应,恳请提供解决建议!
解决方案:
问题核心是ape::mst()返回的邻接矩阵权重未被正确传递到绘图对象中,以下是两种可行的解决方法:
方法1:修复ape生成MST的权重传递
确保igraph对象正确读取邻接矩阵的权重,并在ggnetwork中保留该属性:
set.seed(1) matrix <- matrix(sample(1:20, 10 * 20, replace = TRUE), nrow = 10, ncol = 20) dist <- dist(matrix) # 生成MST邻接矩阵 ape_mst <- ape::mst(dist) # 转换为带权重的igraph对象,显式指定weighted参数 gr_adj <- graph.adjacency(ape_mst, mode = "undirected", weighted = TRUE) # 提取并赋值边权重(过滤邻接矩阵中的0值) E(gr_adj)$weight <- as.vector(ape_mst)[as.vector(ape_mst) > 0] # 用ggnetwork转换,自动保留边属性 gg <- ggnetwork(gr_adj, arrow.gap = 0, layout = layout_with_fr(gr_adj)) # 绘图时调用weight属性作为边标注 ggplot(gg, aes(x = x, y = y, xend = xend, yend = yend)) + geom_edges() + geom_nodelabel(aes(label = name)) + geom_edgelabel(aes(label = round(weight, 3)), size = 2)
方法2:直接用igraph生成MST(更简便)
跳过ape::mst,直接用igraph从距离矩阵生成带权重的MST,权重会自动保留:
set.seed(1) matrix <- matrix(sample(1:20, 10 * 20, replace = TRUE), nrow = 10, ncol = 20) dist <- dist(matrix) # 将距离矩阵转换为igraph对象,再生成MST gr <- graph_from_adjacency_matrix(as.matrix(dist), mode = "undirected", weighted = TRUE) mst_gr <- mst(gr) # 用ggnetwork绘图 gg <- ggnetwork(mst_gr, arrow.gap = 0, layout = layout_with_fr(mst_gr)) ggplot(gg, aes(x = x, y = y, xend = xend, yend = yend)) + geom_edges() + geom_nodelabel(aes(label = name)) + geom_edgelabel(aes(label = round(weight, 3)), size = 2)
验证权重一致性
可以对比Claddis的结果和igraph的边权重,确保标注准确:
library(Claddis) mst_edges <- find_minimum_spanning_edges(dist) igraph_weights <- E(mst_gr)$weight # 排序后对比,结果应为TRUE all(sort(mst_edges$edge_length) == sort(igraph_weights))
内容的提问来源于stack exchange,提问作者infinity-a11y
相关产品推荐
相关产品推荐

