## ------------------0. Global settings ----------------
## 系统报错改为英文
Sys.setenv(LANGUAGE = "en")
## 禁止转化为因子
options(stringsAsFactors = FALSE)
rm(list=ls())

## 加载R包
library(GEOquery)
library(dplyr)
library(tidyverse)
library(limma)
library(data.table)
library(tibble)
library(openxlsx)

getwd()
###################### 一、清洁数据 ######################
###### 1. 获取文件（矩阵+分组）
gset <- getGEO('GSE74602', destdir=".",getGPL =F)

## 1.1 获取表型文件（样本分组信息）
pdata <- gset[["GSE74602_series_matrix.txt.gz"]]@phenoData@data
save(pdata,file = "74602/pdata.Rdata")

## 1.2 获取表达矩阵
exprSet <- gset[["GSE74602_series_matrix.txt.gz"]]@assayData[["exprs"]]
exprSet <- as.data.frame(exprSet)

## 自动log化判断
ex <- exprSet
qx <- as.numeric(quantile(ex, c(0., 0.25, 0.5, 0.75, 0.99, 1.0), na.rm=T))
LogC <- (qx[5] > 100) ||
  (qx[6]-qx[1] > 50 && qx[2] > 0) ||
  (qx[2] > 0 && qx[2] < 1 && qx[4] > 1 && qx[4] < 2)

## 开始判断
if (LogC) { 
  ex[which(ex <= 0)] <- NaN
  ## 取log2
  exprSet <- log2(ex)
  print("log2 transform finished")
}else{
  print("log2 transform not needed")  
}

boxplot(exprSet,outline=FALSE, notch=T, las=2)

## 1.3 normalizeBetweenArrays标准化
exprSet <- normalizeBetweenArrays(exprSet)
boxplot(exprSet,outline=FALSE, notch=T, las=2)
## 这步把矩阵转换为数据框很重要
class(exprSet)
exprSet <- as.data.frame(exprSet)

## 2. 探针-基因名转换
# soft <- getGEO(filename ="GSE74602_family.soft.gz")
# gpl <- soft@gpls[["GPL6104"]]@dataTable@table
# gpl <- gpl[,c(1,12)]

anno <- fread("GSE74602_family.soft.gz",skip = "ID")
anno <- anno[,c(1,12)]

## 探针与symbol基本情况
length(unique(anno$ID))
length(unique(anno$Symbol))

## 3. 探针转换与去重：得到最终“基因层面”表达矩阵
exprSet <- exprSet %>% 
  ## 行名转列名,因为只有变成数据框的列,才可以用inner_join
  rownames_to_column("ID")%>% 
  ## 合并探针的信息
  inner_join(anno,by="ID") %>% 
  ## 去掉多余信息
  select(-ID) %>%  
  ## 重新排列
  select(Symbol,everything()) %>%  
  ## rowMeans求出行的平均数(这边的.代表上面传入的数据)
  ## .[,-1]表示去掉出入数据的第一列，然后求行的平均值
  mutate(rowMean =rowMeans(.[,-1])) %>% 
  ## 把表达量的平均值按从大到小排序
  arrange(desc(rowMean)) %>% 
  ## 去重，symbol留下第一个
  distinct(Symbol,.keep_all = T) %>% 
  ## 反向选择去除rowMean这一列
  select(-rowMean) %>% 
  ## 列名转行名
  column_to_rownames("Symbol")

## 保存清洁后的表达矩阵（便于复现）
save(exprSet, file = "74602/exprSet.Rdata")

######################### 释放空间 #########################
rm(list=ls())
load("74602/pdata.Rdata")
load("74602/exprSet.Rdata")

## 4. 分组信息
# View(pdata)
## 4.1创建分组信息
a <- seq(1, 59, by = 2)                         #代表肿瘤组织
a2 <- a+1                                       #代表正常组织

##4.2数据重排
exp <- exprSet[,c(a2,a)]                        #正常的在前，癌症的在后
save(exp,file = "74602/exp.Rdata")

# # 保存为 Excel 文件
write.xlsx(exp, file = "74602/exprSet_rmdup.xlsx", rowNames = TRUE)


##### 二、WGCNA ###################

#1.1 加载WGCNA包
library(impute)
library(WGCNA)
library(parallel)
library(doParallel)

