########--------GSE98177二代测序数据的分析--------########
# GSE98177数据分析:识别调控IL2RA的增强子

# 1. 加载必要包 --------------------------------------------------------------
library(GEOquery)
## 载入需要的程序包:Biobase
## 载入需要的程序包:BiocGenerics
## 
## 载入程序包:'BiocGenerics'
## The following objects are masked from 'package:stats':
## 
##     IQR, mad, sd, var, xtabs
## The following objects are masked from 'package:base':
## 
##     anyDuplicated, aperm, append, as.data.frame, basename, cbind,
##     colnames, dirname, do.call, duplicated, eval, evalq, Filter, Find,
##     get, grep, grepl, intersect, is.unsorted, lapply, Map, mapply,
##     match, mget, order, paste, pmax, pmax.int, pmin, pmin.int,
##     Position, rank, rbind, Reduce, rownames, sapply, setdiff, table,
##     tapply, union, unique, unsplit, which.max, which.min
## Welcome to Bioconductor
## 
##     Vignettes contain introductory material; view with
##     'browseVignettes()'. To cite Bioconductor, see
##     'citation("Biobase")', and for packages 'citation("pkgname")'.
## Setting options('download.file.method.GEOquery'='auto')
## Setting options('GEOquery.inmemory.gpl'=FALSE)
library(DESeq2)
## 载入需要的程序包:S4Vectors
## Warning: 程序包'S4Vectors'是用R版本4.4.1 来建造的
## 载入需要的程序包:stats4
## 
## 载入程序包:'S4Vectors'
## The following object is masked from 'package:utils':
## 
##     findMatches
## The following objects are masked from 'package:base':
## 
##     expand.grid, I, unname
## 载入需要的程序包:IRanges
## Warning: 程序包'IRanges'是用R版本4.4.1 来建造的
## 
## 载入程序包:'IRanges'
## The following object is masked from 'package:grDevices':
## 
##     windows
## 载入需要的程序包:GenomicRanges
## Warning: 程序包'GenomicRanges'是用R版本4.4.1 来建造的
## 载入需要的程序包:GenomeInfoDb
## 载入需要的程序包:SummarizedExperiment
## 载入需要的程序包:MatrixGenerics
## 载入需要的程序包:matrixStats
## 
## 载入程序包:'matrixStats'
## The following objects are masked from 'package:Biobase':
## 
##     anyMissing, rowMedians
## 
## 载入程序包:'MatrixGenerics'
## The following objects are masked from 'package:matrixStats':
## 
##     colAlls, colAnyNAs, colAnys, colAvgsPerRowSet, colCollapse,
##     colCounts, colCummaxs, colCummins, colCumprods, colCumsums,
##     colDiffs, colIQRDiffs, colIQRs, colLogSumExps, colMadDiffs,
##     colMads, colMaxs, colMeans2, colMedians, colMins, colOrderStats,
##     colProds, colQuantiles, colRanges, colRanks, colSdDiffs, colSds,
##     colSums2, colTabulates, colVarDiffs, colVars, colWeightedMads,
##     colWeightedMeans, colWeightedMedians, colWeightedSds,
##     colWeightedVars, rowAlls, rowAnyNAs, rowAnys, rowAvgsPerColSet,
##     rowCollapse, rowCounts, rowCummaxs, rowCummins, rowCumprods,
##     rowCumsums, rowDiffs, rowIQRDiffs, rowIQRs, rowLogSumExps,
##     rowMadDiffs, rowMads, rowMaxs, rowMeans2, rowMedians, rowMins,
##     rowOrderStats, rowProds, rowQuantiles, rowRanges, rowRanks,
##     rowSdDiffs, rowSds, rowSums2, rowTabulates, rowVarDiffs, rowVars,
##     rowWeightedMads, rowWeightedMeans, rowWeightedMedians,
##     rowWeightedSds, rowWeightedVars
## The following object is masked from 'package:Biobase':
## 
##     rowMedians
library(tidyverse)
## Warning: 程序包'tidyverse'是用R版本4.4.2 来建造的
## Warning: 程序包'lubridate'是用R版本4.4.2 来建造的
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ lubridate::%within%() masks IRanges::%within%()
## ✖ dplyr::collapse()     masks IRanges::collapse()
## ✖ dplyr::combine()      masks Biobase::combine(), BiocGenerics::combine()
## ✖ dplyr::count()        masks matrixStats::count()
## ✖ dplyr::desc()         masks IRanges::desc()
## ✖ tidyr::expand()       masks S4Vectors::expand()
## ✖ dplyr::filter()       masks stats::filter()
## ✖ dplyr::first()        masks S4Vectors::first()
## ✖ dplyr::lag()          masks stats::lag()
## ✖ ggplot2::Position()   masks BiocGenerics::Position(), base::Position()
## ✖ purrr::reduce()       masks GenomicRanges::reduce(), IRanges::reduce()
## ✖ dplyr::rename()       masks S4Vectors::rename()
## ✖ lubridate::second()   masks S4Vectors::second()
## ✖ lubridate::second<-() masks S4Vectors::second<-()
## ✖ dplyr::slice()        masks IRanges::slice()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(ggplot2)
library(pheatmap)
library(clusterProfiler)
## Warning: 程序包'clusterProfiler'是用R版本4.4.1 来建造的
## 
## clusterProfiler v4.12.6 Learn more at https://yulab-smu.top/contribution-knowledge-mining/
## 
## Please cite:
## 
## T Wu, E Hu, S Xu, M Chen, P Guo, Z Dai, T Feng, L Zhou, W Tang, L Zhan,
## X Fu, S Liu, X Bo, and G Yu. clusterProfiler 4.0: A universal
## enrichment tool for interpreting omics data. The Innovation. 2021,
## 2(3):100141
## 
## 载入程序包:'clusterProfiler'
## 
## The following object is masked from 'package:purrr':
## 
##     simplify
## 
## The following object is masked from 'package:IRanges':
## 
##     slice
## 
## The following object is masked from 'package:S4Vectors':
## 
##     rename
## 
## The following object is masked from 'package:stats':
## 
##     filter
library(org.Hs.eg.db)
## 载入需要的程序包:AnnotationDbi
## 
## 载入程序包:'AnnotationDbi'
## 
## The following object is masked from 'package:clusterProfiler':
## 
##     select
## 
## The following object is masked from 'package:dplyr':
## 
##     select
# 2. 数据下载与加载 ----------------------------------------------------------
cat("Step 1: 下载并加载GSE98177数据...\n")
## Step 1: 下载并加载GSE98177数据...
gse <- getGEO("GSE98177", GSEMatrix = TRUE)
## Found 1 file(s)
## GSE98177_series_matrix.txt.gz
# 获取表达矩阵和样本信息
expr_data <- exprs(gse[[1]])  # 标准化表达矩阵(如log2FPKM)
pdata <- pData(gse[[1]])      # 样本元数据
count_data <- read.table("GSE98177_raw_counts_tsv.gz", header=TRUE)

