diff --git a/modules/nf-core/octopusv/plotcircos/environment.yml b/modules/nf-core/octopusv/plotcircos/environment.yml new file mode 100644 index 000000000000..7a8fad1655d6 --- /dev/null +++ b/modules/nf-core/octopusv/plotcircos/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - "bioconda::octopusv=0.4.0" diff --git a/modules/nf-core/octopusv/plotcircos/main.nf b/modules/nf-core/octopusv/plotcircos/main.nf new file mode 100644 index 000000000000..51791dda7566 --- /dev/null +++ b/modules/nf-core/octopusv/plotcircos/main.nf @@ -0,0 +1,48 @@ +process OCTOPUSV_PLOTCIRCOS { + tag "$meta.id" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/octopusv:0.4.0--pyhdfd78af_0': + 'quay.io/biocontainers/octopusv:0.4.0--pyhdfd78af_0' }" + + input: + tuple val(meta), path(svcf), val(output_format) + path(fai) + + output: + tuple val(meta), path("${prefix}.circos.${output_format}"), emit: circos + tuple val(meta), path("${prefix}.circos.oversized_intra.tsv"), emit: oversized_intra + tuple val("${task.process}"), val('octopusv'), eval("python -c \"import importlib.metadata as m; print(m.version('octopusv'))\""), emit: versions_octopusv, topic: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + prefix = task.ext.prefix ?: "${meta.id}" + def fai_arg = fai ? "--fai ${fai}" : "" + def supported_formats = ['pdf', 'png', 'svg'] + + if (!(output_format in supported_formats)) { + error "Unsupported Circos output format: ${output_format}. Supported formats: ${supported_formats.join(', ')}" + } + + """ + octopusv plot-circos \\ + --input-file ${svcf} \\ + --output-file ${prefix}.circos.${output_format} \\ + --sample ${prefix} \\ + ${fai_arg} \\ + ${args} + """ + + stub: + prefix = task.ext.prefix ?: "${meta.id}" + + """ + touch ${prefix}.circos.${output_format} + touch ${prefix}.circos.oversized_intra.tsv + """ +} diff --git a/modules/nf-core/octopusv/plotcircos/meta.yml b/modules/nf-core/octopusv/plotcircos/meta.yml new file mode 100644 index 000000000000..7f6edc670518 --- /dev/null +++ b/modules/nf-core/octopusv/plotcircos/meta.yml @@ -0,0 +1,96 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json +name: "octopusv_plotcircos" +description: "Draw a genome-wide structural variant Circos plot from an OctopuSV SVCF file." +keywords: + - structural variant + - circos + - plot + - visualisation +tools: + - "octopusv": + description: "End-to-end structural variant post-processing: standardize, merge, + compare, and export SVs." + homepage: "https://github.com/ylab-hi/OctopuSV" + documentation: "https://github.com/ylab-hi/OctopuSV" + tool_dev_url: "https://github.com/ylab-hi/octopusV" + doi: "10.1093/bioinformatics/btaf599" + licence: + - "MIT" + identifier: "" + +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - svcf: + type: file + description: Structural variant call file in OctopuSV SVCF format + pattern: "*.svcf" + ontologies: + - edam: "http://edamontology.org/format_3016" # VCF + - output_format: + type: string + description: Output format for the Circos plot (valid values - pdf, png, svg) + - fai: + type: file + description: Optional reference FASTA index used to define chromosome sizes; built-in hg38 sizes are used when absent + pattern: "*.fai" + optional: true + ontologies: + - edam: "http://edamontology.org/format_3475" # TSV +output: + circos: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - "${prefix}.circos.${output_format}": + type: file + description: Genome-wide structural variant Circos plot in the requested output format + pattern: "*circos.${output_format}" + ontologies: + - edam: "http://edamontology.org/format_3508" # PDF + - edam: "http://edamontology.org/format_3603" # PNG + - edam: "http://edamontology.org/format_3604" # SVG + oversized_intra: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - ${prefix}.circos.oversized_intra.tsv: + type: file + description: Intra-chromosomal structural variants exceeding the maximum displayed span + pattern: "*.circos.oversized_intra.tsv" + ontologies: + - edam: "http://edamontology.org/format_3475" # TSV + versions_octopusv: + - - ${task.process}: + type: string + description: The name of the process + - octopusv: + type: string + description: The name of the tool + - python -c "import importlib.metadata as m; print(m.version('octopusv'))": + type: eval + description: The expression to obtain the version of the tool + +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - octopusv: + type: string + description: The name of the tool + - python -c "import importlib.metadata as m; print(m.version('octopusv'))": + type: eval + description: The expression to obtain the version of the tool + +authors: + - "@manascripts" +maintainers: + - "@manascripts" diff --git a/modules/nf-core/octopusv/plotcircos/tests/main.nf.test b/modules/nf-core/octopusv/plotcircos/tests/main.nf.test new file mode 100644 index 000000000000..97c20a6b0567 --- /dev/null +++ b/modules/nf-core/octopusv/plotcircos/tests/main.nf.test @@ -0,0 +1,60 @@ +nextflow_process { + + name "Test Process OCTOPUSV_PLOTCIRCOS" + script "../main.nf" + process "OCTOPUSV_PLOTCIRCOS" + + tag "modules" + tag "modules_nfcore" + tag "octopusv" + tag "octopusv/plotcircos" + + test("homo_sapiens - svcf") { + + when { + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/vcf/octopusv/sk-n-as-severus-ont.svcf', checkIfExists: true), + 'png' + ] + input[1] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + sanitizeOutput(process.out)).match() } + ) + } + } + + test("homo_sapiens - svcf - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/vcf/octopusv/sk-n-as-severus-ont.svcf', checkIfExists: true), + 'png' + ] + input[1] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } +} diff --git a/modules/nf-core/octopusv/plotcircos/tests/main.nf.test.snap b/modules/nf-core/octopusv/plotcircos/tests/main.nf.test.snap new file mode 100644 index 000000000000..685316f6248a --- /dev/null +++ b/modules/nf-core/octopusv/plotcircos/tests/main.nf.test.snap @@ -0,0 +1,70 @@ +{ + "homo_sapiens - svcf": { + "content": [ + { + "circos": [ + [ + { + "id": "test" + }, + "test.circos.png:md5,a47ceda3176b0686a5b73fac95b6e30e" + ] + ], + "oversized_intra": [ + [ + { + "id": "test" + }, + "test.circos.oversized_intra.tsv:md5,bcfe4be36eda15275d2cda3ff1ce7bd0" + ] + ], + "versions_octopusv": [ + [ + "OCTOPUSV_PLOTCIRCOS", + "octopusv", + "0.4.0" + ] + ] + } + ], + "timestamp": "2026-07-20T15:33:24.087743215", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "homo_sapiens - svcf - stub": { + "content": [ + { + "circos": [ + [ + { + "id": "test" + }, + "test.circos.png:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "oversized_intra": [ + [ + { + "id": "test" + }, + "test.circos.oversized_intra.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_octopusv": [ + [ + "OCTOPUSV_PLOTCIRCOS", + "octopusv", + "0.4.0" + ] + ] + } + ], + "timestamp": "2026-07-20T15:33:32.441492316", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + } +} \ No newline at end of file