## 1.2 WGCNA要求：样本为行、基因为列(exp:行是基因，列是样本)
datExpr <- t(exp)  

## 1.3 检查缺失
gsg <- goodSamplesGenes(datExpr, verbose = 3)
gsg$allOK  
# 结果为TRUE，表示所有样本和基因都是合格的

## 1.4 样本聚类，识别异常样本
#dist 计算样本间的距离
#method = "average" 为聚类方法
sampleTree <- hclust(dist(datExpr), method = "average")
plot(sampleTree, 
     main = "Sample clustering to detect outliers", 
     sub = "", xlab = "", cex = 0.6)

## 发现异常样本-成对分析-去除一对 （GSM1923670 GSM1923671）
abnormalSamples <- c("GSM1923670", "GSM1923671")  # 这些是WGCNA中发现的异常样本
datExpr <- datExpr[!rownames(datExpr) %in% abnormalSamples, ]

#1.5 再次聚类
sampleTree <- hclust(dist(datExpr), method = "average")
plot(sampleTree, 
     main = "Sample clustering to detect outliers", 
     sub = "", xlab = "", cex = 0.6)


## 1.6 选择软阈值（并行加速）
#parallel::detectCores() 检测系统总核心数，-1 保留一个核心避免过载
cl <- makeCluster(parallel::detectCores() - 1)  
registerDoParallel(cl)

#设置软阈值候选范围为1到20
powers <- c(1:20)   
sft <- pickSoftThreshold(datExpr, powerVector = powers, verbose = 5)
#pickSoftThreshold函数来评估每个软阈值的效果,计算无标度拓扑网络的拟合度和平均连通性

## 1.7 Scale independence
par(font.lab = 2)  # 同时加粗X轴和Y轴的标签
plot(sft$fitIndices[,1], 
     -sign(sft$fitIndices[,3]) * sft$fitIndices[,2],
     xlab = "Soft Threshold (power)", 
     ylab = "Scale Free Topology Model Fit, signed R^2",
     type = "n", 
     main = "Scale independence")
text(sft$fitIndices[,1], -sign(sft$fitIndices[,3]) * sft$fitIndices[,2], 
     labels = powers, col = "red")
abline(h = 0.9, col = "red")           # 0.9为无标度网络的阈值参考

## 1.8 Mean connectivity
plot(sft$fitIndices[,1], 
     sft$fitIndices[,5],
     xlab = "Soft Threshold (power)", 
     ylab = "Mean Connectivity",
     type = "n", main = "Mean connectivity")
# 用数字标记点
text(sft$fitIndices[,1], sft$fitIndices[,5], 
     labels = powers, col = "red")

# 关闭并行集群
stopCluster(cl)


#### (2) 构建加权网络并识别模块 #####
#2.1计算加权邻接矩阵:表示基因对之间的加权相关性
softPower <- 10  #选择10作为软阈值
adjacency <- adjacency(datExpr, power = softPower)

#2.2 转换为拓扑重叠矩阵（TOM）
#使用邻接矩阵计算拓扑重叠矩阵（TOM），TOM 反映了基因间的共表达相似性
# TOM <- TOMsimilarity(adjacency)       #很费时间
# save(TOM,file = "74602/TOM.Rdata")
load("74602/TOM.Rdata")

#dissTOM 是 TOM 的相异矩阵:表示基因间的不相似性，用于后续的聚类
dissTOM <- 1 - TOM

#2.3 基于 dissTOM 构建基因聚类树(hclust)
geneTree <- hclust(as.dist(dissTOM), method = "average")
# ??hclust

#2.4 动态剪切树识别模块
#cutreeDynamic 函数通过动态剪切树法识别模块，每个模块是一个基因子集
#deepSplit = 3 ：剪切深度，值越大模块划分越精细
#minClusterSize = 30 设置模块的最小基因数量
dynamicMods <- cutreeDynamic(dendro = geneTree,
                             distM = dissTOM,
                             deepSplit = 3, 
                             pamRespectsDendro = FALSE,
                             minClusterSize = 30)

#2.5 将模块编号转换为颜色标签，便于模块的直观展示
dynamicColors <- labels2colors(dynamicMods)

