Thanks! I used local modules because nf-core integration caused issues for standalone execution. Conda was chosen for Codespace compatibility and Docker is also available as an option in this pipeline. The pipeline is modular, so refactoring to nf-core style would be easy. Appreciate the feedback!
GitHub: https://github.com/eya146/nanopore-bacterial-pipeline
I built a Nextflow pipeline for phage-bacteria assembly from Nanopore long-read data. I would appreciate a code review before my interview next week. This is my first metagenomics pipeline. My experience is usually with human genomic data and reference genomes. So any feedback will be greatly appreciated.
Pipeline steps:
QC: NanoPlot
Trimming: Porechop
Filtering: Chopper
Assembly: Flye (--meta)
Polishing: Medaka
Assembly QC: QUAST
Gene prediction: PHANOTATE
Annotation: BLAST (Staph/Strep + viral databases)
Reporting: MultiQC
Results from test data:
Complete circular phage genome: 58.8 kb, 714x coverage
563 predicted proteins
QUAST: 1 contig, N50 = total length, 0 N's
The paradox: The Sample ID says 38phages_SaSt (expects Staph/Strep phages). BLAST hits show Vibrio, Klebsiella, and Pseudomonas phages. Only 14 of 563 proteins matched Staph/Strep. And I found 213 viral phage proteins.
What I know is missing: Docker, CI testing, better error handling. And I need to make the README file
Any feedback appreciated. Thank you!
2 answers
Well great job! If i where you i would rather use prebuilt module from nf-core Module, Docker/Conda, enhance subworkflow to modularized the pipeline and enhance reusability. I would also have a look at nf-core best practice.
while your workflow might work this is not the usual good practice to build a NF workflow.
You should have a 'meta' associative array next to your path, the argument should be defined in a config file (see any nf-core module for more information). This greatly helps to parallelize things.
for example:
process CHOPPER {
tag "Chopper"
input:
path reads
val min_length
val min_quality
output:
path "filtered.fastq", emit: filtered
path "chopper_stats.txt", emit: stats
would be defined as
process CHOPPER {
label "process_single"
tag "${meta.id}"
input:
tuple val(meta),path(reads)
output:
tuple val(meta),path("*.fastq"), emit: filtered
tuple val(meta),path("*stats.txt"), emit: stats
script:
def min_length= task.ext.min_length?:1234
def min_quality= task.ext.min_quality?:1234
def prefix = task.ext.prefix?:"${meta.id}.chopper"
"""
(...)
chopper (....) > ${prefix}.fastq
(...)
}
`
and in the nextflow_config:
params {
min_length = 100
min_quality = 20
}
process {
withName: "CHOPPER" {
ext.min_length = {"${params.min_length}" as int }
ext.min_quality = {"${params.min_quality}" as int }
}
}
EDIT:
(grep -c "^@" filtered.fastq)
this is a bad way to count the number of records in a fastq file because '@' is a valid quality symbol.
you could use:
cat filtered.fastq | paste - - - - |wc -l
Thank you. I hadnt thought of that
Log in to answer this question.
Have you tried asking ChatGPT (or your favorite AI tool) to do a code review? It can generate good pointers.
Where are the samples coming for? Are these just phage sequences?