From 6ab04ad5d568f4e2e50fc84e42f7fd965da9e1cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Cavalcante?= Date: Sat, 30 Mar 2024 16:40:28 -0300 Subject: [PATCH] refactor: Improve styling on MultiQC report (#32) * fix: Make MultiQC detect diamond logs * refactor: Remove sample enumerator * refactor: Update multiqc config with more info * chore: Update multiqc module --- assets/multiqc_config.yml | 10 ++- bin/check_samplesheet.py | 4 +- modules.json | 81 +++++++++++++----- .../diamond/blastx/diamond-blastx.diff | 9 ++ modules/nf-core/diamond/blastx/main.nf | 2 +- modules/nf-core/multiqc/environment.yml | 7 ++ modules/nf-core/multiqc/main.nf | 10 ++- modules/nf-core/multiqc/meta.yml | 11 ++- modules/nf-core/multiqc/multiqc.diff | 14 ++++ modules/nf-core/multiqc/tests/main.nf.test | 84 +++++++++++++++++++ .../nf-core/multiqc/tests/main.nf.test.snap | 41 +++++++++ modules/nf-core/multiqc/tests/tags.yml | 2 + nextflow.config | 2 +- workflows/euryale.nf | 2 +- 14 files changed, 243 insertions(+), 36 deletions(-) create mode 100644 modules/nf-core/multiqc/environment.yml create mode 100644 modules/nf-core/multiqc/multiqc.diff create mode 100644 modules/nf-core/multiqc/tests/main.nf.test create mode 100644 modules/nf-core/multiqc/tests/main.nf.test.snap create mode 100644 modules/nf-core/multiqc/tests/tags.yml diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index 1ae8b26..d40e344 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -1,6 +1,7 @@ report_comment: > This report has been generated by the dalmolingroup/euryale - analysis pipeline. + analysis pipeline. For information about how to interpret these results, see the + documentation. report_section_order: "dalmolingroup-euryale-methods-description": order: -1000 @@ -9,4 +10,11 @@ report_section_order: "dalmolingroup-euryale-summary": order: -1002 +custom_logo_url: https://github.com/dalmolingroup/euryale +custom_logo_title: "dalmolingroup/euryale" + +sp: + diamond: + fn_re: ".*.diamond.log$" + export_plots: true diff --git a/bin/check_samplesheet.py b/bin/check_samplesheet.py index 11b1557..5f6e015 100755 --- a/bin/check_samplesheet.py +++ b/bin/check_samplesheet.py @@ -123,11 +123,9 @@ def validate_unique_samples(self): """ if len(self._seen) != len(self.modified): raise AssertionError("The pair of sample name and FASTQ must be unique.") - seen = Counter() for row in self.modified: sample = row[self._sample_col] - seen[sample] += 1 - row[self._sample_col] = f"{sample}_T{seen[sample]}" + row[self._sample_col] = f"{sample}" def read_head(handle, num_lines=10): diff --git a/modules.json b/modules.json index 4d15e1d..7716936 100644 --- a/modules.json +++ b/modules.json @@ -8,114 +8,153 @@ "bowtie2/align": { "branch": "master", "git_sha": "603ecbd9f45300c9788f197d2a15a005685b4220", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/bowtie2/align/bowtie2-align.diff" }, "bowtie2/build": { "branch": "master", "git_sha": "911696ea0b62df80e900ef244d7867d177971f73", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/bowtie2/build/bowtie2-build.diff" }, "custom/dumpsoftwareversions": { "branch": "master", "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "diamond/blastx": { "branch": "master", "git_sha": "911696ea0b62df80e900ef244d7867d177971f73", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/diamond/blastx/diamond-blastx.diff" }, "diamond/makedb": { "branch": "master", "git_sha": "911696ea0b62df80e900ef244d7867d177971f73", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/diamond/makedb/diamond-makedb.diff" }, "fastp": { "branch": "master", "git_sha": "37a98dd100d74d9188a272197663587de1331a0e", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/fastp/fastp.diff" }, "fastqc": { "branch": "master", "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "gunzip": { "branch": "master", "git_sha": "5c460c5a4736974abde2843294f35307ee2b0e5e", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/gunzip/gunzip.diff" }, "kaiju/kaiju": { "branch": "master", "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/kaiju/kaiju/kaiju-kaiju.diff" }, "kaiju/kaiju2krona": { "branch": "master", "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "kaiju/kaiju2table": { "branch": "master", "git_sha": "911696ea0b62df80e900ef244d7867d177971f73", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/kaiju/kaiju2table/kaiju-kaiju2table.diff" }, "kraken2/kraken2": { "branch": "master", "git_sha": "8fc1d24c710ebe1d5de0f2447ec9439fd3d9d66a", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/kraken2/kraken2/kraken2-kraken2.diff" }, "krakentools/kreport2krona": { "branch": "master", "git_sha": "8fc1d24c710ebe1d5de0f2447ec9439fd3d9d66a", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/krakentools/kreport2krona/krakentools-kreport2krona.diff" }, "krona/ktimporttext": { "branch": "master", "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "megahit": { "branch": "master", "git_sha": "603ecbd9f45300c9788f197d2a15a005685b4220", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/megahit/megahit.diff" }, "multiqc": { "branch": "master", - "git_sha": "c8e35eb2055c099720a75538d1b8adb3fb5a464c", - "installed_by": ["modules"] + "git_sha": "b7ebe95761cd389603f9cc0e0dc384c0f663815a", + "installed_by": [ + "modules" + ], + "patch": "modules/nf-core/multiqc/multiqc.diff" }, "samtools/bam2fq": { "branch": "master", "git_sha": "911696ea0b62df80e900ef244d7867d177971f73", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/bam2fq/samtools-bam2fq.diff" }, "samtools/sort": { "branch": "master", "git_sha": "a0f7be95788366c1923171e358da7d049eb440f9", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/sort/samtools-sort.diff" }, "untar": { "branch": "master", "git_sha": "cc1f997fab6d8fde5dc0e6e2a310814df5b53ce7", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/untar/untar.diff" } } } } } -} +} \ No newline at end of file diff --git a/modules/nf-core/diamond/blastx/diamond-blastx.diff b/modules/nf-core/diamond/blastx/diamond-blastx.diff index 2655857..db7c328 100644 --- a/modules/nf-core/diamond/blastx/diamond-blastx.diff +++ b/modules/nf-core/diamond/blastx/diamond-blastx.diff @@ -26,5 +26,14 @@ Changes in module 'nf-core/diamond/blastx' tuple val(meta), path('*.daa') , optional: true, emit: daa tuple val(meta), path('*.sam') , optional: true, emit: sam tuple val(meta), path('*.tsv') , optional: true, emit: tsv +@@ -58,7 +60,7 @@ + --out ${prefix}.${out_ext} \\ + --log + +- mv diamond.log ${prefix}.log ++ mv diamond.log ${prefix}.diamond.log + + cat <<-END_VERSIONS > versions.yml + "${task.process}": ************************************************************ diff --git a/modules/nf-core/diamond/blastx/main.nf b/modules/nf-core/diamond/blastx/main.nf index 50cf24a..3376fed 100644 --- a/modules/nf-core/diamond/blastx/main.nf +++ b/modules/nf-core/diamond/blastx/main.nf @@ -60,7 +60,7 @@ process DIAMOND_BLASTX { --out ${prefix}.${out_ext} \\ --log - mv diamond.log ${prefix}.log + mv diamond.log ${prefix}.diamond.log cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml new file mode 100644 index 0000000..ca39fb6 --- /dev/null +++ b/modules/nf-core/multiqc/environment.yml @@ -0,0 +1,7 @@ +name: multiqc +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::multiqc=1.21 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 68f66be..78d45b6 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -1,10 +1,10 @@ process MULTIQC { label 'process_single' - conda "bioconda::multiqc=1.13" + conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.13--pyhdfd78af_0' : - 'quay.io/biocontainers/multiqc:1.13--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.21--pyhdfd78af_0' : + 'quay.io/biocontainers/multiqc:1.21--pyhdfd78af_0' }" input: path multiqc_files, stageAs: "?/*" @@ -25,12 +25,14 @@ process MULTIQC { def args = task.ext.args ?: '' def config = multiqc_config ? "--config $multiqc_config" : '' def extra_config = extra_multiqc_config ? "--config $extra_multiqc_config" : '' + def logo = multiqc_logo ? /--cl-config 'custom_logo: "${multiqc_logo}"'/ : '' """ multiqc \\ --force \\ $args \\ $config \\ $extra_config \\ + $logo \\ . cat <<-END_VERSIONS > versions.yml @@ -41,7 +43,7 @@ process MULTIQC { stub: """ - touch multiqc_data + mkdir multiqc_data touch multiqc_plots touch multiqc_report.html diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml index ebc29b2..45a9bc3 100644 --- a/modules/nf-core/multiqc/meta.yml +++ b/modules/nf-core/multiqc/meta.yml @@ -1,4 +1,4 @@ -name: MultiQC +name: multiqc description: Aggregate results from bioinformatics analyses across many samples into a single report keywords: - QC @@ -12,7 +12,6 @@ tools: homepage: https://multiqc.info/ documentation: https://multiqc.info/docs/ licence: ["GPL-3.0-or-later"] - input: - multiqc_files: type: file @@ -30,14 +29,13 @@ input: type: file description: Optional logo file for MultiQC pattern: "*.{png}" - output: - report: type: file description: MultiQC report file pattern: "multiqc_report.html" - data: - type: dir + type: directory description: MultiQC data dir pattern: "multiqc_data" - plots: @@ -53,3 +51,8 @@ authors: - "@bunop" - "@drpatelh" - "@jfy133" +maintainers: + - "@abhi18av" + - "@bunop" + - "@drpatelh" + - "@jfy133" diff --git a/modules/nf-core/multiqc/multiqc.diff b/modules/nf-core/multiqc/multiqc.diff new file mode 100644 index 0000000..41d0077 --- /dev/null +++ b/modules/nf-core/multiqc/multiqc.diff @@ -0,0 +1,14 @@ +Changes in module 'nf-core/multiqc' +--- modules/nf-core/multiqc/main.nf ++++ modules/nf-core/multiqc/main.nf +@@ -4,7 +4,7 @@ + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/multiqc:1.21--pyhdfd78af_0' : +- 'biocontainers/multiqc:1.21--pyhdfd78af_0' }" ++ 'quay.io/biocontainers/multiqc:1.21--pyhdfd78af_0' }" + + input: + path multiqc_files, stageAs: "?/*" + +************************************************************ diff --git a/modules/nf-core/multiqc/tests/main.nf.test b/modules/nf-core/multiqc/tests/main.nf.test new file mode 100644 index 0000000..f1c4242 --- /dev/null +++ b/modules/nf-core/multiqc/tests/main.nf.test @@ -0,0 +1,84 @@ +nextflow_process { + + name "Test Process MULTIQC" + script "../main.nf" + process "MULTIQC" + + tag "modules" + tag "modules_nfcore" + tag "multiqc" + + test("sarscov2 single-end [fastqc]") { + + when { + process { + """ + input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) + input[1] = [] + input[2] = [] + input[3] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, + { assert process.out.data[0] ==~ ".*/multiqc_data" }, + { assert snapshot(process.out.versions).match("multiqc_versions_single") } + ) + } + + } + + test("sarscov2 single-end [fastqc] [config]") { + + when { + process { + """ + input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) + input[1] = Channel.of(file("https://github.com/nf-core/tools/raw/dev/nf_core/pipeline-template/assets/multiqc_config.yml", checkIfExists: true)) + input[2] = [] + input[3] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, + { assert process.out.data[0] ==~ ".*/multiqc_data" }, + { assert snapshot(process.out.versions).match("multiqc_versions_config") } + ) + } + } + + test("sarscov2 single-end [fastqc] - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) + input[1] = [] + input[2] = [] + input[3] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.report.collect { file(it).getName() } + + process.out.data.collect { file(it).getName() } + + process.out.plots.collect { file(it).getName() } + + process.out.versions ).match("multiqc_stub") } + ) + } + + } +} diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap new file mode 100644 index 0000000..bfebd80 --- /dev/null +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -0,0 +1,41 @@ +{ + "multiqc_versions_single": { + "content": [ + [ + "versions.yml:md5,21f35ee29416b9b3073c28733efe4b7d" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-29T08:48:55.657331" + }, + "multiqc_stub": { + "content": [ + [ + "multiqc_report.html", + "multiqc_data", + "multiqc_plots", + "versions.yml:md5,21f35ee29416b9b3073c28733efe4b7d" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-29T08:49:49.071937" + }, + "multiqc_versions_config": { + "content": [ + [ + "versions.yml:md5,21f35ee29416b9b3073c28733efe4b7d" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-29T08:49:25.457567" + } +} \ No newline at end of file diff --git a/modules/nf-core/multiqc/tests/tags.yml b/modules/nf-core/multiqc/tests/tags.yml new file mode 100644 index 0000000..bea6c0d --- /dev/null +++ b/modules/nf-core/multiqc/tests/tags.yml @@ -0,0 +1,2 @@ +multiqc: + - modules/nf-core/multiqc/** diff --git a/nextflow.config b/nextflow.config index a89809e..71d1bcd 100644 --- a/nextflow.config +++ b/nextflow.config @@ -51,7 +51,7 @@ params { // MultiQC options multiqc_config = null multiqc_title = null - multiqc_logo = null + multiqc_logo = "$projectDir/assets/euryale_logo.png" max_multiqc_email_size = '25.MB' multiqc_methods_description = null diff --git a/workflows/euryale.nf b/workflows/euryale.nf index bac4bf0..9c0abbd 100644 --- a/workflows/euryale.nf +++ b/workflows/euryale.nf @@ -154,7 +154,7 @@ workflow EURYALE { ) ALIGNMENT.out.alignments.set{alignments} ch_versions = ch_versions.mix(ALIGNMENT.out.versions) - ch_multiqc_files = ch_multiqc_files.mix(ALIGNMENT.out.multiqc_files.collect()) + ch_multiqc_files = ch_multiqc_files.mix(ALIGNMENT.out.multiqc_files.collect{it[1]}.ifEmpty([])) } if (!params.skip_classification) {