Files

177 lines
5.0 KiB
R
Raw Permalink Normal View History

#!/usr/bin/env Rscript
## ===================== 1. 解析命令行参数 =====================
args <- commandArgs(trailingOnly = TRUE)
if (length(args) < 2) {
stop("用法: Rscript tree_plot.R <treefile> <subfamily_file> [output_pdf] [x_max]\n",
call. = FALSE)
}
treefile <- args[1]
subfamily_file <- args[2]
## 第三个参数:输出 pdf 名称(可选)
if (length(args) >= 3) {
output_pdf <- args[3]
} else {
## 如果没给,就用树文件名去掉后缀自动生成
output_pdf <- sub("\\.[^.]*$", "", treefile)
output_pdf <- paste0(output_pdf, ".pdf")
}
## 第四个参数:x 轴最大值(可选)
if (length(args) >= 4) {
x_max <- as.numeric(args[4])
} else {
x_max <- 18
}
cat("树文件: ", treefile, "\n")
cat("亚家族文件: ", subfamily_file, "\n")
cat("输出文件: ", output_pdf, "\n")
cat("x_max: ", x_max, "\n")
## ===================== 2. 加载所需 R 包 =====================
suppressPackageStartupMessages({
library(ape)
library(ggtree)
library(tidytree)
library(dplyr)
library(RColorBrewer)
library(ggplot2)
})
## ===================== 3. 封装绘图函数 =====================
plot_iqtree_by_subfamily <- function(treefile, subfamily_file, x_max = 18) {
## ---------- 3.1 读树 ----------
tree <- read.tree(treefile)
## 转成 tibble(tidytree::as_tibble)
tree_df <- as_tibble(tree)
## 手动添加 isTip 列:phylo 对象中,1:Ntip 是叶节点
tree_df$isTip <- tree_df$node <= length(tree$tip.label)
## ---------- 3.2 读亚家族文件 ----------
## 格式: 两列,无表头:geneID subfamily
subfam <- read.table(subfamily_file,
header = FALSE,
stringsAsFactors = FALSE)
colnames(subfam) <- c("label", "subfamily") # label 要与树的 tip.label 对应
## ---------- 3.3 生成 support 列 ----------
## 只给内部节点算 bootstrap,tip 为 NA
tree_df$support <- ifelse(
tree_df$isTip,
NA_real_,
suppressWarnings(as.numeric(tree_df$label))
)
## ---------- 3.4 合并 subfamily 信息到 tree_df ----------
tree_df <- dplyr::left_join(tree_df, subfam, by = "label")
## ---------- 3.5 自动配色(按 subfamily) ----------
subfam_levels <- sort(unique(subfam$subfamily))
n_subfam <- length(subfam_levels)
if (n_subfam == 0) {
stop("在亚家族文件中没有检测到任何 subfamily,请检查文件格式。", call. = FALSE)
}
## Set1 最多 9 个颜色;至少 3 个颜色
n_col <- max(3, min(n_subfam, 9))
base_cols <- RColorBrewer::brewer.pal(n_col, "Set1")
subfam_cols <- setNames(base_cols[seq_len(n_subfam)], subfam_levels)
## ---------- 3.6 计算每个 subfamily 的 clade 根节点 node ----------
## 使用 getMRCA,若某 subfamily 只有 1 条基因,则用它自己的 tip 节点
node_subfam <- subfam %>%
dplyr::group_by(subfamily) %>%
dplyr::summarise(
node = {
tips <- label
if (length(tips) == 1) {
which(tree$tip.label == tips)
} else {
getMRCA(tree, tips)
}
},
.groups = "drop"
)
## ---------- 3.7 构建 ggtree 图 ----------
p <- ggtree(tree, branch.length = "none") %<+% tree_df +
## 节点 bootstrap 支持度
geom_nodepoint(
aes(fill = cut(support, c(0, 50, 75, 100))),
shape = 21,
size = 2,
na.rm = TRUE
) +
scale_fill_manual(
values = c("black", "grey", "white"),
guide = "legend",
name = "Bootstrap Percentage (BP)",
breaks = c("(75,100]", "(50,75]", "(0,50]"),
labels = expression(BP > 75,
50 < BP * "<=75",
BP <= 50)
) +
## tip 按亚家族上色
geom_tippoint(
aes(color = subfamily),
size = 2,
na.rm = TRUE
) +
scale_color_manual(
values = subfam_cols,
name = "Subfamily"
) +
## 叶子标签(基因 ID)
geom_tiplab(offset = 0.5, size = 3) +
## 标题 & x 轴范围
ggtitle("Phylogenetic Tree") +
xlim(NA, x_max) +
theme_tree() +
theme(
plot.title = element_text(hjust = 0.5),
legend.background = element_rect(color = "#969696",
fill = "#d9d9d9")
)
## ---------- 3.8 给每个 subfamily 添加 clade 标签 ----------
for (i in seq_len(nrow(node_subfam))) {
this_sub <- node_subfam$subfamily[i]
this_node <- node_subfam$node[i]
this_col <- subfam_cols[[this_sub]]
p <- p +
geom_cladelab(
node = this_node,
label = this_sub,
align = TRUE,
angle = 270,
offset = 6.5,
offset.text = 1,
textcolor = this_col,
barcolor = this_col,
barsize = 1.5,
extend = 0.7
)
}
return(p)
}
## ===================== 4. 调用函数并保存图像 =====================
p <- plot_iqtree_by_subfamily(treefile, subfamily_file, x_max = x_max)
ggsave(output_pdf, p, width = 8, height = 10)
cat("已输出图像到: ", output_pdf, "\n")