我想构建一个“经典”圆形树状图,例如本文答案中显示的那些https://biology.stackexchange.com/questions/14152/how-should-i-put-a-large -使用 R 进行系统发育到科学论文(我相当习惯 R,但到目前为止我从未做过这样的情节)。
我正在使用环境元条形码数据(多操作分类单位,MOTU)。这些是 DNA 序列,每个序列都被识别到一定的分类水平,并分配给它。我正在考虑构建这样一个图的结果数据是每个 MOTU 的分类“路径”,因此是分类分配的序列,例如界;目;类;科;属;物种(下面的示例)。
我尝试过使用
igraph
包构建此图的不同方法,但都不太令人满意。此代码的大部分基于 ```metabaR`` 包 (https://github.com/metabaRfactory/metabaR) 包中的
ggtaxplot
函数。
我认为我可以从这两种方法中得到我想要的东西,但我不确定它们中的任何一种是否真的是有效的方法。非常感谢任何帮助!
我并不完全愿意继续使用 igraph,我可以使用任何其他类似 ggplot 的方法(因为我希望在绘图上添加更多信息,例如标签、颜色)。
非常感谢!
所有这些代码都在 Ubuntu 22.04.2 上的 R 4.2.1 上运行
path <- c("root@no rank:Eukaryota@superkingdom:Opisthokonta@clade:Fungi@kingdom:Fungi incertae sedis@no rank:Mucoromycota@phylum:Mortierellomycotina@subphylum:Mortierellomycetes@class:Mortierellales@order:Mortierellaceae@family:Mortierella@genus:unclassified Mortierella@no rank",
"root@no rank:Eukaryota@superkingdom:Opisthokonta@clade:Fungi@kingdom:Dikarya@subkingdom:Ascomycota@phylum:saccharomyceta@clade:Pezizomycotina@subphylum:leotiomyceta@clade:sordariomyceta@clade:Sordariomycetes@class:Xylariomycetidae@subclass:Xylariales@order:unclassified Xylariales@no rank:Xylariales sp.@species",
"root@no rank:Eukaryota@superkingdom:Opisthokonta@clade:Fungi@kingdom:Fungi incertae sedis@no rank:Mucoromycota@phylum:Mortierellomycotina@subphylum:Mortierellomycetes@class:Mortierellales@order:Mortierellaceae@family:Linnemannia@genus:Linnemannia zychae@species",
"root@no rank:Eukaryota@superkingdom:Opisthokonta@clade:Fungi@kingdom:Fungi incertae sedis@no rank:Mucoromycota@phylum:Mortierellomycotina@subphylum:Mortierellomycetes@class:Mortierellales@order:Mortierellaceae@family",
"root@no rank:Eukaryota@superkingdom:Opisthokonta@clade:Fungi@kingdom:Dikarya@subkingdom:Ascomycota@phylum:saccharomyceta@clade:Pezizomycotina@subphylum:leotiomyceta@clade:sordariomyceta@clade:Sordariomycetes@class:Hypocreomycetidae@subclass:Hypocreales@order",
"root@no rank:Eukaryota@superkingdom:Opisthokonta@clade:Fungi@kingdom:Dikarya@subkingdom:Ascomycota@phylum:saccharomyceta@clade:Pezizomycotina@subphylum:leotiomyceta@clade:sordariomyceta@clade:Leotiomycetes@class:Helotiales@order",
"root@no rank:Eukaryota@superkingdom:Opisthokonta@clade:Fungi@kingdom:Dikarya@subkingdom:Ascomycota@phylum:saccharomyceta@clade:Pezizomycotina@subphylum:leotiomyceta@clade:dothideomyceta@clade:Dothideomycetes@class:Pleosporomycetidae@subclass:Pleosporales@order",
"root@no rank:Eukaryota@superkingdom:Opisthokonta@clade:Fungi@kingdom:Dikarya@subkingdom:Ascomycota@phylum:saccharomyceta@clade:Pezizomycotina@subphylum:leotiomyceta@clade:sordariomyceta@clade:Leotiomycetes@class:Helotiales@order"
)
我尝试过使用
igraph
包构建此图的不同方法,但都不太令人满意。此代码的大部分基于 ```metabaR`` 包 (https://github.com/metabaRfactory/metabaR) 包中的
ggtaxplot
函数:
library(metabaR)
library(magrittr)
library(igraph)
library(ggraph)
# Formatting taxonomic information from path
sep.level = ":"; sep.info = "@"
parse <- unname(taxoparser(path, sep.level, sep.info)) %>%
lapply(X =., FUN = function(x){ x <- x[names(x) %in% c("kingdom", "phylum", "class", "order", "family", "genus", "species")]})
path <- sapply(parse, toString)
parse <- strsplit(path, ", ")
parse.mat <- do.call(rbind, lapply(parse, `length<-`, max(lengths(parse))))
# Building edgelist
edgelist <- NULL
for (i in rev(2:ncol(parse.mat))) {
idx <- which(!is.na(parse.mat[, i]))
kid <- parse.mat[idx, i]
parent <- parse.mat[idx, (i - 1)]
kidfull <- apply(parse.mat[idx, 1:i, drop = F], 1, toString)
parentfull <- apply(parse.mat[idx, 1:(i - 1), drop = F], 1, toString)
edgelist <- rbind(
edgelist,
unique(cbind(
parentfull,
kidfull,
parent, kid
))
)
}
这是我的第一次尝试,使用 ggraph :
# first attempt, using ggraph
mygraph <- graph_from_data_frame( edgelist[,c("parent", "kid")] )
ggraph(mygraph, layout = 'dendrogram', circular = TRUE) +
geom_edge_elbow() +
geom_node_point() +
theme_void()
我喜欢这个图的“外观”,但树状图的所有叶子最终都具有相同的 y 值,而我想展示不同的分类级别。
#second attemp, using igraph
g <- igraph::graph.edgelist(edgelist[rev(1:nrow(edgelist)),
c("parentfull", "kidfull")], directed = F)
# Rename nodes with kid names
igraph::V(g)$name2 <- ifelse(igraph::V(g)$name %in% edgelist[, "parent"],
igraph::V(g)$name,
edgelist[match(igraph::V(g)$name, edgelist[, "kidfull"]), "kid"]
)
# extracting info from igraph object
coords <- layout_as_tree(g, root=1, circular = F, rootlevel = numeric(), mode = "out", flip.y = TRUE)
colnames(coords) <- c("x", "y")
vdf <- data.frame(as.data.frame(get.vertex.attribute(g)), coords)
#vdf$angle <- { 90 - as.numeric(rownames(vdf)) * 360 / nrow(vdf)}
# add segments
edf <- get.data.frame(g)
edf$from.x <- vdf$x[match(edf$from, as.vector(vdf$name))]
edf$from.y <- vdf$y[match(edf$from, as.vector(vdf$name))]
edf$to.x <- vdf$x[match(edf$to, as.vector(vdf$name))]
edf$to.y <- vdf$y[match(edf$to, as.vector(vdf$name))]
ggplot(data = vdf, aes(x = .data$x, y = -.data$y)) +
geom_segment(
data = edf,
aes(
x = .data$from.x, xend = .data$to.x,
y = -.data$from.y, yend = -.data$to.y
), size = 0.2, colour = "grey"
) +
geom_point() +
scale_color_viridis_c() +
theme_void() +
coord_polar() +
geom_text(aes(label = .data$name2),
color = "darkgrey", show.legend = FALSE, hjust = 1)
这里,情节的结构很好,但我不喜欢情节的“网络”外观(曲线),在我看来,这使得层次之间的关系不清楚。
我认为你不应该放弃
ggraph
方法。您的主要问题似乎是您的叶节点绘制在错误的深度。然而,在创建绘图布局时,计算节点深度并将其传递给 height
参数是很简单的。为了使图像更清晰一些,我添加了圆圈来指示毒理学水平:
library(tidygraph)
as_tbl_graph(mygraph) %>%
mutate(depth = node_distance_from(which(node_is_root()))) %>%
ggraph(layout = 'dendrogram', height = -depth, circular = TRUE) +
ggforce::geom_circle(aes(x0 = 0, y0 = 0 , r = r), color = 'gray90',
data = data.frame(r = seq(0, 1, 1/6))) +
geom_edge_elbow() +
geom_node_point() +
theme_void()