#检查实际生成的模块数量
length(unique(dynamicMods))
#查看每个模块的编号和对应的基因数量
table(dynamicMods) 

# 适当调整边距
par(mar = c(5, 5, 4, 2) + 0.1) 
plotDendroAndColors(geneTree, dynamicColors, 
                    "Dynamic Tree Cut", 
                    dendroLabels = FALSE, hang = 0.05,
                    addGuide = TRUE, guideHang = 0.05)
# 关闭x和y轴方向的网格线，使图形更清晰
grid(nx = NA, ny = NA) 


####（3）模块与表型关联 #####
#3.1 计算每个模块特征基因（Module Eigengenes）：每个模块的第一主成分
MEs <- moduleEigengenes(datExpr, colors = dynamicColors)$eigengenes
MEs <- orderMEs(MEs)

#3.2 计算模块特征基因之间的相关性：并对其进行层次聚类
MEs_cor <- cor(MEs, use = "pairwise.complete.obs")
#将相关性矩阵转换为不相似性矩阵（dissimilarity）
#使用层次聚类（hclust）对模块特征基因进行聚类
dissimilarity = 1 - MEs_cor
moduleTree = hclust(as.dist(dissimilarity), method = "average")

#3.3⑥ 绘制模块间的聚类树状图：识别模块间的聚类关系
par(mar = c(5, 8, 3, 2) + 0.1)  # 保持较少的边距
plot(moduleTree, main = "Dendrogram of Module Eigengenes",
     xlab = "", 
     sub = "",
     cex.axis = 0.9,  # 缩小坐标轴字体
     cex.main = 1.2,  # 缩小标题字体
     cex.lab = 1.2    # 缩小标签字体
)


#3.4 模块与表型数据的相关性
#去除异常样本并重新排列表型数据
abnormalSamples <- c("GSM1923670", "GSM1923671")
a <- seq(1, 59, by = 2)                                 #代表肿瘤组织
a2 <- a+1                                               #代表正常组织
trait_data2 <- pdata[c(a2,a),]

# 从 trait_data2 中删除异常样本
trait_data1 <- trait_data2[!rownames(trait_data2) %in% abnormalSamples, ]

# 创建两列的表型数据
trait_data <- data.frame(
  Normal = rep(0, nrow(trait_data1)),    # 创建代表正常组的列
  Tumor = rep(0, nrow(trait_data1))      # 创建代表肿瘤组的列
)
# 为前29行指定正常组，后29行指定肿瘤组（原本是30对，去除了一对）
trait_data[1:29, "Normal"] <- 1  # 前29行为正常组
trait_data[30:58, "Tumor"] <- 1  # 后29行为肿瘤组
rownames(trait_data) <- rownames(trait_data1)
# 保存表型数据
save(trait_data,file="74602/trait_data.Rdata")

#3.5 模块-表型相关性和显著性计算
library(ComplexHeatmap)
library(circlize)
moduleTraitCor <- cor(MEs, trait_data, use = "p")   
moduleTraitPvalue <- corPvalueStudent(moduleTraitCor, nSamples = nrow(datExpr))

#3.6创建热图展示模块与表型的相关性
module_names <- rownames(moduleTraitCor)  # 提取模块名称
module_colors <- gsub("^ME", "", module_names)  # 去掉模块名称的 "ME" 前缀
#将模块颜色和模块名称一一映射，生成 ann_colors
ann_colors <- list(ModuleColor = setNames(module_colors, module_names))

# 创建行注释，颜色映射到 ModuleColor，并移除标题和图例，调整宽度
row_annotation <- data.frame(ModuleColor = module_names)
row_ha <- rowAnnotation(
  ModuleColor = row_annotation$ModuleColor, 
  col = list(ModuleColor = ann_colors$ModuleColor),
  show_annotation_name = FALSE,         
  annotation_width = unit(4, "mm"),      
  show_legend = FALSE                    
)

# 创建包含相关系数和 p 值的文本矩阵
text_matrix <- apply(moduleTraitCor, c(1, 2), function(x) format(round(x, 2), nsmall = 2))
p_matrix <- apply(moduleTraitPvalue, c(1, 2), function(x) formatC(x, format = "e", digits = 2))
text_matrix_combined <- matrix(paste(text_matrix, "\n(", p_matrix, ")"), 
                               nrow = nrow(moduleTraitCor), 
                               ncol = ncol(moduleTraitCor))

