# ======================
# 火山图多风格整合代码
# 包含6种不同风格的火山图实现
# ======================

# 1. 环境设置与包加载 ----
rm(list = ls())
options(stringsAsFactors = F)

# 安装缺失的包
if (!requireNamespace("ggplot2", quietly = TRUE)) install.packages("ggplot2")
if (!requireNamespace("ggrepel", quietly = TRUE)) install.packages("ggrepel")
if (!requireNamespace("dplyr", quietly = TRUE)) install.packages("dplyr")
if (!requireNamespace("export", quietly = TRUE)) install.packages("export")
if (!requireNamespace("ggforce", quietly = TRUE)) install.packages("ggforce")
if (!requireNamespace("plotly", quietly = TRUE)) install.packages("plotly")
if (!requireNamespace("htmlwidgets", quietly = TRUE)) install.packages("htmlwidgets")
if (!requireNamespace("gridExtra", quietly = TRUE)) install.packages("gridExtra")

# 加载包
library(ggplot2)
library(ggrepel)
library(dplyr)
library(export)
library(ggforce)
library(plotly)
library(htmlwidgets)
library(gridExtra)

# 2. 创建模拟数据集 ----
set.seed(123)
n_genes <- 2000
dataset <- data.frame(
  gene = paste0("GENE", 1:n_genes),
  logFC = c(rnorm(n_genes*0.8, 0, 0.5), 
            rnorm(n_genes*0.1, 2, 0.5), 
            rnorm(n_genes*0.1, -2, 0.5)),
  P.Value = c(runif(n_genes*0.8, 0.01, 1), 
              runif(n_genes*0.2, 0.0001, 0.05))
)

# 添加变化类型和标签
dataset <- dataset %>%
  mutate(
    change = case_when(
      P.Value < 0.05 & logFC >= 1 ~ "Up",
      P.Value < 0.05 & logFC <= -1 ~ "Down",
      TRUE ~ "Stable"
    ),
    label = ifelse(change != "Stable", gene, "")
  )

# 3. 基础火山图 ----
basic_volcano <- ggplot(dataset, aes(logFC, -log10(P.Value))) +
  geom_point(aes(color = change), size = 2, alpha = 0.7) +
  scale_color_manual(values = c("Down" = "blue", "Stable" = "gray60", "Up" = "red")) +
  geom_hline(yintercept = -log10(0.05), linetype = "dashed", color = "gray30") +
  geom_vline(xintercept = c(-1, 1), linetype = "dashed", color = "gray30") +
  labs(title = "Basic Volcano Plot",
       x = "log2(Fold Change)",
       y = "-log10(p-value)",
       color = "Expression") +
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 14),
    legend.position = "top"
  ) +
  geom_text_repel(
    data = dataset %>% filter(change != "Stable") %>% 
      slice_min(P.Value, n = 10),
    aes(label = label),
    size = 3,
    max.overlaps = 20
  )

# 4. 现代简约风格 ----
modern_volcano <- ggplot(dataset, aes(logFC, -log10(P.Value))) +
  geom_point(aes(fill = change, size = abs(logFC)), 
             shape = 21, color = "white", stroke = 0.3, alpha = 0.8) +
  scale_fill_manual(values = c("Down" = "#4E79A7", "Stable" = "gray80", "Up" = "#E15759")) +
  scale_size_continuous(range = c(1, 5), guide = "none") +
  geom_hline(yintercept = -log10(0.05), linetype = "dashed", color = "gray40") +
  geom_vline(xintercept = c(-1, 1), linetype = "dashed", color = "gray40") +
  labs(title = "Modern Volcano Plot",
       x = "log2(Fold Change)",
       y = "-log10(p-value)",
       fill = "Expression") +
  theme_minimal() +
  theme(
    panel.grid.minor = element_blank(),
    panel.grid.major = element_line(color = "gray90"),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
    legend.position = "bottom"
  ) +
  ggrepel::geom_text_repel(
    data = dataset %>% filter(P.Value < 0.001 & abs(logFC) > 1.5),
    aes(label = label),
    size = 3.5,
    box.padding = 0.3,
    point.padding = 0.1,
    segment.color = "grey50"
  )

