diff --git a/.github/skip_nf_test.json b/.github/skip_nf_test.json index 1f94d6a31cbe..50d489477088 100644 --- a/.github/skip_nf_test.json +++ b/.github/skip_nf_test.json @@ -107,7 +107,7 @@ "modules/nf-core/universc", "modules/nf-core/vt/decompose", "modules/nf-core/wittyer", - "modules/nf-core/xeniumranger/import-segmentation", + "modules/nf-core/xeniumranger/importsegmentation", "modules/nf-core/xeniumranger/relabel", "modules/nf-core/xeniumranger/rename", "modules/nf-core/xeniumranger/resegment", diff --git a/modules/nf-core/xeniumranger/import-segmentation/main.nf b/modules/nf-core/xeniumranger/importsegmentation/main.nf similarity index 79% rename from modules/nf-core/xeniumranger/import-segmentation/main.nf rename to modules/nf-core/xeniumranger/importsegmentation/main.nf index 0ecdcc0d1bb6..57ff2cb623c3 100644 --- a/modules/nf-core/xeniumranger/import-segmentation/main.nf +++ b/modules/nf-core/xeniumranger/importsegmentation/main.nf @@ -1,11 +1,11 @@ -process XENIUMRANGER_IMPORT_SEGMENTATION { +process XENIUMRANGER_IMPORTSEGMENTATION { tag "$meta.id" label 'process_high' container "quay.io/nf-core/xeniumranger:4.0" input: - tuple val(meta), path(xenium_bundle, stageAs: "bundle/"), path(transcript_assignment), path(viz_polygons), path(nuclei), path(cells), path(coordinate_transform), val(units) + tuple val(meta), path(xenium_bundle, stageAs: "bundle/"), path(transcript_assignment), path(viz_polygons), path(nuclei), path(cells), path(coordinate_transform), val(units), val(expansion_distance) output: tuple val(meta), path("${prefix}"), emit: outs @@ -18,7 +18,7 @@ process XENIUMRANGER_IMPORT_SEGMENTATION { // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { - error "XENIUMRANGER_IMPORT_SEGMENTATION module does not support Conda. Please use Docker / Singularity / Podman instead." + error "XENIUMRANGER_IMPORTSEGMENTATION module does not support Conda. Please use Docker / Singularity / Podman instead." } prefix = task.ext.prefix ?: "${meta.id}" @@ -32,6 +32,9 @@ process XENIUMRANGER_IMPORT_SEGMENTATION { def assembled_args = [] if (task.ext.args) { assembled_args << task.ext.args.trim() } + // --expansion-distance is only valid for nuclei-based imports. + // xeniumranger rejects it for transcript-assignment imports and cells-only imports. + if (nuclei && expansion_distance != null) { assembled_args << "--expansion-distance=${expansion_distance}" } if (nuclei) { assembled_args << "--nuclei=\"${nuclei}\"" } if (cells) { assembled_args << "--cells=\"${cells}\"" } if (transcript_assignment) { assembled_args << "--transcript-assignment=\"${transcript_assignment}\"" } @@ -48,14 +51,14 @@ process XENIUMRANGER_IMPORT_SEGMENTATION { """ xeniumranger import-segmentation \\ - --id="XENIUMRANGER_IMPORT_SEGMENTATION" \\ + --id="XENIUMRANGER_IMPORTSEGMENTATION" \\ --xenium-bundle="${xenium_bundle}" \\ --localcores=${task.cpus} \\ --localmem=${task.memory.toGiga()} \\ ${args} rm -rf "${prefix}" - mv XENIUMRANGER_IMPORT_SEGMENTATION/outs "${prefix}" + mv XENIUMRANGER_IMPORTSEGMENTATION/outs "${prefix}" """ stub: diff --git a/modules/nf-core/xeniumranger/import-segmentation/meta.yml b/modules/nf-core/xeniumranger/importsegmentation/meta.yml similarity index 92% rename from modules/nf-core/xeniumranger/import-segmentation/meta.yml rename to modules/nf-core/xeniumranger/importsegmentation/meta.yml index e222df582a05..9f23de45c536 100644 --- a/modules/nf-core/xeniumranger/import-segmentation/meta.yml +++ b/modules/nf-core/xeniumranger/importsegmentation/meta.yml @@ -1,6 +1,6 @@ -name: xeniumranger_import_segmentation +name: XENIUMRANGER_IMPORTSEGMENTATION description: | - The xeniumranger import-segmentation module runs `xeniumranger import-segmentation` + The xeniumranger importsegmentation module runs `xeniumranger import-segmentation` to recompute Xenium Onboard Analysis outputs using external segmentation results. It supports two execution modes mirroring the Xenium Ranger CLI: an image-based mode that accepts nuclei and/or cell masks (TIFF/NPY) or GeoJSON polygons together @@ -102,6 +102,13 @@ input: enum: - "microns" - "pixels" + - expansion_distance: + type: integer + optional: true + description: | + Distance (in microns) to expand nuclei outward into cell boundaries. Only valid for + nuclei-based imports (`nuclei` must be set); xeniumranger rejects it for + transcript-assignment imports and cells-only imports. Default: 5. Range: 0-100. output: outs: - - meta: @@ -138,4 +145,4 @@ authors: - "@dongzehe" maintainers: - "@khersameesh24" - - "@dongzehe" + - "@dongzehe" \ No newline at end of file diff --git a/modules/nf-core/xeniumranger/import-segmentation/tests/main.nf.test b/modules/nf-core/xeniumranger/importsegmentation/tests/main.nf.test similarity index 68% rename from modules/nf-core/xeniumranger/import-segmentation/tests/main.nf.test rename to modules/nf-core/xeniumranger/importsegmentation/tests/main.nf.test index f85b8a7a0127..1510df320e04 100644 --- a/modules/nf-core/xeniumranger/import-segmentation/tests/main.nf.test +++ b/modules/nf-core/xeniumranger/importsegmentation/tests/main.nf.test @@ -1,44 +1,46 @@ nextflow_process { - name "Test Process XENIUMRANGER_IMPORT_SEGMENTATION" + name "Test Process XENIUMRANGER_IMPORTSEGMENTATION" script "../main.nf" - process "XENIUMRANGER_IMPORT_SEGMENTATION" + process "XENIUMRANGER_IMPORTSEGMENTATION" + config "./nextflow.config" tag "modules" tag "modules_nfcore" tag "xeniumranger" - tag "xeniumranger/import-segmentation" - tag "unzip" + tag "xeniumranger/importsegmentation" + tag "untar" setup { - run("UNZIP") { - script "modules/nf-core/unzip/main.nf" + run("UNTAR") { + script "modules/nf-core/untar/main.nf" process { """ - input[0] = [[], file('https://raw.githubusercontent.com/nf-core/test-datasets/spatialxe/Xenium_V1_Protein_Human_Kidney_tiny_outs.zip', checkIfExists: true)] + input[0] = [[], file('https://raw.githubusercontent.com/nf-core/test-datasets/spatialaxe/xenium_bundle.tar.gz', checkIfExists: true)] """ } } } - test("xeniumranger import-segmentation nuclei") { + test("xeniumranger importsegmentation nuclei") { when { process { """ - input[0] = UNZIP.out.unzipped_archive + input[0] = UNTAR.out.untar .map { meta, bundle -> [ - [id: "test_xeniumranger_import-segmentation"], + [id: "test_xeniumranger_importsegmentation"], bundle, [], [], bundle + "/cells.zarr.zip", [], [], - [] + [], + 5 ] } """ @@ -56,23 +58,24 @@ nextflow_process { } } - test("xeniumranger import-segmentation stub") { + test("xeniumranger importsegmentation stub") { options "-stub" when { process { """ - input[0] = UNZIP.out.unzipped_archive + input[0] = UNTAR.out.untar .map { meta, bundle -> [ - [id: "test_xeniumranger_import-segmentation"], + [id: "test_xeniumranger_importsegmentation"], bundle, [], [], bundle + "/cells.zarr.zip", [], [], - [] + [], + 5 ] } """ diff --git a/modules/nf-core/xeniumranger/import-segmentation/tests/main.nf.test.snap b/modules/nf-core/xeniumranger/importsegmentation/tests/main.nf.test.snap similarity index 63% rename from modules/nf-core/xeniumranger/import-segmentation/tests/main.nf.test.snap rename to modules/nf-core/xeniumranger/importsegmentation/tests/main.nf.test.snap index 337133b2777d..7fb4365541e2 100644 --- a/modules/nf-core/xeniumranger/import-segmentation/tests/main.nf.test.snap +++ b/modules/nf-core/xeniumranger/importsegmentation/tests/main.nf.test.snap @@ -1,56 +1,56 @@ { - "xeniumranger import-segmentation nuclei": { + "xeniumranger importsegmentation stub": { "content": [ { "outs": [ [ { - "id": "test_xeniumranger_import-segmentation" + "id": "test_xeniumranger_importsegmentation" }, - "test_xeniumranger_import-segmentation" + [ + "experiment.xenium:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ] ], "versions_xeniumranger": [ [ - "XENIUMRANGER_IMPORT_SEGMENTATION", + "XENIUMRANGER_IMPORTSEGMENTATION", "xeniumranger", "4.0.1.1" ] ] } ], - "timestamp": "2026-06-16T05:59:47.015555128", + "timestamp": "2026-07-27T15:02:26.958198169", "meta": { "nf-test": "0.9.5", - "nextflow": "26.04.0" + "nextflow": "26.04.6" } }, - "xeniumranger import-segmentation stub": { + "xeniumranger importsegmentation nuclei": { "content": [ { "outs": [ [ { - "id": "test_xeniumranger_import-segmentation" + "id": "test_xeniumranger_importsegmentation" }, - [ - "experiment.xenium:md5,d41d8cd98f00b204e9800998ecf8427e" - ] + "test_xeniumranger_importsegmentation" ] ], "versions_xeniumranger": [ [ - "XENIUMRANGER_IMPORT_SEGMENTATION", + "XENIUMRANGER_IMPORTSEGMENTATION", "xeniumranger", "4.0.1.1" ] ] } ], - "timestamp": "2026-06-16T05:59:56.522779629", + "timestamp": "2026-07-27T15:02:12.93562615", "meta": { "nf-test": "0.9.5", - "nextflow": "26.04.0" + "nextflow": "26.04.6" } } } \ No newline at end of file diff --git a/modules/nf-core/xeniumranger/importsegmentation/tests/nextflow.config b/modules/nf-core/xeniumranger/importsegmentation/tests/nextflow.config new file mode 100644 index 000000000000..39b095f8b2ba --- /dev/null +++ b/modules/nf-core/xeniumranger/importsegmentation/tests/nextflow.config @@ -0,0 +1,7 @@ +process { + withName: XENIUMRANGER_IMPORTSEGMENTATION { + cpus = 2 + memory = '4.GB' + time = '30.m' + } +}