count_data <- count_data %>% rename(ENTREZID = GeneID)
count_data <- count_data %>% mutate(ENTREZID = as.character(ENTREZID))

# 获取所有可能的映射
all_mappings <- select(org.Hs.eg.db,
                       keys = as.character(count_data$ENTREZID),
                       columns = "SYMBOL",
                       keytype = "ENTREZID")
## 'select()' returned 1:1 mapping between keys and columns
# 处理一对多关系 - 选择表达量最高的那个样本的符号
library(dplyr)

final_mapping <- count_data %>%
  left_join(all_mappings, by = "ENTREZID") %>%
  group_by(ENTREZID) %>%
  mutate(SYMBOL = ifelse(all(is.na(SYMBOL)),
                         ENTREZID,
                         na.omit(SYMBOL)[1])) %>%
  # 添加计数使SYMBOL唯一
  group_by(SYMBOL) %>%
  mutate(dup_count = seq_along(SYMBOL),
         UNIQUE_SYMBOL = ifelse(dup_count > 1, 
                                paste0(SYMBOL, "_", dup_count), 
                                as.character(SYMBOL))) %>%
  ungroup() %>%
  distinct(ENTREZID, .keep_all = TRUE)

data = as.data.frame(final_mapping)
row.names(data) = data$UNIQUE_SYMBOL  # 使用唯一的符号作为行名

