添加edgeR也可以做火山图的脚本

可以的。D3.js (配合 Plotly) 完全可以画出 edgeR 结果的火山图。

核心思路: 为了让你网页后端的 JS 代码(绘制火山图的部分)不需要修改,最好的办法是在 Perl 处理数据阶段(第 6 部分),将 edgeR 的输出格式“归一化”成与 DESeq2 相同的 CSV 格式。

只要生成的 CSV 文件包含表头 gene, log2FoldChange, pvalue,你的前端 JS 就能照常工作。

以下是针对你的 Perl 脚本 第 6 部分 (执行分析) 的修改方案。

 

1. 分析数据列对应关系

 

我们需要把 edgeR 的列映射到 JS 需要的列名:

你的 edgeR 数据列 (索引)
含义
目标 CSV 列名 (兼容现有的 JS)

$F[0]
Gene ID
gene

$F[3]
logFC
log2FoldChange

$F[5]
PValue
pvalue

$F[6]
FDR
padj (可选,用于着色参考)

 

2. 修改后的 Perl 代码(替换原脚本第 6 部分)

 

请用下面的代码替换你脚本中的 ######################## 6. 执行分析 ######################## 这一整块:

Perl

########################
# 6. 执行分析
########################
if (-d $work_dir && chdir $work_dir) {

# 6.1 生成当前比较的 samples.txt (保持不变)
if (-e $samples_src_abs) {
open my $SRC, '<', $samples_src_abs or die $!;
open my $OUT, '>', 'samples.txt' or die $!;
while (my $line = <$SRC>) {
if ($line =~ /^($compare1|$compare2)/) {
print $OUT $line;
}
}
close $OUT;
close $SRC;
chmod 0666, 'samples.txt';
}

# 6.2 (如果需要跑 Trinity/DESeq2 的话保留,如果是纯画图,这步其实只针对 DESeq2)
# 如果你的流程是 edgeR,通常结果文件已经存在,或者有对应的 edgeR 命令
# 此处假设结果文件已经生成好了,直接进入格式转换

# 6.3 自动识别结果文件 (兼容 DESeq2 和 edgeR)
my $real_result_file;

# 根据 program 参数决定文件名匹配规则
# 假设 edgeR 的结果文件名类似: groupA_vs_groupB.edgeR.DE_results
opendir(my $DH, ".");
while (my $f = readdir($DH)) {
if ($program eq 'DESeq2') {
# 原有的 DESeq2 逻辑
if ($f =~ /\Q$comName\E\.DESeq2\.DE_results$/) {
my $cand = $f . ".P${Adpvalue}_C${fccutoff}.DE.subset";
if (-e $cand) { $real_result_file = $cand; last; }
}
}
elsif ($program eq 'edgeR' || $program eq 'files') {
# edgeR 逻辑 (假设你的 edgeR 结果文件名包含 output 或者就是 edgeR)
# 你需要根据实际文件名修改这里的正则
if ($f =~ /\Q$comName\E.*edgeR/i || $f =~ /edgeR/i ) {
$real_result_file = $f;
last;
}
}
}
closedir $DH;

# 6.4 生成统一格式的 CSV
if ($real_result_file) {
my $perl_cmd = "";

if ($program eq 'DESeq2') {
# 原有的 DESeq2 转换命令
$perl_cmd = "perl -F'\\t' -ane 'BEGIN { print \",gene,baseMean,log2FoldChange,lfcSE,stat,pvalue,padj\\n\" } if (\$. > 1) { print \"\$F[0],\$F[0],\$F[5],\$F[6],\$F[7],\$F[8],\$F[9],\$F[10]\\n\"; }' $real_result_file > $csv_file";
}
elsif ($program eq 'edgeR' || $program eq 'files') {
# === 新增:edgeR 转换命令 ===
# 逻辑:跳过第一行表头,提取第0(ID), 3(logFC), 5(PValue), 6(FDR) 列
# 注意:edgeR输出有时第一行不对齐,但数据行通常是制表符分隔
$perl_cmd = "perl -F'\\t' -ane 'BEGIN { print \"gene,log2FoldChange,pvalue,padj\\n\" } if (\$. > 1) { print \"\$F[0],\$F[3],\$F[5],\$F[6]\\n\"; }' $real_result_file > $csv_file";
}

# 执行转换
if ($perl_cmd) {
system($perl_cmd);
# 检查生成的 CSV 是否有效
if (-e $csv_file && -s $csv_file) {
my $csv_dest = "${volcano_dir}/${csv_file}";
if (copy($csv_file, $csv_dest)) { $csv_ok = 1; }
}
}
}

# 6.5 拷贝 PDF (保持不变,如果有的话)
if (-e $pdfName) {
my $pdf_dest = "${volcano_dir}/${pdf_file}";
if (copy($pdfName, $pdf_dest)) { $pdf_ok = 1; }
}
}

 

3. 为什么前端 JS 不需要改?

 

请看你原来的 JS 代码段:

JavaScript

data.forEach(function(r, i){
// 这里它尝试读取 r.log2FoldChange 或者 r.log2FoldC
const fc = +(r.log2FoldChange || r.log2FoldC);
// 这里它读取 r.pvalue
const pv = +r.pvalue;
// ...

我在上面的 Perl 修改中,针对 edgeR 的分支专门写了: print "gene,log2FoldChange,pvalue,padj\n"

这意味着生成的 CSV 也就是有了 log2FoldChange 和 pvalue 这两个列名。前端的 D3.js 代码读取 CSV 时,它根本不在乎原始数据是 edgeR 算出来的还是 DESeq2 算出来的,只要列名对得上,它就能画图。

 

4. 注意事项

 

  1. 文件名匹配: 在 6.3 中,我写了 if ($f =~ /\Q$comName\E.*edgeR/i)。你需要确保你的 edgeR 结果文件名符合这个规则。如果你的文件名不包含 edgeR 关键字,请修改这个正则表达式。
  2. 列的顺序: 代码是基于你提供的 edgeR 示例数据(GeneID在第0列,logFC在第3列,PValue在第5列)。如果你的 edgeR 输出文件列顺序不同(比如有些版本会把 GeneID 放在行名里,或者没有 SampleA SampleB 列),你需要调整 print \"\$F[0],\$F[3],\$F[5],\$F[6]\\n\" 中的数字索引。