diff --git a/CHANGELOG.md b/CHANGELOG.md index 9367ca4e..b960e927 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,9 +3,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 1.0.0dev - [date] +## 1.0.1 - [date] -Initial release of nf-core/spatialaxe, created with the [nf-core](https://nf-co.re/) template. +Hotfix to tackle some bugs ### `Added` diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index 47566390..2e796b9a 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -1,5 +1,5 @@ report_comment: > - This report has been generated by the nf-core/spatialaxe analysis pipeline. For information about how to interpret these results, please see the documentation. + This report has been generated by the nf-core/spatialaxe analysis pipeline. For information about how to interpret these results, please see the documentation. report_section_order: "nf-core-spatialaxe-methods-description": order: -1000 diff --git a/conf/modules.config b/conf/modules.config index 21b274a1..81cf6a25 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -82,13 +82,6 @@ process { path: "${params.outdir}/${params.mode}/xeniumranger/import_segementation", mode: params.publish_dir_mode, ] - // --expansion-distance is only valid for nuclei-based imports (it expands nuclei - // into cell boundaries). xeniumranger rejects it for transcript-assignment imports - // (proseg/baysor/segger) and cells-only imports with "--expansion-distance requires - // --nuclei", so only emit it when a nuclei segmentation is being imported. - ext.args = {[ - (nuclei && params.expansion_distance != null) ? "--expansion-distance=${params.expansion_distance}" : "", - ].join(' ').trim()} } // ---------------------------- proseg --------------------------------------------------- diff --git a/modules.json b/modules.json index c215c2ed..494ffa18 100644 --- a/modules.json +++ b/modules.json @@ -53,9 +53,9 @@ "installed_by": ["modules"], "patch": "modules/nf-core/unzip/unzip.diff" }, - "xeniumranger/import-segmentation": { + "xeniumranger/importsegmentation": { "branch": "master", - "git_sha": "39365e944e936511e33b993cdd978e0f12adac9a", + "git_sha": "1fa9ed32cfd532e7d2191b5ffdcc86c783878fb0", "installed_by": ["modules"] }, "xeniumranger/relabel": { diff --git a/modules/nf-core/xeniumranger/import-segmentation/tests/main.nf.test b/modules/nf-core/xeniumranger/import-segmentation/tests/main.nf.test deleted file mode 100644 index 71198099..00000000 --- a/modules/nf-core/xeniumranger/import-segmentation/tests/main.nf.test +++ /dev/null @@ -1,314 +0,0 @@ -nextflow_process { - - name "Test Process XENIUMRANGER_IMPORT_SEGMENTATION" - script "../main.nf" - process "XENIUMRANGER_IMPORT_SEGMENTATION" - config "./nextflow.config" - - tag "modules" - tag "modules_nfcore" - tag "xeniumranger" - tag "xeniumranger/import-segmentation" - tag "unzip" - - setup { - run("UNZIP") { - script "modules/nf-core/unzip/main.nf" - process { - """ - input[0] = [[], file('https://raw.githubusercontent.com/nf-core/test-datasets/spatialaxe/Xenium_Prime_Mouse_Ileum_tiny_outs.zip', checkIfExists: true)] - """ - } - } - } - - test("xeniumranger import-segmentation nuclei npy") { - when { - process { - """ - input[0] = channel.of([ - [id: "test_xeniumranger_import-segmentation"], - ]).combine(UNZIP.out.unzipped_archive.map { it[1] }) - input[1] = 0 - input[2] = [] - input[3] = UNZIP.out.unzipped_archive.map { it[1] } + "/segmentations/nuclei.npy" - input[4] = [] - input[5] = [] - input[6] = [] - """ - } - } - then { - assertAll( - { assert process.success }, - { assert snapshot( - process.out.versions, - process.out.outs.get(0).get(1).findAll { file(it).name !in [ - 'analysis_summary.html', - 'metrics_summary.csv', - 'cell_boundaries.csv.gz', - 'cell_boundaries.parquet', - 'nucleus_boundaries.csv.gz', - 'nucleus_boundaries.parquet', - 'cells.csv.gz', - 'cells.parquet', - 'cells.zarr.zip', - 'transcripts.parquet', - 'transcripts.zarr.zip', - 'clusters.csv', - 'differential_expression.csv', - 'components.csv', - 'projection.csv', - 'variance.csv', - 'analysis.zarr.zip', - 'experiment.xenium', - 'cell_feature_matrix.zarr.zip' - ]} - ).match() - }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'analysis_summary.html' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'metrics_summary.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_boundaries.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_boundaries.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'nucleus_boundaries.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'nucleus_boundaries.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.zarr.zip' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'transcripts.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'clusters.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'differential_expression.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'components.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'projection.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'variance.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'analysis.zarr.zip' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'experiment.xenium' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_feature_matrix.zarr.zip' }).exists() }, - ) - } - } - - - test("xeniumranger import-segmentation nuclei tif") { - when { - process { - """ - input[0] = channel.of([ - [id: "test_xeniumranger_import-segmentation"], - ]).combine(UNZIP.out.unzipped_archive.map { it[1] }) - input[1] = 0 - input[2] = [] - input[3] = UNZIP.out.unzipped_archive.map { it[1] } + "/segmentations/nuclei.npy" - input[4] = [] - input[5] = [] - input[6] = [] - """ - } - } - then { - assertAll( - { assert process.success }, - { assert snapshot( - process.out.versions, - process.out.outs.get(0).get(1).findAll { file(it).name !in [ - 'analysis_summary.html', - 'metrics_summary.csv', - 'cell_boundaries.csv.gz', - 'cell_boundaries.parquet', - 'nucleus_boundaries.csv.gz', - 'nucleus_boundaries.parquet', - 'cells.csv.gz', - 'cells.parquet', - 'cells.zarr.zip', - 'transcripts.parquet', - 'transcripts.zarr.zip', - 'clusters.csv', - 'differential_expression.csv', - 'components.csv', - 'projection.csv', - 'variance.csv', - 'analysis.zarr.zip', - 'experiment.xenium', - 'cell_feature_matrix.zarr.zip' - ]} - ).match() - }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'analysis_summary.html' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'metrics_summary.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_boundaries.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_boundaries.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'nucleus_boundaries.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'nucleus_boundaries.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.zarr.zip' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'transcripts.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'clusters.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'differential_expression.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'components.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'projection.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'variance.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'analysis.zarr.zip' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'experiment.xenium' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_feature_matrix.zarr.zip' }).exists() }, - ) - } - } - - test("xeniumranger import-segmentation segmentation csv") { - when { - process { - """ - input[0] = channel.of([ - [id: "test_xeniumranger_import-segmentation"], - ]).combine(UNZIP.out.unzipped_archive.map { it[1] }) - input[1] = 0 - input[2] = UNZIP.out.unzipped_archive.map { it[1] } + "/segmentations/imagealignment.csv" - input[3] = [] - input[4] = [] - input[5] = UNZIP.out.unzipped_archive.map { it[1] } + "/segmentations/segmentation.csv" - input[6] = UNZIP.out.unzipped_archive.map { it[1] } + "/segmentations/segmentation_polygons.json" - """ - } - } - then { - assertAll( - { assert process.success }, - { assert snapshot( - process.out.versions, - process.out.outs.get(0).get(1).findAll { file(it).name !in [ - 'analysis_summary.html', - 'metrics_summary.csv', - 'cell_boundaries.csv.gz', - 'cell_boundaries.parquet', - 'nucleus_boundaries.csv.gz', - 'nucleus_boundaries.parquet', - 'cells.csv.gz', - 'cells.parquet', - 'cells.zarr.zip', - 'transcripts.parquet', - 'transcripts.zarr.zip', - 'clusters.csv', - 'differential_expression.csv', - 'components.csv', - 'projection.csv', - 'variance.csv', - 'analysis.zarr.zip', - 'experiment.xenium', - 'cell_feature_matrix.zarr.zip' - ]} - ).match() - }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'analysis_summary.html' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'metrics_summary.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_boundaries.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_boundaries.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'nucleus_boundaries.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'nucleus_boundaries.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.zarr.zip' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'transcripts.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'clusters.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'differential_expression.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'components.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'projection.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'variance.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'analysis.zarr.zip' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'experiment.xenium' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_feature_matrix.zarr.zip' }).exists() }, - ) - } - } - - test("xeniumranger import-segmentation") { - when { - process { - """ - input[0] = channel.of([ - [id: "test_xeniumranger_import-segmentation"], - ]).combine(UNZIP.out.unzipped_archive.map { it[1] }) - input[1] = 0 - input[2] = [] - input[3] = UNZIP.out.unzipped_archive.map { it[1] } + "/cells.zarr.zip" - input[4] = [] - input[5] = [] - input[6] = [] - """ - } - } - then { - assertAll( - { assert process.success }, - { assert snapshot( - process.out.versions, - process.out.outs.get(0).get(1).findAll { file(it).name !in [ - 'analysis_summary.html', - 'metrics_summary.csv', - 'cell_boundaries.csv.gz', - 'cell_boundaries.parquet', - 'nucleus_boundaries.csv.gz', - 'nucleus_boundaries.parquet', - 'cells.csv.gz', - 'cells.parquet', - 'cells.zarr.zip', - 'transcripts.parquet', - 'transcripts.zarr.zip', - 'clusters.csv', - 'differential_expression.csv', - 'components.csv', - 'projection.csv', - 'variance.csv', - 'analysis.zarr.zip', - 'experiment.xenium', - 'cell_feature_matrix.zarr.zip' - ]} - ).match() - }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'analysis_summary.html' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'metrics_summary.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_boundaries.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_boundaries.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'nucleus_boundaries.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'nucleus_boundaries.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.zarr.zip' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'transcripts.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'clusters.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'differential_expression.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'components.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'projection.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'variance.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'analysis.zarr.zip' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'experiment.xenium' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_feature_matrix.zarr.zip' }).exists() }, - ) - } - } - - test("xeniumranger import-segmentation stub") { - options "-stub" - when { - process { - """ - input[0] = channel.of([ - [id: "test_xeniumranger_import-segmentation"], - ]).combine(UNZIP.out.unzipped_archive.map { it[1] }) - input[1] = 0 - input[2] = [] - input[3] = UNZIP.out.unzipped_archive.map { it[1] } + "/cells.zarr.zip" - input[4] = [] - input[5] = [] - input[6] = [] - """ - } - } - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } -} \ No newline at end of file diff --git a/modules/nf-core/xeniumranger/import-segmentation/tests/main.nf.test.snap b/modules/nf-core/xeniumranger/import-segmentation/tests/main.nf.test.snap deleted file mode 100644 index 1c312ae0..00000000 --- a/modules/nf-core/xeniumranger/import-segmentation/tests/main.nf.test.snap +++ /dev/null @@ -1,127 +0,0 @@ -{ - "xeniumranger import-segmentation": { - "content": [ - [ - "versions.yml:md5,d76e870d71abf94ed9ae972a08b83f63" - ], - [ - "dispersion.csv:md5,e8b1abb880ece8fb730ce34a15f958b4", - "features_selected.csv:md5,c5e32d69f001f938ed316d2108a21e00", - "cell_feature_matrix.h5:md5,96cb400f1b1dd6f8796daea0ad5c74e6", - "barcodes.tsv.gz:md5,04ea06796d6b28517c288904ca043582", - "features.tsv.gz:md5,7862242129681900a9cc4086dc83b62e", - "matrix.mtx.gz:md5,489f86fbd8d65d6b973bb9cc7c5a76f1", - "gene_panel.json:md5,8890dd5fd90706e751554ac3fdfdedde", - "morphology.ome.tif:md5,6b65fff28a38a001b8f25061737fbf9b", - "morphology_focus_0000.ome.tif:md5,90e796ad634d14e62cf2ebcadf2eaf98" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" - }, - "timestamp": "2024-10-30T00:13:13.575888" - }, - "xeniumranger import-segmentation nuclei npy": { - "content": [ - [ - "versions.yml:md5,d76e870d71abf94ed9ae972a08b83f63" - ], - [ - "dispersion.csv:md5,e8b1abb880ece8fb730ce34a15f958b4", - "features_selected.csv:md5,c5e32d69f001f938ed316d2108a21e00", - "cell_feature_matrix.h5:md5,96cb400f1b1dd6f8796daea0ad5c74e6", - "barcodes.tsv.gz:md5,04ea06796d6b28517c288904ca043582", - "features.tsv.gz:md5,7862242129681900a9cc4086dc83b62e", - "matrix.mtx.gz:md5,489f86fbd8d65d6b973bb9cc7c5a76f1", - "gene_panel.json:md5,8890dd5fd90706e751554ac3fdfdedde", - "morphology.ome.tif:md5,6b65fff28a38a001b8f25061737fbf9b", - "morphology_focus_0000.ome.tif:md5,90e796ad634d14e62cf2ebcadf2eaf98" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" - }, - "timestamp": "2024-10-29T23:03:26.726334" - }, - "xeniumranger import-segmentation segmentation csv": { - "content": [ - [ - "versions.yml:md5,d76e870d71abf94ed9ae972a08b83f63" - ], - [ - "dispersion.csv:md5,e8b1abb880ece8fb730ce34a15f958b4", - "features_selected.csv:md5,c5e32d69f001f938ed316d2108a21e00", - "cell_feature_matrix.h5:md5,5d74ea595561e0300b6c3e5ec8d06fff", - "barcodes.tsv.gz:md5,97496a9b448d9380cff0575b8e7a6f57", - "features.tsv.gz:md5,7862242129681900a9cc4086dc83b62e", - "matrix.mtx.gz:md5,f93ed82a2a74c154392fc6237642f1d2", - "gene_panel.json:md5,8890dd5fd90706e751554ac3fdfdedde", - "morphology.ome.tif:md5,6b65fff28a38a001b8f25061737fbf9b", - "morphology_focus_0000.ome.tif:md5,90e796ad634d14e62cf2ebcadf2eaf98" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" - }, - "timestamp": "2024-10-29T23:22:58.158857" - }, - "xeniumranger import-segmentation stub": { - "content": [ - { - "0": [ - [ - { - "id": "test_xeniumranger_import-segmentation" - }, - "fake_file.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - "versions.yml:md5,d76e870d71abf94ed9ae972a08b83f63" - ], - "outs": [ - [ - { - "id": "test_xeniumranger_import-segmentation" - }, - "fake_file.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,d76e870d71abf94ed9ae972a08b83f63" - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" - }, - "timestamp": "2024-10-30T22:49:39.204133" - }, - "xeniumranger import-segmentation nuclei tif": { - "content": [ - [ - "versions.yml:md5,d76e870d71abf94ed9ae972a08b83f63" - ], - [ - "dispersion.csv:md5,e8b1abb880ece8fb730ce34a15f958b4", - "features_selected.csv:md5,c5e32d69f001f938ed316d2108a21e00", - "cell_feature_matrix.h5:md5,96cb400f1b1dd6f8796daea0ad5c74e6", - "barcodes.tsv.gz:md5,04ea06796d6b28517c288904ca043582", - "features.tsv.gz:md5,7862242129681900a9cc4086dc83b62e", - "matrix.mtx.gz:md5,489f86fbd8d65d6b973bb9cc7c5a76f1", - "gene_panel.json:md5,8890dd5fd90706e751554ac3fdfdedde", - "morphology.ome.tif:md5,6b65fff28a38a001b8f25061737fbf9b", - "morphology_focus_0000.ome.tif:md5,90e796ad634d14e62cf2ebcadf2eaf98" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" - }, - "timestamp": "2024-10-29T23:11:37.18721" - } -} \ No newline at end of file diff --git a/modules/nf-core/xeniumranger/import-segmentation/tests/nextflow.config b/modules/nf-core/xeniumranger/import-segmentation/tests/nextflow.config deleted file mode 100644 index e69de29b..00000000 diff --git a/modules/nf-core/xeniumranger/import-segmentation/tests/tags.yml b/modules/nf-core/xeniumranger/import-segmentation/tests/tags.yml deleted file mode 100644 index 90c2b805..00000000 --- a/modules/nf-core/xeniumranger/import-segmentation/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -xeniumranger/import-segmentation: - - "modules/nf-core/xeniumranger/import-segmentation/**" diff --git a/modules/nf-core/xeniumranger/import-segmentation/main.nf b/modules/nf-core/xeniumranger/importsegmentation/main.nf similarity index 77% rename from modules/nf-core/xeniumranger/import-segmentation/main.nf rename to modules/nf-core/xeniumranger/importsegmentation/main.nf index 264b8a72..57ff2cb6 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 "nf-core/xeniumranger:4.0" + 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 e222df58..801aa47a 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: diff --git a/modules/nf-core/xeniumranger/importsegmentation/tests/main.nf.test b/modules/nf-core/xeniumranger/importsegmentation/tests/main.nf.test new file mode 100644 index 00000000..1510df32 --- /dev/null +++ b/modules/nf-core/xeniumranger/importsegmentation/tests/main.nf.test @@ -0,0 +1,91 @@ +nextflow_process { + + name "Test Process XENIUMRANGER_IMPORTSEGMENTATION" + script "../main.nf" + process "XENIUMRANGER_IMPORTSEGMENTATION" + config "./nextflow.config" + + tag "modules" + tag "modules_nfcore" + tag "xeniumranger" + tag "xeniumranger/importsegmentation" + tag "untar" + + + setup { + + run("UNTAR") { + script "modules/nf-core/untar/main.nf" + process { + """ + input[0] = [[], file('https://raw.githubusercontent.com/nf-core/test-datasets/spatialaxe/xenium_bundle.tar.gz', checkIfExists: true)] + """ + } + } + + } + + test("xeniumranger importsegmentation nuclei") { + when { + process { + """ + input[0] = UNTAR.out.untar + .map { meta, bundle -> + [ + [id: "test_xeniumranger_importsegmentation"], + bundle, + [], + [], + bundle + "/cells.zarr.zip", + [], + [], + [], + 5 + ] + } + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert process.out.outs != null }, + { assert file(process.out.outs.get(0).get(1)).isDirectory() }, + { assert file(process.out.outs.get(0).get(1)).list().size() > 0 }, + { assert snapshot(sanitizeOutput(process.out, unstableKeys: ["outs"])).match()}, + ) + } + } + + test("xeniumranger importsegmentation stub") { + options "-stub" + + when { + process { + """ + input[0] = UNTAR.out.untar + .map { meta, bundle -> + [ + [id: "test_xeniumranger_importsegmentation"], + bundle, + [], + [], + bundle + "/cells.zarr.zip", + [], + [], + [], + 5 + ] + } + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } +} diff --git a/modules/nf-core/xeniumranger/importsegmentation/tests/main.nf.test.snap b/modules/nf-core/xeniumranger/importsegmentation/tests/main.nf.test.snap new file mode 100644 index 00000000..7fb43655 --- /dev/null +++ b/modules/nf-core/xeniumranger/importsegmentation/tests/main.nf.test.snap @@ -0,0 +1,56 @@ +{ + "xeniumranger importsegmentation stub": { + "content": [ + { + "outs": [ + [ + { + "id": "test_xeniumranger_importsegmentation" + }, + [ + "experiment.xenium:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "versions_xeniumranger": [ + [ + "XENIUMRANGER_IMPORTSEGMENTATION", + "xeniumranger", + "4.0.1.1" + ] + ] + } + ], + "timestamp": "2026-07-27T15:02:26.958198169", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.6" + } + }, + "xeniumranger importsegmentation nuclei": { + "content": [ + { + "outs": [ + [ + { + "id": "test_xeniumranger_importsegmentation" + }, + "test_xeniumranger_importsegmentation" + ] + ], + "versions_xeniumranger": [ + [ + "XENIUMRANGER_IMPORTSEGMENTATION", + "xeniumranger", + "4.0.1.1" + ] + ] + } + ], + "timestamp": "2026-07-27T15:02:12.93562615", + "meta": { + "nf-test": "0.9.5", + "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 00000000..39b095f8 --- /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' + } +} diff --git a/nextflow.config b/nextflow.config index cf75ae06..eef01269 100644 --- a/nextflow.config +++ b/nextflow.config @@ -385,7 +385,7 @@ manifest { mainScript = 'main.nf' defaultBranch = 'master' nextflowVersion = '!>=25.04.0' - version = '1.1.0dev' + version = '1.0.1' doi = '' } diff --git a/ro-crate-metadata.json b/ro-crate-metadata.json index d5575c0b..0a88ac08 100644 --- a/ro-crate-metadata.json +++ b/ro-crate-metadata.json @@ -21,9 +21,9 @@ { "@id": "./", "@type": "Dataset", - "creativeWorkStatus": "InProgress", - "datePublished": "2026-06-17T15:15:09+00:00", - "description": "