# 移除临时列
dat = data[,c(2:19)]

# 3. 样本分组设计 -----------------------------------------------------------
cat("Step 2: 设置样本分组...\n")
## Step 2: 设置样本分组...
pdata$condition <- factor(c(
  rep("NonTargeting", 2), rep("TSS_sg1", 2), rep("TSS_sg2", 2),
  rep("CaRE3_sg1", 2), rep("CaRE3_sg2", 2), rep("CaRE4_sg1", 2),
  rep("CaRE4_sg2", 2), rep("PBS", 2), rep("Stimulated", 2)
))

pdata$condition <- factor(pdata$condition, 
                          levels = c("NonTargeting", "TSS_sg1", "TSS_sg2",
                                     "CaRE3_sg1", "CaRE3_sg2", "CaRE4_sg1",
                                     "CaRE4_sg2", "PBS", "Stimulated"))

# 4. 差异表达分析 ----------------------------------------------------------
cat("Step 3: 进行差异表达分析...\n")
## Step 3: 进行差异表达分析...
# 差异分析
dds <- DESeqDataSetFromMatrix(
countData = dat,
colData = pdata,
design = ~ condition
)

# 运行DESeq2
dds <- DESeq(dds)
## estimating size factors
## estimating dispersions
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## fitting model and testing
# 比较组分析
res_care3_sg1 <- results(dds, contrast = c("condition", "CaRE3_sg1", "NonTargeting"))
res_care3_sg2 <- results(dds, contrast = c("condition", "CaRE3_sg2", "NonTargeting"))
res_care4_sg1 <- results(dds, contrast = c("condition", "CaRE4_sg1", "NonTargeting"))

# 5. IL2RA表达分析 ---------------------------------------------------------
cat("Step 4: 分析IL2RA表达模式...\n")
## Step 4: 分析IL2RA表达模式...
il2ra_id <- "IL2RA"  # 假设IL2RA存在于数据中

# 提取归一化表达数据
il2ra_expr <- log2(counts(dds, normalized=TRUE)[il2ra_id, ] + 1)
il2ra_df <- data.frame(
  expr = as.numeric(il2ra_expr),
  condition = pdata$condition
)

# 绘制表达箱线图
ggplot(il2ra_df, aes(x = condition, y = expr, fill = condition)) +
  geom_boxplot() +
  geom_jitter(width = 0.2) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  labs(
    title = "IL2RA Expression Across Conditions",
    y = "Normalized Counts (log2)",
    x = ""
  )

# 6. 差异基因热图 ----------------------------------------------------------
cat("Step 5: 生成差异基因热图...\n")
## Step 5: 生成差异基因热图...
# 获取显著差异基因(padj < 0.05 & |log2FC| > 1)
sig_genes <- rownames(res_care3_sg1)[
  which(res_care3_sg1$padj < 0.05 & abs(res_care3_sg1$log2FoldChange) > 1)
]

# 确保sig_genes存在于vsd数据中
vsd <- vst(dds, blind=FALSE)
sig_genes <- sig_genes[sig_genes %in% rownames(assay(vsd))]

