Files
PlantAI-dev/scripts/plot_interspecies_synteny.R
T
2026-08-03 18:42:47 +08:00

202 lines
6.4 KiB
R
Executable File

#!/usr/bin/env Rscript
# 绘制种间共线性图 (使用ggplot2)
# 输入:collinearity文件, bed文件
# 输出:PDF和PNG
# 布局:Ath染色体在上排,Ft染色体在下排,连线连接对应位置
suppressPackageStartupMessages({
library(ggplot2)
library(dplyr)
library(stringr)
})
args <- commandArgs(trailingOnly = TRUE)
if (length(args) < 4) {
stop("用法: Rscript plot_interspecies_synteny.R <collinearity> <ref_bed> <target_bed> <output_prefix>", call. = FALSE)
}
collinearity_file <- args[1]
ref_bed <- args[2]
target_bed <- args[3]
output_prefix <- args[4]
# 读取BED文件
read_bed <- function(bed_file) {
bed <- read.table(bed_file, sep="\t", stringsAsFactors=FALSE,
col.names=c("chr", "start", "end", "gene"))
bed$mid <- (bed$start + bed$end) / 2
return(bed)
}
# 读取collinearity文件
read_collinearity <- function(col_file) {
lines <- readLines(col_file)
blocks <- list()
current_block <- NULL
for (line in lines) {
if (grepl("^## Alignment", line)) {
m <- str_match(line, "Alignment\\s+(\\d+):.*N=(\\d+)\\s+(\\w+)&(\\w+)")
if (!is.na(m[1])) {
if (!is.null(current_block) && nrow(current_block$genes) > 0) {
blocks[[length(blocks) + 1]] <- current_block
}
current_block <- list(
id = as.integer(m[2]),
n = as.integer(m[3]),
ref_chr = m[4],
target_chr = m[5],
genes = data.frame(ref_gene=character(), target_gene=character(), stringsAsFactors=FALSE)
)
}
} else if (grepl("^\\s*\\d+-\\s+\\d+:", line) && !is.null(current_block)) {
parts <- str_split(line, "\\t")[[1]]
if (length(parts) >= 3) {
ref_gene <- str_trim(parts[2])
target_gene <- str_trim(parts[3])
current_block$genes <- rbind(current_block$genes,
data.frame(ref_gene=ref_gene, target_gene=target_gene,
stringsAsFactors=FALSE))
}
}
}
if (!is.null(current_block) && nrow(current_block$genes) > 0) {
blocks[[length(blocks) + 1]] <- current_block
}
return(blocks)
}
# 主程序
cat("读取BED文件...\n")
ref_data <- read_bed(ref_bed)
target_data <- read_bed(target_bed)
cat(" Ath基因:", nrow(ref_data), "\n")
cat(" Ft基因:", nrow(target_data), "\n")
cat("读取collinearity文件...\n")
blocks <- read_collinearity(collinearity_file)
cat(sprintf(" 共%d个共线性块\n", length(blocks)))
if (length(blocks) == 0) {
cat("警告:没有共线性块,无法绘图\n")
quit(save="no", status=1)
}
# 准备染色体数据 - 按物种分组,同一物种的染色体水平排列
ref_chr <- ref_data %>%
group_by(chr) %>%
summarise(len = max(end), .groups = "drop") %>%
arrange(chr) %>%
mutate(chr_num = row_number())
target_chr <- target_data %>%
group_by(chr) %>%
summarise(len = max(end), .groups = "drop") %>%
arrange(chr) %>%
mutate(chr_num = row_number())
# 计算统一的缩放比例
max_chr_len <- max(c(ref_chr$len, target_chr$len))
# 计算染色体在图中的位置
# Ath在上排 (y=2), Ft在下排 (y=1)
chr_width_pct <- 80 / max(nrow(ref_chr), nrow(target_chr)) # 每条染色体占总宽度的百分比
chr_spacing <- 2 # 染色体之间的间距
# Ath染色体位置 (上排, y=2)
ref_chr <- ref_chr %>%
mutate(
x_start = (chr_num - 1) * (100 / nrow(ref_chr)) + 5,
x_end = x_start + (len / max_chr_len) * (80 / nrow(ref_chr)),
y = 2 # 上排
)
# Ft染色体位置 (下排, y=1)
target_chr <- target_chr %>%
mutate(
x_start = (chr_num - 1) * (100 / nrow(target_chr)) + 5,
x_end = x_start + (len / max_chr_len) * (80 / nrow(target_chr)),
y = 1 # 下排
)
# 准备连线数据
links <- data.frame()
for (block in blocks) {
block_links <- block$genes %>%
left_join(ref_data %>% select(gene, ref_chr=chr, ref_pos=mid), by=c("ref_gene"="gene")) %>%
left_join(target_data %>% select(gene, target_chr=chr, target_pos=mid), by=c("target_gene"="gene")) %>%
left_join(ref_chr %>% select(chr, ref_x_start=x_start, ref_x_end=x_end, ref_len=len), by=c("ref_chr"="chr")) %>%
left_join(target_chr %>% select(chr, target_x_start=x_start, target_x_end=x_end, target_len=len), by=c("target_chr"="chr")) %>%
filter(!is.na(ref_pos), !is.na(target_pos))
if (nrow(block_links) > 0) {
# 计算在图中的实际x坐标
block_links <- block_links %>%
mutate(
x1 = ref_x_start + (ref_pos / ref_len) * (ref_x_end - ref_x_start),
x2 = target_x_start + (target_pos / target_len) * (target_x_end - target_x_start)
)
links <- rbind(links, block_links)
}
}
cat(sprintf(" 共%d条连线\n", nrow(links)))
if (nrow(links) == 0) {
cat("警告:没有有效连线,无法绘图\n")
quit(save="no", status=1)
}
# 创建染色体矩形数据
chr_rects <- rbind(
ref_chr %>% select(chr, x_start, x_end, y) %>% mutate(species="Ath"),
target_chr %>% select(chr, x_start, x_end, y) %>% mutate(species="Ft")
)
# 绘图
cat("绘制共线性图...\n")
p <- ggplot() +
# 绘制染色体矩形
geom_rect(data=chr_rects,
aes(xmin=x_start, xmax=x_end, ymin=y-0.15, ymax=y+0.15, fill=species),
color="black", linewidth=0.3) +
# 绘制连线 (连接上排和下排)
geom_segment(data=links,
aes(x=x1, y=2-0.15, xend=x2, yend=1+0.15),
alpha=0.15, color="steelblue", linewidth=0.1) +
# 染色体标签
geom_text(data=chr_rects, aes(x=(x_start+x_end)/2, y=y, label=chr),
vjust=-1.5, size=2.5) +
# 物种标签
annotate("text", x=2, y=2, label="Ath", hjust=1, size=4, fontface="bold", color="#E69F00") +
annotate("text", x=2, y=1, label="Ft", hjust=1, size=4, fontface="bold", color="#56B4E9") +
scale_fill_manual(values=c("Ath"="#E69F00", "Ft"="#56B4E9")) +
coord_cartesian(xlim=c(-5, 105), ylim=c(0.5, 2.5), clip="off") +
labs(title="Interspecies Synteny: Ft vs Ath") +
theme_minimal() +
theme(
panel.grid = element_blank(),
axis.text = element_blank(),
axis.title = element_blank(),
plot.title = element_text(hjust=0.5, face="bold", size=14),
legend.position = "none"
)
# 保存
output_pdf <- paste0(output_prefix, ".pdf")
output_png <- paste0(output_prefix, ".png")
ggsave(output_pdf, p, width=14, height=8)
cat(sprintf("PDF: %s\n", output_pdf))
png(filename=output_png, width=4200, height=2400, res=300)
print(p)
dev.off()
cat(sprintf("PNG: %s\n", output_png))
cat("完成\n")