# 5. 学术黑白风格 ----
academic_volcano <- ggplot(dataset, aes(logFC, -log10(P.Value))) +
  geom_point(aes(shape = change), size = 2.5, alpha = 0.7, fill = "black") +
  scale_shape_manual(values = c("Down" = 25, "Stable" = 21, "Up" = 24)) +
  geom_hline(yintercept = -log10(0.05), linetype = "dashed") +
  geom_vline(xintercept = c(-1, 1), linetype = "dashed") +
  labs(title = "Academic Volcano Plot",
       x = "log2(Fold Change)",
       y = "-log10(p-value)",
       shape = "Expression") +
  theme_classic() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 14),
    legend.position = "right",
    axis.line = element_line(color = "black"),
    axis.ticks = element_line(color = "black")
  ) +
  annotate("text", x = -2.5, y = -log10(0.05)+0.3, 
           label = "p = 0.05", size = 3) +
  annotate("text", x = 1.8, y = max(-log10(dataset$P.Value))-0.5, 
           label = "Up-regulated", size = 4, fontface = "italic") +
  annotate("text", x = -1.8, y = max(-log10(dataset$P.Value))-0.5, 
           label = "Down-regulated", size = 4, fontface = "italic")

# 6. 渐变火山图 ----
gradient_volcano <- ggplot(dataset, aes(logFC, -log10(P.Value))) +
  geom_point(aes(color = -log10(P.Value), size = abs(logFC)*0.8 + 1), 
             alpha = 0.8) +
  scale_color_gradientn(
    colours = c("#313695", "#4575B4", "#74ADD1", "#ABD9E9", "#E0F3F8", 
                "#FFFFBF", "#FEE090", "#FDAE61", "#F46D43", "#D73027", "#A50026"),
    name = "-log10(p-value)",
    limits = c(0, max(-log10(dataset$P.Value))),
    breaks = c(1, 2, 3, 4)
  ) +
  geom_hline(yintercept = -log10(0.05), linetype = "dashed", color = "gray30") +
  geom_vline(xintercept = c(-1, 1), linetype = "dashed", color = "gray30") +
  labs(title = "Gradient Volcano Plot",
       x = "log2(Fold Change)",
       y = "-log10(p-value)") +
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
    legend.position = "right",
    panel.grid = element_line(color = "gray95")
  ) +
  ggrepel::geom_text_repel(
    data = dataset %>% filter(-log10(P.Value) > 3 & abs(logFC) > 1.5),
    aes(label = label),
    size = 3,
    box.padding = 0.4,
    segment.color = "grey40"
  )

# 7. 倾斜火山图(45度视角) ----
tilted_volcano <- ggplot(dataset, aes(logFC, -log10(P.Value))) +
  geom_point(aes(fill = change), 
             shape = 21, color = "white", size = 3, alpha = 0.7) +
  scale_fill_manual(values = c("Down" = "#1F77B4", "Stable" = "gray80", "Up" = "#FF7F0E")) +
  labs(title = "Tilted Volcano Plot (45° Perspective)",
       x = "log2(Fold Change)",
       y = "-log10(p-value)",
       fill = "Expression") +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 14, margin = margin(b = 15)),
    legend.position = "bottom"
  ) +
  # 应用45度视角变换
  coord_trans(
    x = ggforce::trans_reverser("identity"),
    y = "identity"
  ) +
  # 添加对角线参考线
  geom_abline(slope = 1, intercept = 0, linetype = "dashed", alpha = 0.3, color = "gray40") +
  geom_abline(slope = -1, intercept = 0, linetype = "dashed", alpha = 0.3, color = "gray40") +
  # 添加阈值线
  geom_hline(yintercept = -log10(0.05), linetype = "dotted", alpha = 0.5) +
  geom_vline(xintercept = c(-1, 1), linetype = "dotted", alpha = 0.5) +
  # 添加象限标注
  annotate("text", x = -3, y = 5, label = "Low FC\nHigh Sig", size = 3.5, color = "gray30") +
  annotate("text", x = 3, y = 5, label = "High FC\nHigh Sig", size = 3.5, color = "gray30") +
  annotate("text", x = -3, y = 0.5, label = "Low FC\nLow Sig", size = 3.5, color = "gray30") +
  annotate("text", x = 3, y = 0.5, label = "High FC\nLow Sig", size = 3.5, color = "gray30")