# 如果找到显著基因则绘制热图
if(length(sig_genes) > 0){
  vsd <- vst(dds, blind=FALSE)
  mat <- assay(vsd)[sig_genes, , drop=FALSE]
  
  # 检查mat是否有有效数据
  if(all(is.finite(mat))) {
    # 对数据进行缩放
    mat_scaled <- t(scale(t(mat)))
    
    # 设置热图颜色
    heatmap_colors <- colorRampPalette(c("blue", "white", "red"))(100)
    
    # 只有当基因和样本数都≥2时才绘制聚类热图
    if(nrow(mat_scaled) >= 2 && ncol(mat_scaled) >= 2){
      pheatmap(mat_scaled,
               annotation_col = pdata["condition"],
               show_rownames = ifelse(length(sig_genes) < 50, TRUE, FALSE),
               scale = "none",
               color = heatmap_colors,
               main = "Differentially Expressed Genes in CaRE3 vs Control",
               cluster_rows = TRUE,
               cluster_cols = TRUE,
               fontsize_row = 8,
               fontsize_col = 8)
    } else if (nrow(mat_scaled) >= 1) {
      # 如果只有1个基因但有足够样本,绘制非聚类热图
      cat("注意: 只有", nrow(mat_scaled), "个差异基因 - 绘制简化热图\n")
      pheatmap(mat_scaled,
               annotation_col = pdata["condition"],
               show_rownames = TRUE,
               scale = "none",
               color = heatmap_colors,
               main = paste("Single DEG:", rownames(mat_scaled)),
               cluster_rows = FALSE,
               cluster_cols = FALSE,
               fontsize_row = 8,
               fontsize_col = 8)
    }
  } else {
    cat("警告: 热图数据包含非有限值(NA/NaN/Inf)\n")
    problematic_genes <- apply(mat, 1, function(x) any(!is.finite(x)))
    print(names(which(problematic_genes)))
  }
} else {
  cat("未检测到满足条件的显著差异基因\n")
}
## 注意: 只有 1 个差异基因 - 绘制简化热图

# 7. 功能富集分析 ----------------------------------------------------------
cat("Step 6: 进行功能富集分析...\n")
## Step 6: 进行功能富集分析...
# 示例基因列表(实际应使用差异分析结果)
example_genes <- c("IL2RA", "CD28", "CD3D", "CD4", "FOXP3", "STAT5A")

# 转换基因ID
entrez_ids <- mapIds(org.Hs.eg.db,
                     keys = example_genes,
                     column = "ENTREZID",
                     keytype = "SYMBOL")
## 'select()' returned 1:1 mapping between keys and columns
# GO富集分析
go_enrich <- enrichGO(
  gene = na.omit(entrez_ids),
  OrgDb = org.Hs.eg.db,
  ont = "BP",
  pAdjustMethod = "BH",
  readable = TRUE
)

# 绘制富集结果
if(nrow(go_enrich) > 0){
  dotplot(go_enrich, title = "GO Enrichment Analysis")
} else {
  cat("未检测到显著富集的GO terms\n")
}

# 8. 结果汇总 --------------------------------------------------------------
cat("\n===== 分析完成 =====\n")
## 
## ===== 分析完成 =====
cat("关键结论检查:\n")
## 关键结论检查:
cat("1. 检查IL2RA在各处理组中的表达变化\n")
## 1. 检查IL2RA在各处理组中的表达变化
cat("2. 验证差异基因是否富集于T细胞激活相关通路\n")
## 2. 验证差异基因是否富集于T细胞激活相关通路
cat("3. 比较CaRE3和CaRE4处理组的差异基因重叠情况\n")
## 3. 比较CaRE3和CaRE4处理组的差异基因重叠情况
cat("Step 4: 分析IL2RA表达模式...\n")
## Step 4: 分析IL2RA表达模式...
cat("Step 5: 生成差异基因热图...\n")
## Step 5: 生成差异基因热图...
cat("Step 6: 进行功能富集分析...\n")
## Step 6: 进行功能富集分析...