Package: result-dir
一个可复用生物信息流程结果目录结构背景开发生物信息流程无外乎跑一些软件，得到一些分析结果。通常情况下，我们会把一个流程分为数个步骤，每个步骤有一个单独的文件夹。例如，我的分析流程第一步运行质控，我就定义一个文件夹叫1.qc/，这个步骤产生的所有结果均保存在1.qc/文件夹下。下面是我开发的一个Nanopore 16S鉴定流程的结果目录：.
├── 1.qc
│   ├── nanoplot
│   ├── raw_reads.fastq
│   ├── reads.fasta
│   └── reads.filtered.fastq
├── 2.pick-ref
│   ├── blastn.filtered.txt
│   ├── blastn.txt
│   ├── ref.fasta
│   └── ref.fasta.fai
├── 3.align
│   ├── depth.txt
│   ├── minimap2.filtered.bam
│   ├── minimap2.sam
│   ├── minimap2.sorted.bam
│   └── minimap2.sorted.bam.bai
├── 4.variant-calling
│   ├── medaka_consensus.hdf
│   ├── medaka_variant.vcf.gz
│   └── medaka_variant.vcf.gz.csi
├── 5.consensus
│   ├── pre_consensus.fasta
│   └── consensus.fasta
└── 6.assign
    └── blastn.txt问题为了方便，以下以bash脚本演示，其实该流程是使用Python写的。第一种复用质控步骤，我们运行Filtlong过滤reads，然后使用seqtk转换为fasta格式：filtlong--min_length500--min_mean_q101.qc/raw_reads.fastq>1.qc/reads.filtered.fastq
seqtkseq-a1.qc/reads.filtered.fastq>1.qc/reads.fasta可以看到这里的1.qc/reads.filtered.fastq我们写了两次，这个地方是第一种复用。有人说这个简单，定义变量不就行了：raw_reads=1.qc/raw_reads.fastqreads_filtered=1.qc/reads.filtered.fastqreads=1.qc/reads.fasta
filtlong--min_length500--min_mean_q10${raw_reads}>${reads_filtered}seqtkseq-a${reads_filtered}>${reads}这种方法的确能马马虎虎地解决第一种复用的问题。为什么说马马虎虎？因为我们的1.qc/仍旧写了3次。第二种复用假如说我们每一步骤都是一个单独的脚本怎么办？例如，质控步骤是qc.sh，选择参考是pick-ref.sh。而我们的选择参考需要用质控步骤的1.qc/reads.fasta。blastn-query1.qc/reads.fasta-db/path/to/silva-out2.pick-ref/blastn.txt因为pick-ref.sh与qc.sh是两个不同的脚本，无法引用qc.sh里面的变量，所以1.qc/reads.fasta在这个脚本里面又写了一次，这个地方是第二种复用。有人说，这个也简单，把变量的定义放到一个单独的脚本里面，然后各个脚本去导入。有了这个思想，你就明白result_dir想要做什么了。result_dir就是想要这些目录结构在整个项目中只写一次，包括文件夹名字也只写一次。安装pipinstallresult_dir使用result_dir只有两个类File和Dir，File代表文件，Dir代表文件夹。FileFile代表项目中的文件。想要建立一个文件直接实例化File就行，例如：raw_reads=File('raw_reads.fastq')File对象是可调用的，调用直接返回该文件的路径：path=raw_reads()# path为raw_reads.fastqDirDir代表文件夹。分为两种情况，如果要建立一个空文件夹，直接实例化Dir就行：Dir('1.qc')如果该文件夹里面还有子文件、子文件夹则需要继承Dir，创建Dir的子类才行：classQCDir(Dir):raw_reads_file=File('raw_reads.fastq')nanoplot_dir=Dir('nanoplot')reads_filtered_file=File('reads.filtered.fastq')reads_file=File('reads.fasta')QCDir是一个文件夹，该文件夹下有一个子文件夹和三个文件。qc_dir=QCDir('1.qc')# 即当前目录下的1.qc文件夹qc_dir=QCDir('/Users/dev/Projects/ont-16s/1.qc')# 即/Users/dev/Projects/ont-16s下的1.qcDir对象有是可调用的，调用直接返回该文件夹的路径：path1=qc_dir()# path1为1.qcpath2=qc_dir.nanoplot_dir()# path2为1.qc/nanoplotpath3=qc_dir.reads_file()# path3为1.qc/reads.fastaDir对象还有一个方法make，这个方法可以创建该文件夹及其下面的所有子文件夹。qc_dir.make()Nanopore 16S鉴定流程结果目录示例fromresult_dirimportFile,DirclassQCDir(Dir):raw_reads_file=File('raw_reads.fastq')nanoplot_dir=Dir('nanoplot')reads_filtered_file=File('reads.filtered.fastq')reads_file=File('reads.fasta')classPickRefDir(Dir):blastn_file=File('blastn.txt')filtered_blastn_file=File('blastn.filtered.txt')ref_file=File('ref.fasta')classAlignDir(Dir):minimap2_file=File('minimap2.sam')filtered_minimap2_file=File('minimap2.filtered.bam')sorted_minimap2_file=File('minimap2.sorted.bam')depth_file=File('depth.txt')classVariantCallingDir(Dir):medaka_consensus_file=File('medaka_consensus.hdf')medaka_variant_file=File('medaka_variant.vcf')compressed_medaka_variant_file=File('medaka_variant.vcf.gz')classConsensusDir(Dir):masked_file=File('masked.fasta')pre_consensus_file=File('pre_consensus.fasta')consensus_file=File('consensus.fasta')classAssignDir(Dir):blastn_file=File('blastn.txt')classONT16SDir(Dir):qc=QCDir('1.qc')pick_ref=PickRefDir('2.pick-ref')align=AlignDir('3.align')variant_calling=VariantCallingDir('4.variant-calling')consensus=ConsensusDir('5.consensus')assign=AssignDir('6.assign')if__name__=='__main__':ont_16s_dir=ONT16SDir('/Users/dev/Projects/ont_16s')# 实例化最上层文件夹ont_16s_dir.make()# 创建所有文件夹（包含子文件夹）print(ont_16s_dir.pick_ref.blastn_file())