# 8. 3D火山图(交互式) ----
# 添加第三维度数据(模拟表达量)
dataset$Expression <- rnorm(nrow(dataset), mean = 10, sd = 3) + abs(dataset$logFC)*2

# 创建颜色映射
color_map <- c("Up" = "#FF0000", "Down" = "#0000FF", "Stable" = "#CCCCCC")
dataset$color <- color_map[dataset$change]

# 创建3D火山图
volcano3d <- plot_ly(
  data = dataset,
  x = ~logFC,
  y = ~-log10(P.Value),
  z = ~Expression,
  type = "scatter3d",
  mode = "markers",
  marker = list(
    size = ~-log10(P.Value)*0.8 + 3,
    color = ~color,
    opacity = 0.7,
    line = list(width = 0)
  ),
  text = ~paste(
    "Gene: ", gene,
    " logFC: ", round(logFC, 3),
    " p-value: ", format.pval(P.Value, digits = 2),
    " Expression: ", round(Expression, 1)
  ),
  hoverinfo = "text"
) %>%
  layout(
    title = list(text = "3D Volcano Plot", y = 0.95),
    scene = list(
      xaxis = list(title = "log2(Fold Change)"),
      yaxis = list(title = "-log10(p-value)"),
      zaxis = list(title = "Expression Level"),
      camera = list(
        eye = list(x = 1.8, y = 1.8, z = 0.8)  # 调整视角
      )
    ),
    margin = list(l = 0, r = 0, b = 0, t = 40),
    showlegend = FALSE
  ) %>%
  add_annotations(
    x = 0.05,
    y = 0.95,
    xref = "paper",
    yref = "paper",
    text = "Color Legend: Red: Up-regulated Blue: Down-regulated",
    showarrow = FALSE,
    font = list(size = 12)
  )

# 9. 保存所有图形 ----
# 保存2D图形
graph2png(basic_volcano, "basic_volcano.png", width = 9, height = 7)
graph2png(modern_volcano, "modern_volcano.png", width = 9, height = 7)
graph2png(academic_volcano, "academic_volcano.png", width = 9, height = 7)
graph2png(gradient_volcano, "gradient_volcano.png", width = 10, height = 8)
graph2png(tilted_volcano, "tilted_volcano.png", width = 10, height = 8)

# 保存3D交互图
htmlwidgets::saveWidget(
  widget = volcano3d,
  file = "3D_volcano.html",
  selfcontained = TRUE
)

# 10. 并排显示2D图形 ----
grid_volcano <- gridExtra::grid.arrange(
  basic_volcano, 
  modern_volcano,
  academic_volcano,
  gradient_volcano,
  tilted_volcano,
  ncol = 3,
  top = "Comparative Volcano Plots"
)

# 保存组合图
graph2png(grid_volcano, "combined_volcano.png", width = 18, height = 12)

# 11. 在R中查看所有图形 ----
# 显示2D图形
print(basic_volcano)
print(modern_volcano)
print(academic_volcano)
print(gradient_volcano)
print(tilted_volcano)

# 显示3D图形(在RStudio中查看)
# volcano3d