901 lines
33 KiB
R
901 lines
33 KiB
R
#!/usr/bin/env Rscript
|
||||
|
|
# 启动子元件与进化树组合绘图 - 修复short_desc列问题
|
|||
|
|
|
|||
|
|
# 清理环境
|
|||
|
|
rm(list = ls())
|
|||
|
|
|
|||
|
|
####----加载R包----####
|
|||
|
|
required_packages <- c("tidyverse", "readxl", "writexl", "ggh4x",
|
|||
|
|
"ggtree", "treeio", "ape", "patchwork", "aplot", "RColorBrewer", "ggnewscale")
|
|||
|
|
missing_packages <- required_packages[!required_packages %in% installed.packages()[,"Package"]]
|
|||
|
|
if(length(missing_packages) > 0) {
|
|||
|
|
cat("安装缺少的包:", paste(missing_packages, collapse = ", "), "\n")
|
|||
|
|
install.packages(missing_packages, repos = "https://cloud.r-project.org")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
library(tidyverse)
|
|||
|
|
library(readxl)
|
|||
|
|
library(writexl)
|
|||
|
|
library(ggh4x)
|
|||
|
|
library(ggtree)
|
|||
|
|
library(treeio)
|
|||
|
|
library(ape)
|
|||
|
|
library(patchwork)
|
|||
|
|
library(aplot)
|
|||
|
|
library(RColorBrewer)
|
|||
|
|
library(ggnewscale)
|
|||
|
|
|
|||
|
|
####----函数定义:处理元件描述----####
|
|||
|
|
create_short_descriptions <- function(cir_element.desc) {
|
|||
|
|
cir_element.desc %>%
|
|||
|
|
mutate(
|
|||
|
|
description = str_trim(description),
|
|||
|
|
description = str_replace_all(description, '""', '"'),
|
|||
|
|
|
|||
|
|
short_desc = case_when(
|
|||
|
|
element == "Myb-binding site" ~ "Myb-site (RNR1b, cell cycle)",
|
|||
|
|
element == "MYB recognition site" ~ "MYB-site (ProDH, dehydration)",
|
|||
|
|
element == "CCGTCC motif" ~ "CCGTCC motif (H3, S-phase)",
|
|||
|
|
|
|||
|
|
str_detect(description, "^cis-acting element involved in the abscisic acid") ~ "ABA responsive",
|
|||
|
|
str_detect(description, "^cis-acting regulatory element involved in light") ~ "Light responsive",
|
|||
|
|
str_detect(description, "^cis-acting element involved in low-temperature") ~ "Cold responsive",
|
|||
|
|
str_detect(description, "^cis-acting element involved in defense and stress") ~ "Stress responsive",
|
|||
|
|
str_detect(description, "^cis-acting regulatory element involved in seed-specific") ~ "Seed specific",
|
|||
|
|
str_detect(description, "^cis-acting element involved in gibberellin") ~ "GA responsive",
|
|||
|
|
str_detect(description, "^cis-acting element involved in salicylic acid") ~ "SA responsive",
|
|||
|
|
str_detect(description, "^cis-acting regulatory element involved in the MeJA") ~ "JA responsive",
|
|||
|
|
str_detect(description, "^cis-acting element involved in auxin") ~ "Auxin responsive",
|
|||
|
|
|
|||
|
|
str_detect(description, "MYB binding site involved") ~ {
|
|||
|
|
extracted <- str_extract(description, "MYB binding site involved in .+? regulation")
|
|||
|
|
ifelse(is.na(extracted), description, str_replace(extracted, "MYB binding site involved in ", ""))
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
TRUE ~ {
|
|||
|
|
sapply(description, function(desc) {
|
|||
|
|
first_sent <- str_extract(desc, "^[^.]+\\.?")
|
|||
|
|
|
|||
|
|
if (!is.na(first_sent) && nchar(first_sent) > 50) {
|
|||
|
|
words <- str_split(first_sent, " ")[[1]]
|
|||
|
|
if (length(words) >= 6) {
|
|||
|
|
paste(paste(words[1:6], collapse = " "), "...")
|
|||
|
|
} else {
|
|||
|
|
substr(first_sent, 1, 50)
|
|||
|
|
}
|
|||
|
|
} else if (is.na(first_sent)) {
|
|||
|
|
if (nchar(desc) > 40) {
|
|||
|
|
paste0(substr(desc, 1, 40), "...")
|
|||
|
|
} else {
|
|||
|
|
desc
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
first_sent
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
short_desc = ifelse(nchar(short_desc) > 50,
|
|||
|
|
paste0(substr(short_desc, 1, 50), "..."),
|
|||
|
|
short_desc),
|
|||
|
|
|
|||
|
|
# 基于元件名称的分类(优先)+ 基于description的分类(补充)
|
|||
|
|
category = case_when(
|
|||
|
|
# 1. 核心启动子元件 (最高优先级)
|
|||
|
|
str_detect(element, "(?i)TATA|CAAT|Inr|Y-patch") ~ "Core promoter",
|
|||
|
|
|
|||
|
|
# 2. 激素响应元件
|
|||
|
|
str_detect(element, "(?i)ABRE") ~ "ABA signaling",
|
|||
|
|
str_detect(element, "(?i)P-box|Py-box|GARE") ~ "GA signaling",
|
|||
|
|
str_detect(element, "(?i)CGTCA|TGACG") ~ "JA signaling",
|
|||
|
|
str_detect(element, "(?i)TCA|as-1") ~ "SA signaling",
|
|||
|
|
str_detect(element, "(?i)TGA|AuxRE") ~ "Auxin response",
|
|||
|
|
str_detect(element, "(?i)ERE") ~ "Ethylene response",
|
|||
|
|
|
|||
|
|
# 3. 胁迫响应元件
|
|||
|
|
str_detect(element, "(?i)DRE|CRT|LTR|ARE|STRE|WRE|W.box|W-box") ~ "Stress response",
|
|||
|
|
str_detect(element, "(?i)MBS") & str_detect(description, "(?i)drought|stress") ~ "Stress response",
|
|||
|
|
|
|||
|
|
# 4. 转录因子结合位点
|
|||
|
|
str_detect(element, "(?i)^MYB$|^Myb$|MYB-like|MRE") ~ "MYB-related",
|
|||
|
|
str_detect(element, "(?i)^MYC$|E-box|CANNTG") ~ "MYC-related",
|
|||
|
|
str_detect(element, "(?i)WRKY") ~ "WRKY-related",
|
|||
|
|
|
|||
|
|
# 5. 光响应元件
|
|||
|
|
str_detect(element, "(?i)G-box|G-Box|GT1|I-box|Sp1|Box.4|GATA") ~ "Light response",
|
|||
|
|
|
|||
|
|
# 6. 发育调控元件
|
|||
|
|
str_detect(element, "(?i)RY|AAGAA|CAT|GCN4|Skn-1") ~ "Development",
|
|||
|
|
|
|||
|
|
# 7. 基于description的补充分类
|
|||
|
|
str_detect(description, "(?i)abscisic|ABA") ~ "ABA signaling",
|
|||
|
|
str_detect(description, "(?i)gibberellin|GA") ~ "GA signaling",
|
|||
|
|
str_detect(description, "(?i)jasmonate|MeJA|JA") ~ "JA signaling",
|
|||
|
|
str_detect(description, "(?i)salicylic|SA") ~ "SA signaling",
|
|||
|
|
str_detect(description, "(?i)auxin|Aux") ~ "Auxin response",
|
|||
|
|
str_detect(description, "(?i)ethylene") ~ "Ethylene response",
|
|||
|
|
str_detect(description, "(?i)light|Light") ~ "Light response",
|
|||
|
|
str_detect(description, "(?i)drought|dehydration|low.temperature|stress|anaerobic|cold") ~ "Stress response",
|
|||
|
|
str_detect(description, "(?i)seed.specific|endosperm|seed") ~ "Development",
|
|||
|
|
str_detect(description, "(?i)meristem") ~ "Development",
|
|||
|
|
str_detect(description, "(?i)wound|pathogen|defense") ~ "Stress response",
|
|||
|
|
str_detect(description, "(?i)cell.cycle|DNA.synthesis|replication|cell.division") ~ "Cell cycle",
|
|||
|
|
|
|||
|
|
# 8. 其他
|
|||
|
|
TRUE ~ "Other"
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
####----函数:智能读取分组文件----####
|
|||
|
|
read_group_file_smart <- function(file_path) {
|
|||
|
|
cat("尝试读取分组文件:", file_path, "\n")
|
|||
|
|
|
|||
|
|
# 读取第一行判断格式
|
|||
|
|
first_line <- readLines(file_path, n = 1)
|
|||
|
|
|
|||
|
|
# 尝试不同的读取方式
|
|||
|
|
tryCatch({
|
|||
|
|
# 方式1: 制表符分隔(这是最可能的)
|
|||
|
|
df <- read.delim(file_path, header = TRUE, sep = "\t", stringsAsFactors = FALSE,
|
|||
|
|
fileEncoding = "UTF-8", quote = "")
|
|||
|
|
if (ncol(df) >= 2) {
|
|||
|
|
# 检查是否有需要的列
|
|||
|
|
if ("label" %in% colnames(df) && "Subgroup" %in% colnames(df)) {
|
|||
|
|
cat("成功以制表符读取,找到label和Subgroup列\n")
|
|||
|
|
return(df)
|
|||
|
|
} else {
|
|||
|
|
# 尝试自动重命名
|
|||
|
|
if (length(colnames(df)) >= 2) {
|
|||
|
|
colnames(df)[1:2] <- c("label", "Subgroup")
|
|||
|
|
cat("自动重命名列为: label, Subgroup\n")
|
|||
|
|
return(df)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}, error = function(e) {
|
|||
|
|
cat("制表符读取失败:", e$message, "\n")
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
tryCatch({
|
|||
|
|
# 方式2: 空格分隔
|
|||
|
|
df <- read.table(file_path, header = TRUE, stringsAsFactors = FALSE,
|
|||
|
|
fileEncoding = "UTF-8")
|
|||
|
|
if (ncol(df) >= 2) {
|
|||
|
|
# 检查是否有需要的列
|
|||
|
|
if ("label" %in% colnames(df) && "Subgroup" %in% colnames(df)) {
|
|||
|
|
cat("成功以空格读取,找到label和Subgroup列\n")
|
|||
|
|
return(df)
|
|||
|
|
} else {
|
|||
|
|
# 尝试自动重命名
|
|||
|
|
if (length(colnames(df)) >= 2) {
|
|||
|
|
colnames(df)[1:2] <- c("label", "Subgroup")
|
|||
|
|
cat("自动重命名列为: label, Subgroup\n")
|
|||
|
|
return(df)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}, error = function(e) {
|
|||
|
|
cat("空格读取失败:", e$message, "\n")
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
# 如果所有方法都失败,尝试读取原始内容并解析
|
|||
|
|
cat("尝试方式3: 读取原始内容并解析\n")
|
|||
|
|
lines <- readLines(file_path, encoding = "UTF-8")
|
|||
|
|
|
|||
|
|
# 删除空行
|
|||
|
|
lines <- lines[lines != ""]
|
|||
|
|
|
|||
|
|
# 解析每一行
|
|||
|
|
parsed_data <- lapply(lines, function(line) {
|
|||
|
|
# 尝试分割:先按制表符,再按多个空格
|
|||
|
|
parts <- str_split(line, "\t")[[1]]
|
|||
|
|
if (length(parts) < 2) {
|
|||
|
|
parts <- str_split(line, "\\s+")[[1]]
|
|||
|
|
}
|
|||
|
|
return(parts)
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
# 提取列名和数据
|
|||
|
|
col_names <- parsed_data[[1]]
|
|||
|
|
data_rows <- parsed_data[-1]
|
|||
|
|
|
|||
|
|
# 创建数据框
|
|||
|
|
df <- as.data.frame(do.call(rbind, data_rows), stringsAsFactors = FALSE)
|
|||
|
|
colnames(df) <- col_names
|
|||
|
|
|
|||
|
|
# 确保有两列
|
|||
|
|
if (ncol(df) >= 2) {
|
|||
|
|
# 重命名为标准列名
|
|||
|
|
if (ncol(df) == 2) {
|
|||
|
|
colnames(df) <- c("label", "Subgroup")
|
|||
|
|
} else {
|
|||
|
|
# 只取前两列
|
|||
|
|
df <- df[, 1:2]
|
|||
|
|
colnames(df) <- c("label", "Subgroup")
|
|||
|
|
cat("只取前两列作为label和Subgroup\n")
|
|||
|
|
}
|
|||
|
|
cat("成功解析文件\n")
|
|||
|
|
return(df)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
stop("无法解析分组文件,请检查文件格式")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
####----命令行参数处理----####
|
|||
|
|
args <- commandArgs(trailingOnly = TRUE)
|
|||
|
|
|
|||
|
|
if (length(args) < 1 || args[1] %in% c("-h", "--help")) {
|
|||
|
|
cat("
|
|||
|
|
启动子元件与进化树组合绘图
|
|||
|
|
|
|||
|
|
用法:
|
|||
|
|
Rscript promoter_analysis.R [树文件] [分组文件] [启动子文件] [元件描述文件] [输出前缀]
|
|||
|
|
|
|||
|
|
示例:
|
|||
|
|
Rscript promoter_analysis.R tree.nwk groups.txt promoter.tab elements.csv my_analysis
|
|||
|
|
Rscript promoter_analysis.R tree.nwk groups.txt NA elements.csv my_analysis # 无启动子数据
|
|||
|
|
|
|||
|
|
")
|
|||
|
|
quit(save = "no", status = 0)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 解析命令行参数
|
|||
|
|
cat("=== 解析命令行参数 ===\n")
|
|||
|
|
cat("接收到的参数数量:", length(args), "\n")
|
|||
|
|
|
|||
|
|
# 设置默认值
|
|||
|
|
tree_file <- NULL
|
|||
|
|
group_file <- NULL
|
|||
|
|
promoter_file <- NULL
|
|||
|
|
element_desc_file <- NULL
|
|||
|
|
output_prefix <- "output"
|
|||
|
|
|
|||
|
|
# 根据参数数量分配
|
|||
|
|
if (length(args) >= 1) tree_file <- args[1]
|
|||
|
|
if (length(args) >= 2) group_file <- args[2]
|
|||
|
|
if (length(args) >= 3) promoter_file <- ifelse(args[3] == "NA", NULL, args[3])
|
|||
|
|
if (length(args) >= 4) element_desc_file <- args[4]
|
|||
|
|
if (length(args) >= 5) output_prefix <- args[5]
|
|||
|
|
|
|||
|
|
cat("参数设置:\n")
|
|||
|
|
cat(" 树文件:", ifelse(is.null(tree_file), "未指定", tree_file), "\n")
|
|||
|
|
cat(" 分组文件:", ifelse(is.null(group_file), "未指定", group_file), "\n")
|
|||
|
|
cat(" 启动子文件:", ifelse(is.null(promoter_file), "未指定", promoter_file), "\n")
|
|||
|
|
cat(" 元件描述文件:", ifelse(is.null(element_desc_file), "未指定", element_desc_file), "\n")
|
|||
|
|
cat(" 输出前缀:", output_prefix, "\n\n")
|
|||
|
|
|
|||
|
|
####----检查必需文件----####
|
|||
|
|
# 检查树文件
|
|||
|
|
if (is.null(tree_file) || !file.exists(tree_file)) {
|
|||
|
|
stop("错误: 树文件不存在或未指定。请提供有效的树文件路径。")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 检查分组文件
|
|||
|
|
if (is.null(group_file) || !file.exists(group_file)) {
|
|||
|
|
stop("错误: 分组文件不存在或未指定。请提供有效的分组文件路径。")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
####----加载数据----####
|
|||
|
|
|
|||
|
|
# 1. 读取进化树文件
|
|||
|
|
cat("=== 步骤1: 读取进化树文件 ===\n")
|
|||
|
|
cat("读取文件:", tree_file, "\n")
|
|||
|
|
tree <- treeio::read.newick(file = tree_file, node.label = "support")
|
|||
|
|
|
|||
|
|
# 清理基因ID
|
|||
|
|
tree_clean <- as_tibble(tree) %>%
|
|||
|
|
dplyr::mutate(
|
|||
|
|
label = str_trim(label),
|
|||
|
|
label = str_remove(label, pattern = "\\.\\d+\\.T\\d+$"),
|
|||
|
|
label = str_remove(label, pattern = "\\.T\\d+$"),
|
|||
|
|
label = str_remove(label, pattern = "\\.\\d+$")
|
|||
|
|
) %>%
|
|||
|
|
as.treedata()
|
|||
|
|
|
|||
|
|
# 2. 读取分组文件(使用智能读取函数)
|
|||
|
|
cat("\n=== 步骤2: 读取分组文件 ===\n")
|
|||
|
|
group_df <- read_group_file_smart(group_file)
|
|||
|
|
|
|||
|
|
# 清理分组文件中的基因ID
|
|||
|
|
group_df <- group_df %>%
|
|||
|
|
mutate(
|
|||
|
|
label = str_trim(label),
|
|||
|
|
label = str_remove(label, pattern = "\\.\\d+\\.T\\d+$"),
|
|||
|
|
label = str_remove(label, pattern = "\\.T\\d+$"),
|
|||
|
|
label = str_remove(label, pattern = "\\.\\d+$"),
|
|||
|
|
Subgroup = str_trim(Subgroup)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
cat("分组统计:\n")
|
|||
|
|
print(table(group_df$Subgroup))
|
|||
|
|
|
|||
|
|
# 3. 检查基因ID匹配
|
|||
|
|
cat("\n=== 检查基因ID匹配 ===\n")
|
|||
|
|
tree_labels <- tree_clean@phylo$tip.label
|
|||
|
|
group_labels <- group_df$label
|
|||
|
|
|
|||
|
|
common_genes <- intersect(tree_labels, group_labels)
|
|||
|
|
cat("树中基因数量:", length(tree_labels), "\n")
|
|||
|
|
cat("分组文件中基因数量:", length(group_labels), "\n")
|
|||
|
|
cat("匹配的基因数量:", length(common_genes), "\n")
|
|||
|
|
|
|||
|
|
if (length(common_genes) == 0) {
|
|||
|
|
stop("错误: 树和分组文件没有共同的基因ID!")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 只保留匹配的基因
|
|||
|
|
group_df <- group_df %>%
|
|||
|
|
filter(label %in% common_genes)
|
|||
|
|
|
|||
|
|
# 3. 读取启动子元件数据(如果有)
|
|||
|
|
promoter_data_exists <- FALSE
|
|||
|
|
if (!is.null(promoter_file) && file.exists(promoter_file)) {
|
|||
|
|
cat("\n=== 步骤3: 读取启动子元件数据 ===\n")
|
|||
|
|
cat("读取文件:", promoter_file, "\n")
|
|||
|
|
|
|||
|
|
promoter <- tryCatch({
|
|||
|
|
data.table::fread(
|
|||
|
|
file = promoter_file,
|
|||
|
|
header = FALSE,
|
|||
|
|
sep = "\t",
|
|||
|
|
stringsAsFactors = FALSE
|
|||
|
|
)
|
|||
|
|
}, error = function(e) {
|
|||
|
|
cat("读取启动子文件时出错:", e$message, "\n")
|
|||
|
|
return(NULL)
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
if (!is.null(promoter) && ncol(promoter) >= 8) {
|
|||
|
|
promoter <- promoter %>%
|
|||
|
|
dplyr::select(1, 2, 8) %>%
|
|||
|
|
purrr::set_names("X1", "X2", "X3") %>%
|
|||
|
|
dplyr::filter(!str_detect(X2, pattern = "Unname")) %>%
|
|||
|
|
dplyr::filter(!is.na(X2)) %>%
|
|||
|
|
dplyr::filter(!str_detect(X3, "short_function")) %>%
|
|||
|
|
dplyr::mutate(
|
|||
|
|
X1 = str_trim(X1),
|
|||
|
|
X1 = str_remove(string = X1, pattern = "\\.\\d+\\.T\\d+$"),
|
|||
|
|
X1 = str_remove(string = X1, pattern = "\\.T\\d+$"),
|
|||
|
|
X1 = str_remove(string = X1, pattern = "\\.\\d+$")
|
|||
|
|
) %>%
|
|||
|
|
filter(X1 %in% tree_labels)
|
|||
|
|
|
|||
|
|
cat("启动子数据行数:", nrow(promoter), "\n")
|
|||
|
|
|
|||
|
|
if (nrow(promoter) > 0) {
|
|||
|
|
promoter_data_exists <- TRUE
|
|||
|
|
cat("启动子数据可用\n")
|
|||
|
|
} else {
|
|||
|
|
cat("警告: 启动子数据中没有与树匹配的基因\n")
|
|||
|
|
promoter <- NULL
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
cat("警告: 启动子文件列数不足或读取失败,跳过启动子分析\n")
|
|||
|
|
promoter <- NULL
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
cat("\n=== 步骤3: 无启动子文件,跳过启动子分析 ===\n")
|
|||
|
|
promoter <- NULL
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 4. 读取或生成元件描述文件
|
|||
|
|
if (promoter_data_exists) {
|
|||
|
|
if (!is.null(element_desc_file) && file.exists(element_desc_file)) {
|
|||
|
|
cat("\n=== 步骤4: 读取元件描述文件 ===\n")
|
|||
|
|
cat("读取文件:", element_desc_file, "\n")
|
|||
|
|
|
|||
|
|
# 根据文件扩展名选择读取方式
|
|||
|
|
file_ext <- tools::file_ext(element_desc_file)
|
|||
|
|
|
|||
|
|
if (file_ext == "csv") {
|
|||
|
|
cir_element.desc <- read.csv(element_desc_file, stringsAsFactors = FALSE)
|
|||
|
|
} else if (file_ext %in% c("xls", "xlsx")) {
|
|||
|
|
cir_element.desc <- read_xlsx(element_desc_file)
|
|||
|
|
} else {
|
|||
|
|
cir_element.desc <- read.delim(element_desc_file, stringsAsFactors = FALSE)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 检查列名
|
|||
|
|
if (!"element" %in% names(cir_element.desc)) {
|
|||
|
|
if (any(grepl("element|name|motif", names(cir_element.desc), ignore_case = TRUE))) {
|
|||
|
|
element_col <- names(cir_element.desc)[grepl("element|name|motif", names(cir_element.desc), ignore_case = TRUE)][1]
|
|||
|
|
names(cir_element.desc)[names(cir_element.desc) == element_col] <- "element"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!"description" %in% names(cir_element.desc)) {
|
|||
|
|
if (any(grepl("description|desc|function", names(cir_element.desc), ignore_case = TRUE))) {
|
|||
|
|
desc_col <- names(cir_element.desc)[grepl("description|desc|function", names(cir_element.desc), ignore_case = TRUE)][1]
|
|||
|
|
names(cir_element.desc)[names(cir_element.desc) == desc_col] <- "description"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 处理描述,创建简短标签和分类
|
|||
|
|
cir_element.desc <- create_short_descriptions(cir_element.desc)
|
|||
|
|
|
|||
|
|
# 保存处理后的元件描述
|
|||
|
|
write_xlsx(cir_element.desc, paste0(output_prefix, "_element_descriptions.xlsx"))
|
|||
|
|
cat("已保存处理后的元件描述到:", paste0(output_prefix, "_element_descriptions.xlsx"), "\n")
|
|||
|
|
|
|||
|
|
# 合并描述信息到promoter数据
|
|||
|
|
promoter <- promoter %>%
|
|||
|
|
left_join(cir_element.desc, by = c("X2" = "element"))
|
|||
|
|
|
|||
|
|
# 移除没有描述的行
|
|||
|
|
promoter <- promoter[!is.na(promoter$description), ]
|
|||
|
|
|
|||
|
|
if (nrow(promoter) == 0) {
|
|||
|
|
cat("警告: 合并后没有数据,跳过启动子分析\n")
|
|||
|
|
promoter_data_exists <- FALSE
|
|||
|
|
} else {
|
|||
|
|
# 保存合并后的promoter数据用于调试
|
|||
|
|
write.csv(promoter, paste0(output_prefix, "_promoter_merged.csv"), row.names = FALSE)
|
|||
|
|
cat("已保存合并后的启动子数据用于调试\n")
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
# 没有描述文件,创建简化版本
|
|||
|
|
cat("\n=== 步骤4: 无元件描述文件,使用简化模式 ===\n")
|
|||
|
|
cat("提示: 如需完整功能描述,请使用 scripts/tiqu_miaoshuwenjian.py 从PlantCARE数据库查询\n")
|
|||
|
|
|
|||
|
|
# 从promoter数据中提取唯一元件列表
|
|||
|
|
unique_elements <- unique(promoter$X2)
|
|||
|
|
cat("发现", length(unique_elements), "个唯一元件\n")
|
|||
|
|
|
|||
|
|
# 创建简化描述表
|
|||
|
|
cir_element.desc <- data.frame(
|
|||
|
|
element = unique_elements,
|
|||
|
|
description = unique_elements,
|
|||
|
|
short_desc = unique_elements,
|
|||
|
|
category = "Other",
|
|||
|
|
stringsAsFactors = FALSE
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 合并到promoter数据
|
|||
|
|
promoter <- promoter %>%
|
|||
|
|
left_join(cir_element.desc, by = c("X2" = "element"))
|
|||
|
|
|
|||
|
|
# 保存简化描述
|
|||
|
|
write_xlsx(cir_element.desc, paste0(output_prefix, "_element_descriptions_simple.xlsx"))
|
|||
|
|
cat("已保存简化元件描述到:", paste0(output_prefix, "_element_descriptions_simple.xlsx"), "\n")
|
|||
|
|
}
|
|||
|
|
} else if (promoter_data_exists) {
|
|||
|
|
cat("\n警告: 有启动子数据但无元件描述文件,无法进行功能分类\n")
|
|||
|
|
promoter_data_exists <- FALSE
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
####----绘制进化树----####
|
|||
|
|
cat("\n=== 绘制进化树 ===\n")
|
|||
|
|
|
|||
|
|
# 确定亚家族数量和颜色
|
|||
|
|
subgroups <- unique(group_df$Subgroup)
|
|||
|
|
|
|||
|
|
# 定义颜色方案
|
|||
|
|
subgroup_colors <- c(
|
|||
|
|
"I" = "#66c2a5", "II" = "#fc8d62", "III" = "#8da0cb", "IV" = "#e78ac3",
|
|||
|
|
"V" = "#a6d854", "VI" = "#ffd92f", "VII" = "#e5c494", "VIII" = "#b3b3b3"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 为存在的亚家族选择颜色
|
|||
|
|
available_colors <- c()
|
|||
|
|
for (sg in subgroups) {
|
|||
|
|
if (sg %in% names(subgroup_colors)) {
|
|||
|
|
available_colors[sg] <- subgroup_colors[sg]
|
|||
|
|
} else {
|
|||
|
|
available_colors[sg] <- "#999999"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 绘制进化树
|
|||
|
|
p.tree <- ggtree(tree_clean, branch.length = "none") %<+% group_df +
|
|||
|
|
geom_tree(aes(color = Subgroup), size = 1.2) +
|
|||
|
|
scale_color_manual(values = available_colors, name = "Subfamily") +
|
|||
|
|
ggnewscale::new_scale_fill() +
|
|||
|
|
geom_nodepoint(
|
|||
|
|
aes(fill = cut(support, c(0, 50, 75, 100))),
|
|||
|
|
shape = 21, size = 3
|
|||
|
|
) +
|
|||
|
|
scale_fill_manual(
|
|||
|
|
values = c("black", "grey", "white"),
|
|||
|
|
guide = "legend",
|
|||
|
|
name = "Bootstrap Percentage",
|
|||
|
|
breaks = c("(75,100]", "(50,75]", "(0,50]"),
|
|||
|
|
labels = c("BP > 75", "50 < BP ≤ 75", "BP ≤ 50")
|
|||
|
|
) +
|
|||
|
|
geom_tiplab(offset = 0.3, size = 3) +
|
|||
|
|
geom_tippoint(aes(x = x + 0.2), shape = 21, fill = "#3690c0", size = 2) +
|
|||
|
|
theme_tree() +
|
|||
|
|
theme(
|
|||
|
|
legend.position = "right",
|
|||
|
|
legend.background = element_rect(color = "#808080", linetype = 1),
|
|||
|
|
legend.box = "vertical",
|
|||
|
|
legend.margin = margin(6, 6, 6, 6)
|
|||
|
|
) +
|
|||
|
|
xlim(NA, 16)
|
|||
|
|
|
|||
|
|
# 保存单独的树图 (PDF + PNG)
|
|||
|
|
tree_output_pdf <- paste0(output_prefix, "_phylogenetic_tree.pdf")
|
|||
|
|
tree_output_png <- paste0(output_prefix, "_phylogenetic_tree.png")
|
|||
|
|
ggsave(filename = tree_output_pdf, plot = p.tree, height = 10, width = 8)
|
|||
|
|
# 使用png()函数直接生成PNG(ggsave在conda环境中有API版本冲突问题)
|
|||
|
|
png(filename = tree_output_png, width = 1200, height = 1500, res = 150)
|
|||
|
|
print(p.tree)
|
|||
|
|
dev.off()
|
|||
|
|
cat("已保存进化树:", tree_output_pdf, "\n")
|
|||
|
|
cat("已保存进化树PNG:", tree_output_png, "\n")
|
|||
|
|
|
|||
|
|
####----绘制启动子热图(如果数据存在)----####
|
|||
|
|
if (promoter_data_exists && nrow(promoter) > 0) {
|
|||
|
|
cat("\n=== 绘制启动子热图 ===\n")
|
|||
|
|
|
|||
|
|
# 获取树中的基因顺序
|
|||
|
|
id_vector <- get_taxa_name(p.tree)
|
|||
|
|
|
|||
|
|
# 筛选元件:移除出现次数太少的元件
|
|||
|
|
element_counts <- promoter %>%
|
|||
|
|
pull(X2) %>%
|
|||
|
|
table() %>%
|
|||
|
|
as_tibble() %>%
|
|||
|
|
purrr::set_names("element", "count") %>%
|
|||
|
|
dplyr::arrange(desc(count))
|
|||
|
|
|
|||
|
|
cat("元件出现次数统计(前20):\n")
|
|||
|
|
print(head(element_counts, 20))
|
|||
|
|
|
|||
|
|
# 保留出现次数>=3的元件
|
|||
|
|
retain_elements <- element_counts %>%
|
|||
|
|
dplyr::filter(count >= 3) %>%
|
|||
|
|
pull(element)
|
|||
|
|
|
|||
|
|
cat(sprintf("保留出现次数>=3的元件: %d个\n", length(retain_elements)))
|
|||
|
|
|
|||
|
|
if (length(retain_elements) == 0) {
|
|||
|
|
cat("警告: 没有元件出现次数>=3,跳过热图绘制\n")
|
|||
|
|
} else {
|
|||
|
|
# 在每个功能类别中,保留出现次数最多的前5个元件
|
|||
|
|
promoter_summary <- promoter %>%
|
|||
|
|
dplyr::filter(X2 %in% retain_elements) %>%
|
|||
|
|
group_by(category, X2) %>%
|
|||
|
|
summarise(count = n(), .groups = 'drop')
|
|||
|
|
|
|||
|
|
promoter_retained <- promoter_summary %>%
|
|||
|
|
group_by(category) %>%
|
|||
|
|
top_n(5, count) %>%
|
|||
|
|
pull(X2) %>%
|
|||
|
|
unique()
|
|||
|
|
|
|||
|
|
cat(sprintf("最终保留元件: %d个\n", length(promoter_retained)))
|
|||
|
|
|
|||
|
|
if (length(promoter_retained) > 0) {
|
|||
|
|
# 准备热图数据 - 关键修复部分
|
|||
|
|
cat("准备热图数据...\n")
|
|||
|
|
|
|||
|
|
# 首先,从promoter数据中提取需要的信息
|
|||
|
|
promoter_filtered <- promoter %>%
|
|||
|
|
dplyr::filter(X2 %in% promoter_retained) %>%
|
|||
|
|
dplyr::select(X1, X2, category, short_desc) %>%
|
|||
|
|
mutate(
|
|||
|
|
X2 = factor(X2, levels = promoter_retained, ordered = TRUE)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 创建所有基因-元件的组合
|
|||
|
|
all_combinations <- expand.grid(
|
|||
|
|
X1 = unique(c(promoter_filtered$X1, id_vector)),
|
|||
|
|
X2 = unique(promoter_filtered$X2),
|
|||
|
|
stringsAsFactors = FALSE
|
|||
|
|
) %>%
|
|||
|
|
mutate(X2 = factor(X2, levels = promoter_retained, ordered = TRUE))
|
|||
|
|
|
|||
|
|
# 汇总每个基因-元件的数量
|
|||
|
|
promoter_counts <- promoter_filtered %>%
|
|||
|
|
group_by(X1, X2, category, short_desc) %>%
|
|||
|
|
summarise(count = n(), .groups = 'drop')
|
|||
|
|
|
|||
|
|
# 合并数据
|
|||
|
|
heatmap_data <- all_combinations %>%
|
|||
|
|
left_join(promoter_counts, by = c("X1", "X2")) %>%
|
|||
|
|
# 从cir_element.desc获取category和short_desc,避免列名冲突
|
|||
|
|
left_join(
|
|||
|
|
cir_element.desc %>%
|
|||
|
|
select(element, category_desc = category, short_desc_element = short_desc),
|
|||
|
|
by = c("X2" = "element")
|
|||
|
|
) %>%
|
|||
|
|
mutate(
|
|||
|
|
count = ifelse(is.na(count), 0, count),
|
|||
|
|
X1 = factor(X1, levels = rev(id_vector), ordered = TRUE),
|
|||
|
|
# 使用promoter数据中的category和short_desc,如果缺失则使用cir_element.desc中的
|
|||
|
|
category = ifelse(is.na(category), category_desc, category),
|
|||
|
|
short_desc = ifelse(is.na(short_desc), short_desc_element, short_desc),
|
|||
|
|
count_cat = cut(
|
|||
|
|
count,
|
|||
|
|
breaks = c(0, 1, 2, 3, 5, 10, 20, 50, 100, 200),
|
|||
|
|
include.lowest = TRUE,
|
|||
|
|
right = FALSE
|
|||
|
|
)
|
|||
|
|
) %>%
|
|||
|
|
select(-category_desc, -short_desc_element) # 删除临时列
|
|||
|
|
|
|||
|
|
# 检查heatmap_data的列
|
|||
|
|
cat("heatmap_data列名:", colnames(heatmap_data), "\n")
|
|||
|
|
cat("short_desc列是否存在:", "short_desc" %in% colnames(heatmap_data), "\n")
|
|||
|
|
cat("category列是否存在:", "category" %in% colnames(heatmap_data), "\n")
|
|||
|
|
cat("heatmap_data行数:", nrow(heatmap_data), "\n")
|
|||
|
|
|
|||
|
|
# 绘制热图
|
|||
|
|
cat("绘制热图...\n")
|
|||
|
|
|
|||
|
|
p.promoter <- ggplot(heatmap_data, aes(x = interaction(X2, short_desc), y = X1)) +
|
|||
|
|
geom_tile(fill = "white", color = "grey80", size = 0.3) +
|
|||
|
|
geom_point(
|
|||
|
|
aes(fill = count_cat),
|
|||
|
|
shape = 22, size = 8
|
|||
|
|
) +
|
|||
|
|
geom_text(aes(label = ifelse(count > 0, count, "")), size = 2.5) +
|
|||
|
|
scale_fill_manual(
|
|||
|
|
values = c(
|
|||
|
|
"[0,1)" = "#f7fbff",
|
|||
|
|
"[1,2)" = "#c6dbef",
|
|||
|
|
"[2,3)" = "#9ecae1",
|
|||
|
|
"[3,5)" = "#6baed6",
|
|||
|
|
"[5,10)" = "#4292c6",
|
|||
|
|
"[10,20)" = "#2171b5",
|
|||
|
|
"[20,50)" = "#08519c",
|
|||
|
|
"[50,100)" = "#08306b",
|
|||
|
|
"[100,200]" = "#041d3a"
|
|||
|
|
),
|
|||
|
|
name = "元件数量",
|
|||
|
|
drop = FALSE
|
|||
|
|
) +
|
|||
|
|
guides(x = "axis_nested") +
|
|||
|
|
labs(x = "", y = "") +
|
|||
|
|
theme_bw() +
|
|||
|
|
theme(
|
|||
|
|
axis.text.x = element_text(
|
|||
|
|
color = "black",
|
|||
|
|
angle = 90,
|
|||
|
|
size = 8,
|
|||
|
|
hjust = 1,
|
|||
|
|
vjust = 0.5
|
|||
|
|
),
|
|||
|
|
axis.text.y = element_text(color = "black", size = 9),
|
|||
|
|
legend.position = "right",
|
|||
|
|
legend.background = element_rect(color = "#808080", linetype = 1),
|
|||
|
|
axis.ticks.length.x.top = unit(0.2, "cm"),
|
|||
|
|
axis.ticks.y = element_blank(),
|
|||
|
|
panel.border = element_blank(),
|
|||
|
|
panel.grid = element_blank(),
|
|||
|
|
plot.margin = unit(c(0.3, 0.3, 0.3, 0.3), "cm")
|
|||
|
|
) +
|
|||
|
|
scale_x_discrete(expand = c(0, 0), position = "top") +
|
|||
|
|
guides(fill = guide_legend(ncol = 1))
|
|||
|
|
|
|||
|
|
# 保存热图 (PDF + PNG) - 单独热图保留
|
|||
|
|
heatmap_output_pdf <- paste0(output_prefix, "_promoter_heatmap.pdf")
|
|||
|
|
heatmap_output_png <- paste0(output_prefix, "_promoter_heatmap.png")
|
|||
|
|
ggsave(filename = heatmap_output_pdf, plot = p.promoter, height = 12, width = 14)
|
|||
|
|
png(filename = heatmap_output_png, width = 2100, height = 1800, res = 150)
|
|||
|
|
print(p.promoter)
|
|||
|
|
dev.off()
|
|||
|
|
cat("已保存启动子热图:", heatmap_output_pdf, "\n")
|
|||
|
|
cat("已保存启动子热图PNG:", heatmap_output_png, "\n")
|
|||
|
|
|
|||
|
|
####----新版组合图:仿Motif风格(三面板布局)----####
|
|||
|
|
cat("\n=== 绘制新版组合图(仿Motif风格)===\n")
|
|||
|
|
|
|||
|
|
# 准备亚家族颜色(与Motif一致使用Dark2)
|
|||
|
|
subfam_levels <- sort(unique(group_df$Subgroup))
|
|||
|
|
n_subfam <- length(subfam_levels)
|
|||
|
|
base_cols_sf <- brewer.pal(8, "Dark2")
|
|||
|
|
subfam_cols_vec <- rep_len(base_cols_sf, n_subfam)
|
|||
|
|
subfam_cols <- setNames(subfam_cols_vec, subfam_levels)
|
|||
|
|
|
|||
|
|
# 从p.tree对象中提取树的坐标数据
|
|||
|
|
tree_dat <- p.tree$data
|
|||
|
|
tip_dat <- tree_dat %>%
|
|||
|
|
filter(isTip) %>%
|
|||
|
|
select(label, x, y) %>%
|
|||
|
|
left_join(group_df %>% select(label, Subgroup), by = "label")
|
|||
|
|
|
|||
|
|
# 计算亚家族范围(Y轴范围)
|
|||
|
|
subfam_ranges <- tip_dat %>%
|
|||
|
|
filter(!is.na(Subgroup)) %>%
|
|||
|
|
group_by(Subgroup) %>%
|
|||
|
|
summarise(
|
|||
|
|
ymin = min(y),
|
|||
|
|
ymax = max(y),
|
|||
|
|
ymid = (ymin + ymax) / 2,
|
|||
|
|
.groups = 'drop'
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 获取树的基本坐标
|
|||
|
|
x_tree_min <- min(tree_dat$x, na.rm = TRUE)
|
|||
|
|
x_tip_max <- max(tip_dat$x, na.rm = TRUE)
|
|||
|
|
max_y <- max(tree_dat$y, na.rm = TRUE)
|
|||
|
|
tree_core_width <- x_tip_max - x_tree_min
|
|||
|
|
|
|||
|
|
# 计算三个面板的X坐标(仿Motif风格)
|
|||
|
|
label_offset <- 0.4
|
|||
|
|
x_label_left <- x_tip_max + label_offset
|
|||
|
|
label_panel_width <- max(1.5, tree_core_width * 0.5)
|
|||
|
|
|
|||
|
|
# Panel A: 树 + gene ID
|
|||
|
|
x_A_left <- x_tree_min
|
|||
|
|
x_A_right <- x_label_left + label_panel_width
|
|||
|
|
|
|||
|
|
# Panel B: 亚家族竖线(中间)
|
|||
|
|
gap1 <- max(0.3, tree_core_width * 0.1)
|
|||
|
|
r_B <- 0.4
|
|||
|
|
x_B_left <- x_A_right + gap1
|
|||
|
|
width_B <- tree_core_width * r_B
|
|||
|
|
x_B_right <- x_B_left + width_B
|
|||
|
|
x_subfam <- (x_B_left + x_B_right) / 2
|
|||
|
|
|
|||
|
|
# Panel C: 启动子热图区域(右侧)
|
|||
|
|
gap2 <- max(0.3, tree_core_width * 0.1)
|
|||
|
|
r_C <- 1.6
|
|||
|
|
x_C_left <- x_B_right + gap2
|
|||
|
|
width_C <- tree_core_width * r_C
|
|||
|
|
x_C_right <- x_C_left + width_C
|
|||
|
|
|
|||
|
|
# 准备热图数据 - 将热图转换为矩形数据
|
|||
|
|
# 为每个基因-元件组合创建矩形
|
|||
|
|
heatmap_rect <- heatmap_data %>%
|
|||
|
|
mutate(
|
|||
|
|
# Y坐标保持与树一致
|
|||
|
|
ymin = as.numeric(X1) - 0.4,
|
|||
|
|
ymax = as.numeric(X1) + 0.4,
|
|||
|
|
# X坐标:将元件位置映射到Panel C
|
|||
|
|
# 计算每个元件在热图中的顺序位置
|
|||
|
|
element_index = as.numeric(factor(interaction(X2, short_desc))),
|
|||
|
|
n_elements = n_distinct(interaction(X2, short_desc)),
|
|||
|
|
# 每个元件占据的宽度
|
|||
|
|
elem_width = width_C / n_elements,
|
|||
|
|
xmin = x_C_left + (element_index - 1) * elem_width,
|
|||
|
|
xmax = x_C_left + element_index * elem_width
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 为不同数量级别设置颜色
|
|||
|
|
count_colors <- c(
|
|||
|
|
"[0,1)" = "#f7fbff",
|
|||
|
|
"[1,2)" = "#c6dbef",
|
|||
|
|
"[2,3)" = "#9ecae1",
|
|||
|
|
"[3,5)" = "#6baed6",
|
|||
|
|
"[5,10)" = "#4292c6",
|
|||
|
|
"[10,20)" = "#2171b5",
|
|||
|
|
"[20,50)" = "#08519c",
|
|||
|
|
"[50,100)" = "#08306b",
|
|||
|
|
"[100,200]" = "#041d3a"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 构建组合图(仿Motif风格)
|
|||
|
|
p_combo <- p.tree +
|
|||
|
|
# Panel B: 亚家族竖线
|
|||
|
|
geom_segment(
|
|||
|
|
data = subfam_ranges,
|
|||
|
|
inherit.aes = FALSE,
|
|||
|
|
aes(x = x_subfam, xend = x_subfam, y = ymin, yend = ymax, colour = Subgroup),
|
|||
|
|
linewidth = 1.5
|
|||
|
|
) +
|
|||
|
|
geom_text(
|
|||
|
|
data = subfam_ranges,
|
|||
|
|
inherit.aes = FALSE,
|
|||
|
|
aes(x = x_subfam + width_B * 0.08, y = ymid, label = Subgroup, colour = Subgroup),
|
|||
|
|
hjust = 0, size = 3.5
|
|||
|
|
) +
|
|||
|
|
scale_color_manual(values = subfam_cols, name = "Subfamily") +
|
|||
|
|
|
|||
|
|
# Panel C: 启动子元件矩形(使用new_scale_fill)
|
|||
|
|
ggnewscale::new_scale_fill() +
|
|||
|
|
geom_rect(
|
|||
|
|
data = heatmap_rect %>% filter(count > 0),
|
|||
|
|
inherit.aes = FALSE,
|
|||
|
|
aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill = count_cat),
|
|||
|
|
color = "grey80", size = 0.2
|
|||
|
|
) +
|
|||
|
|
geom_text(
|
|||
|
|
data = heatmap_rect %>% filter(count > 0),
|
|||
|
|
inherit.aes = FALSE,
|
|||
|
|
aes(x = (xmin + xmax) / 2, y = (ymin + ymax) / 2, label = count),
|
|||
|
|
size = 2, color = "white"
|
|||
|
|
) +
|
|||
|
|
scale_fill_manual(values = count_colors, name = "Element Count", drop = FALSE) +
|
|||
|
|
|
|||
|
|
# 设置坐标范围
|
|||
|
|
coord_cartesian(xlim = c(x_A_left, x_C_right + tree_core_width * 0.1)) +
|
|||
|
|
expand_limits(y = max_y + 1.5) +
|
|||
|
|
|
|||
|
|
# 添加表头
|
|||
|
|
annotate("text", x = (x_A_left + x_A_right) / 2, y = max_y + 1.2,
|
|||
|
|
label = "Phylogenetic tree", fontface = "bold", size = 4) +
|
|||
|
|
annotate("text", x = x_subfam, y = max_y + 1.2,
|
|||
|
|
label = "Subfamily", fontface = "bold", size = 4) +
|
|||
|
|
annotate("text", x = (x_C_left + x_C_right) / 2, y = max_y + 1.2,
|
|||
|
|
label = "Promoter Elements", fontface = "bold", size = 4) +
|
|||
|
|
|
|||
|
|
theme(
|
|||
|
|
legend.position = "right",
|
|||
|
|
legend.background = element_rect(color = "#969696", fill = "#d9d9d9")
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 保存新版组合图
|
|||
|
|
combined_new_pdf <- paste0(output_prefix, "_tree_promoter_combo_new.pdf")
|
|||
|
|
combined_new_png <- paste0(output_prefix, "_tree_promoter_combo_new.png")
|
|||
|
|
|
|||
|
|
ggsave(filename = combined_new_pdf, plot = p_combo, width = 16, height = 14)
|
|||
|
|
png(filename = combined_new_png, width = 4800, height = 4200, res = 300)
|
|||
|
|
print(p_combo)
|
|||
|
|
dev.off()
|
|||
|
|
|
|||
|
|
cat("已保存新版组合图(仿Motif风格):", combined_new_pdf, "\n")
|
|||
|
|
cat("已保存新版组合图PNG:", combined_new_png, "\n")
|
|||
|
|
|
|||
|
|
# 保留旧版组合图生成代码(兼容)
|
|||
|
|
####----旧版组合图(可选)----####
|
|||
|
|
cat("\n=== 同时生成旧版组合图 ===\n")
|
|||
|
|
p.promoter2 <- p.promoter + theme(axis.text.y = element_blank())
|
|||
|
|
combined_plot <- p.promoter2 %>% insert_left(p.tree, width = 0.7)
|
|||
|
|
|
|||
|
|
combined_output_pdf <- paste0(output_prefix, "_tree_promoter_combined.pdf")
|
|||
|
|
combined_output_png <- paste0(output_prefix, "_tree_promoter_combined.png")
|
|||
|
|
ggsave(filename = combined_output_pdf, plot = combined_plot, height = 14, width = 16)
|
|||
|
|
png(filename = combined_output_png, width = 2400, height = 2100, res = 150)
|
|||
|
|
print(combined_plot)
|
|||
|
|
dev.off()
|
|||
|
|
cat("已保存旧版组合图:", combined_output_pdf, "\n")
|
|||
|
|
|
|||
|
|
} else {
|
|||
|
|
cat("\n=== 跳过启动子热图绘制(保留元件不足) ===\n")
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
cat("\n=== 跳过启动子相关绘图(无数据或数据不足) ===\n")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
####----输出统计信息----####
|
|||
|
|
cat("\n===== 分析完成 =====\n")
|
|||
|
|
cat("生成的文件:\n")
|
|||
|
|
cat("1.", tree_output_pdf, "\n")
|
|||
|
|
cat(" ", tree_output_png, "\n")
|
|||
|
|
|
|||
|
|
if (exists("heatmap_output_pdf") && file.exists(heatmap_output_pdf)) {
|
|||
|
|
cat("2.", heatmap_output_pdf, "\n")
|
|||
|
|
cat(" ", heatmap_output_png, "\n")
|
|||
|
|
}
|
|||
|
|
if (exists("combined_output_pdf") && file.exists(combined_output_pdf)) {
|
|||
|
|
cat("3.", combined_output_pdf, "\n")
|
|||
|
|
cat(" ", combined_output_png, "\n")
|
|||
|
|
}
|
|||
|
|
if (exists("combined_new_pdf") && file.exists(combined_new_pdf)) {
|
|||
|
|
cat("3a. 新版组合图(仿Motif风格):", combined_new_pdf, "\n")
|
|||
|
|
cat(" ", combined_new_png, "\n")
|
|||
|
|
}
|
|||
|
|
if (exists("final_output_pdf") && file.exists(final_output_pdf)) {
|
|||
|
|
cat("4.", final_output_pdf, "\n")
|
|||
|
|
cat(" ", final_output_png, "\n")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 保存分组统计
|
|||
|
|
group_summary <- group_df %>%
|
|||
|
|
group_by(Subgroup) %>%
|
|||
|
|
summarise(Genes = n(), .groups = 'drop')
|
|||
|
|
|
|||
|
|
group_summary_file <- paste0(output_prefix, "_subgroup_summary.xlsx")
|
|||
|
|
write_xlsx(group_summary, group_summary_file)
|
|||
|
|
cat("5.", group_summary_file, "\n")
|
|||
|
|
|
|||
|
|
# 保存参数记录
|
|||
|
|
params <- data.frame(
|
|||
|
|
参数 = c("树文件", "分组文件", "启动子文件", "元件描述文件", "输出前缀"),
|
|||
|
|
值 = c(tree_file, group_file,
|
|||
|
|
ifelse(is.null(promoter_file), "未提供", promoter_file),
|
|||
|
|
ifelse(is.null(element_desc_file), "未提供", element_desc_file),
|
|||
|
|
output_prefix)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
params_file <- paste0(output_prefix, "_analysis_parameters.csv")
|
|||
|
|
write.csv(params, params_file, row.names = FALSE)
|
|||
|
|
cat("6.", params_file, "\n")
|
|||
|
|
|
|||
|
|
cat("\n===== 分析完成 =====\n")
|