Heatmap(
  moduleTraitCor, 
  name = "Correlation", 
  left_annotation = row_ha,        # 将 ModuleColor 显示在左侧
  show_row_names = TRUE,           # 显示行名
  show_column_names = TRUE,        # 显示列名
  column_names_rot = 0,            # 确保列名水平显示
  col = colorRamp2(c(-1, 0, 1), c("blue", "white", "red")), 
  cluster_rows = FALSE,            # 关闭行聚类
  cluster_columns = FALSE,         # 关闭列聚类
  show_heatmap_legend = TRUE,      
  heatmap_legend_param = list(     
    title = "",
    legend_height = unit(12, "cm"), 
    legend_width = unit(2, "cm")    
  ),
  width = unit(10, "cm"),          
  height = unit(24, "cm"),         
  row_names_gp = gpar(fontsize = 8, fontface = "bold"),  
  row_names_side = "left",         # 将行名显示在左侧
  column_names_gp = gpar(fontface = "bold"),  
  cell_fun = function(j, i, x, y, width, height, fill) {  # 在方格内显示相关性和 p 值
    grid.text(text_matrix_combined[i, j], x, y, gp = gpar(fontsize = 7))
  }
)


####################WGCNA结束（提取基因）#######################################
# 提取“blue”模块的基因
blue_modulegenes <- colnames(datExpr)[dynamicColors == "blue"]
# 提取“turquoise”模块的基因
turquoise_modulegenes <- colnames(datExpr)[dynamicColors == "turquoise"]
# 合并两个模块的基因
WGCNA_modulegenes <- c(blue_modulegenes, turquoise_modulegenes)

####保存合并后的基因列表为 Rdata 文件
save(WGCNA_modulegenes, file = "74602/WGCNA_modulegenes.Rdata")


##### 获取差异基因 进行veen图合并#########
load("74602/pdata.Rdata")
load("74602/exp.Rdata")
dim(exp)
#2.去除异常值
####发现异常样本-成对分析-去除一对 （GSM1923670 GSM1923671）
abnormalSamples <- c("GSM1923670", "GSM1923671")  
clean_exp <- exp[,-c(1,31)]
save(clean_exp,file = "74602/clean_exp.Rdata")
# load("74602/clean_exp.Rdata")
dim(clean_exp)

#3.转化为因子 
#ref代表control组的值作为参考，得到的结果是tumor/control
group <- c(rep('control',29),rep('T',29))
# group <- factor(group) %>% relevel(group, ref="control")
## levels里面，把对照组放在前面
group <- factor(group,levels = c("control","T"))
print(group)

# 4. 主成分分析PCA
### 行是样本,列是基因
res.pca <- prcomp(t(clean_exp), scale = TRUE)

library(factoextra)
# 绘制 PCA 图，样本颜色根据 group 分组
fviz_pca_ind(res.pca,
             col.ind = group,   # 根据分组上色
             palette = "jco", 
             addEllipses = TRUE,  # 添加椭圆
             legend.title = "Groups")

#5.构建比较矩阵
design <- model.matrix(~ group)              # 创建设计矩阵
colnames(design) <- levels(group)            # 命名列名
rownames(design) <- colnames(clean_exp)      # 对应样本名
design

#6. lmFit()：线性模型拟合
fit <- lmFit(clean_exp,design)

#7. eBayes()：贝叶斯检验
fit2 <- eBayes(fit)

#8. 输出差异分析结果
allDiff=topTable(fit2,adjust='fdr',coef=2,number=Inf) 

#9. 这个数据（所有差异基因）很重要需要保存一下 
save(allDiff,file = "74602/allDiff.Rdata")
write.xlsx(allDiff, file = "74602/allDiff.xlsx", rowNames = TRUE)

#####（二）作图环节（显示所有基因:火山图）##########################
load("74602/allDiff.Rdata")
#1. 画个火山图(所有基因)
library(ggplot2)                         
library(ggrepel)                               
library(dplyr)

log2(2) #2倍为高表达

logFCfilter = 1
logFCcolor = 3.5

data<-allDiff
data$gene <- rownames(data)

