如何在R中绘制带时间维度、含单子节点的树状数据?
解决方案
方法1:用igraph + ggraph绘制(推荐,完美支持单子节点)
igraph可直接从边列表构建图,ggraph能灵活控制坐标轴与边长度,适配时间维度需求:
- 安装并加载依赖包:
install.packages(c("igraph", "ggraph")) library(igraph) library(ggraph)
- 构建图对象并添加属性:
# 过滤掉根节点的NA边 tree_edges = tree[!is.na(tree$dt), ] # 从边列表构建有向图 g = graph_from_data_frame(tree_edges, directed = TRUE, vertices = data.frame(id = unique(c(tree$i.fr, tree$i.to)))) # 给节点添加时间属性 V(g)$t = tree$t[match(V(g)$id, tree$i.fr)] # 手动设置根节点时间 V(g)$t[V(g)$id == 0] = 0
- 绘制树状图:
ggraph(g, layout = "dendrogram", circular = FALSE) + geom_edge_link(aes(length = dt), edge_width = 1, color = "gray50") + geom_node_point(aes(x = t), size = 4, color = "darkblue") + geom_node_text(aes(x = t, label = id), hjust = -0.3, size = 3.5) + scale_x_continuous(name = "时间t", breaks = unique(tree$t)) + y_axis(NULL) + theme_minimal() + theme(panel.grid = element_blank())
该方案会将节点按时间t排列在x轴,边长按dt比例展示,所有单子节点均会保留。
方法2:修复phylo对象后用ggtree绘制
若偏好ggtree,需修正phylo对象的格式问题(ape要求节点编号规则严格):
- 重新编号节点:
# 提取所有节点 nodes = unique(c(tree$i.fr, tree$i.to)) # 区分叶子节点(无子节点)和内部节点 leaf_nodes = setdiff(tree$i.to, tree$i.fr) internal_nodes = setdiff(nodes, leaf_nodes) # 按ape规则编号:叶子节点从1开始,内部节点从Ntip+1开始 Ntip = length(leaf_nodes) leaf_map = setNames(seq(Ntip), leaf_nodes) internal_map = setNames(Ntip + seq_along(internal_nodes), internal_nodes) full_map = c(leaf_map, internal_map)
- 构建合规的
phylo对象:
# 生成边矩阵 edge_matrix = cbind(full_map[as.character(tree$i.fr)], full_map[as.character(tree$i.to)]) # 过滤NA的边长度 edge_lengths = tree$dt[!is.na(tree$dt)] # 构建phylo对象 correct_phylo = list( edge = edge_matrix, tip.label = as.character(leaf_nodes), Nnode = length(internal_nodes), edge.length = edge_lengths ) class(correct_phylo) = "phylo"
- 用
ggtree绘制时间轴树:
install.packages("ggtree") library(ggtree) # 计算每个节点的累计时间 node_times = numeric(length(nodes)) names(node_times) = nodes node_times["0"] = 0 for (i in seq(nrow(tree))[-1]) { node_times[as.character(tree$i.to[i])] = node_times[as.character(tree$i.fr[i])] + tree$dt[i] } # 绘制时将x轴映射为节点时间 ggtree(correct_phylo, aes(x = node_times[as.character(node)])) + geom_tiplab() + geom_nodelab() + scale_x_continuous(name = "时间t") + theme_tree2()
内容的提问来源于stack exchange,提问作者jessexknight
相关产品推荐
相关产品推荐

