Denovo bug fixes
This commit is contained in:
parent
b56cec9994
commit
03b8ba51f6
10
README.md
10
README.md
@ -115,13 +115,12 @@ For example:
|
|||||||
* wf-isoforms-report.html
|
* wf-isoforms-report.html
|
||||||
- Summary and plots of reads, alignments and the transcript assembly and annotation
|
- Summary and plots of reads, alignments and the transcript assembly and annotation
|
||||||
- One file per run with results from each sample merged
|
- One file per run with results from each sample merged
|
||||||
|
|
||||||
####Transcript isoform table
|
Note transcript isoform table is currently only available for the reference-guilded assembly.
|
||||||
Note: Currently only available for the reference-guilded assembly
|
|
||||||
The report includes a searchable filterable table of transcript isoforms<br>
|
|
||||||
Note: If using a large dataset with 10s of thousands of predicted isoforms, to speed up searching, the table can be limited
|
Note: If using a large dataset with 10s of thousands of predicted isoforms, to speed up searching, the table can be limited
|
||||||
by read coverage, which can be set with `transcript_table_cov_thresh = 50` (default 50x)
|
by read coverage, which can be set with `transcript_table_cov_thresh = 50` (default 50x)
|
||||||
|
|
||||||
|
#### Output files
|
||||||
Each sample will also have it's own directory containing the following (dependent on assembly approach and input options)
|
Each sample will also have it's own directory containing the following (dependent on assembly approach and input options)
|
||||||
* {sampleid}_gffcompare
|
* {sampleid}_gffcompare
|
||||||
* Directory containing all output from gffcompare
|
* Directory containing all output from gffcompare
|
||||||
@ -133,11 +132,8 @@ Each sample will also have it's own directory containing the following (dependen
|
|||||||
- A transcriptome derived from the query reads + reference annotation
|
- A transcriptome derived from the query reads + reference annotation
|
||||||
* merged_transcriptome.fas
|
* merged_transcriptome.fas
|
||||||
-A transcriptome made from the combined query reads and reference annotation
|
-A transcriptome made from the combined query reads and reference annotation
|
||||||
* final_polished_cds.fas (de novo only)
|
|
||||||
* CDS sequences derived from reads
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Useful links
|
## Useful links
|
||||||
|
|
||||||
* [nextflow](https://www.nextflow.io/)
|
* [nextflow](https://www.nextflow.io/)
|
||||||
|
|||||||
54
bin/merge_gff.py
Executable file
54
bin/merge_gff.py
Executable file
@ -0,0 +1,54 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Merge and fix gff files.
|
||||||
|
|
||||||
|
Merge multiple gff files into single file.
|
||||||
|
Rename gene and transcript ids to avoid attribute conflicts from
|
||||||
|
independently-created files.
|
||||||
|
"""
|
||||||
|
import argparse
|
||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
|
||||||
|
from natsort import natsorted
|
||||||
|
|
||||||
|
|
||||||
|
def main(gff_files: str, outfile: str):
|
||||||
|
"""Entry point."""
|
||||||
|
regx_id = re.compile(r'gene_id "STRG\.(\d+)"')
|
||||||
|
|
||||||
|
start = 1
|
||||||
|
with open(outfile, 'w') as fh:
|
||||||
|
for gff in gff_files:
|
||||||
|
|
||||||
|
text = Path(gff).read_text()
|
||||||
|
if start != 1:
|
||||||
|
# Strip headers
|
||||||
|
text = [x for x in text.splitlines() if not x.startswith('#')]
|
||||||
|
text = '\n'.join(text)
|
||||||
|
|
||||||
|
ids = natsorted(set(re.findall(regx_id, text)))
|
||||||
|
new_gene_ids = list(range(start, start + len(ids)))
|
||||||
|
id_map = dict(zip(ids, new_gene_ids))
|
||||||
|
|
||||||
|
for old_id, new_id in id_map.items():
|
||||||
|
text = text.replace(
|
||||||
|
f'gene_id "STRG.{old_id}"',
|
||||||
|
f'gene_id "STRG.{new_id}"')
|
||||||
|
text = text.replace(
|
||||||
|
f'transcript_id "STRG.{old_id}.',
|
||||||
|
f'transcript_id "STRG.{new_id}.')
|
||||||
|
fh.write(text)
|
||||||
|
fh.write('\n')
|
||||||
|
start += len(ids)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--gff_files", help="gff files to merge",
|
||||||
|
required=True, nargs='+')
|
||||||
|
parser.add_argument("--out_file", help="where to save merged files",
|
||||||
|
required=True)
|
||||||
|
args = parser.parse_args()
|
||||||
|
main(args.gff_files, args.out_file)
|
||||||
@ -6,7 +6,7 @@ from collections import Counter, defaultdict, OrderedDict
|
|||||||
import math
|
import math
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from aplanat import bars, lines
|
from aplanat import bars, hist, lines
|
||||||
from aplanat.components import fastcat
|
from aplanat.components import fastcat
|
||||||
from aplanat.components import simple as scomponents
|
from aplanat.components import simple as scomponents
|
||||||
from aplanat.report import WFReport
|
from aplanat.report import WFReport
|
||||||
@ -648,7 +648,8 @@ def transcript_table(report, df_tmaps, covr_threshold):
|
|||||||
### Query transcript table
|
### Query transcript table
|
||||||
|
|
||||||
Low coverage transcripts are removed to speed up the table viewing. <br>
|
Low coverage transcripts are removed to speed up the table viewing. <br>
|
||||||
This can be set with the parameter `args.min_isoform_cov` in the config.
|
This can be set with the parameter `transcript_table_cov_thresh` in the
|
||||||
|
config.
|
||||||
''')
|
''')
|
||||||
section.plot(cov_plt)
|
section.plot(cov_plt)
|
||||||
# Filter on converge threshold
|
# Filter on converge threshold
|
||||||
@ -724,17 +725,9 @@ def tanscriptome_summary(report, gffs, sample_ids, denovo=False):
|
|||||||
|
|
||||||
transcript_lens.append(tr_len)
|
transcript_lens.append(tr_len)
|
||||||
|
|
||||||
num_bins = max(isoforms_per_gene)
|
bar_isos = hist.histogram(
|
||||||
if num_bins > 12:
|
[isoforms_per_gene], colors=[Colors.cerulean],
|
||||||
num_bins = 12
|
title="isoforms per gene")
|
||||||
|
|
||||||
hist_, bins = np.histogram(isoforms_per_gene, bins=num_bins)
|
|
||||||
|
|
||||||
bar_isos = bars.simple_bar([str(round(x_, 1)) for x_ in bins], hist_,
|
|
||||||
title="Isoforms per gene",
|
|
||||||
colors=Colors.cerulean,
|
|
||||||
x_axis_label='Num. isoforms',
|
|
||||||
y_axis_label='Num. genes')
|
|
||||||
|
|
||||||
bar_isos.xaxis.major_label_orientation = math.pi / 2.8
|
bar_isos.xaxis.major_label_orientation = math.pi / 2.8
|
||||||
plots.append(bar_isos)
|
plots.append(bar_isos)
|
||||||
|
|||||||
@ -39,16 +39,13 @@ process dump_clusters {
|
|||||||
|
|
||||||
process build_backbones {
|
process build_backbones {
|
||||||
/*
|
/*
|
||||||
This step can fail in what seems to at the racon stage giving an 'empty overlap error set' message
|
Build coding
|
||||||
As a temporary fix, do racon_cmd || true to prevent it crashing the pipeline, and then move on to next cluster
|
|
||||||
|
|
||||||
This process needs some work
|
|
||||||
*/
|
*/
|
||||||
label "isoforms"
|
label "isoforms"
|
||||||
input:
|
input:
|
||||||
tuple val(sample_id), path(cluster_fq)
|
tuple val(sample_id), path(cluster_fq)
|
||||||
output:
|
output:
|
||||||
tuple val(sample_id), path("*final_polished_cds.fa"), emit: polished_cds
|
tuple val(sample_id), path("*final_polished_cds.fa"), emit: polished_cds, optional: true
|
||||||
script:
|
script:
|
||||||
def cluster_fq_bl = new BlankSeparatedList(cluster_fq)
|
def cluster_fq_bl = new BlankSeparatedList(cluster_fq)
|
||||||
"""
|
"""
|
||||||
@ -56,64 +53,70 @@ process build_backbones {
|
|||||||
UNID=\$(echo ${cluster_fq_bl[1]} | grep -o -E '[0-9]+')
|
UNID=\$(echo ${cluster_fq_bl[1]} | grep -o -E '[0-9]+')
|
||||||
|
|
||||||
for cluster in $cluster_fq_bl
|
for cluster in $cluster_fq_bl
|
||||||
do
|
do
|
||||||
clfq=`basename \$cluster`
|
clfq=`basename \$cluster`
|
||||||
cln=\${clfq%.*}
|
cln=\${clfq%.*}
|
||||||
|
|
||||||
echo Building backbone for cluster: \$cln
|
echo Building backbone for cluster: \$cln
|
||||||
echo "\tSampling input reads for backbone construction."
|
echo "\tSampling input reads for backbone construction."
|
||||||
sample=\${cln}_sample.fq
|
sample=\${cln}_sample.fq
|
||||||
seqkit head --quiet -n 100 \$cluster > \$sample
|
seqkit head --quiet -n 100 \$cluster > \$sample
|
||||||
seqkit sample --quiet -n 500 -2 -s 100 \$cluster >> \$sample
|
seqkit sample --quiet -n 500 -2 -s 100 \$cluster >> \$sample
|
||||||
echo "\tConstructing spoa consensus."
|
echo "\tConstructing spoa consensus."
|
||||||
spoa_cons=\${cln}_spoa.fa
|
spoa_cons=\${cln}_spoa.fa
|
||||||
spoa -m 5 -n -4 -g -8 -e -6 -q -10 -c -15 -l 1 -r 0 \$sample > \$spoa_cons
|
spoa -m 5 -n -4 -g -8 -e -6 -q -10 -c -15 -l 1 -r 0 \$sample > \$spoa_cons
|
||||||
|
|
||||||
echo "\tPolishing the consensus using racon."
|
echo "\tPolishing the consensus using racon."
|
||||||
|
|
||||||
# polish 1
|
# polish 1
|
||||||
samgz=\${cln}_aln.sam.gz
|
samgz=\${cln}_aln.sam.gz
|
||||||
racon_cons=\${cln}_racon.fa
|
racon_cons=\${cln}_racon.fa
|
||||||
racon_cons1=\${cln}_racon1.fa
|
tmpcons=\${cln}_tmcons.fa
|
||||||
|
|
||||||
minimap2 -t ${params.threads} -ax splice ${params.minimap2_opts} \$spoa_cons \$sample | gzip - > \$samgz
|
minimap2 -t ${params.threads} -ax splice ${params.minimap2_opts} \$spoa_cons \$sample | gzip - > \$samgz
|
||||||
racon -t ${params.threads} --no-trimming -u -w 2000 \$sample \$samgz \$spoa_cons > \$racon_cons || true
|
exitcode=0
|
||||||
if [ -f \$racon_cons ];
|
racon -t ${params.threads} --no-trimming -u -w 2000 \$sample \$samgz \$spoa_cons > \$racon_cons || exitcode=1
|
||||||
then
|
if [[ \$exitcode -eq 0 ]];
|
||||||
cat \$racon_cons | seqkit replace -p ".*" -r cluster_\${cln} > \$racon_cons1
|
then
|
||||||
else
|
# Rename consensus sequence name with cluster id
|
||||||
continue
|
cat \$racon_cons | seqkit replace -p ".*" -r cluster_\${cln} > \$tmpcons
|
||||||
fi
|
mv \$tmpcons \$racon_cons
|
||||||
|
else
|
||||||
|
echo "Polishing failed for \${cln}"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
# polish 2
|
# polish 2
|
||||||
samgz1=\${cln}_aln_1.sam.gz
|
minimap2 -t ${params.threads} -ax splice ${params.minimap2_opts} \$racon_cons \$sample | gzip - > \$samgz
|
||||||
racon_cons2=\${cln}_racon2.fa
|
exitcode=0
|
||||||
minimap2 -t ${params.threads} -ax splice ${params.minimap2_opts} \$racon_cons1 \$sample | gzip - > \$samgz1
|
racon -t ${params.threads} -u --no-trimming \$sample \$samgz \$racon_cons > \$tmpcons || exitcode=1
|
||||||
racon -t ${params.threads} -u --no-trimming \$sample \$samgz1 \$racon_cons1 > \$racon_cons2 || true
|
if [[ \$exitcode -eq 0 ]];
|
||||||
if [ -f \$racon_cons2 ];
|
then
|
||||||
then
|
echo "success polish 2"
|
||||||
echo "success polish 2"
|
mv \$tmpcons \$racon_cons
|
||||||
else
|
else
|
||||||
continue
|
echo "Polishing failed for \${cln}"
|
||||||
fi
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
# polish 3
|
# polish 3
|
||||||
samgz2=\${cln}_aln_2.sam.gz
|
minimap2 -t ${params.threads} -ax splice ${params.minimap2_opts} \$racon_cons \$sample | gzip - > \$samgz
|
||||||
minimap2 -t ${params.threads} -ax splice ${params.minimap2_opts} \$racon_cons2 \$sample | gzip - > \$samgz2
|
exitcode=0
|
||||||
EXITCODE=0
|
racon -t ${params.threads} -u \$sample \$samgz \$racon_cons > \$tmpcons || exitcode=1
|
||||||
racon -t ${params.threads} -u \$sample \$samgz2 \$racon_cons2 >> ${sample_id}_\${UNID}_final_polished_cds.fa || EXITCODE=\$?
|
if [[ \$exitcode -eq 0 ]];
|
||||||
if [ \$EXITCODE -eq 0 ];
|
then
|
||||||
then
|
cat \$tmpcons >> ${sample_id}_\${UNID}_final_polished_cds.fa
|
||||||
echo "finished"
|
echo "polishing 3 success"
|
||||||
fi
|
else
|
||||||
|
echo "Polishing failed for \${cln}"
|
||||||
|
fi
|
||||||
|
|
||||||
done
|
done
|
||||||
echo "Finished backbones"
|
echo "Finished backbones"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
process merge_cds {
|
process merge_cds {
|
||||||
label "isoforms"
|
label "isoforms"
|
||||||
input:
|
input:
|
||||||
@ -121,7 +124,6 @@ process merge_cds {
|
|||||||
output:
|
output:
|
||||||
tuple val(sample_id), path("${sample_id}_cds.fa"), emit: final_polished_cds
|
tuple val(sample_id), path("${sample_id}_cds.fa"), emit: final_polished_cds
|
||||||
script:
|
script:
|
||||||
def merge_list
|
|
||||||
"""
|
"""
|
||||||
for FILE in *final_polished_cds.fa
|
for FILE in *final_polished_cds.fa
|
||||||
do
|
do
|
||||||
@ -138,14 +140,13 @@ process cds_align {
|
|||||||
tuple val(sample_id), path("${sample_id}_reads_aln_sorted.bam"), emit: bam
|
tuple val(sample_id), path("${sample_id}_reads_aln_sorted.bam"), emit: bam
|
||||||
tuple val(sample_id), path("${sample_id}_read_aln_stats.tsv"), emit: stats
|
tuple val(sample_id), path("${sample_id}_read_aln_stats.tsv"), emit: stats
|
||||||
script:
|
script:
|
||||||
def ab = "${sample_id}_reads_aln_sorted.bam"
|
|
||||||
"""
|
"""
|
||||||
minimap2 -t ${params.threads} \
|
minimap2 -t ${params.threads} \
|
||||||
-ax splice ${params.minimap2_opts} $polished_cds $sorted_reads_dir/sorted_reads.fastq |\
|
-ax splice ${params.minimap2_opts} $polished_cds $sorted_reads_dir/sorted_reads.fastq |\
|
||||||
samtools view -b - |\
|
samtools view -b - |\
|
||||||
samtools sort -o $ab;
|
samtools sort -o "${sample_id}_reads_aln_sorted.bam";
|
||||||
samtools index $ab;
|
samtools index "${sample_id}_reads_aln_sorted.bam";
|
||||||
((seqkit bam -s -j ${params.threads} ${ab} 2>&1) | tee ${sample_id}_read_aln_stats.tsv ) || true
|
((seqkit bam -s -j ${params.threads} "${sample_id}_reads_aln_sorted.bam" 2>&1) | tee ${sample_id}_read_aln_stats.tsv ) || true
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,16 +169,14 @@ process make_batches {
|
|||||||
|
|
||||||
minimum_batch_size = 2000
|
minimum_batch_size = 2000
|
||||||
"""
|
"""
|
||||||
nr_bases=\$(seqkit stats -T $fastq|cut -f 5| sed '2q;d')
|
|
||||||
|
|
||||||
b=0
|
b=0
|
||||||
if [ ${params.batch_size} -lt \$b ];
|
if [ ${params.batch_size} -lt \$b ];
|
||||||
then
|
then
|
||||||
nr_bases=\$(seqkit stats -T $fastq|cut -f 5| sed '2q;d')
|
nr_bases=\$(seqkit stats -T $fastq|cut -f 5| sed '2q;d')
|
||||||
let batch_size=\$nr_bases/1000/$maxcpus
|
let batch_size=\$nr_bases/1000/$maxcpus
|
||||||
if [ \$batch_size -lt $minimum_batch_size ];
|
if [ \$batch_size -lt $minimum_batch_size ];
|
||||||
then
|
then
|
||||||
batch_size=$minimum_batch_size
|
batch_size=$minimum_batch_size
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
batch_size=${params.batch_size}
|
batch_size=${params.batch_size}
|
||||||
@ -186,11 +185,12 @@ process make_batches {
|
|||||||
echo "Batch size:\$batch_size";
|
echo "Batch size:\$batch_size";
|
||||||
echo "Num bases: \$nr_bases";
|
echo "Num bases: \$nr_bases";
|
||||||
|
|
||||||
init_cls_options="--batch-size \$batch_size --kmer-size ${params.kmer_size} \
|
init_cls_options="--batch-size \$batch_size --kmer-size ${params.kmer_size} --window-size ${params.window_size} \
|
||||||
--window-size ${params.window_size} --min-shared ${params.min_shared} --min-qual ${params.min_qual} \
|
--min-shared ${params.min_shared} --min-qual ${params.min_qual} \
|
||||||
--mapped-threshold ${params.mapped_threshold} --aligned-threshold ${params.aligned_threshold} \
|
--mapped-threshold ${params.mapped_threshold} --aligned-threshold ${params.aligned_threshold} \
|
||||||
--min-fraction ${params.min_fraction} --min-prob-no-hits ${params.min_prob_no_hits} \
|
--min-fraction ${params.min_fraction} --min-prob-no-hits ${params.min_prob_no_hits} \
|
||||||
-M ${params.batch_max_seq} -P ${params.consensus_period} -g ${params.consensus_minimum} -c ${params.consensus_maximum} -F ${params.min_left_cls} "
|
-M ${params.batch_max_seq} -P ${params.consensus_period} -g ${params.consensus_minimum} \
|
||||||
|
-c ${params.consensus_maximum} -F ${params.min_left_cls} "
|
||||||
mkdir -p sorted; isONclust2 sort \$init_cls_options -v -o sorted $fastq;
|
mkdir -p sorted; isONclust2 sort \$init_cls_options -v -o sorted $fastq;
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -206,7 +206,6 @@ process clustering() {
|
|||||||
script:
|
script:
|
||||||
"""
|
"""
|
||||||
run_isonclust2.py $sorted_batches
|
run_isonclust2.py $sorted_batches
|
||||||
|
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,8 +215,8 @@ process cluster_quality() {
|
|||||||
label "isoforms"
|
label "isoforms"
|
||||||
|
|
||||||
input:
|
input:
|
||||||
tuple val(sample_id), path(reads_fl), path(final_clusters_dir)
|
|
||||||
path reference
|
path reference
|
||||||
|
tuple val(sample_id), path(reads_fl), path(final_clusters_dir)
|
||||||
output:
|
output:
|
||||||
tuple val(sample_id),
|
tuple val(sample_id),
|
||||||
path("${sample_id}_cluster_qc"), emit: cluster_qc_dir
|
path("${sample_id}_cluster_qc"), emit: cluster_qc_dir
|
||||||
@ -229,16 +228,15 @@ process cluster_quality() {
|
|||||||
def bam = "${qc_dir}/ref_aln.bam"
|
def bam = "${qc_dir}/ref_aln.bam"
|
||||||
|
|
||||||
"""
|
"""
|
||||||
echo $qc_dir_raw
|
|
||||||
mkdir $qc_dir
|
mkdir $qc_dir
|
||||||
mkdir $qc_dir_raw
|
mkdir $qc_dir_raw
|
||||||
minimap2 -ax splice -t 2 $reference $reads_fl |\
|
minimap2 -ax splice -t 2 $reference $reads_fl |\
|
||||||
samtools view -q 2 -F 2304 -b - |\
|
samtools view -q 2 -F 2304 -b - |\
|
||||||
samtools sort - -o $bam;
|
samtools sort - -o $bam;
|
||||||
samtools index $bam;
|
samtools index $bam;
|
||||||
compute_cluster_quality.py --sizes $final_clusters_dir/clusters_info.tsv \
|
compute_cluster_quality.py --sizes $final_clusters_dir/clusters_info.tsv \
|
||||||
--outfile ${qc_dir}/cluster_quality.csv --ont --clusters $final_clusters_dir/clusters.tsv \
|
--outfile ${qc_dir}/cluster_quality.csv --ont --clusters $final_clusters_dir/clusters.tsv \
|
||||||
--classes $bam --report ${qc_dir}/cluster_quality.pdf --raw_data_out $qc_dir_raw
|
--classes $bam --report ${qc_dir}/cluster_quality.pdf --raw_data_out $qc_dir_raw
|
||||||
"""
|
"""
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -248,37 +246,35 @@ workflow denovo_assembly {
|
|||||||
fastq_reads_fl
|
fastq_reads_fl
|
||||||
reference
|
reference
|
||||||
main:
|
main:
|
||||||
|
|
||||||
make_batches(fastq_reads_fl)
|
make_batches(fastq_reads_fl)
|
||||||
|
|
||||||
clustering(make_batches.output.sorted_batches)
|
clustering(make_batches.out.sorted_batches)
|
||||||
|
|
||||||
dump_clusters(clustering.output.root_cluster
|
dump_clusters(
|
||||||
.join(make_batches.output.sorted_reads_dir))
|
clustering.out.root_cluster
|
||||||
|
.join(make_batches.out.sorted_reads_dir))
|
||||||
|
|
||||||
build_backbones(dump_clusters.output.final_clusters
|
build_backbones(
|
||||||
.flatMap(map_sample_ids_cls)
|
dump_clusters.out.final_clusters
|
||||||
.groupTuple(size: 10, remainder: true)
|
.flatMap(map_sample_ids_cls)
|
||||||
)
|
.groupTuple(size: 10, remainder: true))
|
||||||
|
|
||||||
merge_cds(build_backbones.output.polished_cds
|
merge_cds(
|
||||||
.flatMap(map_sample_ids_cls)
|
build_backbones.out.polished_cds
|
||||||
.groupTuple()
|
.flatMap(map_sample_ids_cls)
|
||||||
)
|
.groupTuple())
|
||||||
|
|
||||||
cds_align(merge_cds.out.final_polished_cds.view()
|
cds_align(
|
||||||
.join(make_batches.output.sorted_reads_dir))
|
merge_cds.out.final_polished_cds
|
||||||
|
.join(make_batches.out.sorted_reads_dir))
|
||||||
|
|
||||||
if (!reference.name.startsWith('OPTIONAL_FILE')){
|
if (!reference.name.startsWith('OPTIONAL_FILE')){
|
||||||
|
cluster_quality(reference, fastq_reads_fl
|
||||||
|
.join(dump_clusters.out.final_clusters_dir))
|
||||||
|
|
||||||
cluster_quality(fastq_reads_fl
|
cluster_quality.out.cluster_qc_dir.set { opt_qual_ch }
|
||||||
.join(dump_clusters.output.final_clusters_dir), reference)
|
|
||||||
|
|
||||||
cluster_quality.out.cluster_qc_dir
|
cluster_quality.out.cluster_qc_raw.set { opt_qual_raw_ch }
|
||||||
.set { opt_qual_ch }
|
|
||||||
|
|
||||||
cluster_quality.output.cluster_qc_raw
|
|
||||||
.set { opt_qual_raw_ch }
|
|
||||||
|
|
||||||
} else{
|
} else{
|
||||||
Channel.empty().set { opt_qual_ch }
|
Channel.empty().set { opt_qual_ch }
|
||||||
@ -286,9 +282,9 @@ workflow denovo_assembly {
|
|||||||
}
|
}
|
||||||
|
|
||||||
emit:
|
emit:
|
||||||
bam = cds_align.output.bam
|
bam = cds_align.out.bam
|
||||||
cds = merge_cds.out.final_polished_cds
|
cds = merge_cds.out.final_polished_cds
|
||||||
stats = cds_align.output.stats
|
stats = cds_align.out.stats
|
||||||
opt_qual_ch
|
opt_qual_ch
|
||||||
opt_qual_raw_ch
|
opt_qual_raw_ch
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
name: epi2melabs-wf-isoforms-test
|
name: epi2melabs-wf-isoforms
|
||||||
channels:
|
channels:
|
||||||
- epi2melabs
|
- epi2melabs
|
||||||
- bioconda
|
- bioconda
|
||||||
@ -26,3 +26,4 @@ dependencies:
|
|||||||
- isonclust2==2.3
|
- isonclust2==2.3
|
||||||
- parallel
|
- parallel
|
||||||
- scikit-learn==1.0.2
|
- scikit-learn==1.0.2
|
||||||
|
- natsort
|
||||||
|
|||||||
99
main.nf
99
main.nf
@ -42,6 +42,7 @@ process getVersions {
|
|||||||
python -c "import pysam; print(f'pysam,{pysam.__version__}')" >> versions.txt
|
python -c "import pysam; print(f'pysam,{pysam.__version__}')" >> versions.txt
|
||||||
python -c "import aplanat; print(f'aplanat,{aplanat.__version__}')" >> versions.txt
|
python -c "import aplanat; print(f'aplanat,{aplanat.__version__}')" >> versions.txt
|
||||||
python -c "import pandas; print(f'pandas,{pandas.__version__}')" >> versions.txt
|
python -c "import pandas; print(f'pandas,{pandas.__version__}')" >> versions.txt
|
||||||
|
python -c "import sklearn; print(f'scikit-learn,{sklearn.__version__}')" >> versions.txt
|
||||||
fastcat --version | sed 's/^/fastcat,/' >> versions.txt
|
fastcat --version | sed 's/^/fastcat,/' >> versions.txt
|
||||||
minimap2 --version | sed 's/^/minimap2,/' >> versions.txt
|
minimap2 --version | sed 's/^/minimap2,/' >> versions.txt
|
||||||
samtools --version | head -n 1 | sed 's/ /,/' >> versions.txt
|
samtools --version | head -n 1 | sed 's/ /,/' >> versions.txt
|
||||||
@ -105,7 +106,7 @@ process build_minimap_index{
|
|||||||
path "genome_index.mmi", emit: index
|
path "genome_index.mmi", emit: index
|
||||||
script:
|
script:
|
||||||
"""
|
"""
|
||||||
minimap2 -t ${params.threads} ${params.minimap_index_opts} -I 1000G -d "genome_index.mmi" ${reference}
|
minimap2 -t ${params.threads} ${params.minimap_index_opts} -I 1000G -d "genome_index.mmi" ${reference}
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +129,7 @@ process split_bam{
|
|||||||
if (params["bundle_min_reads"] != false)
|
if (params["bundle_min_reads"] != false)
|
||||||
"""
|
"""
|
||||||
seqkit bam -j ${params.threads} -N ${params.bundle_min_reads} ${bam} -o bam_bundles/
|
seqkit bam -j ${params.threads} -N ${params.bundle_min_reads} ${bam} -o bam_bundles/
|
||||||
mv bam_bundles/* .
|
mv bam_bundles/* .
|
||||||
for f in *:*; do mv -v "\$f" \$(echo "\$f" | tr ':' '-'); done
|
for f in *:*; do mv -v "\$f" \$(echo "\$f" | tr ':' '-'); done
|
||||||
"""
|
"""
|
||||||
else
|
else
|
||||||
@ -145,7 +146,7 @@ process assemble_transcripts{
|
|||||||
Take aligned reads in bam format that may be a chunk of a larger alignment file.
|
Take aligned reads in bam format that may be a chunk of a larger alignment file.
|
||||||
Optionally use reference annotation to guide assembly.
|
Optionally use reference annotation to guide assembly.
|
||||||
|
|
||||||
Output gff annotation files in a tuple with `sample_id` for combining into samples late rin the pipeline.
|
Output gff annotation files in a tuple with `sample_id` for combining into samples later in the pipeline.
|
||||||
*/
|
*/
|
||||||
label 'isoforms'
|
label 'isoforms'
|
||||||
cpus params.threads
|
cpus params.threads
|
||||||
@ -158,16 +159,17 @@ process assemble_transcripts{
|
|||||||
script:
|
script:
|
||||||
def out_filename = bam.name.replaceFirst(~/\.[^\.]+$/, '') + "_${sample_id}.gff"
|
def out_filename = bam.name.replaceFirst(~/\.[^\.]+$/, '') + "_${sample_id}.gff"
|
||||||
def G_FLAG = ref_annotation.name.startsWith('OPTIONAL_FILE') ? '' : "-G ${ref_annotation}"
|
def G_FLAG = ref_annotation.name.startsWith('OPTIONAL_FILE') ? '' : "-G ${ref_annotation}"
|
||||||
|
def prefix = bam.name.split('-')[0][5..-1]
|
||||||
"""
|
"""
|
||||||
stringtie --rf ${G_FLAG} -L -v -A gene_abund.tab -p ${params.threads} ${params.stringtie_opts} -o ${out_filename} \
|
stringtie --rf ${G_FLAG} -L -v -A gene_abund.tab -p ${params.threads} ${params.stringtie_opts} -o ${out_filename} \
|
||||||
${bam} 2>/dev/null
|
-l $prefix ${bam} 2>/dev/null
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
process merge_gff_bundles{
|
process merge_gff_bundles{
|
||||||
/*
|
/*
|
||||||
Merge gff bundles into a single gff file.
|
Merge gff bundles into a single gff file per sample.
|
||||||
*/
|
*/
|
||||||
label 'isoforms'
|
label 'isoforms'
|
||||||
|
|
||||||
@ -215,14 +217,14 @@ process run_gffcompare{
|
|||||||
mkdir $out_dir
|
mkdir $out_dir
|
||||||
echo "Doing comparison of reference annotation: ${ref_annotation} and the query annotation"
|
echo "Doing comparison of reference annotation: ${ref_annotation} and the query annotation"
|
||||||
|
|
||||||
gffcompare -o ${out_dir}/str_merged -r ${ref_annotation} \
|
gffcompare -o ${out_dir}/str_merged -r ${ref_annotation} \
|
||||||
${params.gffcompare_opts} ${query_annotation}
|
${params.gffcompare_opts} ${query_annotation}
|
||||||
|
|
||||||
generate_tracking_summary.py --tracking $out_dir/str_merged.tracking \
|
generate_tracking_summary.py --tracking $out_dir/str_merged.tracking \
|
||||||
--output_dir ${out_dir} --annotation ${ref_annotation}
|
--output_dir ${out_dir} --annotation ${ref_annotation}
|
||||||
|
|
||||||
mv *.tmap $out_dir
|
mv *.tmap $out_dir
|
||||||
mv *.refmap $out_dir
|
mv *.refmap $out_dir
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -231,7 +233,6 @@ process run_gffcompare{
|
|||||||
process get_transcriptome{
|
process get_transcriptome{
|
||||||
/*
|
/*
|
||||||
Write out a transcriptome file based on the query gff annotations.
|
Write out a transcriptome file based on the query gff annotations.
|
||||||
TODO: Do we need to touch merged_transcriptome or can we just pass it?
|
|
||||||
*/
|
*/
|
||||||
label 'isoforms'
|
label 'isoforms'
|
||||||
|
|
||||||
@ -244,13 +245,10 @@ process get_transcriptome{
|
|||||||
def transcriptome = "${sample_id}_transcriptome.fas"
|
def transcriptome = "${sample_id}_transcriptome.fas"
|
||||||
def merged_transcriptome = "${sample_id}_merged_transcriptome.fas"
|
def merged_transcriptome = "${sample_id}_merged_transcriptome.fas"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
gffread -g ${reference_seq} -w ${transcriptome} ${transcripts_gff}
|
gffread -g ${reference_seq} -w ${transcriptome} ${transcripts_gff}
|
||||||
if [ "\$(ls -A $gffcmp_dir)" ];
|
if [ "\$(ls -A $gffcmp_dir)" ];
|
||||||
then
|
then
|
||||||
echo "Yes"
|
gffread -F -g ${reference_seq} -w ${merged_transcriptome} $gffcmp_dir/str_merged.annotated.gtf
|
||||||
gffread -F -g ${reference_seq} -w ${merged_transcriptome} \
|
|
||||||
$gffcmp_dir/str_merged.annotated.gtf
|
|
||||||
fi
|
fi
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
@ -274,7 +272,6 @@ process makeReport {
|
|||||||
script:
|
script:
|
||||||
// Convert the sample_id arrayList.
|
// Convert the sample_id arrayList.
|
||||||
sids = new BlankSeparatedList(sample_ids)
|
sids = new BlankSeparatedList(sample_ids)
|
||||||
|
|
||||||
def report_name = "wf-isoforms-report.html"
|
def report_name = "wf-isoforms-report.html"
|
||||||
def OPT_ALN = denovo ? '' : "--alignment_stats ${aln_stats}"
|
def OPT_ALN = denovo ? '' : "--alignment_stats ${aln_stats}"
|
||||||
def OPT_DENOVO = denovo ? "--denovo" : ''
|
def OPT_DENOVO = denovo ? "--denovo" : ''
|
||||||
@ -365,61 +362,63 @@ workflow pipeline {
|
|||||||
run_gffcompare(merge_gff_bundles.out.gff, ref_annotation)
|
run_gffcompare(merge_gff_bundles.out.gff, ref_annotation)
|
||||||
|
|
||||||
if (params.denovo){
|
if (params.denovo){
|
||||||
// Use the perd-sample, de novo-assembled CDS
|
// Use the per-sample, de novo-assembled CDS
|
||||||
seq_for_transcriptome_build = m.cds
|
seq_for_transcriptome_build = m.cds
|
||||||
}else {
|
}else {
|
||||||
// If doing reference based assembly, there is only one reference
|
// For reference based assembly, there is only one reference
|
||||||
// So map this reference to all sample_ids
|
// So map this reference to all sample_ids
|
||||||
seq_for_transcriptome_build = sample_ids.flatten().combine(Channel.fromPath(params.ref_genome))
|
seq_for_transcriptome_build = sample_ids.flatten().combine(Channel.fromPath(params.ref_genome))
|
||||||
}
|
}
|
||||||
|
|
||||||
makeReport(software_versions,
|
makeReport(
|
||||||
workflow_params,
|
software_versions,
|
||||||
params.denovo,
|
workflow_params,
|
||||||
summariseConcatReads.out.summary
|
params.denovo,
|
||||||
.join(m.stats)
|
summariseConcatReads.out.summary
|
||||||
.join(run_gffcompare.out.gffcmp_dir)
|
.join(m.stats)
|
||||||
.join(preprocess_reads.out.report)
|
.join(run_gffcompare.out.gffcmp_dir)
|
||||||
.join(merge_gff_bundles.out.gff)
|
.join(preprocess_reads.out.report)
|
||||||
.toList().transpose().toList()
|
.join(merge_gff_bundles.out.gff)
|
||||||
)
|
.toList().transpose().toList())
|
||||||
|
|
||||||
report = makeReport.out.report
|
report = makeReport.out.report
|
||||||
|
|
||||||
get_transcriptome(merge_gff_bundles.out.gff
|
get_transcriptome(
|
||||||
|
merge_gff_bundles.out.gff
|
||||||
.join(run_gffcompare.out.gffcmp_dir)
|
.join(run_gffcompare.out.gffcmp_dir)
|
||||||
.join(seq_for_transcriptome_build))
|
.join(seq_for_transcriptome_build))
|
||||||
|
|
||||||
if (use_ref_ann){
|
if (use_ref_ann){
|
||||||
results = preprocess_reads.out.report
|
results = preprocess_reads.out.report
|
||||||
.concat(run_gffcompare.output.gffcmp_dir,
|
.concat(
|
||||||
m.stats,
|
run_gffcompare.output.gffcmp_dir,
|
||||||
get_transcriptome.out.flatMap(map_sample_ids_cls))
|
m.stats,
|
||||||
.map {it -> it[1]}
|
get_transcriptome.out.flatMap(map_sample_ids_cls))
|
||||||
.concat(makeReport.out.report)
|
.map {it -> it[1]}
|
||||||
|
.concat(makeReport.out.report)
|
||||||
|
|
||||||
}
|
}
|
||||||
if (!use_ref_ann && !params.denovo){
|
if (!use_ref_ann && !params.denovo){
|
||||||
results = preprocess_reads.out.report
|
results = preprocess_reads.out.report
|
||||||
.concat(m.stats,
|
.concat(m.stats,
|
||||||
get_transcriptome.out.flatMap(map_sample_ids_cls))
|
get_transcriptome.out.flatMap(map_sample_ids_cls))
|
||||||
.map {it -> it[1]}
|
.map {it -> it[1]}
|
||||||
.concat(makeReport.out.report)
|
.concat(makeReport.out.report)
|
||||||
|
|
||||||
}
|
}
|
||||||
if (params.denovo){
|
if (params.denovo){
|
||||||
results = m.cds
|
results = m.cds
|
||||||
.concat(m.stats,
|
.concat(m.stats,
|
||||||
seq_for_transcriptome_build,
|
seq_for_transcriptome_build,
|
||||||
get_transcriptome.out.flatMap(map_sample_ids_cls),
|
get_transcriptome.out.flatMap(map_sample_ids_cls),
|
||||||
merge_gff_bundles.out.gff,
|
merge_gff_bundles.out.gff,
|
||||||
m.opt_qual_ch.flatMap {it ->
|
m.opt_qual_ch.flatMap {it ->
|
||||||
l = []
|
l = []
|
||||||
for (x in it[1..-1]){
|
for (x in it[1..-1]){
|
||||||
l.add(tuple(it[0], x))
|
l.add(tuple(it[0], x))
|
||||||
}
|
}
|
||||||
return l
|
return l
|
||||||
})
|
})
|
||||||
.map {it -> it[1]}
|
.map {it -> it[1]}
|
||||||
.concat(makeReport.out.report)
|
.concat(makeReport.out.report)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,23 +16,23 @@ process map_reads{
|
|||||||
tuple val(sample_id), path("${sample_id}_reads_aln_sorted.bam"), emit: bam
|
tuple val(sample_id), path("${sample_id}_reads_aln_sorted.bam"), emit: bam
|
||||||
tuple val(sample_id), path("${sample_id}_read_aln_stats.tsv"), emit: stats
|
tuple val(sample_id), path("${sample_id}_read_aln_stats.tsv"), emit: stats
|
||||||
script:
|
script:
|
||||||
def ContextFilter = """AlnContext: { Ref: "${reference}", LeftShift: -${params.poly_context}, RightShift: ${params.poly_context},
|
def ContextFilter = """AlnContext: { Ref: "${reference}", LeftShift: -${params.poly_context},
|
||||||
RegexEnd: "[Aa]{${params.max_poly_run},}",
|
RightShift: ${params.poly_context}, RegexEnd: "[Aa]{${params.max_poly_run},}",
|
||||||
Stranded: True,Invert: True, Tsv: "internal_priming_fail.tsv"} """
|
Stranded: True,Invert: True, Tsv: "internal_priming_fail.tsv"} """
|
||||||
"""
|
"""
|
||||||
seqkit fq2fa ${fastq_reads} -o "reads.fa";
|
seqkit fq2fa ${fastq_reads} -o "reads.fa";
|
||||||
minimap2 -t ${params.threads} -ax splice ${params.minimap2_opts} ${index} "reads.fa"\
|
minimap2 -t ${params.threads} -ax splice ${params.minimap2_opts} ${index} "reads.fa"\
|
||||||
| samtools view -q ${params.minimum_mapping_quality} -F 2304 -Sb -\
|
| samtools view -q ${params.minimum_mapping_quality} -F 2304 -Sb -\
|
||||||
| seqkit bam -j ${params.threads} -x -T '${ContextFilter}' -\
|
| seqkit bam -j ${params.threads} -x -T '${ContextFilter}' -\
|
||||||
| samtools sort -@ ${params.threads} -o "${sample_id}_reads_aln_sorted.bam" - ;
|
| samtools sort -@ ${params.threads} -o "${sample_id}_reads_aln_sorted.bam" - ;
|
||||||
((cat "${sample_id}_reads_aln_sorted.bam" | seqkit bam -s -j ${params.threads} - 2>&1) | tee ${sample_id}_read_aln_stats.tsv ) || true
|
((cat "${sample_id}_reads_aln_sorted.bam" | seqkit bam -s -j ${params.threads} - 2>&1) | tee ${sample_id}_read_aln_stats.tsv ) || true
|
||||||
|
|
||||||
if [[ -s "internal_priming_fail.tsv" ]];
|
if [[ -s "internal_priming_fail.tsv" ]];
|
||||||
then
|
then
|
||||||
tail -n +2 "internal_priming_fail.tsv" | awk '{{print ">" \$1 "\\n" \$4 }}' - > "context_internal_priming_fail_start.fasta"
|
tail -n +2 "internal_priming_fail.tsv" | awk '{{print ">" \$1 "\\n" \$4 }}' - > "context_internal_priming_fail_start.fasta"
|
||||||
tail -n +2 "internal_priming_fail.tsv" | awk '{{print ">" \$1 "\\n" \$6 }}' - > "context_internal_priming_fail_end.fasta"
|
tail -n +2 "internal_priming_fail.tsv" | awk '{{print ">" \$1 "\\n" \$6 }}' - > "context_internal_priming_fail_end.fasta"
|
||||||
fi
|
fi
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
workflow reference_assembly {
|
workflow reference_assembly {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user