#1.1 标记上下调
index = data$adj.P.Val <0.05 & abs(data$logFC) > logFCfilter
data$group <- 0
data$group[index & data$logFC>0] = 1
data$group[index & data$logFC<0] = -1
data$group <- factor(data$group,levels = c(1,0,-1),labels =c("Up","NS","Down") )
table(data$group)


#1.3（加点） 正式画图
ggplot(data=data, aes(x=logFC, y =-log10(adj.P.Val),color=group)) +
  geom_point(alpha=0.8, size=0.8)+
  scale_color_manual(values = c("red", "grey50", "blue4"))+
  labs(x="log2 (fold change)",y="-log10 (adj.P.Val)")+
  theme(plot.title = element_text(hjust = 0.4))+
  geom_hline(yintercept = -log10(0.05),lty=4,lwd=0.8,alpha=0.8)+
  geom_vline(xintercept = c(-logFCfilter,logFCfilter),lty=4,lwd=0.8,alpha=0.8)+
  theme_bw()+
  theme(panel.border = element_blank(),
        panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(),   
        axis.line = element_line(colour = "black"))+
  theme(legend.position="top")+
  geom_point(data=subset(data, abs(logFC) >= 4),alpha=0.8, size=3,col="green")+
  geom_text_repel(data=subset(data, abs(logFC) > 4), 
                  aes(label=gene),color="black",alpha = 0.8)


#2 定义差异基因：差异倍数2倍，矫正后的p值小于0.05
library(dplyr)
diffgene_7 <- allDiff %>% 
  filter(adj.P.Val < 0.05) %>% 
  filter(abs(logFC) >1)
#1630
# save(diffgene_7,file = "74602/diffgene.Rdata")

########################################################
########################################################
#3.绘制Veen图###############
load("74602/WGCNA_modulegenes.Rdata")
load("74602/diffgene.Rdata")
load("113513/diffgene.Rdata")
load("44076/diffgene.Rdata")

GSE74602 <- rownames(diffgene_7)
GSE113513 <- rownames(diffgene_1)
GSE44076 <- rownames(diffgene_4)

class(WGCNA_modulegenes)
class(GSE74602)
class(GSE113513)
class(GSE44076)


# 安装并加载VennDiagram包
if (!requireNamespace("VennDiagram", quietly = TRUE)) {
  install.packages("VennDiagram")}
library(VennDiagram)

# 创建列表来存储四个基因集
gene_sets <- list(
  GSE74602 = GSE74602, 
  GSE113513 = GSE113513, 
  WGCNA_modulegenes = WGCNA_modulegenes, 
  GSE44076 = GSE44076)

# 绘制Venn图并存储结果
venn.plot <- venn.diagram(
  x = gene_sets,
  category.names = c("GSE74602", "GSE113513", "WGCNA_modulegenes","GSE44076"),
  filename = NULL,
  output = TRUE,
  fill = c("lightblue", "lightpink", "lightgreen","orange"),
  alpha = 0.6,
  cex = 1.5,         # 调小文本大小
  cat.cex = 1.2,     # 调小标签文本大小
  cat.col = c("blue", "purple",  "red", "orange"),
  margin = 0.1,     # 增加图形边缘的空间
  scaled = TRUE      # 根据比例缩放
)

grid::grid.draw(venn.plot)


# 保存四个集合的交集
common_genes <- Reduce(intersect, list(GSE74602, WGCNA_modulegenes, GSE113513,GSE44076))
common_genes_data <- clean_exp[rownames(clean_exp) %in% common_genes, ]
common_genes_diff <- allDiff[rownames(allDiff) %in% common_genes,]

class(common_genes_data)
class(common_genes_diff)
# 查看交集结果
print(common_genes)

## 保存结果
save(common_genes,file = "74602/common_genes.Rdata")
# load("74602/common_genes.Rdata")
save(common_genes_data,file = "74602/common_genes_data.Rdata")

# 保存结果 Excel 文件
write_xlsx(data.frame(Genes = common_genes), path = "74602/common_genes.xlsx")
write.xlsx(common_genes_data, file = "74602/common_genes_data.xlsx",
           rowNames = TRUE, colNames = TRUE)
##########################################################################
##########################################################################

