Skip to content

Commit 9ba0c20

Browse files
committed
add porechop_abi, chopper, and savont to summary report
1 parent 601a5fe commit 9ba0c20

3 files changed

Lines changed: 153 additions & 11 deletions

File tree

assets/report_template.Rmd

Lines changed: 137 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,19 @@ params:
7474
input_fasta: FALSE
7575
input_folder: FALSE
7676
mqc_plot: FALSE
77+
porechop_abi_log_paths: FALSE
78+
chopper_stats_path: FALSE
7779
cutadapt_summary: FALSE
80+
savont_asv_table_path : FALSE
81+
savont_stats_path: FALSE
7882
dada_filtntrim_args: FALSE
7983
dada_qc_f_path: FALSE
8084
dada_qc_r_path: ""
8185
dada_pp_qc_f_path: ""
8286
dada_pp_qc_r_path: ""
8387
dada_err_path: FALSE
8488
dada_err_run: ""
85-
asv_table_path: FALSE
89+
dada_asv_table_path: FALSE
8690
path_asv_fa: FALSE
8791
path_dada2_tab: FALSE
8892
dada_stats_path: FALSE
@@ -272,6 +276,52 @@ _The cause is likely a bug in Kaleido, a dependency of MultiQC. There is no need
272276
}
273277
```
274278

279+
<!-- Subsection on Porechop_ABI -->
280+
281+
```{r, eval = !isFALSE(params$porechop_abi_log_paths), results='asis'}
282+
cat(paste0("
283+
## Adapter removal with Porechop_ABI
284+
285+
[Porechop_ABI](https://pubmed.ncbi.nlm.nih.gov/36698762/) removed adapters from reads.
286+
This is important to not have any remaining non-biological remnants in the read data.
287+
288+
Information about changes to the data can be found in the [MultiQC report](../multiqc/multiqc_report.html) and
289+
Porechop_ABI log files can be found in folder [porechop_abi](../porechop_abi).
290+
"))
291+
```
292+
293+
<!-- Subsection on Chopper -->
294+
295+
```{r, eval = !isFALSE(params$chopper_stats_path), results='asis'}
296+
cat(paste0("
297+
## Read filtering with Chopper
298+
299+
[Chopper](https://pubmed.ncbi.nlm.nih.gov/37171891/) filtered reads based on quality cutoffs.
300+
Reducing the data and number of reads can speed up subsequent steps, but is not strictely required.
301+
"))
302+
303+
# import tsv
304+
chopper_stats <- read.table(file = params$chopper_stats_path, header = TRUE, sep = "\t")
305+
chopper_stats$passing_percent <- chopper_stats$chopper_output / chopper_stats$chopper_input * 100
306+
chopper_max_discarded <- round( 100 - min(chopper_stats$passing_percent), 1 )
307+
chopper_avg_passed <- round(mean(chopper_stats$passing_percent),1)
308+
309+
# prep text
310+
chopper_text <- paste0("Less than ",
311+
chopper_max_discarded, "% of the sequences were discarded per sample and a mean of ",
312+
chopper_avg_passed, "% of the sequences (",min(chopper_stats$chopper_output)," to ",
313+
max(chopper_stats$chopper_output),") per sample passed the filtering.
314+
")
315+
cat(chopper_text)
316+
317+
# display table
318+
datatable(chopper_stats, options = list(
319+
scrollX = TRUE,
320+
scrollY = "300px",
321+
paging = FALSE))
322+
323+
```
324+
275325
<!-- Subsection on Cutadapt -->
276326

277327
```{r, eval = !isFALSE(params$cutadapt_summary), results='asis'}
@@ -314,6 +364,68 @@ datatable(cutadapt_summary, options = list(
314364
paging = FALSE))
315365
```
316366

367+
<!-- Subsection on Savont ASVs -->
368+
369+
```{r, eval = !isFALSE(params$savont_asv_table_path) || !isFALSE(params$savont_stats_path), results='asis'}
370+
cat(paste0("
371+
# ASV inference using Savont
372+
373+
[Savont](https://doi.org/10.64898/2026.05.26.727271) generates Amplicon Sequence Variants (ASVs) at single-nucleotide resolution
374+
from long-read amplicon sequencing data such as Oxford Nanopore (ONT) R10.4 sequencing (preferably with SUP basecalling) or PacBio HiFi sequencing.
375+
376+
Savont filters reads (98% quality), produces ASVs, and removes apparent PCR chimera.
377+
"))
378+
```
379+
380+
<!-- Subsection on Savont ASVs -->
381+
382+
```{r, eval = !isFALSE(params$savont_asv_table_path), results='asis'}
383+
cat("## Inferred ASVs\n\n")
384+
385+
#import asv table
386+
asv_table <- read.table(file = params$savont_asv_table_path, header = TRUE, sep = "\t")
387+
n_asv <- nrow(asv_table)
388+
n_asv_final <- nrow(asv_table) #this is to report the original number later in the methods section
389+
390+
# Output text
391+
cat("Savont generated", n_asv,
392+
"amplicon sequence variants (ASVs) across all samples. ")
393+
if ( params$dada_sample_inference == "independent" ) {
394+
cat("The ASVs can be found in [`savont/pooled_final_asvs.fasta`](../savont/). And the corresponding",
395+
" quantification of the ASVs across samples is in [`savont/independent_feature-table.tsv`](../savont/).",
396+
"ASVs were inferred for each sample independently",
397+
"and per-sample information can be found in [`savont/per-sample](../savont/per-sample/). ")
398+
} else if ( params$dada_sample_inference == "pooled" ) {
399+
cat("The ASVs can be found in [`savont/pooled_final_asvs.fasta`](../savont/). And the corresponding",
400+
" quantification of the ASVs across samples is in [`savont/pooled_feature-table.tsv`](../savont/).",
401+
"ASVs were inferred from pooled sample information. ")
402+
}
403+
```
404+
405+
<!-- Subsection on Savont per-sample counts -->
406+
407+
```{r, eval = !isFALSE(params$savont_stats_path), results='asis'}
408+
cat(paste0("
409+
## Read counts per sample
410+
411+
The following table shows the read numbers per sample after ASV inference.
412+
"))
413+
414+
# import tsv
415+
savont_stats <- read.table(file = params$savont_stats_path, header = TRUE, sep = "\t")
416+
417+
datatable(savont_stats, options = list(
418+
scrollX = TRUE,
419+
scrollY = "300px",
420+
paging = FALSE))
421+
422+
cat(paste0("
423+
The ASV count table contained in total ",sum(savont_stats$savont_output)," counts,
424+
at least ",min(savont_stats$savont_output)," and at most ",max(savont_stats$savont_output)," per sample
425+
(average ",round(sum(savont_stats$savont_output)/length(savont_stats$savont_output),0),").
426+
"))
427+
```
428+
317429
<!-- Subsection on DADA2 QC filtering -->
318430

319431
```{r, eval = !isFALSE(params$dada_filtntrim_args), results='asis'}
@@ -401,9 +513,9 @@ that position. Original plots can be found in folder [dada2/QC/](../dada2/QC/) w
401513
"))
402514
```
403515

404-
<!-- Section on sequences / DADA2 ASVs -->
516+
<!-- Section on DADA2 ASVs -->
405517

406-
```{r, eval = !isFALSE(params$dada_err_path) || !isFALSE(params$dada_stats_path) || !isFALSE(params$asv_table_path), results='asis'}
518+
```{r, eval = !isFALSE(params$dada_err_path) || !isFALSE(params$dada_stats_path) || !isFALSE(params$dada_asv_table_path), results='asis'}
407519
cat(paste0("
408520
# ASV inference using DADA2
409521
@@ -595,13 +707,13 @@ Samples that are very different in lost reads (per stage) to the majority of sam
595707

596708
<!-- Subsection on DADA2 ASVs -->
597709

598-
```{r, eval = !isFALSE(params$asv_table_path), results='asis'}
710+
```{r, eval = !isFALSE(params$dada_asv_table_path), results='asis'}
599711
cat("## Inferred ASVs\n\n")
600712
601713
#import asv table
602-
asv_table <- read.table(file = params$asv_table_path, header = TRUE, sep = "\t")
714+
asv_table <- read.table(file = params$dada_asv_table_path, header = TRUE, sep = "\t")
603715
n_asv <- length(asv_table$ASV_ID)
604-
n_asv_dada <- length(asv_table$ASV_ID) #this is to report the original number later in the methods section
716+
n_asv_final <- length(asv_table$ASV_ID) #this is to report the original number later in the methods section
605717
606718
# Output text
607719
cat("Finally,", n_asv,
@@ -638,7 +750,7 @@ n_asv_vsearch_cluster <- nrow(vsearch_cluster)
638750
cat(paste0("
639751
## Clustering of ASVs
640752
641-
[VSEARCH](https://peerj.com/articles/2584/) clustered ",n_asv_dada," ASVs into ",n_asv_vsearch_cluster,"
753+
[VSEARCH](https://peerj.com/articles/2584/) clustered ",n_asv_final," ASVs into ",n_asv_vsearch_cluster,"
642754
centroids with pairwise identity of ",params$vsearch_cluster_id,".
643755
Clustered ASV sequences and abundances can be found in folder [vsearch_cluster](../vsearch_cluster).
644756
"))
@@ -1893,6 +2005,13 @@ Data quality was evaluated with FastQC ([Andrews, 2010](https://www.bioinformati
18932005
and summarized with MultiQC ([Ewels et al., 2016](https://pubmed.ncbi.nlm.nih.gov/27312411/)).
18942006
"))
18952007
```
2008+
```{r, eval = !isFALSE(params$porechop_abi_log_paths), results='asis'}
2009+
cat("[Porechop_ABI](https://pubmed.ncbi.nlm.nih.gov/36698762/) removed adapters from reads. ")
2010+
```
2011+
```{r, eval = !isFALSE(params$chopper_stats_path), results='asis'}
2012+
cat("[Chopper](https://pubmed.ncbi.nlm.nih.gov/37171891/) filtered reads based on quality cutoffs: ")
2013+
cat(chopper_text)
2014+
```
18962015
```{r, eval = !isFALSE(params$cutadapt_summary), results='asis'}
18972016
cutadapt_intro = "Cutadapt ([Marcel et al., 2011](https://doi.org/10.14806/ej.17.1.200)) trimmed primers"
18982017
if ( isFALSE(params$flag_retain_untrimmed) ) {
@@ -1901,6 +2020,15 @@ if ( isFALSE(params$flag_retain_untrimmed) ) {
19012020
cat(paste0(cutadapt_intro, "."))
19022021
}
19032022
```
2023+
```{r, eval = !isFALSE(params$savont_asv_table_path), results='asis'}
2024+
cat(paste0("
2025+
[Savont](https://doi.org/10.64898/2026.05.26.727271) filtered reads (98% quality), produced ASVs, and removed PCR chimera.
2026+
Ultimately, ",n_asv_final," amplicon sequencing variants (ASVs) were obtained across all samples.
2027+
The ASV count table contained in total ",sum(savont_stats$savont_output)," counts,
2028+
at least ",min(savont_stats$savont_output)," and at most ",max(savont_stats$savont_output)," per sample
2029+
(average ",round(sum(savont_stats$savont_output)/length(savont_stats$savont_output),0),").
2030+
"))
2031+
```
19042032
```{r, eval = !isFALSE(params$dada_filtntrim_args), results='asis'}
19052033
if ( !isFALSE(params$cutadapt_summary) && isFALSE(params$flag_retain_untrimmed) ) {
19062034
cat("Adapter and primer-free sequences were processed ")
@@ -1952,7 +2080,7 @@ if ( isFALSE(params$flag_single_end) ) {
19522080
}
19532081
cat(paste0("
19542082
and remove polymerase chain reaction (PCR) chimeras;
1955-
ultimately, ",n_asv_dada," amplicon sequencing variants (ASVs) were obtained across all samples.
2083+
ultimately, ",n_asv_final," amplicon sequencing variants (ASVs) were obtained across all samples.
19562084
Between ",min(dada_stats_p$analysis),"% and ",max(dada_stats_p$analysis),"% reads per sample
19572085
(average ",dada_stats_p_analysis_average,"%) were retained.
19582086
The ASV count table contained in total ",sum(dada_stats_ex$analysis)," counts,
@@ -1963,7 +2091,7 @@ at least ",min(dada_stats_ex$analysis)," and at most ",max(dada_stats_ex$analysi
19632091

19642092
```{r, eval = !isFALSE(params$vsearch_cluster), results='asis'}
19652093
cat(paste0("
1966-
VSEARCH ([Rognes et al., 2016](https://peerj.com/articles/2584/)) clustered ",n_asv_dada," ASVs into ",n_asv_vsearch_cluster,"
2094+
VSEARCH ([Rognes et al., 2016](https://peerj.com/articles/2584/)) clustered ",n_asv_final," ASVs into ",n_asv_vsearch_cluster,"
19672095
centroids with pairwise identity of ",params$vsearch_cluster_id,"."))
19682096
```
19692097
```{r, eval = (params$decontam != "none"), results='asis'}

modules/local/summary_report.nf

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ process SUMMARY_REPORT {
1616
path(input_fasta)
1717
tuple val(meta_mqc), path(mqc_plots)
1818
path(cutadapt_summary)
19+
tuple val(meta_porechop_abi), path(porechop_abi_log_paths)
20+
path(chopper_stats)
21+
path(savont_asv_table)
22+
path(savont_stats)
1923
val(find_truncation_values)
2024
path(dada_filtntrim_args)
2125
path(dada_qual_stats)
@@ -94,6 +98,10 @@ process SUMMARY_REPORT {
9498
cutadapt_summary ?
9599
params.retain_untrimmed ? "flag_retain_untrimmed=TRUE,cutadapt_summary='$cutadapt_summary'" :
96100
"cutadapt_summary='$cutadapt_summary'" : "",
101+
porechop_abi_log_paths ? "porechop_abi_log_paths='"+porechop_abi_log_paths.join(',')+"'" : "",
102+
chopper_stats ? "chopper_stats_path='$chopper_stats'" : "",
103+
savont_asv_table ? "savont_asv_table_path='$savont_asv_table'" : "",
104+
savont_stats ? "savont_stats_path='$savont_stats'" : "",
97105
"truncq=$params.truncq",
98106
find_truncation_values ? "trunc_qmin=$params.trunc_qmin,trunc_rmin=$params.trunc_rmin" : "",
99107
"trunclenf='$params.trunclenf'",
@@ -106,7 +114,7 @@ process SUMMARY_REPORT {
106114
dada_err_svgs && meta.run.size() == 1 && meta.single_end ?
107115
"dada_err_path='$dada_err_svgs',dada_err_run='"+meta.run+"'" :
108116
dada_err_svgs ? "dada_err_path='"+dada_err_svgs.join(',')+"',dada_err_run='"+meta.run.join(',')+"'" : "",
109-
dada_asv_table ? "asv_table_path='$dada_asv_table'" : "",
117+
dada_asv_table ? "dada_asv_table_path='$dada_asv_table'" : "",
110118
dada_asv_fa ? "path_asv_fa='$dada_asv_fa'": "",
111119
dada_tab ? "path_dada2_tab='$dada_tab'" : "",
112120
dada_stats ? "dada_stats_path='$dada_stats'" : "",

workflows/ampliseq.nf

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,11 +510,12 @@ workflow AMPLISEQ {
510510
CHOPPER ( ch_reads_trimming, [] )
511511

512512
// Count reads of input and output files
513-
ch_stats = ch_reads_trimming
513+
ch_stats_chopper = ch_reads_trimming
514514
.map { meta, fastq -> [meta.sample, fastq.countFastq()] }
515515
.join( CHOPPER.out.fastq.map { meta, fastq -> [meta.sample, fastq.countFastq()]}, by: 0 )
516516
.collectFile(keepHeader: true, skip: 1, sort: true, cache: true) { sample, read_counts_in, read_counts_out ->
517517
["chopper_readcounts.tsv", "sample\tchopper_input\tchopper_output\n${sample}\t${read_counts_in}\t${read_counts_out}\n"] }
518+
ch_stats = ch_stats_chopper
518519

519520
// Filter samples for sufficient reads
520521
ch_reads_trimming_check =
@@ -1304,6 +1305,11 @@ workflow AMPLISEQ {
13041305
ch_input_fasta.ifEmpty( [] ), // fasta input
13051306
!params.input_fasta && !params.skip_fastqc && !params.skip_multiqc ? MULTIQC.out.plots : [[],[]], //.collect().flatten().collectFile(name: "fastqc_per_sequence_quality_scores_plot.svg")
13061307
!params.skip_cutadapt ? CUTADAPT_WORKFLOW.out.summary.collect().ifEmpty( [] ) : [],
1308+
params.nanopore && !params.skip_porechop_abi ? PORECHOP_ABI.out.log.ifEmpty( [] ) : [],
1309+
params.nanopore && !params.skip_chopper ? ch_stats_chopper.ifEmpty( [] ) : [],
1310+
params.nanopore && params.sample_inference == "independent" ? SAVONT_EXPORT.out.asv :
1311+
params.nanopore && params.sample_inference == "pooled" ? SAVONT_ASV.out.asv : [],
1312+
params.nanopore ? ch_stats_savont.ifEmpty( [] ) : [],
13071313
find_truncation_values,
13081314
!params.nanopore ? DADA2_PREPROCESSING.out.args.first().ifEmpty( [] ) : [],
13091315
!params.nanopore && !params.skip_dada_quality ? DADA2_PREPROCESSING.out.qc_svg.ifEmpty( [] ) : [],

0 commit comments

Comments
 (0)