\n \n \n \"nf-core/spatialaxe\"\n \n

\n\n[![Open in GitHub Codespaces](https://img.shields.io/badge/Open_In_GitHub_Codespaces-black?labelColor=grey&logo=github)](https://github.com/codespaces/new/nf-core/spatialaxe)\n[![GitHub Actions CI Status](https://github.com/nf-core/spatialaxe/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-core/spatialaxe/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-core/spatialaxe/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/spatialaxe/actions/workflows/linting.yml)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/spatialaxe/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.04.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.4.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.4.1)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-core/spatialaxe)\n\n[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23spatialaxe-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/spatialaxe)[![Follow on Bluesky](https://img.shields.io/badge/bluesky-%40nf__core-1185fe?labelColor=000000&logo=bluesky)](https://bsky.app/profile/nf-co.re)[![Follow on Mastodon](https://img.shields.io/badge/mastodon-nf__core-6364ff?labelColor=FFFFFF&logo=mastodon)](https://mstdn.science/@nf_core)[![Watch on YouTube](http://img.shields.io/badge/youtube-nf--core-FF0000?labelColor=000000&logo=youtube)](https://www.youtube.com/c/nf-core)\n\n## Introduction\n\n**nf-core/spatialaxe** is a bioinformatics best-practice processing and quality control pipeline for Xenium (and soon Atera) data. The current plan for the pipeline implementation is shown in the metromap below. **The pipeline is under active developement and changes might occure frequently**.\n\n![nf-core/spatialaxe-metromap](docs/images/spatialaxe-metromap.png)\n\n> [!NOTE]\n> We are currently extending the pipeline for the [10x Atera system](https://www.10xgenomics.com/platforms/atera).\n\n## Tools supported\n\nThe pipeline supports the following tools:\n\n- Segmenation methods:\n - [Baysor](https://doi.org/10.1038/s41587-021-01044-w)\n - [Cellpose](https://doi.org/10.1038/s41592-020-01018-x)\n - [Xenium ranger (XR)](https://www.10xgenomics.com/support/software/xenium-ranger/latest)\n - [StarDist](https://doi.org/10.48550/arXiv.2203.02284)\n- Segmentation free methods:\n - [Ficture](https://doi.org/10.1038/s41592-024-02415-2)\n - [Baysor](https://doi.org/10.1038/s41587-021-01044-w)\n- Transcript assignment methods:\n - [Segger](https://doi.org/10.1101/2025.03.14.643160)\n - [Proseg](https://doi.org/10.1038/s41592-025-02697-0)\n- Utility methods:\n - [SpatialData](https://doi.org/10.1038/s41592-024-02212-x)\n - [Baysor](https://doi.org/10.1038/s41587-021-01044-w)\n- QC methods:\n - [MultiQC Xenium Extra Plugin](https://github.com/MultiQC/xenium-extra)\n - [OPT](https://github.com/JEFworks-Lab/off-target-probe-tracker)\n\n## Usage\n\nOn release, automated continuous integration tests run the pipeline on a full-sized dataset on the AWS cloud infrastructure. This ensures that the pipeline runs on AWS, has sensible resource allocation defaults set to run on real-world datasets, and permits the persistent storage of results to benchmark between pipeline releases and other analysis sources. The results obtained from the full-sized test can be viewed on the [nf-core website](https://nf-co.re/spatialaxe/results).\n\n> [!NOTE]\n> The pipeline does not support conda currently. We are working on it.\n\n## Quick Start\n\n`samplesheet.csv`:\n\n```csv\nsample,bundle,image\ntest_sample,/path/to/xenium-bundle,/path/to/morphology.ome.tif\n```\n\nNow, you can run the pipeline using:\n\n### Run image-based segmentation mode
\n\n`CELLPOSE -> BAYSOR -> XR-IMPORT_SEGMENTATION -> SPATIALDATA -> QC`\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode \n```\n\n### Run coordinate-based segmentation mode
\n\n`PROSEG -> PROSEG2BAYSOR -> XR-IMPORT_SEGMENTATION -> SPATIALDATA -> QC`\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode coordinate\n```\n\n### Run segfree mode
\n\n`BAYSOR_SEGFREE`\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode segfree\n```\n\n### Run preview mode
\n\n`BAYSOR_PREVIEW`\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode preview\n```\n\n### Run just the quality control
\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode qc\n```\n\n### Additional information\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; see [docs](https://nf-co.re/docs/usage/getting_started/configuration#custom-configuration-files).\n\nFor more details and further functionality, please refer to the [usage documentation](https://nf-co.re/spatialaxe/usage) and the [parameter documentation](https://nf-co.re/spatialaxe/parameters).\n\n## Pipeline output\n\nTo see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/spatialaxe/results) tab on the nf-core website pipeline page.\nFor more details about the output files and reports, please refer to the\n[output documentation](https://nf-co.re/spatialaxe/output).\n\n## Runtime and resource estimations\n\n| Tool | Compute | Runtime (min / med / max) | Peak RSS (min / med / max) |\n| ------------------------- | ------- | ------------------------- | -------------------------- |\n| Cellpose | GPU | 1m / 4m / 1.4h | 10 GB / 26 GB / 554 GB |\n| Cellpose | CPU | 1.3h / 2.3h / 6.5h | 161 GB / 426 GB / 1115 GB |\n| StarDist | GPU | 1m / 4m / 7m | 5 GB / 12 GB / 18 GB |\n| StarDist | CPU | 5m / 6m / 7m | 18 GB / 18 GB / 18 GB |\n| Segger (create_dataset) | GPU | 2m / 9m / 31m | 1.7 GB / 14 GB / 50 GB |\n| Segger (create_dataset) | CPU | 13m / 21m / 46m | 13 GB / 19 GB / 49 GB |\n| Segger (train) | GPU | 10m / 43m / 2.9h | 30 GB / 33 GB / 60 GB |\n| Segger (predict) | GPU | 2m / 16m / 59m | 10 GB / 25 GB / 87 GB |\n| Baysor (whole-image) | CPU | 2m / 30m / 17h | 6 GB / 10 GB / 650 GB |\n| Baysor (tiled) | CPU | 1m / 18m / 13h | 0.2 GB / 34 GB / 530 GB |\n| Proseg | CPU | 1m / 18m / 6.8h | 279 MB / 3.8 GB / 136 GB |\n| XeniumRanger (resegment) | CPU | 18m / 39m / 3.7h | 28 GB / 54 GB / 60 GB |\n| XeniumRanger (import_seg) | CPU | 2m / 7m / 2.7h | 2.6 GB / 11 GB / 51 GB |\n| Ficture (preprocess) | CPU | 3m / 4m / 13m | 331 MB / 357 MB / 21 GB |\n\n- Cellpose GPU vs CPU: 35x faster on GPU (4m median vs 2.3h), 16x less memory (26 GB vs 426 GB)\n- Segger: Only tool that truly requires GPU for all 3 steps (create_dataset, train, predict)\n- StarDist: Very fast on CPU, GPU is not necessary to run its default model\n\n## Credits\n\nnf-core/spatialaxe is mainly developed by [Sameesh Kher](https://github.com/khersameesh24), [Dongze He](https://github.com/dongzehe), and [Florian Heyl](https://github.com/heylf).\n\nWe thank the following people for their extensive assistance in the development of this pipeline:\n\n- Tobias Krause\n- Kre\u0161imir Be\u0161tak (kbestak)\n- Matthias H\u00f6rtenhuber (mashehu)\n- Maxime Garcia (maxulysse)\n- K\u00fcbra Narc\u0131 (kubranarci)\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md).\n\nFor further information or help, don't hesitate to get in touch on the [Slack `#spatialaxe` channel](https://nfcore.slack.com/channels/spatialaxe) (you can join with [this invite](https://nf-co.re/join/slack)).\n\n## Citations\n\n\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nYou can cite the `nf-core` publication as follows:\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", + "creativeWorkStatus": "Stable", + "datePublished": "2026-07-23T13:01:17+00:00", + "description": "

\n \n \n \"nf-core/spatialaxe\"\n \n

\n\n[![Open in GitHub Codespaces](https://img.shields.io/badge/Open_In_GitHub_Codespaces-black?labelColor=grey&logo=github)](https://github.com/codespaces/new/nf-core/spatialaxe)\n[![GitHub Actions CI Status](https://github.com/nf-core/spatialaxe/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-core/spatialaxe/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-core/spatialaxe/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/spatialaxe/actions/workflows/linting.yml)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/spatialaxe/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.04.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.4.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.4.1)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-core/spatialaxe)\n\n[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23spatialaxe-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/spatialaxe)[![Follow on Bluesky](https://img.shields.io/badge/bluesky-%40nf__core-1185fe?labelColor=000000&logo=bluesky)](https://bsky.app/profile/nf-co.re)[![Follow on Mastodon](https://img.shields.io/badge/mastodon-nf__core-6364ff?labelColor=FFFFFF&logo=mastodon)](https://mstdn.science/@nf_core)[![Watch on YouTube](http://img.shields.io/badge/youtube-nf--core-FF0000?labelColor=000000&logo=youtube)](https://www.youtube.com/c/nf-core)\n\n## Introduction\n\n**nf-core/spatialaxe** is a bioinformatics best-practice processing and quality control pipeline for Xenium (and soon Atera) data. The current plan for the pipeline implementation is shown in the metromap below. **The pipeline is under active developement and changes might occure frequently**.\n\n![nf-core/spatialaxe-metromap](docs/images/spatialaxe-metromap.png)\n\n> [!NOTE]\n> We are currently extending the pipeline for the [10x Atera system](https://www.10xgenomics.com/platforms/atera).\n\n## Tools supported\n\nThe pipeline supports the following tools:\n\n- Segmenation methods:\n - [Baysor](https://doi.org/10.1038/s41587-021-01044-w)\n - [Cellpose](https://doi.org/10.1038/s41592-020-01018-x)\n - [Xenium ranger (XR)](https://www.10xgenomics.com/support/software/xenium-ranger/latest)\n - [StarDist](https://doi.org/10.48550/arXiv.2203.02284)\n- Segmentation free methods:\n - [Ficture](https://doi.org/10.1038/s41592-024-02415-2)\n - [Baysor](https://doi.org/10.1038/s41587-021-01044-w)\n- Transcript assignment methods:\n - [Segger](https://doi.org/10.1101/2025.03.14.643160)\n - [Proseg](https://doi.org/10.1038/s41592-025-02697-0)\n- Utility methods:\n - [SpatialData](https://doi.org/10.1038/s41592-024-02212-x)\n - [Baysor](https://doi.org/10.1038/s41587-021-01044-w)\n- QC methods:\n - [MultiQC Xenium Extra Plugin](https://github.com/MultiQC/xenium-extra)\n - [OPT](https://github.com/JEFworks-Lab/off-target-probe-tracker)\n\n## Usage\n\nOn release, automated continuous integration tests run the pipeline on a full-sized dataset on the AWS cloud infrastructure. This ensures that the pipeline runs on AWS, has sensible resource allocation defaults set to run on real-world datasets, and permits the persistent storage of results to benchmark between pipeline releases and other analysis sources. The results obtained from the full-sized test can be viewed on the [nf-core website](https://nf-co.re/spatialaxe/results).\n\n> [!NOTE]\n> The pipeline does not support conda currently. We are working on it.\n\n## Quick Start\n\n`samplesheet.csv`:\n\n```csv\nsample,bundle,image\ntest_sample,/path/to/xenium-bundle,/path/to/morphology.ome.tif\n```\n\nNow, you can run the pipeline using:\n\n### Run image-based segmentation mode
\n\n`CELLPOSE -> BAYSOR -> XR-IMPORT_SEGMENTATION -> SPATIALDATA -> QC`\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode \n```\n\n### Run coordinate-based segmentation mode
\n\n`PROSEG -> PROSEG2BAYSOR -> XR-IMPORT_SEGMENTATION -> SPATIALDATA -> QC`\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode coordinate\n```\n\n### Run segfree mode
\n\n`BAYSOR_SEGFREE`\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode segfree\n```\n\n### Run preview mode
\n\n`BAYSOR_PREVIEW`\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode preview\n```\n\n### Run just the quality control
\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode qc\n```\n\n### Additional information\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; see [docs](https://nf-co.re/docs/usage/getting_started/configuration#custom-configuration-files).\n\nFor more details and further functionality, please refer to the [usage documentation](https://nf-co.re/spatialaxe/usage) and the [parameter documentation](https://nf-co.re/spatialaxe/parameters).\n\n## Pipeline output\n\nTo see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/spatialaxe/results) tab on the nf-core website pipeline page.\nFor more details about the output files and reports, please refer to the\n[output documentation](https://nf-co.re/spatialaxe/output).\n\n## Runtime and resource estimations\n\n| Tool | Compute | Runtime (min / med / max) | Peak RSS (min / med / max) |\n| ------------------------- | ------- | ------------------------- | -------------------------- |\n| Cellpose | GPU | 1m / 4m / 1.4h | 10 GB / 26 GB / 554 GB |\n| Cellpose | CPU | 1.3h / 2.3h / 6.5h | 161 GB / 426 GB / 1115 GB |\n| StarDist | GPU | 1m / 4m / 7m | 5 GB / 12 GB / 18 GB |\n| StarDist | CPU | 5m / 6m / 7m | 18 GB / 18 GB / 18 GB |\n| Segger (create_dataset) | GPU | 2m / 9m / 31m | 1.7 GB / 14 GB / 50 GB |\n| Segger (create_dataset) | CPU | 13m / 21m / 46m | 13 GB / 19 GB / 49 GB |\n| Segger (train) | GPU | 10m / 43m / 2.9h | 30 GB / 33 GB / 60 GB |\n| Segger (predict) | GPU | 2m / 16m / 59m | 10 GB / 25 GB / 87 GB |\n| Baysor (whole-image) | CPU | 2m / 30m / 17h | 6 GB / 10 GB / 650 GB |\n| Baysor (tiled) | CPU | 1m / 18m / 13h | 0.2 GB / 34 GB / 530 GB |\n| Proseg | CPU | 1m / 18m / 6.8h | 279 MB / 3.8 GB / 136 GB |\n| XeniumRanger (resegment) | CPU | 18m / 39m / 3.7h | 28 GB / 54 GB / 60 GB |\n| XeniumRanger (import_seg) | CPU | 2m / 7m / 2.7h | 2.6 GB / 11 GB / 51 GB |\n| Ficture (preprocess) | CPU | 3m / 4m / 13m | 331 MB / 357 MB / 21 GB |\n\n- Cellpose GPU vs CPU: 35x faster on GPU (4m median vs 2.3h), 16x less memory (26 GB vs 426 GB)\n- Segger: Only tool that truly requires GPU for all 3 steps (create_dataset, train, predict)\n- StarDist: Very fast on CPU, GPU is not necessary to run its default model\n\n## Credits\n\nnf-core/spatialaxe is mainly developed by [Sameesh Kher](https://github.com/khersameesh24), [Dongze He](https://github.com/dongzehe), and [Florian Heyl](https://github.com/heylf).\n\nWe thank the following people for their extensive assistance in the development of this pipeline:\n\n- Tobias Krause\n- Krešimir Beštak (kbestak)\n- Matthias Hörtenhuber (mashehu)\n- Maxime Garcia (maxulysse)\n- Kübra Narcı (kubranarci)\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md).\n\nFor further information or help, don't hesitate to get in touch on the [Slack `#spatialaxe` channel](https://nfcore.slack.com/channels/spatialaxe) (you can join with [this invite](https://nf-co.re/join/slack)).\n\n## Citations\n\n\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nYou can cite the `nf-core` publication as follows:\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", "hasPart": [ { "@id": "main.nf" @@ -105,7 +105,7 @@ }, "mentions": [ { - "@id": "#f9351d64-871a-4ac7-b2f8-a41f21061c8e" + "@id": "#261e6187-b79f-4b98-ba5b-c00684be47bc" } ], "name": "nf-core/spatialaxe" @@ -132,19 +132,21 @@ "SoftwareSourceCode", "ComputationalWorkflow" ], - "contributor": [ + "author": [ { "@id": "https://orcid.org/0009-0008-2420-6464" }, - { - "@id": "#79ea84f2-1720-4192-abf8-4298bf91da8f" - }, { "@id": "https://orcid.org/0000-0002-3651-5685" } ], + "contributor": [ + { + "@id": "https://orcid.org/0000-0001-8259-7434" + } + ], "dateCreated": "", - "dateModified": "2026-06-26T11:19:26Z", + "dateModified": "2026-07-23T15:01:17Z", "dct:conformsTo": "https://bioschemas.org/profiles/ComputationalWorkflow/1.0-RELEASE/", "keywords": [ "nf-core", @@ -161,6 +163,14 @@ "license": [ "MIT" ], + "maintainer": [ + { + "@id": "https://orcid.org/0009-0008-2420-6464" + }, + { + "@id": "https://orcid.org/0000-0002-3651-5685" + } + ], "name": [ "nf-core/spatialaxe" ], @@ -172,10 +182,10 @@ }, "url": [ "https://github.com/nf-core/spatialaxe", - "https://nf-co.re/spatialaxe/dev/" + "https://nf-co.re/spatialaxe/1.0.1/" ], "version": [ - "1.1.0dev" + "1.0.1" ] }, { @@ -191,11 +201,11 @@ "version": "!>=25.04.0" }, { - "@id": "#f9351d64-871a-4ac7-b2f8-a41f21061c8e", + "@id": "#261e6187-b79f-4b98-ba5b-c00684be47bc", "@type": "TestSuite", "instance": [ { - "@id": "#6665fb11-77f3-4e28-a01c-3b13037a23a0" + "@id": "#e58b049c-0f60-4176-ae4e-f6fd057d8c60" } ], "mainEntity": { @@ -204,7 +214,7 @@ "name": "Test suite for nf-core/spatialaxe" }, { - "@id": "#6665fb11-77f3-4e28-a01c-3b13037a23a0", + "@id": "#e58b049c-0f60-4176-ae4e-f6fd057d8c60", "@type": "TestInstance", "name": "GitHub Actions workflow for testing nf-core/spatialaxe", "resource": "repos/nf-core/spatialaxe/actions/workflows/nf-test.yml", @@ -345,18 +355,26 @@ { "@id": "https://orcid.org/0009-0008-2420-6464", "@type": "Person", - "email": "khersameesh24@gmail.com", - "name": "Sameesh Kher" + "affiliation": "German Cancer Research Center (DKFZ), Heidelberg, DE", + "email": "sameesh.kher@dkfz-heidelberg.de", + "name": "Sameesh Kher", + "url": "https://github.com/khersameesh24" }, { - "@id": "#79ea84f2-1720-4192-abf8-4298bf91da8f", + "@id": "https://orcid.org/0000-0002-3651-5685", "@type": "Person", - "name": "Dongze He" + "affiliation": "German Cancer Research Center (DKFZ), Heidelberg, DE", + "email": "florian.heyl@dkfz-heidelberg.de", + "name": "Florian Heyl", + "url": "https://github.com/heylf" }, { - "@id": "https://orcid.org/0000-0002-3651-5685", + "@id": "https://orcid.org/0000-0001-8259-7434", "@type": "Person", - "name": "Florian Heyl" + "affiliation": "Altos Labs, San Diego, USA", + "email": "dongzehe.zaza@gmail.com", + "name": "Dongze He", + "url": "https://github.com/dongzehe" } ] } \ No newline at end of file diff --git a/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf b/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf index d5acc0a1..48236e8c 100644 --- a/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf +++ b/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf @@ -4,7 +4,7 @@ include { BAYSOR_PREPROCESS_TRANSCRIPTS } from '../../../modules/local/baysor/preprocess/main' include { BAYSOR_RUN } from '../../../modules/local/baysor/run/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow BAYSOR_RUN_PRIOR_SEGMENTATION_MASK { @@ -18,6 +18,7 @@ workflow BAYSOR_RUN_PRIOR_SEGMENTATION_MASK { min_qv // value: minimum transcript QV min_x // value: spatial filter lower x bound min_y // value: spatial filter lower y bound + expansion_distance // value: nuclear expansion distance main: @@ -69,13 +70,14 @@ workflow BAYSOR_RUN_PRIOR_SEGMENTATION_MASK { polygons2d, [], ch_coordinate_space.val, + expansion_distance, ) } - XENIUMRANGER_IMPORT_SEGMENTATION( + XENIUMRANGER_IMPORTSEGMENTATION( ch_imp_seg_inputs ) - ch_redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs + ch_redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs emit: coordinate_space = ch_coordinate_space // channel: [ "pixels" ] diff --git a/subworkflows/local/baysor_run_transcripts_parquet/main.nf b/subworkflows/local/baysor_run_transcripts_parquet/main.nf index aff27051..c64bf71a 100644 --- a/subworkflows/local/baysor_run_transcripts_parquet/main.nf +++ b/subworkflows/local/baysor_run_transcripts_parquet/main.nf @@ -15,7 +15,7 @@ include { BAYSOR_RUN } from '../../../modules/local/baysor include { BAYSOR_PREPROCESS_TRANSCRIPTS } from '../../../modules/local/baysor/preprocess/main' include { XENIUM_PATCH_STITCH } from '../../../modules/local/xenium_patch/stitch/main' include { RECONSTRUCT_PATCHES } from '../../../modules/local/utility/reconstruct_patches/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET { @@ -35,6 +35,7 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET { min_qv // value: minimum transcript QV min_x // value: spatial filter lower x bound min_y // value: spatial filter lower y bound + expansion_distance // value: nuclear expansion distance main: @@ -112,11 +113,12 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET { xr_transcript_metadata, xr_cell_polygons, [], [], [], - "microns" + "microns", + expansion_distance, ) } - XENIUMRANGER_IMPORT_SEGMENTATION (ch_xr) + XENIUMRANGER_IMPORTSEGMENTATION (ch_xr) } else { @@ -154,13 +156,14 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET { segmentation_csv, polygons2d, [], [], [], - ch_coordinate_space.val) + ch_coordinate_space.val, + expansion_distance) } - XENIUMRANGER_IMPORT_SEGMENTATION(ch_xr) + XENIUMRANGER_IMPORTSEGMENTATION(ch_xr) } emit: - redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs + redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs coordinate_space = ch_coordinate_space } diff --git a/subworkflows/local/baysor_run_transcripts_parquet_tiled/main.nf b/subworkflows/local/baysor_run_transcripts_parquet_tiled/main.nf index 70045331..db290209 100644 --- a/subworkflows/local/baysor_run_transcripts_parquet_tiled/main.nf +++ b/subworkflows/local/baysor_run_transcripts_parquet_tiled/main.nf @@ -6,7 +6,7 @@ include { XENIUM_PATCH_DIVIDE } from '../../../modules/local/xenium include { BAYSOR_PREPROCESS_TRANSCRIPTS } from '../../../modules/local/baysor/preprocess/main' include { BAYSOR_RUN } from '../../../modules/local/baysor/run/main' include { XENIUM_PATCH_STITCH } from '../../../modules/local/xenium_patch/stitch/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET_TILED { @@ -19,6 +19,7 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET_TILED { min_qv // value: minimum transcript QV min_x // value: spatial filter lower x bound min_y // value: spatial filter lower y bound + expansion_distance // value: nuclear expansion distance main: @@ -93,12 +94,12 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET_TILED { .combine(XENIUM_PATCH_STITCH.out.xr_polygons_transcript, by: 0) .combine(ch_coordinate_space) .map { meta, bundle, geojson, csv, coord_space -> - tuple(meta, bundle, csv, geojson, [], [], [], coord_space) + tuple(meta, bundle, csv, geojson, [], [], [], coord_space, expansion_distance) } - XENIUMRANGER_IMPORT_SEGMENTATION ( ch_xr ) + XENIUMRANGER_IMPORTSEGMENTATION ( ch_xr ) emit: coordinate_space = ch_coordinate_space // channel: [ "microns" ] - redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] + redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] } diff --git a/subworkflows/local/cellpose_baysor_import_segmentation/main.nf b/subworkflows/local/cellpose_baysor_import_segmentation/main.nf index 38bbcc74..06a15a41 100644 --- a/subworkflows/local/cellpose_baysor_import_segmentation/main.nf +++ b/subworkflows/local/cellpose_baysor_import_segmentation/main.nf @@ -11,7 +11,7 @@ include { CONVERT_MASK_UINT32 } from '../../../modules/local/utilit include { BAYSOR_PREPROCESS_TRANSCRIPTS } from '../../../modules/local/baysor/preprocess/main' include { RESIZE_TIF } from '../../../modules/local/utility/resize_tif/main' include { GET_TRANSCRIPTS_COORDINATES } from '../../../modules/local/utility/get_coordinates/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { take: @@ -30,6 +30,7 @@ workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { nucleus_segmentation_only // value: bool sharpen_tiff // value: bool stardist_nuclei_model // value: stardist pretrained model name + expansion_distance // value: nuclear expansion distance main: @@ -180,12 +181,13 @@ workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { [], [], ch_coordinate_space.val, + expansion_distance, ) } - XENIUMRANGER_IMPORT_SEGMENTATION(ch_imp_seg_inputs) + XENIUMRANGER_IMPORTSEGMENTATION(ch_imp_seg_inputs) emit: coordinate_space = ch_coordinate_space // channel: [ val("microns") ] - redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] + redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] } diff --git a/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf b/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf index 6bb38ded..9b95f912 100644 --- a/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf +++ b/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf @@ -9,7 +9,7 @@ include { CELLPOSE as CELLPOSE_CELLS } from '../../../modules/nf-core/cell include { EXTRACT_DAPI } from '../../../modules/local/utility/extract_dapi/main' include { STARDIST as STARDIST_NUCLEI } from '../../../modules/nf-core/stardist/main' include { CONVERT_MASK_UINT32 } from '../../../modules/local/utility/convert_mask_uint32/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { take: @@ -20,6 +20,7 @@ workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { nucleus_segmentation_only // value: bool sharpen_tiff // value: bool stardist_nuclei_model // value: stardist pretrained model name + expansion_distance // value: nuclear expansion distance main: @@ -106,9 +107,10 @@ workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { [], [], coord_space, + expansion_distance, ) } - XENIUMRANGER_IMPORT_SEGMENTATION( + XENIUMRANGER_IMPORTSEGMENTATION( ch_imp_seg_inputs ) } @@ -128,14 +130,15 @@ workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { cells_seg, [], coord_space, + expansion_distance, ) } - XENIUMRANGER_IMPORT_SEGMENTATION( + XENIUMRANGER_IMPORTSEGMENTATION( ch_imp_seg_inputs ) } emit: coordinate_space = ch_coordinate_space // channel: [ ["pixels"] ] - redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] + redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] } diff --git a/subworkflows/local/proseg_preset_proseg2baysor/main.nf b/subworkflows/local/proseg_preset_proseg2baysor/main.nf index 3f9d8c99..000167c5 100644 --- a/subworkflows/local/proseg_preset_proseg2baysor/main.nf +++ b/subworkflows/local/proseg_preset_proseg2baysor/main.nf @@ -4,12 +4,13 @@ include { PROSEG } from '../../../modules/local/proseg/preset/main' include { PROSEG2BAYSOR } from '../../../modules/local/proseg/proseg2baysor/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow PROSEG_PRESET_PROSEG2BAYSOR { take: ch_bundle_path // channel: [ val(meta), ["path-to-xenium-bundle"] ] ch_transcripts_file // channel: [ val(meta), [ "transcripts.parquet" ] ] + expansion_distance // value: nuclear expansion distance main: @@ -37,14 +38,15 @@ workflow PROSEG_PRESET_PROSEG2BAYSOR { [], [], ch_coordinate_space.val, + expansion_distance, ) } - XENIUMRANGER_IMPORT_SEGMENTATION( + XENIUMRANGER_IMPORTSEGMENTATION( ch_imp_seg_inputs ) emit: coordinate_space = ch_coordinate_space // channel: [ "microns" ] - redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] + redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] } diff --git a/subworkflows/local/proseg_preset_proseg2baysor_tiled/main.nf b/subworkflows/local/proseg_preset_proseg2baysor_tiled/main.nf index 7ff6b783..5fe72560 100644 --- a/subworkflows/local/proseg_preset_proseg2baysor_tiled/main.nf +++ b/subworkflows/local/proseg_preset_proseg2baysor_tiled/main.nf @@ -6,13 +6,14 @@ include { XENIUM_PATCH_DIVIDE } from '../../../modules/local/xenium include { PROSEG } from '../../../modules/local/proseg/preset/main' include { PROSEG2BAYSOR } from '../../../modules/local/proseg/proseg2baysor/main' include { XENIUM_PATCH_STITCH } from '../../../modules/local/xenium_patch/stitch/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow PROSEG_PRESET_PROSEG2BAYSOR_TILED { take: ch_bundle_path // channel: [ val(meta), ["path-to-xenium-bundle"] ] ch_transcripts_file // channel: [ val(meta), [ "transcripts.parquet" ] ] + expansion_distance // value: nuclear expansion distance main: @@ -75,12 +76,12 @@ workflow PROSEG_PRESET_PROSEG2BAYSOR_TILED { .combine(XENIUM_PATCH_STITCH.out.xr_polygons_transcript, by: 0) .combine(ch_coordinate_space) .map { meta, bundle, geojson, csv, coord_space -> - tuple(meta, bundle, csv, geojson, [], [], [], coord_space) + tuple(meta, bundle, csv, geojson, [], [], [], coord_space, expansion_distance) } - XENIUMRANGER_IMPORT_SEGMENTATION ( ch_xr ) + XENIUMRANGER_IMPORTSEGMENTATION ( ch_xr ) emit: coordinate_space = ch_coordinate_space // channel: [ "microns" ] - redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] + redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] } diff --git a/subworkflows/local/segger_create_train_predict/main.nf b/subworkflows/local/segger_create_train_predict/main.nf index 3f832d61..152e0342 100644 --- a/subworkflows/local/segger_create_train_predict/main.nf +++ b/subworkflows/local/segger_create_train_predict/main.nf @@ -6,13 +6,14 @@ include { SEGGER2XR } from '../../../modules/local/utilit include { SEGGER_TRAIN } from '../../../modules/local/segger/train/main' include { SEGGER_PREDICT } from '../../../modules/local/segger/predict/main' include { SEGGER_CREATE_DATASET } from '../../../modules/local/segger/create_dataset/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow SEGGER_CREATE_TRAIN_PREDICT { take: ch_bundle // channel: [ val(meta), ["path-to-xenium-bundle"] ] ch_transcripts_file // channel: [ val(meta), [bundle + "/transcripts.parquet"]] segger_model // value: path to a pre-trained segger model checkpoint (or null) + expansion_distance // value: nuclear expansion distance main: @@ -64,14 +65,15 @@ workflow SEGGER_CREATE_TRAIN_PREDICT { [], // cells [], // coordinate_transform ch_coordinate_space.val, + expansion_distance, ) } - XENIUMRANGER_IMPORT_SEGMENTATION( + XENIUMRANGER_IMPORTSEGMENTATION( ch_imp_seg_inputs ) emit: coordinate_space = ch_coordinate_space // channel: [ "microns" ] - redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] + redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] } diff --git a/subworkflows/local/stardist_resolift_morphology_ome_tif/main.nf b/subworkflows/local/stardist_resolift_morphology_ome_tif/main.nf index bc255409..d002d291 100644 --- a/subworkflows/local/stardist_resolift_morphology_ome_tif/main.nf +++ b/subworkflows/local/stardist_resolift_morphology_ome_tif/main.nf @@ -6,7 +6,7 @@ include { RESOLIFT } from '../../../modules/local/resoli include { EXTRACT_DAPI } from '../../../modules/local/utility/extract_dapi/main' include { STARDIST as STARDIST_NUCLEI } from '../../../modules/nf-core/stardist/main' include { CONVERT_MASK_UINT32 } from '../../../modules/local/utility/convert_mask_uint32/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow STARDIST_RESOLIFT_MORPHOLOGY_OME_TIF { take: @@ -14,6 +14,7 @@ workflow STARDIST_RESOLIFT_MORPHOLOGY_OME_TIF { ch_bundle_path // channel: [ val(meta), ["path-to-xenium-bundle"] ] sharpen_tiff // value: bool stardist_nuclei_model // value: stardist pretrained model name + expansion_distance // value: nuclear expansion distance main: @@ -58,13 +59,14 @@ workflow STARDIST_RESOLIFT_MORPHOLOGY_OME_TIF { [], [], ch_coordinate_space.val, + expansion_distance, ) } - XENIUMRANGER_IMPORT_SEGMENTATION( + XENIUMRANGER_IMPORTSEGMENTATION( ch_imp_seg_inputs ) emit: coordinate_space = ch_coordinate_space // channel: [ ["pixels"] ] - redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] + redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] } diff --git a/subworkflows/local/xeniumranger_import_segmentation_redefine_bundle/main.nf b/subworkflows/local/xeniumranger_import_segmentation_redefine_bundle/main.nf index 4c7b41d5..a2d298f8 100644 --- a/subworkflows/local/xeniumranger_import_segmentation_redefine_bundle/main.nf +++ b/subworkflows/local/xeniumranger_import_segmentation_redefine_bundle/main.nf @@ -2,9 +2,9 @@ // Run xeniumranger import-segmentation // -include { XENIUMRANGER_IMPORT_SEGMENTATION as IMP_SEG_COUNT_MATRIX_EXP_DISTANCE } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION as IMP_SEG_POLYGON_GEOJSON_INPUT } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION as IMP_SEG_TRANS_MATRIX_INPUT } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION as IMP_SEG_COUNT_MATRIX_EXP_DISTANCE } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION as IMP_SEG_POLYGON_GEOJSON_INPUT } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION as IMP_SEG_TRANS_MATRIX_INPUT } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE { @@ -40,6 +40,7 @@ workflow XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE { [], [], ch_coordinate_space.val, + expansion_distance, ) } @@ -65,6 +66,7 @@ workflow XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE { [], [], ch_coordinate_space.val, + expansion_distance, ) } @@ -88,6 +90,7 @@ workflow XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE { polygons_geojson, [], ch_coordinate_space.val, + expansion_distance, ) } @@ -117,6 +120,7 @@ workflow XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE { polygons_geojson, alignment_csv_file, ch_coordinate_space.val, + expansion_distance, ) } diff --git a/subworkflows/local/xeniumranger_resegment_morphology_ome_tif/main.nf b/subworkflows/local/xeniumranger_resegment_morphology_ome_tif/main.nf index bcd97584..0a5c81ee 100644 --- a/subworkflows/local/xeniumranger_resegment_morphology_ome_tif/main.nf +++ b/subworkflows/local/xeniumranger_resegment_morphology_ome_tif/main.nf @@ -3,12 +3,13 @@ // include { XENIUMRANGER_RESEGMENT } from '../../../modules/nf-core/xeniumranger/resegment/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow XENIUMRANGER_RESEGMENT_MORPHOLOGY_OME_TIF { take: ch_bundle_path // channel: [ val(meta), ["path-to-xenium-bundle"] ] nucleus_segmentation_only // value: bool + expansion_distance // value: nuclear expansion distance main: @@ -41,14 +42,15 @@ workflow XENIUMRANGER_RESEGMENT_MORPHOLOGY_OME_TIF { cells_zarr, [], "pixels", + expansion_distance, ) } - XENIUMRANGER_IMPORT_SEGMENTATION( + XENIUMRANGER_IMPORTSEGMENTATION( ch_imp_seg_inputs ) - ch_redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs + ch_redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs } else { diff --git a/tests/coordinate_mode.nf.test.snap b/tests/coordinate_mode.nf.test.snap index 72a452ec..96d5cb15 100644 --- a/tests/coordinate_mode.nf.test.snap +++ b/tests/coordinate_mode.nf.test.snap @@ -24,9 +24,9 @@ "untar": 1.34 }, "Workflow": { - "nf-core/spatialaxe": "v1.1.0dev" + "nf-core/spatialaxe": "v1.0.1" }, - "XENIUMRANGER_IMPORT_SEGMENTATION": { + "XENIUMRANGER_IMPORTSEGMENTATION": { "xeniumranger": "4.0.1.1" } }, @@ -98,12 +98,11 @@ "coordinate/untar/test_run/nucleus_boundaries.parquet", "coordinate/untar/test_run/transcripts.parquet", "coordinate/untar/test_run/transcripts.zarr.zip", - "coordinate/xeniumranger", - "coordinate/xeniumranger/import_segementation", - "coordinate/xeniumranger/import_segementation/test_run", - "coordinate/xeniumranger/import_segementation/test_run/experiment.xenium", "pipeline_info", - "pipeline_info/nf_core_spatialaxe_software_mqc_versions.yml" + "pipeline_info/nf_core_spatialaxe_software_mqc_versions.yml", + "xeniumranger", + "xeniumranger/test_run", + "xeniumranger/test_run/experiment.xenium" ], [ ".stub:md5,d41d8cd98f00b204e9800998ecf8427e", @@ -143,10 +142,10 @@ "experiment.xenium:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "timestamp": "2026-05-18T21:58:08.945192717", + "timestamp": "2026-07-28T12:22:02.690566285", "meta": { "nf-test": "0.9.5", - "nextflow": "25.10.4" + "nextflow": "26.04.6" } } } \ No newline at end of file diff --git a/tests/default.nf.test.snap b/tests/default.nf.test.snap index 3289c2a0..840d3c89 100644 --- a/tests/default.nf.test.snap +++ b/tests/default.nf.test.snap @@ -24,9 +24,9 @@ "untar": 1.34 }, "Workflow": { - "nf-core/spatialaxe": "v1.1.0dev" + "nf-core/spatialaxe": "v1.0.1" }, - "XENIUMRANGER_IMPORT_SEGMENTATION": { + "XENIUMRANGER_IMPORTSEGMENTATION": { "xeniumranger": "4.0.1.1" } }, @@ -98,12 +98,11 @@ "coordinate/untar/test_run/nucleus_boundaries.parquet", "coordinate/untar/test_run/transcripts.parquet", "coordinate/untar/test_run/transcripts.zarr.zip", - "coordinate/xeniumranger", - "coordinate/xeniumranger/import_segementation", - "coordinate/xeniumranger/import_segementation/test_run", - "coordinate/xeniumranger/import_segementation/test_run/experiment.xenium", "pipeline_info", - "pipeline_info/nf_core_spatialaxe_software_mqc_versions.yml" + "pipeline_info/nf_core_spatialaxe_software_mqc_versions.yml", + "xeniumranger", + "xeniumranger/test_run", + "xeniumranger/test_run/experiment.xenium" ], [ ".stub:md5,d41d8cd98f00b204e9800998ecf8427e", @@ -143,10 +142,10 @@ "experiment.xenium:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "timestamp": "2026-05-18T21:55:37.544217665", + "timestamp": "2026-07-28T12:20:41.663589777", "meta": { "nf-test": "0.9.5", - "nextflow": "25.10.4" + "nextflow": "26.04.6" } } } \ No newline at end of file diff --git a/tests/image_mode.nf.test.snap b/tests/image_mode.nf.test.snap index a9b73c2c..d70b912f 100644 --- a/tests/image_mode.nf.test.snap +++ b/tests/image_mode.nf.test.snap @@ -30,18 +30,13 @@ "untar": 1.34 }, "Workflow": { - "nf-core/spatialaxe": "v1.1.0dev" + "nf-core/spatialaxe": "v1.0.1" }, - "XENIUMRANGER_IMPORT_SEGMENTATION": { + "XENIUMRANGER_IMPORTSEGMENTATION": { "xeniumranger": "4.0.1.1" } }, [ - "coordinate", - "coordinate/xeniumranger", - "coordinate/xeniumranger/import_segementation", - "coordinate/xeniumranger/import_segementation/test_run", - "coordinate/xeniumranger/import_segementation/test_run/experiment.xenium", "image", "image/baysor", "image/baysor/preprocess", @@ -115,10 +110,12 @@ "image/utility/resize_tif/test_run", "image/utility/resize_tif/test_run/resized_morphology_focus_0000.ome_cp_masks.tif.tif", "pipeline_info", - "pipeline_info/nf_core_spatialaxe_software_mqc_versions.yml" + "pipeline_info/nf_core_spatialaxe_software_mqc_versions.yml", + "xeniumranger", + "xeniumranger/test_run", + "xeniumranger/test_run/experiment.xenium" ], [ - "experiment.xenium:md5,d41d8cd98f00b204e9800998ecf8427e", "filtered_transcripts.csv:md5,d41d8cd98f00b204e9800998ecf8427e", "segmentation.csv:md5,d41d8cd98f00b204e9800998ecf8427e", "segmentation_polygons_2d.json:md5,d41d8cd98f00b204e9800998ecf8427e", @@ -155,13 +152,14 @@ "nucleus_boundaries.parquet:md5,d41d8cd98f00b204e9800998ecf8427e", "transcripts.parquet:md5,d41d8cd98f00b204e9800998ecf8427e", "transcripts.zarr.zip:md5,d41d8cd98f00b204e9800998ecf8427e", - "resized_morphology_focus_0000.ome_cp_masks.tif.tif:md5,d41d8cd98f00b204e9800998ecf8427e" + "resized_morphology_focus_0000.ome_cp_masks.tif.tif:md5,d41d8cd98f00b204e9800998ecf8427e", + "experiment.xenium:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "timestamp": "2026-05-18T22:00:39.030306506", + "timestamp": "2026-07-28T12:22:39.999118613", "meta": { "nf-test": "0.9.5", - "nextflow": "25.10.4" + "nextflow": "26.04.6" } } } \ No newline at end of file diff --git a/tests/preview_mode.nf.test.snap b/tests/preview_mode.nf.test.snap index 3d364f04..cc286151 100644 --- a/tests/preview_mode.nf.test.snap +++ b/tests/preview_mode.nf.test.snap @@ -18,7 +18,7 @@ "untar": 1.34 }, "Workflow": { - "nf-core/spatialaxe": "v1.1.0dev" + "nf-core/spatialaxe": "v1.0.1" } }, [ @@ -111,10 +111,10 @@ "umap_mqc.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "timestamp": "2026-06-17T11:15:30.764424637", + "timestamp": "2026-07-23T15:57:29.316600844", "meta": { "nf-test": "0.9.5", - "nextflow": "26.04.2" + "nextflow": "26.04.6" } } } \ No newline at end of file diff --git a/tests/segfree_mode.nf.test.snap b/tests/segfree_mode.nf.test.snap index ac663a43..90a83476 100644 --- a/tests/segfree_mode.nf.test.snap +++ b/tests/segfree_mode.nf.test.snap @@ -12,7 +12,7 @@ "untar": 1.34 }, "Workflow": { - "nf-core/spatialaxe": "v1.1.0dev" + "nf-core/spatialaxe": "v1.0.1" } }, [ @@ -88,10 +88,10 @@ "transcripts.zarr.zip:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "timestamp": "2026-05-18T22:02:39.947804998", + "timestamp": "2026-07-23T15:57:58.134363385", "meta": { "nf-test": "0.9.5", - "nextflow": "25.10.4" + "nextflow": "26.04.6" } } } \ No newline at end of file diff --git a/workflows/spatialaxe.nf b/workflows/spatialaxe.nf index 643e737a..3ff05db9 100644 --- a/workflows/spatialaxe.nf +++ b/workflows/spatialaxe.nf @@ -434,6 +434,7 @@ workflow SPATIALAXE { nucleus_segmentation_only, sharpen_tiff, stardist_nuclei_model, + expansion_distance, ) ch_redefined_bundle = CELLPOSE_BAYSOR_IMPORT_SEGMENTATION.out.redefined_bundle ch_coordinate_space = CELLPOSE_BAYSOR_IMPORT_SEGMENTATION.out.coordinate_space @@ -445,6 +446,7 @@ workflow SPATIALAXE { XENIUMRANGER_RESEGMENT_MORPHOLOGY_OME_TIF( ch_bundle_path, nucleus_segmentation_only, + expansion_distance, ) ch_redefined_bundle = XENIUMRANGER_RESEGMENT_MORPHOLOGY_OME_TIF.out.redefined_bundle ch_coordinate_space = XENIUMRANGER_RESEGMENT_MORPHOLOGY_OME_TIF.out.coordinate_space @@ -464,6 +466,7 @@ workflow SPATIALAXE { min_qv, min_x, min_y, + expansion_distance, ) } ch_redefined_bundle = BAYSOR_RUN_PRIOR_SEGMENTATION_MASK.out.redefined_bundle @@ -481,6 +484,7 @@ workflow SPATIALAXE { nucleus_segmentation_only, sharpen_tiff, stardist_nuclei_model, + expansion_distance, ) ch_redefined_bundle = CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF.out.redefined_bundle ch_coordinate_space = CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF.out.coordinate_space @@ -494,6 +498,7 @@ workflow SPATIALAXE { ch_bundle_path, sharpen_tiff, stardist_nuclei_model, + expansion_distance, ) ch_redefined_bundle = STARDIST_RESOLIFT_MORPHOLOGY_OME_TIF.out.redefined_bundle ch_coordinate_space = STARDIST_RESOLIFT_MORPHOLOGY_OME_TIF.out.coordinate_space @@ -514,6 +519,7 @@ workflow SPATIALAXE { PROSEG_PRESET_PROSEG2BAYSOR_TILED( ch_bundle_path, ch_transcripts_file, + expansion_distance, ) ch_redefined_bundle = PROSEG_PRESET_PROSEG2BAYSOR_TILED.out.redefined_bundle ch_coordinate_space = PROSEG_PRESET_PROSEG2BAYSOR_TILED.out.coordinate_space @@ -521,6 +527,7 @@ workflow SPATIALAXE { PROSEG_PRESET_PROSEG2BAYSOR( ch_bundle_path, ch_transcripts_file, + expansion_distance, ) ch_redefined_bundle = PROSEG_PRESET_PROSEG2BAYSOR.out.redefined_bundle ch_coordinate_space = PROSEG_PRESET_PROSEG2BAYSOR.out.coordinate_space @@ -534,6 +541,7 @@ workflow SPATIALAXE { ch_bundle_path, ch_transcripts_file, segger_model, + expansion_distance, ) ch_redefined_bundle = SEGGER_CREATE_TRAIN_PREDICT.out.redefined_bundle ch_coordinate_space = SEGGER_CREATE_TRAIN_PREDICT.out.coordinate_space @@ -565,6 +573,7 @@ workflow SPATIALAXE { min_qv, min_x, min_y, + expansion_distance, ) ch_redefined_bundle = BAYSOR_RUN_TRANSCRIPTS_PARQUET.out.redefined_bundle ch_coordinate_space = BAYSOR_RUN_TRANSCRIPTS_PARQUET.out.coordinate_space