第一个批质控管道:编写最简单的FastQC管道、运行与查看结果
好了,前面的章节我们把Nextflow的环境搭好了,核心概念也聊了一遍。现在该动手了。我自己的习惯是——学任何新工具,先跑通一个最简单的例子再说。别一上来就折腾复杂的多步流程,那样出了问题你都不知道是哪儿崩的。
所以这一章,我们就写一个只做FastQC的管道。输入一批FASTQ文件,挨个跑FastQC,然后把结果收拢到一起。你想想看,这个场景在生物信息里多常见:新拿到一批测序数据,第一件事就是看看质量咋样。
4.1 准备工作:目录结构与模块
在写脚本之前,先把工作区整理好。我个人习惯是每个项目建一个独立的文件夹,里面按功能分几个子目录:
fastqc_demo/
├── input/ # 放FASTQ文件(或软链接)
├── output/ # 跑完后结果放这里
└── main.nf # Nextflow脚本
输入数据:你可以从公共数据库下载几个小FASTQ做测试,或者用seqkit模拟几条reads。我不建议拿真实大样本跑第一个demo,跑半天卡住了你都不知道是不是脚本写错了。我曾经见过一个同学直接拿全基因组数据试,结果跑了三小时才发现FastQC参数写反了……
seqkit sample -n 10000 big.fastq.gz > small.fastq 可以快速抽一万条reads,够你测试用。
模块加载:如果你用集群或者conda环境,记得保证fastqc命令在$PATH里。或者更推荐的方式是在nextflow.config里声明conda环境,后面我们会细讲。这一章为了简单,我们假设fastqc已经装好了。
# 验证一下
fastqc --version
# 输出类似:FastQC v0.12.1
4.2 第一个main.nf:就一个process
打开main.nf,我们写一个最简单的Nextflow管道。嗯,这里要注意——不要一开始就写workflow块,先从一个process开始,把逻辑讲清楚。
#!/usr/bin/env nextflow
params.input = "$projectDir/input/*{1,2}.fastq.gz"
process fastqc {
input:
path read
output:
path "${read.baseName}_fastqc.html"
path "${read.baseName}_fastqc.zip"
script:
"""
fastqc -o . $read
"""
}
workflow {
reads_ch = Channel.fromPath(params.input)
fastqc(reads_ch)
}
这段代码不长,但包含了Nextflow管道的骨架:process定义、input/output声明、script执行命令,以及workflow里channel的创建与调用。
- params.input:用参数驱动输入路径,方便将来调整。字符串里通配符
*{1,2}.fastq.gz会匹配类似sample1_1.fastq.gz和sample1_2.fastq.gz这样成对的文件。 - path read:声明一个路径类型的输入。Nextflow会在执行前把文件stage到工作目录。
- output:两个产物——HTML报告和zip压缩包。文件名用了
${read.baseName},这是Nextflow提供的变量,会去掉后缀得到纯文件名。 - script:就是shell命令。注意这里
-o .表示输出到当前目录,Nextflow的工作目录是独立创建的,不会污染源数据。 - workflow:创建
reads_chchannel,传入process。每个文件都会被当成一个独立的job并行执行。
4.3 运行管道
写好了脚本,怎么跑?直接在命令行执行:
cd fastqc_demo
nextflow run main.nf --input 'input/*.fastq.gz'
--input的参数用单引号包起来,或者用双引号但转义。更稳妥的做法是在main.nf里用params.input定好默认值,运行时就不必每次敲了。
正常输出应该类似这样(注意看日志里的进程名和状态):
N E X T F L O W ~ version 24.10.0
Launching `main.nf` [romantic_tesla] DSL2 - revision: xxxxxx
executor > local (4)
[4d/8f2a03] process > fastqc (1) [100%] 4 of 4 ✔
看到4个进程全部成功(4 of 4 ✔),大功告成。如果看到FAILED,别慌——去work/目录下找对应的task目录,里面有.command.sh、.command.out、.command.err,一步步排查。
4.4 查看结果
管道默认把输出放在output/吗?不是的。上面脚本里output声明只是告诉了Nextflow“这个process会生产这些文件”,但最终结果会按publishDir指令放到指定目录。为了简化,我们先不加publishDir,结果会留在work/各自的task目录里。但你可以用下面命令把报告汇总到results/:
find work/ -name '*_fastqc.html' -exec cp {} results/ \;
find work/ -name '*_fastqc.zip' -exec cp {} results/ \;
然后打开任意一个HTML文件,你就能看到经典的FastQC图表了:Per base sequence quality、Per sequence GC content、Adapter Content……这些我就不展开了,不是本章重点。重点是——你通过一个不到20行的脚本,完成了一整批文件的质控,而且它是可重复的、并行的、避免污染原始数据的。
4.5 一张图看懂这个管道
下面这张SVG图概括了我们刚才做的每一步的核心逻辑。你记住这个结构,后面无论管道复杂多少倍,骨架都是这样的。
4.6 常见问题与调试技巧
| 问题 | 可能原因 | 解决方法 |
|---|---|---|
| 没有匹配到任何文件 | 通配符写错,或路径不对 | 用ls检查路径,或者用nextflow run ... --input 'input/*.fastq.gz' -resume并看日志 |
| 进程一直挂起 | executor配置不对(默认local一般没问题) | 检查是否写了对集群executor的引用,本地调试用-process.executor local |
FastQC报No such file |
input声明的path没有正确stage | 确认文件没有被其他进程删除,或者用file类型而非path(但path更推荐) |
| 多个样本共享同一个输出目录 | 没有用publishDir或者用了但不带mode: 'copy' |
加publishDir 'results', mode: 'copy'在process顶部 |
因为我们是第一次写管道,我建议你先把最精简的版本跑通,再加publishDir、资源限制、conda环境这些花活。一步到位往往不是效率最高的学习方式。
好了,现在你手头应该有一个能运行的FASTQC管道了。哪怕它很简单,但并行、可重复、可参数化这几个Nextflow的核心理念你都已经亲手实践了。后面的章节,我们会往里面加MultiQC汇总、加样本表驱动、加资源管理……你会看到,底层的设计思路跟这个20行的demo是一脉相承的。