Yuanclaw / modules /go_analysis.R
huashu's picture
Export YuanSeq to Hugging Face without binary assets
7e6a9d1
# =====================================================
# GO富集分析模块
# =====================================================
go_analysis_server <- function(input, output, session, deg_results) {
# =====================================================
# 辅助函数:清理基因符号
# =====================================================
clean_gene_symbols <- function(gene_symbols, species_code) {
# 清理基因符号:去除空格、特殊字符,标准化大小写
cleaned <- trimws(gene_symbols) # 去除首尾空格
cleaned <- gsub("[\t\n\r]", "", cleaned) # 去除空白字符
# 去除版本号(如.1, .2等)
cleaned <- gsub("\\.[0-9]+$", "", cleaned)
# 去除常见的假基因后缀
cleaned <- gsub("-ps$", "", cleaned, ignore.case = TRUE)
cleaned <- gsub("-rs$", "", cleaned, ignore.case = TRUE)
cleaned <- gsub("-as$", "", cleaned, ignore.case = TRUE)
# 识别并处理ENSEMBL ID
# ENSEMBL ID模式:ENS(MUS)?G[0-9]+(人类:ENSG,小鼠:ENSMUSG)
is_ensembl_id <- grepl("^ENS(MUS)?G[0-9]+$", cleaned, ignore.case = TRUE)
# 根据物种和ID类型标准化大小写
if (species_code == "mmu") {
# 小鼠基因处理
cleaned <- sapply(seq_along(cleaned), function(i) {
gene <- cleaned[i]
if (is_ensembl_id[i]) {
# ENSEMBL ID:全部大写
return(toupper(gene))
} else if (grepl("^[A-Za-z]", gene)) {
# 基因符号:首字母大写,其余小写
return(paste0(toupper(substr(gene, 1, 1)), tolower(substr(gene, 2, nchar(gene)))))
} else {
# 其他情况(如数字ID)
return(gene)
}
}, USE.NAMES = FALSE)
} else {
# 人类基因:全部大写(包括ENSEMBL ID和基因符号)
cleaned <- toupper(cleaned)
}
# 去除连字符、点等特殊字符(保留字母和数字)
# 注意:对于ENSEMBL ID,这可能会去除有效的版本号,但我们已经处理了版本号
cleaned <- gsub("[^[:alnum:]]", "", cleaned)
return(cleaned)
}
# =====================================================
# 辅助函数:识别基因ID类型
# =====================================================
identify_gene_id_types <- function(gene_ids, species_code) {
# 初始化结果列表
result <- list(
ensembl_ids = character(0),
gene_symbols = character(0),
entrez_ids = character(0),
other_ids = character(0)
)
for (gene in gene_ids) {
# 检查是否是ENSEMBL ID
if (grepl("^ENS(MUS)?G[0-9]+$", gene, ignore.case = TRUE)) {
result$ensembl_ids <- c(result$ensembl_ids, gene)
}
# 检查是否是ENTREZID(纯数字)
else if (grepl("^[0-9]+$", gene)) {
result$entrez_ids <- c(result$entrez_ids, gene)
}
# 检查是否是基因符号(以字母开头)
else if (grepl("^[A-Za-z]", gene)) {
result$gene_symbols <- c(result$gene_symbols, gene)
}
# 其他类型
else {
result$other_ids <- c(result$other_ids, gene)
}
}
return(result)
}
# =====================================================
# 辅助函数:智能基因符号转换
# =====================================================
smart_gene_conversion <- function(gene_ids, db_obj, target_column = "ENTREZID") {
# 尝试不同的keytype来转换基因ID
keytypes_to_try <- c("SYMBOL", "ALIAS", "ENSEMBL", "ENTREZID")
# 记录调试信息
debug_info <- list()
debug_info$input_count <- length(gene_ids)
debug_info$input_samples <- head(gene_ids, 10)
debug_info$attempts <- list()
for (keytype in keytypes_to_try) {
tryCatch({
# 先检查哪些基因ID在当前keytype中有效
valid_keys <- keys(db_obj, keytype = keytype)
matched_ids <- gene_ids[gene_ids %in% valid_keys]
# 记录尝试信息
attempt_info <- list(
keytype = keytype,
valid_keys_count = length(valid_keys),
matched_count = length(matched_ids),
matched_samples = head(matched_ids, 5)
)
debug_info$attempts[[keytype]] <- attempt_info
if (length(matched_ids) > 0) {
# 尝试转换匹配的基因ID
converted <- AnnotationDbi::mapIds(
db_obj,
keys = matched_ids,
column = target_column,
keytype = keytype,
multiVals = "first"
)
# 返回成功转换的结果
successful <- converted[!is.na(converted)]
if (length(successful) > 0) {
debug_info$final_keytype <- keytype
debug_info$success_count <- length(successful)
debug_info$failed_count <- length(matched_ids) - length(successful)
# 打印调试信息(在开发环境中)
if (Sys.getenv("SHINY_DEBUG") == "TRUE") {
cat("\n=== 基因转换调试信息 ===\n")
cat("输入基因数量:", debug_info$input_count, "\n")
cat("输入基因示例:", paste(debug_info$input_samples, collapse=", "), "\n")
cat("成功使用的keytype:", keytype, "\n")
cat("匹配的基因数量:", length(matched_ids), "\n")
cat("成功转换的基因数量:", length(successful), "\n")
cat("失败的基因数量:", debug_info$failed_count, "\n")
}
return(list(
converted = successful,
keytype_used = keytype,
matched_count = length(matched_ids),
success_count = length(successful),
debug_info = debug_info
))
}
}
}, error = function(e) {
# 记录错误信息
debug_info$attempts[[keytype]]$error <- e$message
# 继续尝试下一个keytype
NULL
})
}
# 如果所有keytype都失败,返回详细的调试信息
debug_info$all_failed <- TRUE
# 打印详细的调试信息
if (Sys.getenv("SHINY_DEBUG") == "TRUE") {
cat("\n=== 基因转换失败调试信息 ===\n")
cat("输入基因数量:", debug_info$input_count, "\n")
cat("输入基因示例:", paste(debug_info$input_samples, collapse=", "), "\n")
cat("\n尝试的keytype结果:\n")
for (keytype in keytypes_to_try) {
if (!is.null(debug_info$attempts[[keytype]])) {
attempt <- debug_info$attempts[[keytype]]
cat(" ", keytype, ":\n")
cat(" 有效key数量:", attempt$valid_keys_count, "\n")
cat(" 匹配数量:", attempt$matched_count, "\n")
if (!is.null(attempt$matched_samples)) {
cat(" 匹配示例:", paste(attempt$matched_samples, collapse=", "), "\n")
}
if (!is.null(attempt$error)) {
cat(" 错误:", attempt$error, "\n")
}
}
}
}
return(list(
converted = NULL,
keytype_used = NULL,
matched_count = 0,
success_count = 0,
debug_info = debug_info,
error_message = "所有keytype尝试都失败了"
))
}
# =====================================================
# GO 分析 - 基于差异基因
# =====================================================
go_data_processed <- eventReactive(input$run_go, {
req(deg_results())
# 从deg_results中提取差异分析结果和背景基因
deg_data <- deg_results()
res_df <- deg_data$deg_df
background_genes <- deg_data$background_genes
# 清理背景基因符号
if (!is.null(background_genes) && length(background_genes) > 0) {
background_genes <- clean_gene_symbols(background_genes, input$go_species)
}
# 显示进度提示
withProgress(message = 'GO分析进行中...', value = 0, {
# 进度1: 准备数据 (10%)
incProgress(0.1, detail = "准备分析数据...")
target_status <- switch(input$go_direction, "Up" = "Up", "Down" = "Down", "All" = c("Up", "Down"))
ids <- res_df %>% dplyr::filter(Status %in% target_status & !is.na(ENTREZID)) %>% dplyr::pull(ENTREZID)
if(length(ids) == 0) {
showNotification("无有效ENTREZID,请检查基因注释结果", type="error")
return(NULL)
}
tryCatch({
# 进度2: 加载数据库 (20%)
incProgress(0.1, detail = "加载基因注释数据库...")
# 根据物种选择对应的org包
db_pkg <- if(input$go_species == "mmu") "org.Mm.eg.db" else "org.Hs.eg.db"
if(!require(db_pkg, character.only = TRUE, quietly = TRUE)) {
showNotification(paste("请先安装", db_pkg, "包"), type="error")
return(NULL)
}
db_obj <- get(db_pkg)
# 准备背景基因集(如果可用)
universe <- NULL
if(!is.null(background_genes) && length(background_genes) > 0) {
# 清理背景基因符号
cleaned_background <- clean_gene_symbols(background_genes, input$go_species)
# 将背景基因符号转换为ENTREZID(使用智能转换)
conversion_result <- smart_gene_conversion(cleaned_background, db_obj, "ENTREZID")
# 检查转换结果
if(!is.null(conversion_result$converted) && length(conversion_result$converted) > 0) {
bg_entrez <- conversion_result$converted
universe <- bg_entrez
# 显示成功信息
if(!is.null(conversion_result$keytype_used)) {
showNotification(paste("使用", length(universe), "个检测到的基因作为背景基因集(通过",
conversion_result$keytype_used, "转换)"), type = "message")
} else {
showNotification(paste("使用", length(universe), "个检测到的基因作为背景基因集"), type = "message")
}
# 如果有失败的情况,显示警告
if(conversion_result$matched_count > conversion_result$success_count) {
failed_count <- conversion_result$matched_count - conversion_result$success_count
showNotification(paste("警告:", failed_count, "个背景基因无法转换为ENTREZID"), type = "warning")
}
} else {
# 转换失败,显示详细的错误信息
error_msg <- "背景基因转换失败"
if(!is.null(conversion_result$error_message)) {
error_msg <- paste(error_msg, ": ", conversion_result$error_message)
}
# 提供具体的建议
if(length(cleaned_background) > 0) {
sample_genes <- head(cleaned_background, 5)
error_msg <- paste0(error_msg, "\n示例基因:", paste(sample_genes, collapse=", "))
# 分析基因ID类型并提供具体建议
id_types <- identify_gene_id_types(sample_genes, input$go_species)
error_msg <- paste0(error_msg, "\n\n检测到的ID类型分析:")
if(length(id_types$ensembl_ids) > 0) {
error_msg <- paste0(error_msg, "\n• ENSEMBL ID: ", length(id_types$ensembl_ids), "个")
error_msg <- paste0(error_msg, "\n 示例:", paste(head(id_types$ensembl_ids, 3), collapse=", "))
error_msg <- paste0(error_msg, "\n 建议:这些是ENSEMBL ID,不是基因符号。")
error_msg <- paste0(error_msg, "\n 请使用基因符号(如Trp53)或确保数据库包含这些ENSEMBL ID")
}
if(length(id_types$gene_symbols) > 0) {
error_msg <- paste0(error_msg, "\n• 基因符号: ", length(id_types$gene_symbols), "个")
error_msg <- paste0(error_msg, "\n 示例:", paste(head(id_types$gene_symbols, 3), collapse=", "))
# 检查大小写问题
if(input$go_species == "hsa") {
lower_case <- id_types$gene_symbols[grepl("^[a-z]", id_types$gene_symbols)]
if(length(lower_case) > 0) {
error_msg <- paste0(error_msg, "\n 大小写问题:", length(lower_case), "个基因是小写")
error_msg <- paste0(error_msg, "\n 建议:人类基因需要大写(如TP53,不是tp53)")
}
} else if(input$go_species == "mmu") {
# 检查小鼠基因大小写
not_proper_case <- id_types$gene_symbols[!grepl("^[A-Z][a-z]+$", id_types$gene_symbols) & grepl("^[A-Za-z]", id_types$gene_symbols)]
if(length(not_proper_case) > 0) {
error_msg <- paste0(error_msg, "\n 大小写问题:", length(not_proper_case), "个基因大小写不正确")
error_msg <- paste0(error_msg, "\n 建议:小鼠基因需要首字母大写,其余小写(如Trp53,不是trp53或TRP53)")
}
}
}
if(length(id_types$other_ids) > 0) {
error_msg <- paste0(error_msg, "\n• 其他ID类型: ", length(id_types$other_ids), "个")
error_msg <- paste0(error_msg, "\n 示例:", paste(head(id_types$other_ids, 3), collapse=", "))
error_msg <- paste0(error_msg, "\n 建议:请检查这些ID的格式是否正确")
}
}
showNotification(error_msg, type = "error", duration = 15)
# 在调试模式下显示更多信息
if(Sys.getenv("SHINY_DEBUG") == "TRUE" && !is.null(conversion_result$debug_info)) {
cat("\n=== 背景基因转换详细调试信息 ===\n")
print(conversion_result$debug_info)
}
}
}
# 进度3: 进行GO富集分析 (40%)
incProgress(0.2, detail = "进行GO富集分析...")
# 进行GO富集分析(使用背景基因集)
go_obj <- clusterProfiler::enrichGO(
gene = ids,
OrgDb = db_obj,
keyType = "ENTREZID",
ont = input$go_ontology, # BP, MF, CC
pAdjustMethod = "BH",
pvalueCutoff = input$go_p,
qvalueCutoff = 0.2,
readable = TRUE, # 将ENTREZID转换为Gene Symbol
universe = universe # 关键改进:使用背景基因集
)
if(is.null(go_obj) || nrow(go_obj@result) == 0) {
showNotification("GO富集分析没有结果。", type = "warning")
return(NULL)
}
# 进度4: 处理结果数据 (60%)
incProgress(0.2, detail = "处理分析结果...")
df <- go_obj@result
# 简化描述(移除物种信息)
df$Description <- gsub("\\s*\\(.*\\)$", "", df$Description)
# 将GeneRatio从字符格式转换为数值比例
if ("GeneRatio" %in% colnames(df)) {
df$GeneRatio_numeric <- sapply(strsplit(df$GeneRatio, "/"), function(x) {
as.numeric(x[1]) / as.numeric(x[2])
})
}
# 将BgRatio从字符格式转换为数值比例
if ("BgRatio" %in% colnames(df)) {
df$BgRatio_numeric <- sapply(strsplit(df$BgRatio, "/"), function(x) {
as.numeric(x[1]) / as.numeric(x[2])
})
}
# 计算富集倍数(Fold Enrichment)
if ("GeneRatio_numeric" %in% colnames(df) && "BgRatio_numeric" %in% colnames(df)) {
df$Fold_Enrichment <- df$GeneRatio_numeric / df$BgRatio_numeric
# 处理除零错误(如果BgRatio为0)
df$Fold_Enrichment[is.infinite(df$Fold_Enrichment) | is.na(df$Fold_Enrichment)] <- NA
}
# 进度5: 完成 (100%)
incProgress(0.4, detail = "分析完成!")
Sys.sleep(0.5) # 短暂延迟,让用户看到完成消息
return(df)
}, error = function(e) {
showNotification(paste("GO分析错误:", e$message), type="error")
return(NULL)
})
})
})
# GO结果下载
output$download_go <- downloadHandler(
filename = function() {
paste0("GO_Enrichment_Results_", Sys.Date(), ".csv")
},
content = function(file) {
df <- go_data_processed()
if(!is.null(df)) {
write.csv(df, file, row.names = FALSE)
}
}
)
# GO图表生成reactive
go_plot_obj <- reactive({
df <- go_data_processed()
if(is.null(df)) return(NULL)
# 根据用户选择确定X轴变量
x_var <- switch(input$go_x_axis,
"GeneRatio" = "GeneRatio_numeric",
"BgRatio" = "BgRatio_numeric",
"Count" = "Count",
"FoldEnrichment" = "Fold_Enrichment")
# 根据X轴变量排序数据,并选择Top N
# 降序排列( Fold Enrichment最大的在上面)
df_sorted <- df[order(df[[x_var]], decreasing = TRUE), ]
top_n <- min(input$go_top_n, nrow(df_sorted))
df_top <- df_sorted[1:top_n, ]
x_label <- switch(input$go_x_axis,
"GeneRatio" = "Gene Ratio",
"BgRatio" = "Background Ratio",
"Count" = "Gene Count",
"FoldEnrichment" = "Fold Enrichment")
# 创建点图 - Y轴已经按X轴变量排序,所以直接使用Description即可
p <- ggplot(df_top, aes(x = .data[[x_var]], y = reorder(Description, .data[[x_var]]))) +
geom_point(aes(size = Count, color = p.adjust)) +
scale_color_gradient(low = input$go_low_col, high = input$go_high_col) +
theme_bw(base_size = input$go_font_size) +
labs(x = x_label, y = "GO Term",
title = paste("GO Enrichment Analysis (", input$go_ontology, ")", sep = ""),
size = "Gene Count", color = "Adj. P-value") +
theme(axis.text.y = element_text(face = ifelse(input$go_bold, "bold", "plain")))
return(p)
})
# GO图表下载
output$download_go_plot <- downloadHandler(
filename = function() {
paste0("GO_Dotplot_", Sys.Date(), ".", input$go_export_format)
},
content = function(file) {
p <- go_plot_obj()
if(is.null(p)) return(NULL)
# 根据格式保存
if (input$go_export_format == "png") {
png(file, width = 10, height = 8, units = "in", res = 300)
} else if (input$go_export_format == "pdf") {
pdf(file, width = 10, height = 8)
} else if (input$go_export_format == "svg") {
svg(file, width = 10, height = 8)
}
print(p)
dev.off()
}
)
# GO点图
output$go_dotplot <- renderPlot({
go_plot_obj()
})
# GO结果表格
output$go_table <- DT::renderDataTable({
df <- go_data_processed()
if(is.null(df)) return(NULL)
# 选择显示的列(添加Fold_Enrichment)
display_cols <- c("ID", "Description", "GeneRatio", "BgRatio", "Fold_Enrichment",
"pvalue", "p.adjust", "qvalue", "geneID", "Count")
display_cols <- display_cols[display_cols %in% colnames(df)]
# 格式化富集倍数(保留2位小数)
if ("Fold_Enrichment" %in% colnames(df)) {
df$Fold_Enrichment <- round(df$Fold_Enrichment, 2)
}
DT::datatable(df[, display_cols],
options = list(
pageLength = 10,
scrollX = TRUE,
dom = 'Bfrtip',
buttons = c('copy', 'csv', 'excel', 'pdf')
),
rownames = FALSE,
class = "display compact")
})
# =====================================================
# 单列基因 GO 富集分析
# =====================================================
single_gene_go_data <- eventReactive(input$run_single_gene_go, {
req(input$single_gene_go_file)
tryCatch({
# 读取基因列表文件
gene_df <- read.csv(input$single_gene_go_file$datapath)
if(!"SYMBOL" %in% colnames(gene_df)) {
showNotification("CSV文件必须包含'SYMBOL'列", type="error")
return(NULL)
}
gene_symbols <- gene_df$SYMBOL
# 根据物种选择对应的org包
db_pkg <- if(input$single_gene_species == "mmu") "org.Mm.eg.db" else "org.Hs.eg.db"
if(!require(db_pkg, character.only = TRUE, quietly = TRUE)) {
showNotification(paste("请先安装", db_pkg, "包"), type="error")
return(NULL)
}
# 将Gene Symbol转换为ENTREZID(使用智能转换)
db_obj <- get(db_pkg)
# 清理基因符号
cleaned_genes <- clean_gene_symbols(gene_symbols, input$single_gene_species)
# 使用智能转换函数
conversion_result <- smart_gene_conversion(cleaned_genes, db_obj, "ENTREZID")
if(is.null(conversion_result)) {
# 如果智能转换失败,尝试直接使用SYMBOL keytype
tryCatch({
entrez_ids <- AnnotationDbi::mapIds(db_obj,
keys = cleaned_genes,
column = "ENTREZID",
keytype = "SYMBOL",
multiVals = "first")
entrez_ids <- entrez_ids[!is.na(entrez_ids)]
}, error = function(e) {
showNotification(paste("基因符号转换失败:", e$message), type = "error")
return(NULL)
})
} else {
entrez_ids <- conversion_result$converted
showNotification(paste("成功转换", length(entrez_ids), "个基因ID(通过",
conversion_result$keytype_used, "转换)"), type = "message")
}
if(length(entrez_ids) == 0) {
showNotification("无法将基因符号转换为ENTREZID", type="error")
return(NULL)
}
# 对于单列基因分析,无法获取背景基因集
# 显示警告信息,说明这可能导致假阳性
if(input$single_gene_use_background == "no") {
universe <- NULL
showNotification("警告:未使用背景基因集,结果可能包含假阳性", type = "warning")
} else {
# 尝试获取所有可能的基因作为背景(全基因组)
# 注意:这仍然不是理想的背景,但比没有好
all_genes <- keys(db_obj, keytype = "ENTREZID")
universe <- all_genes
showNotification(paste("使用全基因组(", length(universe), "个基因)作为背景基因集"), type = "message")
}
# 进行GO富集分析
go_obj <- clusterProfiler::enrichGO(
gene = entrez_ids,
OrgDb = db_obj,
keyType = "ENTREZID",
ont = input$single_gene_go_ontology,
pAdjustMethod = "BH",
pvalueCutoff = input$single_gene_go_p,
qvalueCutoff = 0.2,
readable = TRUE,
universe = universe # 使用背景基因集
)
if(is.null(go_obj) || nrow(go_obj@result) == 0) {
showNotification("单列基因GO富集分析没有结果。", type = "warning")
return(NULL)
}
df <- go_obj@result
df$Description <- gsub("\\s*\\(.*\\)$", "", df$Description)
# 将GeneRatio从字符格式转换为数值比例
if ("GeneRatio" %in% colnames(df)) {
df$GeneRatio_numeric <- sapply(strsplit(df$GeneRatio, "/"), function(x) {
as.numeric(x[1]) / as.numeric(x[2])
})
}
# 将BgRatio从字符格式转换为数值比例
if ("BgRatio" %in% colnames(df)) {
df$BgRatio_numeric <- sapply(strsplit(df$BgRatio, "/"), function(x) {
as.numeric(x[1]) / as.numeric(x[2])
})
}
# 计算富集倍数(Fold Enrichment)
if ("GeneRatio_numeric" %in% colnames(df) && "BgRatio_numeric" %in% colnames(df)) {
df$Fold_Enrichment <- df$GeneRatio_numeric / df$BgRatio_numeric
# 处理除零错误(如果BgRatio为0)
df$Fold_Enrichment[is.infinite(df$Fold_Enrichment) | is.na(df$Fold_Enrichment)] <- NA
}
return(df)
}, error = function(e) {
showNotification(paste("单列基因GO分析错误:", e$message), type="error")
return(NULL)
})
})
# 单列基因GO结果下载
output$download_single_gene_go <- downloadHandler(
filename = function() {
paste0("Single_Gene_GO_Results_", Sys.Date(), ".csv")
},
content = function(file) {
df <- single_gene_go_data()
if(!is.null(df)) {
write.csv(df, file, row.names = FALSE)
}
}
)
# 单列基因GO图表生成reactive
single_gene_go_plot_obj <- reactive({
df <- single_gene_go_data()
if(is.null(df)) return(NULL)
# 根据用户选择确定X轴变量
x_var <- switch(input$single_gene_go_x_axis,
"GeneRatio" = "GeneRatio_numeric",
"BgRatio" = "BgRatio_numeric",
"Count" = "Count",
"FoldEnrichment" = "Fold_Enrichment")
# 根据X轴变量排序数据,并选择Top N
# 降序排列( Fold Enrichment最大的在上面)
df_sorted <- df[order(df[[x_var]], decreasing = TRUE), ]
top_n <- min(20, nrow(df_sorted))
df_top <- df_sorted[1:top_n, ]
x_label <- switch(input$single_gene_go_x_axis,
"GeneRatio" = "Gene Ratio",
"BgRatio" = "Background Ratio",
"Count" = "Gene Count",
"FoldEnrichment" = "Fold Enrichment")
# 创建点图
p <- ggplot(df_top, aes(x = .data[[x_var]], y = reorder(Description, .data[[x_var]]))) +
geom_point(aes(size = Count, color = p.adjust)) +
scale_color_gradient(low = input$single_gene_go_low_col, high = input$single_gene_go_high_col) +
theme_bw(base_size = input$single_gene_go_font_size) +
labs(x = x_label, y = "GO Term",
title = paste("Single Gene GO Enrichment (", input$single_gene_go_ontology, ")", sep = ""),
size = "Gene Count", color = "Adj. P-value") +
theme(axis.text.y = element_text(face = ifelse(input$single_gene_go_bold, "bold", "plain")))
return(p)
})
# 单列基因GO图表下载
output$download_single_gene_go_plot <- downloadHandler(
filename = function() {
paste0("Single_Gene_GO_Dotplot_", Sys.Date(), ".", input$single_gene_go_export_format)
},
content = function(file) {
p <- single_gene_go_plot_obj()
if(is.null(p)) return(NULL)
# 根据格式保存
if (input$single_gene_go_export_format == "png") {
png(file, width = 10, height = 8, units = "in", res = 300)
} else if (input$single_gene_go_export_format == "pdf") {
pdf(file, width = 10, height = 8)
} else if (input$single_gene_go_export_format == "svg") {
svg(file, width = 10, height = 8)
}
print(p)
dev.off()
}
)
# 单列基因GO点图
output$single_gene_go_dotplot <- renderPlot({
single_gene_go_plot_obj()
})
# 单列基因GO结果表格
output$single_gene_go_table <- DT::renderDataTable({
df <- single_gene_go_data()
if(is.null(df)) return(NULL)
# 选择显示的列(添加Fold_Enrichment)
display_cols <- c("ID", "Description", "GeneRatio", "BgRatio", "Fold_Enrichment",
"pvalue", "p.adjust", "qvalue", "geneID", "Count")
display_cols <- display_cols[display_cols %in% colnames(df)]
# 格式化富集倍数(保留2位小数)
if ("Fold_Enrichment" %in% colnames(df)) {
df$Fold_Enrichment <- round(df$Fold_Enrichment, 2)
}
DT::datatable(df[, display_cols],
options = list(
pageLength = 10,
scrollX = TRUE,
dom = 'Bfrtip',
buttons = c('copy', 'csv', 'excel', 'pdf')
),
rownames = FALSE,
class = "display compact")
})
# 返回GO结果供其他模块使用
return(reactive({ go_data_processed() }))
}