From d3ec027ebb8b924784fb50ddaf15c9ca5156fe95 Mon Sep 17 00:00:00 2001 From: Sameesh Kher Date: Sat, 20 Sep 2025 02:15:31 +0000 Subject: [PATCH 01/12] towards multisample support --- modules/local/proseg/preset/main.nf | 51 +++++++++---------- modules/local/proseg/proseg2baysor/main.nf | 32 +++++++----- nextflow.config | 7 --- .../local/proseg_preset_proseg2baysor/main.nf | 6 +-- 4 files changed, 42 insertions(+), 54 deletions(-) diff --git a/modules/local/proseg/preset/main.nf b/modules/local/proseg/preset/main.nf index 8cedfe82..273b5be8 100644 --- a/modules/local/proseg/preset/main.nf +++ b/modules/local/proseg/preset/main.nf @@ -8,16 +8,10 @@ process PROSEG { tuple val(meta), path(transcripts) output: - tuple val(meta), path("cell-polygons.geojson.gz"), emit: cell_polygons_2d - path("transcript-metadata.csv.gz") , emit: transcript_metadata - path("expected-counts.csv.gz") , emit: expected_counts - path("cell-metadata.csv.gz") , emit: cell_metadata - path("gene-metadata.csv.gz") , emit: gene_metadata - path("rates.csv.gz") , emit: rates - path("cell-polygons-layers.geojson.gz") , emit: cell_polygons_layers - path("cell-hulls.geojson.gz") , emit: cell_hulls - path("union-cell-polygons.geojson.gz") , emit: union_cell_polygons - path("versions.yml") , emit: versions + tuple val(meta), + path("cell-polygons.geojson.gz"), + path("transcript-metadata.csv.gz"), emit: seg_outs + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -40,14 +34,14 @@ process PROSEG { --${params.format} \\ ${transcripts} \\ --nthreads ${task.cpus} \\ - --output-expected-counts expected-counts.csv.gz \\ - --output-cell-metadata cell-metadata.csv.gz \\ - --output-transcript-metadata transcript-metadata.csv.gz \\ - --output-gene-metadata gene-metadata.csv.gz \\ - --output-rates rates.csv.gz \\ - --output-cell-polygons cell-polygons.geojson.gz \\ - --output-cell-polygon-layers cell-polygons-layers.geojson.gz \\ - --output-cell-hulls cell-hulls.geojson.gz \\ + --output-expected-counts ${prefix}/expected-counts.csv.gz \\ + --output-cell-metadata ${prefix}/cell-metadata.csv.gz \\ + --output-transcript-metadata ${prefix}/transcript-metadata.csv.gz \\ + --output-gene-metadata ${prefix}/gene-metadata.csv.gz \\ + --output-rates ${prefix}/rates.csv.gz \\ + --output-cell-polygons ${prefix}/cell-polygons.geojson.gz \\ + --output-cell-polygon-layers ${prefix}/cell-polygons-layers.geojson.gz \\ + --output-cell-hulls ${prefix}/cell-hulls.geojson.gz \\ ${args} cat <<-END_VERSIONS > versions.yml @@ -61,19 +55,20 @@ process PROSEG { if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "PROSEG module does not support Conda. Please use Docker / Singularity / Podman instead." } - def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" """ - touch expected-counts.csv.gz - touch cell-metadata.csv.gz - touch transcript-metadata.csv.gz - touch gene-metadata.csv.gz - touch rates.csv.gz - touch cell-polygons.geojson.gz - touch cell-polygons-layers.geojson.gz - touch cell-hulls.geojson.gz - touch union-cell-polygons.geojson.gz + mkdir -p ${prefix} + touch "${prefix}/expected-counts.csv.gz" + touch "${prefix}/cell-metadata.csv.gz" + touch "${prefix}/transcript-metadata.csv.gz" + touch "${prefix}/gene-metadata.csv.gz" + touch "${prefix}/rates.csv.gz" + touch "${prefix}/cell-polygons.geojson.gz" + touch "${prefix}/cell-polygons-layers.geojson.gz" + touch "${prefix}/cell-hulls.geojson.gz" + touch "${prefix}/union-cell-polygons.geojson.gz" cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/proseg/proseg2baysor/main.nf b/modules/local/proseg/proseg2baysor/main.nf index e841f966..4e695454 100644 --- a/modules/local/proseg/proseg2baysor/main.nf +++ b/modules/local/proseg/proseg2baysor/main.nf @@ -5,26 +5,29 @@ process PROSEG2BAYSOR { container "khersameesh24/proseg:2.0.0" input: - tuple val(meta), path(cell_polygons) - path(transcript_metadata) + tuple val(meta), path(cell_polygons), path(transcript_metadata) output: - tuple val(meta), path("xr-cell-polygons.geojson"), emit: xr_polygons - path("xr-transcript-metadata.csv") , emit: xr_metadata - path("versions.yml") , emit: versions + tuple val(meta), path("${meta}/cell-polygons.geojson") , emit: xr_polygons + tuple val(meta), path("${meta}/transcript-metadata.csv"), emit: xr_metadata + path("versions.yml") , emit: versions script: // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { - error "PROSEG2BAYSOR (preprocess) module does not support Conda. Please use Docker / Singularity / Podman instead." + error "PROSEG2BAYSOR module does not support Conda. Please use Docker / Singularity / Podman instead." } + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ - proseg-to-baysor \ - ${transcript_metadata} \ - ${cell_polygons} \ - --output-transcript-metadata xr-transcript-metadata.csv \ - --output-cell-polygons xr-cell-polygons.geojson + proseg-to-baysor \\ + ${transcript_metadata} \\ + ${cell_polygons} \\ + --output-transcript-metadata ${prefix}/transcript-metadata.csv \\ + --output-cell-polygons ${prefix}/cell-polygons.geojson \\ + ${args} cat <<-END_VERSIONS > versions.yml "${task.process}": @@ -38,12 +41,13 @@ process PROSEG2BAYSOR { if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "PROSEG module does not support Conda. Please use Docker / Singularity / Podman instead." } - def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" """ - touch xr-transcript-metadata.csv - touch xr-cell-polygons.geojson + mkdir -p ${prefix} + touch "${prefix}/transcript-metadata.csv" + touch "${prefix}/cell-polygons.geojson" cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/nextflow.config b/nextflow.config index 31579809..534a9fd1 100644 --- a/nextflow.config +++ b/nextflow.config @@ -209,13 +209,6 @@ profiles { executor.name = 'local' executor.cpus = 8 executor.memory = 16.GB - process { - resourceLimits = [ - memory: 16.GB, - cpus : 8, - time : 1.h - ] - } } gpu { docker.runOptions = '-u $(id -u):$(id -g) --gpus all' diff --git a/subworkflows/local/proseg_preset_proseg2baysor/main.nf b/subworkflows/local/proseg_preset_proseg2baysor/main.nf index 90448094..92f141d3 100644 --- a/subworkflows/local/proseg_preset_proseg2baysor/main.nf +++ b/subworkflows/local/proseg_preset_proseg2baysor/main.nf @@ -23,7 +23,7 @@ workflow PROSEG_PRESET_PROSEG2BAYSOR { ch_versions = ch_versions.mix( PROSEG.out.versions ) // run proseg-to-baysor on the data generated with the proseg run - PROSEG2BAYSOR ( PROSEG.out.cell_polygons_2d, PROSEG.out.transcript_metadata ) + PROSEG2BAYSOR ( PROSEG.out.seg_outs ) ch_versions = ch_versions.mix( PROSEG2BAYSOR.out.versions ) ch_metadata = PROSEG2BAYSOR.out.xr_metadata @@ -45,10 +45,6 @@ workflow PROSEG_PRESET_PROSEG2BAYSOR { emit: - cell_polygons_2d = PROSEG.out.cell_polygons_2d // channel: [ val(meta), [ "cell-polygons.geojson.gz" ] ] - - xr_polygons = PROSEG2BAYSOR.out.xr_polygons // channel: [ val(meta), [ "xr-cell-polygons.geojson" ] ] - xr_metadata = PROSEG2BAYSOR.out.xr_metadata // channel: [ [ "xr-transcript-metadata.csv" ] ] coordinate_space = ch_coordinate_space // channel: [ "microns" ] redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.bundle // channel: [ val(meta), ["redefined-xenium-bundle"] ] From 794e692202cb760d5bb88b056b74f104b9655177 Mon Sep 17 00:00:00 2001 From: Sameesh Kher Date: Sat, 20 Sep 2025 21:48:39 +0000 Subject: [PATCH 02/12] towards multisample support --- assets/multiqc_config.yml | 21 -------------- modules/local/baysor/create_dataset/main.nf | 11 +++++-- .../templates/create_dataset.py | 11 ++++--- modules/local/baysor/preprocess/main.nf | 21 +++++++++++--- .../templates/preprocess_transcripts.py | 7 +++-- modules/local/baysor/preview/main.nf | 17 +++++++---- modules/local/baysor/run/main.nf | 29 ++++++++----------- modules/local/baysor/segfree/main.nf | 10 +++++-- modules/local/proseg/preset/main.nf | 27 +++++++++-------- modules/local/proseg/proseg2baysor/main.nf | 10 ++++--- modules/local/resolift/main.nf | 29 ++++++++++--------- modules/local/segger/create_dataset/main.nf | 14 +++++++-- modules/local/segger/predict/main.nf | 16 +++++++--- modules/local/segger/train/main.nf | 15 +++++++--- modules/local/spatialdata/merge/main.nf | 19 ++++++++---- .../spatialdata/merge/templates/merge.py | 29 ++++++++++--------- modules/local/spatialdata/meta/main.nf | 18 ++++++++---- .../local/spatialdata/meta/templates/meta.py | 5 ++-- modules/local/spatialdata/write/main.nf | 16 ++++++---- .../spatialdata/write/templates/write.py | 2 +- modules/local/utility/segger2xr/main.nf | 18 +++++++++--- .../utility/segger2xr/templates/segger2xr.py | 9 +++--- .../spatialconverter/parquet_to_csv/main.nf | 18 +++++++++--- .../templates/parquet_to_csv.py | 13 ++++++--- .../local/proseg_preset_proseg2baysor/main.nf | 4 ++- .../spatialdata_write_meta_merge/main.nf | 9 ++---- workflows/spatialxe.nf | 2 +- 27 files changed, 241 insertions(+), 159 deletions(-) diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index 503f3c54..a8b797b3 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -14,25 +14,4 @@ export_plots: true disable_version_detection: true -run_module: - - xenium - -module_order: - - xenium - log_filesize_limit: 5000000000 # 5GB - -sp: - cell_feature_matrix: - fn: cell_feature_matrix.h5 - cells: - fn: cells.parquet - experiment: - fn: experiment.xenium - num_lines: 50 - metrics: - contents: num_cells_detected - fn: metrics_summary.csv - num_lines: 5 - transcripts: - fn: transcripts.parquet diff --git a/modules/local/baysor/create_dataset/main.nf b/modules/local/baysor/create_dataset/main.nf index ef09970e..2e1cf670 100644 --- a/modules/local/baysor/create_dataset/main.nf +++ b/modules/local/baysor/create_dataset/main.nf @@ -9,8 +9,8 @@ process BAYSOR_CREATE_DATASET { val(sample_fraction) output: - tuple val(meta), path("sampled_transcripts.csv"), emit: sampled_transcripts - path("versions.yml") , emit: versions + tuple val(meta), path("${meta.id}/sampled_transcripts.csv"), emit: sampled_transcripts + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -21,6 +21,8 @@ process BAYSOR_CREATE_DATASET { error "BAYSOR_CREATE_DATASET module does not support Conda. Please use Docker / Singularity / Podman instead." } + def prefix = task.ext.prefix ?: "${meta.id}" + template 'create_dataset.py' stub: @@ -29,8 +31,11 @@ process BAYSOR_CREATE_DATASET { error "BAYSOR_CREATE_DATASET module does not support Conda. Please use Docker / Singularity / Podman instead." } + def prefix = task.ext.prefix ?: "${meta.id}" + """ - touch sampled_transcripts.csv + mkdir -p ${prefix} + touch "${prefix}/sampled_transcripts.csv" cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/baysor/create_dataset/templates/create_dataset.py b/modules/local/baysor/create_dataset/templates/create_dataset.py index 21db550b..51c67ab5 100644 --- a/modules/local/baysor/create_dataset/templates/create_dataset.py +++ b/modules/local/baysor/create_dataset/templates/create_dataset.py @@ -14,7 +14,8 @@ def generate_dataset( transcripts: Path, sampled_transcripts: Path, sample_fraction: float = 0.3, - random_state: int = 42 + random_state: int = 42, + prefix: str = "" ) -> None: """ Reads a csv file & randomly samples a fraction of rows, @@ -28,8 +29,8 @@ def generate_dataset( """ random.seed(random_state) - - with open(transcripts, mode='rt', newline='') as infile, \ + output_path = f"{prefix}/{transcripts}" + with open(output_path, mode='rt', newline='') as infile, \ open(sampled_transcripts, mode='wt', newline='') as outfile: reader = csv.reader(infile) @@ -61,13 +62,15 @@ def main() -> None: """ transcripts: str = "${transcripts}" sample_fraction: float = "${sample_fraction}" + prefix: str = "${meta.id}" sampled_transcripts: str = "sampled_transcripts.csv" # generate dataset BaysorPreview.generate_dataset ( transcripts=transcripts, sampled_transcripts=sampled_transcripts, - sample_fraction=sample_fraction + sample_fraction=sample_fraction, + prefix=prefix ) # generate versions.yml diff --git a/modules/local/baysor/preprocess/main.nf b/modules/local/baysor/preprocess/main.nf index 1a240af7..8e14ccac 100644 --- a/modules/local/baysor/preprocess/main.nf +++ b/modules/local/baysor/preprocess/main.nf @@ -13,22 +13,35 @@ process BAYSOR_PREPROCESS_TRANSCRIPTS { val(min_y) output: - tuple val(meta), path("*.parquet"), emit: transcripts_parquet - path("versions.yml") , emit: versions + tuple val(meta), + path("${meta.id}/filtered_transcripts.parquet"), emit: transcripts_parquet + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when script: + // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { - error "PREPROCESS_TRANSCRIPTS module does not support Conda. Please use Docker / Singularity / Podman instead." + error "BAYSOR_PREPROCESS_TRANSCRIPTS module does not support Conda. Please use Docker / Singularity / Podman instead." } + def prefix = task.ext.prefix ?: "${meta.id}" + template 'preprocess_transcripts.py' stub: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "BAYSOR_PREPROCESS_TRANSCRIPTS module does not support Conda. Please use Docker / Singularity / Podman instead." + } + + def prefix = task.ext.prefix ?: "${meta.id}" + """ - touch ${transcripts}.parquet + mkdir -p ${prefix} + touch ${prefix}/filtered_transcripts.parquet + cat <<-END_VERSIONS > versions.yml "${task.process}": baysor_preprocess_transcripts: "1.0.0" diff --git a/modules/local/baysor/preprocess/templates/preprocess_transcripts.py b/modules/local/baysor/preprocess/templates/preprocess_transcripts.py index 9820e16d..5851b133 100644 --- a/modules/local/baysor/preprocess/templates/preprocess_transcripts.py +++ b/modules/local/baysor/preprocess/templates/preprocess_transcripts.py @@ -9,7 +9,8 @@ def filter_transcripts ( min_x: float = 0.0, max_x: float = 24000.0, min_y: float = 0.0, - max_y: float = 24000.0 + max_y: float = 24000.0, + prefix: str = "" ) -> None: """ Filter transcripts based on the specified thresholds @@ -48,7 +49,7 @@ def filter_transcripts ( # Output filtered transcripts to parquet filtered_df.to_parquet( - '_'.join(["X"+str(min_x)+"-"+str(max_x), "Y"+str(min_y)+"-"+str(max_y), "filtered_transcripts.parquet"]), + '_'.join(["X"+str(min_x)+"-"+str(max_x), "Y"+str(min_y)+"-"+str(max_y), f"{prefix}/filtered_transcripts.parquet"]), index=False ) @@ -66,9 +67,11 @@ def generate_version_yml() -> None: if __name__ == "__main__": transcripts: str = "${transcripts}" + prefix: str = "${meta.id}" filter_transcripts ( transcripts=transcripts, + prefix=prefix ) generate_version_yml() diff --git a/modules/local/baysor/preview/main.nf b/modules/local/baysor/preview/main.nf index e6c2e67d..a641d468 100644 --- a/modules/local/baysor/preview/main.nf +++ b/modules/local/baysor/preview/main.nf @@ -9,9 +9,8 @@ process BAYSOR_PREVIEW { path(config) output: - tuple val(meta), path("preview.html"), emit: preview_html - path("preview_preview_log.log") , emit: preview_log - path("versions.yml") , emit: versions + tuple val(meta), path("${meta.id}/preview.html"), emit: preview_html + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -21,14 +20,20 @@ process BAYSOR_PREVIEW { if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "BAYSOR_PREVIEW module does not support Conda. Please use Docker / Singularity / Podman instead." } + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" """ + mkdir -p ${prefix} + baysor preview \\ ${transcripts} \\ --config ${config} \\ ${args} + mv preview.html ${prefix}/preview.html + cat <<-END_VERSIONS > versions.yml "${task.process}": baysor: 0.7.1 @@ -41,9 +46,11 @@ process BAYSOR_PREVIEW { error "BAYSOR_PREVIEW module does not support Conda. Please use Docker / Singularity / Podman instead." } + def prefix = task.ext.prefix ?: "${meta.id}" + """ - touch preview.html - touch preview_preview_log.log + mkdir -p ${prefix} + touch "${prefix}/preview.html" cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/baysor/run/main.nf b/modules/local/baysor/run/main.nf index 455308e2..2344fdcd 100644 --- a/modules/local/baysor/run/main.nf +++ b/modules/local/baysor/run/main.nf @@ -11,15 +11,10 @@ process BAYSOR_RUN { val(scale) output: - tuple val(meta), path("segmentation.csv"), emit: segmentation - path("segmentation_polygons_2d.json") , emit: polygons2d - path("segmentation_polygons_3d.json") , emit: polygons3d - path("*.toml") , emit: params - path("*.log") , emit: log - path("*.loom") , emit: loom - path("*.html") , emit: htmls - path("segmentation_cell_stats.csv") , emit: stats - path("versions.yml") , emit: versions + tuple val(meta), + path("${meta.id}/segmentation.csv"), + path("${meta.id}/segmentation_polygons_2d.json"), emit: segmentation + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -29,7 +24,9 @@ process BAYSOR_RUN { if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "BAYSOR_RUN module does not support Conda. Please use Docker / Singularity / Podman instead." } + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" def prior_seg = "${prior_segmentation}" ? "${prior_segmentation}" : "" def scaling_factor = scale ? "--scale=${scale}": "" @@ -38,6 +35,7 @@ process BAYSOR_RUN { ${transcripts} \\ ${prior_seg} \\ ${scaling_factor} \\ + --output=${prefix} \\ --config=${config} \\ --plot \\ --polygon-format=GeometryCollectionLegacy \\ @@ -55,15 +53,12 @@ process BAYSOR_RUN { error "BAYSOR_RUN module does not support Conda. Please use Docker / Singularity / Podman instead." } + def prefix = task.ext.prefix ?: "${meta.id}" + """ - touch segmentation.csv - touch segmentation_polygons_2d.json - touch segmentation_polygons_3d.json - touch segmentation_log.log - touch segmentation_counts.loom - touch segmentation_cell_stats.csv - touch segmentation_params.dump.toml - touch segmentation_run.html + mkdir -p ${prefix} + touch "${prefix}/segmentation.csv" + touch "${prefix}/segmentation_polygons_2d.json" cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/baysor/segfree/main.nf b/modules/local/baysor/segfree/main.nf index 409c1c6c..24e96928 100644 --- a/modules/local/baysor/segfree/main.nf +++ b/modules/local/baysor/segfree/main.nf @@ -10,7 +10,6 @@ process BAYSOR_SEGFREE { output: tuple val(meta), path("ncvs.loom"), emit: ncvs - path("ncvs_segfree_log.log") , emit: ncvs_log path("versions.yml") , emit: versions when: @@ -21,12 +20,15 @@ process BAYSOR_SEGFREE { if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "BAYSOR_SEGFREE module does not support Conda. Please use Docker / Singularity / Podman instead." } + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" """ baysor segfree \\ ${transcripts} \\ --config ${config} \\ + --output=${prefix} \\ ${args} cat <<-END_VERSIONS > versions.yml @@ -41,9 +43,11 @@ process BAYSOR_SEGFREE { error "BAYSOR_SEGFREE module does not support Conda. Please use Docker / Singularity / Podman instead." } + def prefix = task.ext.prefix ?: "${meta.id}" + """ - touch ncvs.loom - touch ncvs_segfree_log.log + mkdir -p ${prefix} + touch "${prefix}/ncvs.loom" cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/proseg/preset/main.nf b/modules/local/proseg/preset/main.nf index 273b5be8..cca3e853 100644 --- a/modules/local/proseg/preset/main.nf +++ b/modules/local/proseg/preset/main.nf @@ -9,9 +9,9 @@ process PROSEG { output: tuple val(meta), - path("cell-polygons.geojson.gz"), - path("transcript-metadata.csv.gz"), emit: seg_outs - path("versions.yml") , emit: versions + path("${meta.id}/cell-polygons.geojson.gz"), + path("${meta.id}/transcript-metadata.csv.gz"), emit: seg_outs + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -21,6 +21,7 @@ process PROSEG { if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "PROSEG module does not support Conda. Please use Docker / Singularity / Podman instead." } + def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" @@ -30,18 +31,20 @@ process PROSEG { } """ + mkdir -p ${prefix} + proseg \\ --${params.format} \\ ${transcripts} \\ --nthreads ${task.cpus} \\ - --output-expected-counts ${prefix}/expected-counts.csv.gz \\ - --output-cell-metadata ${prefix}/cell-metadata.csv.gz \\ - --output-transcript-metadata ${prefix}/transcript-metadata.csv.gz \\ - --output-gene-metadata ${prefix}/gene-metadata.csv.gz \\ - --output-rates ${prefix}/rates.csv.gz \\ - --output-cell-polygons ${prefix}/cell-polygons.geojson.gz \\ - --output-cell-polygon-layers ${prefix}/cell-polygons-layers.geojson.gz \\ - --output-cell-hulls ${prefix}/cell-hulls.geojson.gz \\ + --output-expected-counts "${prefix}/expected-counts.csv.gz" \\ + --output-cell-metadata "${prefix}/cell-metadata.csv.gz" \\ + --output-transcript-metadata "${prefix}/transcript-metadata.csv.gz" \\ + --output-gene-metadata "${prefix}/gene-metadata.csv.gz" \\ + --output-rates "${prefix}/rates.csv.gz" \\ + --output-cell-polygons "${prefix}/cell-polygons.geojson.gz" \\ + --output-cell-polygon-layers "${prefix}/cell-polygons-layers.geojson.gz" \\ + --output-cell-hulls "${prefix}/cell-hulls.geojson.gz" \\ ${args} cat <<-END_VERSIONS > versions.yml @@ -59,7 +62,7 @@ process PROSEG { def prefix = task.ext.prefix ?: "${meta.id}" """ - mkdir -p ${prefix} + mkdir -p ${prefix}/ touch "${prefix}/expected-counts.csv.gz" touch "${prefix}/cell-metadata.csv.gz" touch "${prefix}/transcript-metadata.csv.gz" diff --git a/modules/local/proseg/proseg2baysor/main.nf b/modules/local/proseg/proseg2baysor/main.nf index 4e695454..dae2ef98 100644 --- a/modules/local/proseg/proseg2baysor/main.nf +++ b/modules/local/proseg/proseg2baysor/main.nf @@ -8,9 +8,9 @@ process PROSEG2BAYSOR { tuple val(meta), path(cell_polygons), path(transcript_metadata) output: - tuple val(meta), path("${meta}/cell-polygons.geojson") , emit: xr_polygons - tuple val(meta), path("${meta}/transcript-metadata.csv"), emit: xr_metadata - path("versions.yml") , emit: versions + tuple val(meta), path("${meta.id}/cell-polygons.geojson") , emit: xr_polygons + tuple val(meta), path("${meta.id}/transcript-metadata.csv"), emit: xr_metadata + path("versions.yml") , emit: versions script: // Exit if running this module with -profile conda / -profile mamba @@ -22,6 +22,8 @@ process PROSEG2BAYSOR { def prefix = task.ext.prefix ?: "${meta.id}" """ + mkdir -p ${prefix} + proseg-to-baysor \\ ${transcript_metadata} \\ ${cell_polygons} \\ @@ -39,7 +41,7 @@ process PROSEG2BAYSOR { stub: // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { - error "PROSEG module does not support Conda. Please use Docker / Singularity / Podman instead." + error "PROSEG2BAYSOR module does not support Conda. Please use Docker / Singularity / Podman instead." } def prefix = task.ext.prefix ?: "${meta.id}" diff --git a/modules/local/resolift/main.nf b/modules/local/resolift/main.nf index c6faaf36..c7467c92 100644 --- a/modules/local/resolift/main.nf +++ b/modules/local/resolift/main.nf @@ -5,11 +5,12 @@ process RESOLIFT { container "quay.io/khersameesh24/resolift:1.0.0" input: - tuple val(meta), path(input) + tuple val(meta), path(morphology_tiff) output: - tuple val(meta), path("*.tiff"), emit: enhanced_tiff - path("versions.yml") , emit: versions + tuple val(meta), + path("${meta.id}/morphology.ome.enhanced.tiff"), emit: enhanced_tiff + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -17,40 +18,40 @@ process RESOLIFT { script: // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { - error "ResoLift module does not support Conda. Please use Docker / Singularity / Podman instead." + error "RESOLIFT module does not support Conda. Please use Docker / Singularity / Podman instead." } + def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" - if ("$input" == "${prefix}.tiff") error "Input and output names are the same, set prefix in module configuration to disambiguate!" - def VERSION = '1.0.0' // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. """ + mkdir -p ${prefix} + resolift \\ - -i $input \\ - -o ${prefix}.tiff \\ + -i ${morphology_tiff} \\ + -o ${prefix}/morphology.ome.enhanced.tiff \\ ${args} cat <<-END_VERSIONS > versions.yml "${task.process}": - resolift: ${VERSION} + resolift: v1.0.0 END_VERSIONS """ stub: // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { - error "ResoLift module does not support Conda. Please use Docker / Singularity / Podman instead." + error "RESOLIFT module does not support Conda. Please use Docker / Singularity / Podman instead." } def prefix = task.ext.prefix ?: "${meta.id}" - if ("$input" == "${prefix}.tiff") error "Input and output names are the same, set prefix in module configuration to disambiguate!" - def VERSION = '1.0.0' // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. """ - touch ${prefix}.tiff + mkdir -p ${prefix} + touch "${prefix}/morphology.ome.enhanced.tiff" cat <<-END_VERSIONS > versions.yml "${task.process}": - resolift: ${VERSION} + resolift: v1.0.0 END_VERSIONS """ } diff --git a/modules/local/segger/create_dataset/main.nf b/modules/local/segger/create_dataset/main.nf index c2d5c3a6..f109fd31 100644 --- a/modules/local/segger/create_dataset/main.nf +++ b/modules/local/segger/create_dataset/main.nf @@ -8,13 +8,14 @@ process SEGGER_CREATE_DATASET { tuple val(meta), path(base_dir) output: - tuple val(meta), path("${meta.id}") , emit: datasetdir - path("versions.yml") , emit: versions + tuple val(meta), path("${meta.id}"), emit: datasetdir + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when script: + // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "SEGGER_CREATE_DATASET module does not support Conda. Please use Docker / Singularity / Podman instead." } @@ -25,7 +26,7 @@ process SEGGER_CREATE_DATASET { // check for platform values if ( !(params.format in ['xenium']) ) { - error "${params.format} is an invalid platform type. Please specify xenium, cosmx, or merscope" + error "${params.format} is an invalid platform type." } """ @@ -45,9 +46,16 @@ process SEGGER_CREATE_DATASET { """ stub: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "SEGGER_CREATE_DATASET module does not support Conda. Please use Docker / Singularity / Podman instead." + } + def prefix = task.ext.prefix ?: "${meta.id}" + """ mkdir -p ${prefix}/ + touch "${prefix}/fake_file.txt" cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/segger/predict/main.nf b/modules/local/segger/predict/main.nf index ca5c0e2f..cc63dc90 100644 --- a/modules/local/segger/predict/main.nf +++ b/modules/local/segger/predict/main.nf @@ -11,14 +11,15 @@ process SEGGER_PREDICT { output: - tuple val(meta), path("${meta.id}_benchmarks_dir") , emit: benchmarks - tuple val(meta), path("${meta.id}_benchmarks_dir/*/segger_transcripts.parquet"), emit: transcripts + tuple val(meta), path("${meta.id}/benchmarks_dir") , emit: benchmarks + tuple val(meta), path("${meta.id}/benchmarks_dir/*/segger_transcripts.parquet"), emit: transcripts path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when script: + // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "SEGGER_PREDICT module does not support Conda. Please use Docker / Singularity / Podman instead." } @@ -32,7 +33,7 @@ process SEGGER_PREDICT { --models_dir ${models_dir} \\ --segger_data_dir ${segger_dataset} \\ --transcripts_file ${transcripts} \\ - --benchmarks_dir ${prefix}_benchmarks_dir \\ + --benchmarks_dir ${prefix}/benchmarks_dir \\ --batch_size ${params.batch_size_predict} \\ --use_cc ${params.cc_analysis} \\ --knn_method ${params.segger_knn_method} \\ @@ -46,9 +47,16 @@ process SEGGER_PREDICT { """ stub: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "SEGGER_PREDICT module does not support Conda. Please use Docker / Singularity / Podman instead." + } + def prefix = task.ext.prefix ?: "${meta.id}" + """ - mkdir -p ${prefix}_benchmarks_dir/ + mkdir -p "${prefix}/benchmarks_dir" + touch "${prefix}/fake_file.txt" cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/segger/train/main.nf b/modules/local/segger/train/main.nf index 18d4dc0d..8ca932c7 100644 --- a/modules/local/segger/train/main.nf +++ b/modules/local/segger/train/main.nf @@ -8,13 +8,14 @@ process SEGGER_TRAIN { tuple val(meta), path(dataset_dir) output: - tuple val(meta), path("${meta.id}_trained_models"), emit: trained_models + tuple val(meta), path("${meta.id}/trained_models"), emit: trained_models path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when script: + // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "SEGGER_TRAIN module does not support Conda. Please use Docker / Singularity / Podman instead." } @@ -26,7 +27,7 @@ process SEGGER_TRAIN { """ python3 ${script_path} \\ --dataset_dir ${dataset_dir} \\ - --models_dir ${prefix}_trained_models \\ + --models_dir ${prefix}/trained_models \\ --sample_tag ${prefix} \\ --batch_size ${params.batch_size_train} \\ --max_epochs ${params.max_epochs} \\ @@ -42,10 +43,16 @@ process SEGGER_TRAIN { """ stub: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "SEGGER_TRAIN module does not support Conda. Please use Docker / Singularity / Podman instead." + } + def prefix = task.ext.prefix ?: "${meta.id}" + """ - mkdir -p ${prefix}_trained_models/ - touch ${prefix}_trained_models/fakefile.txt + mkdir -p ${prefix}/trained_models/ + touch ${prefix}/trained_models/fakefile.txt cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/spatialdata/merge/main.nf b/modules/local/spatialdata/merge/main.nf index 8f524734..55a227c9 100644 --- a/modules/local/spatialdata/merge/main.nf +++ b/modules/local/spatialdata/merge/main.nf @@ -5,12 +5,11 @@ process SPATIALDATA_MERGE { container "heylf/spatialdata:0.2.6" input: - tuple val(meta), path(ref_bundle, stageAs: "*") - path(add_bundle, stageAs: "*") + tuple val(meta), path(raw_bundle, stageAs: "*"), path(redefined_bundle, stageAs: "*") output: - tuple val(meta), path("spatialdata_merged"), emit: merged_bundle - path("versions.yml") , emit: versions + tuple val(meta), path("${meta.id}/spatialdata_merged"), emit: merged_bundle + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -22,13 +21,21 @@ process SPATIALDATA_MERGE { } def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" template 'merge.py' stub: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + exit 1, "SPATIALDATA_WRITE module does not support Conda. Please use Docker / Singularity / Podman instead." + } + + def prefix = task.ext.prefix ?: "${meta.id}" + """ - mkdir -p "spatialdata_merged/" - touch spatialdata_merged/fake_file.txt + mkdir -p "${prefix}/spatialdata_merged/" + touch "${prefix}/spatialdata_merged/fake_file.txt" cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/spatialdata/merge/templates/merge.py b/modules/local/spatialdata/merge/templates/merge.py index 6bf908ce..4802b40a 100755 --- a/modules/local/spatialdata/merge/templates/merge.py +++ b/modules/local/spatialdata/merge/templates/merge.py @@ -10,26 +10,27 @@ def main(): print("[START]") - reference_bundle = "${ref_bundle}" - add_bundle = "${add_bundle}" - output_folder = "./spatialdata_merged" + raw_bundle = "${raw_bundle}" + redefined_bundle = "${redefined_bundle}" + output_path = "${meta.id}" + output_folder = "spatialdata_merged" # Ensure the output folder exists - if os.path.exists(output_folder): - shutil.rmtree(output_folder) - os.makedirs(output_folder) + if os.path.exists(f"{output_path}/{output_folder}"): + shutil.rmtree(f"{output_path}/{output_folder}") + os.makedirs(f"{output_path}/{output_folder}") # Copy the entire reference bundle as is - for root, _, files in os.walk(reference_bundle): - rel_path = os.path.relpath(root, reference_bundle) - target_path = os.path.join(output_folder, rel_path) + for root, _, files in os.walk(raw_bundle): + rel_path = os.path.relpath(root, raw_bundle) + target_path = os.path.join(f"{output_path}/{output_folder}", rel_path) os.makedirs(target_path, exist_ok=True) for file in files: shutil.copy(os.path.join(root, file), os.path.join(target_path, file)) # Rename folders in Points, Shapes, and Tables to raw_* for category in ["points", "shapes", "tables"]: - category_path = os.path.join(output_folder, category) + category_path = os.path.join(f"{output_path}/{output_folder}", category) if os.path.exists(category_path): for folder in next(os.walk(category_path))[1]: #os.listdir(category_path): old_path = os.path.join(category_path, folder) @@ -37,16 +38,16 @@ def main(): new_path = os.path.join(category_path, f"raw_{folder}") os.rename(old_path, new_path) - # Copy folders from add_bundle and rename them as reference_* + # Copy folders from redefined_bundle and rename them as redefined_* for category in ["points", "shapes", "tables"]: - add_category_path = os.path.join(add_bundle, category) - output_category_path = os.path.join(output_folder, category) + add_category_path = os.path.join(redefined_bundle, category) + output_category_path = os.path.join(f"{output_path}/{output_folder}", category) os.makedirs(output_category_path, exist_ok=True) if os.path.exists(add_category_path): for folder in next(os.walk(add_category_path))[1]: src_folder = os.path.join(add_category_path, folder) - dest_folder = os.path.join(output_category_path, f"reference_{folder}") + dest_folder = os.path.join(output_category_path, f"redefined_{folder}") shutil.copytree(src_folder, dest_folder) #Output version information diff --git a/modules/local/spatialdata/meta/main.nf b/modules/local/spatialdata/meta/main.nf index ac3c9278..8f39c802 100644 --- a/modules/local/spatialdata/meta/main.nf +++ b/modules/local/spatialdata/meta/main.nf @@ -5,12 +5,11 @@ process SPATIALDATA_META { container "heylf/spatialdata:0.2.6" input: - tuple val(meta), path(spatialdata_bundle, stageAs: "*") - path(xenium_bundle, stageAs: "*") + tuple val(meta), path(spatialdata_bundle, stageAs: "*"), path(xenium_bundle, stageAs: "*") output: - tuple val(meta), path("spatialdata_meta"), emit: metadata - path("versions.yml") , emit: versions + tuple val(meta), path("${meta.id}/spatialdata_meta"), emit: metadata + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -22,14 +21,21 @@ process SPATIALDATA_META { } def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" template 'meta.py' stub: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + exit 1, "SPATIALDATA_META module does not support Conda. Please use Docker / Singularity / Podman instead." + } + + def prefix = task.ext.prefix ?: "${meta.id}" """ - mkdir -p "spatialdata_meta/" - touch "spatialdata_meta/fake_file.txt" + mkdir -p "${prefix}/spatialdata_meta/" + touch "${prefix}/spatialdata_meta/fake_file.txt" cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/spatialdata/meta/templates/meta.py b/modules/local/spatialdata/meta/templates/meta.py index 5c181505..dc23dcdf 100755 --- a/modules/local/spatialdata/meta/templates/meta.py +++ b/modules/local/spatialdata/meta/templates/meta.py @@ -11,7 +11,8 @@ def main(): spatialdata_bundle = "${spatialdata_bundle}" xenium_bundle = "${xenium_bundle}" - metadata = "${meta}" + output_path = "${meta.id}" + metadata = "${meta.id}" output = "spatialdata_meta" sdata = sd.read_zarr(f"{spatialdata_bundle}") @@ -44,7 +45,7 @@ def main(): metadata_gene_panel = json.load(f) sdata['raw_table'].uns['gene_panel'] = json.dumps(metadata_gene_panel) - sdata.write(f"./{output}", overwrite=True, consolidate_metadata=True, format=None) + sdata.write(f"{output_path}/{output}", overwrite=True, consolidate_metadata=True, format=None) #Output version information with open("versions.yml", "w") as f: diff --git a/modules/local/spatialdata/write/main.nf b/modules/local/spatialdata/write/main.nf index f9bac411..7beb6786 100644 --- a/modules/local/spatialdata/write/main.nf +++ b/modules/local/spatialdata/write/main.nf @@ -11,8 +11,8 @@ process SPATIALDATA_WRITE { val(coordinate_space) output: - tuple val(meta), path("${outputfolder}"), emit: spatialdata - path("versions.yml") , emit: versions + tuple val(meta), path("${meta.id}/${outputfolder}"), emit: spatialdata + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -23,16 +23,22 @@ process SPATIALDATA_WRITE { exit 1, "SPATIALDATA_WRITE module does not support Conda. Please use Docker / Singularity / Podman instead." } - def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" template 'write.py' stub: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + exit 1, "SPATIALDATA_WRITE module does not support Conda. Please use Docker / Singularity / Podman instead." + } + def prefix = task.ext.prefix ?: "${meta.id}" def outdir = "${outputfolder}" + """ - mkdir -p "${outdir}/" - touch "${outdir}/fake_file.txt" + mkdir -p "${prefix}/${outdir}" + touch "${prefix}/${outdir}/fake_file.txt" cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/spatialdata/write/templates/write.py b/modules/local/spatialdata/write/templates/write.py index dd9e9d1e..ca70dba8 100755 --- a/modules/local/spatialdata/write/templates/write.py +++ b/modules/local/spatialdata/write/templates/write.py @@ -10,7 +10,7 @@ def main(): print("[START]") input_path = "${bundle}" - output_path = "." + output_path = "${meta.id}" outputfolder = "${outputfolder}" segmented_object = "${segmented_object}" coordinate_space = "${coordinate_space}" diff --git a/modules/local/utility/segger2xr/main.nf b/modules/local/utility/segger2xr/main.nf index cba9173d..15e50835 100644 --- a/modules/local/utility/segger2xr/main.nf +++ b/modules/local/utility/segger2xr/main.nf @@ -2,19 +2,20 @@ process SEGGER2XR { tag "$meta.id" label 'process_low' - container "ghcr.io/scverse/spatialdata:spatialdata0.3.0_spatialdata-io0.1.7_spatialdata-plot0.2.9" + container "community.wave.seqera.io/library/pip_pandas:5c59aaec7d5d4750" input: tuple val(meta), path(transcripts) output: - tuple val(meta), path("transcripts.parquet"), emit: transcripts_parquet - path("versions.yml") , emit: versions + tuple val(meta), path("${meta.id}/transcripts.parquet"), emit: transcripts_parquet + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when script: + // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "SEGGER2XR module does not support Conda. Please use Docker / Singularity / Podman instead." } @@ -22,8 +23,17 @@ process SEGGER2XR { template 'segger2xr.py' stub: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "SEGGER2XR module does not support Conda. Please use Docker / Singularity / Podman instead." + } + + def prefix = task.ext.prefix ?: "${meta.id}" + """ - touch ${transcripts}.parquet + mkdir -p ${prefix} + touch "${prefix}/transcripts.parquet" + cat <<-END_VERSIONS > versions.yml "${task.process}": segger2xr: "${task.version}" diff --git a/modules/local/utility/segger2xr/templates/segger2xr.py b/modules/local/utility/segger2xr/templates/segger2xr.py index cffd9f07..f34c3291 100644 --- a/modules/local/utility/segger2xr/templates/segger2xr.py +++ b/modules/local/utility/segger2xr/templates/segger2xr.py @@ -44,16 +44,17 @@ def refine_transcripts(parquet_path: str) -> pd.DataFrame: return df -def main(input_file: str) -> None: +def main(input_file: str, prefix: str) -> None: transcripts = refine_transcripts(input_file) - transcripts.to_parquet("transcripts.parquet", engine="pyarrow") + transcripts.to_parquet(f"{prefix}/transcripts.parquet", engine="pyarrow") if __name__ == "__main__": - transcripts = "${transcripts}" + transcripts: str = "${transcripts}" + prefix: str = "${meta.id}" - main(input_file=transcripts) + main(input_file=transcripts, prefix=prefix) #Output versions.yml with open("versions.yml", "w") as f: diff --git a/modules/local/utility/spatialconverter/parquet_to_csv/main.nf b/modules/local/utility/spatialconverter/parquet_to_csv/main.nf index a18019cd..9d2d0fca 100644 --- a/modules/local/utility/spatialconverter/parquet_to_csv/main.nf +++ b/modules/local/utility/spatialconverter/parquet_to_csv/main.nf @@ -2,20 +2,21 @@ process PARQUET_TO_CSV { tag "$meta.id" label 'process_low' - container "heylf/spatialdata:0.2.6" + container "community.wave.seqera.io/library/pip_pandas:5c59aaec7d5d4750" input: tuple val(meta), path(transcripts) val(extension) output: - tuple val(meta), path("*.csv*"), emit: transcripts_csv - path("versions.yml") , emit: versions + tuple val(meta), path("${meta.id}/*.csv*"), emit: transcripts_csv + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when script: + // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "PARQUET_TO_CSV module does not support Conda. Please use Docker / Singularity / Podman instead." } @@ -23,8 +24,17 @@ process PARQUET_TO_CSV { template 'parquet_to_csv.py' stub: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "PARQUET_TO_CSV module does not support Conda. Please use Docker / Singularity / Podman instead." + } + + def prefix = task.ext.prefix ?: "${meta.id}" + """ - touch ${transcripts}.csv + mkdir -p ${prefix} + touch "${prefix}/${transcripts}.csv" + cat <<-END_VERSIONS > versions.yml "${task.process}": spatialconverter: "${task.version}" diff --git a/modules/local/utility/spatialconverter/parquet_to_csv/templates/parquet_to_csv.py b/modules/local/utility/spatialconverter/parquet_to_csv/templates/parquet_to_csv.py index f13ba23d..9ca97dcb 100755 --- a/modules/local/utility/spatialconverter/parquet_to_csv/templates/parquet_to_csv.py +++ b/modules/local/utility/spatialconverter/parquet_to_csv/templates/parquet_to_csv.py @@ -6,17 +6,20 @@ def convert_parquet ( transcripts: Path, - extension: str = '.csv' + extension: str = '.csv', + prefix: str = "" ) -> None: df = pd.read_parquet(transcripts, engine = 'pyarrow') + prefix.mkdir(parents=True, exist_ok=True) + if extension == ".gz": output = transcripts.replace(".parquet", ".csv.gz") - df.to_csv(f"{output}", compression='gzip', index=False) + df.to_csv(f"{prefix}/{output}", compression='gzip', index=False) else: output = transcripts.replace(".parquet", ".csv") - df.to_csv(f"{output}", index=False) + df.to_csv(f"{prefix}/{output}", index=False) return None @@ -25,11 +28,13 @@ def convert_parquet ( transcripts: str = "${transcripts}" extension: str = "${extension}" + prefix: str = "${meta.id}" # generate transcripts.csv(.gz) convert_parquet ( transcripts=transcripts, - extension=extension + extension=extension, + prefix=prefix ) #Output versions.yml diff --git a/subworkflows/local/proseg_preset_proseg2baysor/main.nf b/subworkflows/local/proseg_preset_proseg2baysor/main.nf index 92f141d3..f7e25fc8 100644 --- a/subworkflows/local/proseg_preset_proseg2baysor/main.nf +++ b/subworkflows/local/proseg_preset_proseg2baysor/main.nf @@ -26,7 +26,9 @@ workflow PROSEG_PRESET_PROSEG2BAYSOR { PROSEG2BAYSOR ( PROSEG.out.seg_outs ) ch_versions = ch_versions.mix( PROSEG2BAYSOR.out.versions ) - ch_metadata = PROSEG2BAYSOR.out.xr_metadata + ch_metadata = PROSEG2BAYSOR.out.xr_metadata.map { + _meta, trans_meta -> return [ trans_meta ] + } ch_polygons = PROSEG2BAYSOR.out.xr_polygons.map { _meta, polygons -> return [ polygons ] } diff --git a/subworkflows/local/spatialdata_write_meta_merge/main.nf b/subworkflows/local/spatialdata_write_meta_merge/main.nf index 47bc385b..ed5b5798 100644 --- a/subworkflows/local/spatialdata_write_meta_merge/main.nf +++ b/subworkflows/local/spatialdata_write_meta_merge/main.nf @@ -61,12 +61,8 @@ workflow SPATIALDATA_WRITE_META_MERGE { // merge raw & redefined spatialdata objects - ch_just_redefined_bundle = SPATIALDATA_WRITE_REDEFINED_BUNDLE.out.spatialdata.map { - _meta, bundle -> return [ bundle ] - } SPATIALDATA_MERGE_RAW_REDEFINED ( - SPATIALDATA_WRITE_RAW_BUNDLE.out.spatialdata, - ch_just_redefined_bundle + SPATIALDATA_WRITE_RAW_BUNDLE.out.spatialdata.combine(ch_redefined_bundle, by: 0) ) ch_versions = ch_versions.mix ( SPATIALDATA_MERGE_RAW_REDEFINED.out.versions ) @@ -76,8 +72,7 @@ workflow SPATIALDATA_WRITE_META_MERGE { _meta, bundle -> return [ bundle ] } SPATIALDATA_META ( - SPATIALDATA_MERGE_RAW_REDEFINED.out.merged_bundle, - ch_just_bundle_path + SPATIALDATA_MERGE_RAW_REDEFINED.out.merged_bundle.combine(ch_just_bundle_path, by: 0) ) ch_versions = ch_versions.mix ( SPATIALDATA_META.out.versions ) diff --git a/workflows/spatialxe.nf b/workflows/spatialxe.nf index d062aa1b..7ebd9aca 100644 --- a/workflows/spatialxe.nf +++ b/workflows/spatialxe.nf @@ -492,7 +492,7 @@ workflow SPATIALXE { file("${path}/*") } - ch_multiqc_files = ch_multiqc_files.mix ( ch_redefined_bundle_files.collect() ) + ch_multiqc_files = ch_multiqc_files.mix ( ch_redefined_bundle_files.flatten() ) MULTIQC ( ch_multiqc_files.collect(), From 7b663a195000ad530dbf8ca0bea4fc3893732101 Mon Sep 17 00:00:00 2001 From: Sameesh Kher Date: Mon, 22 Sep 2025 00:44:13 +0000 Subject: [PATCH 03/12] changes towards multisample support --- assets/multiqc_config.yml | 15 +++++++ modules/local/baysor/run/main.nf | 4 +- modules/local/spatialdata/meta/main.nf | 3 -- .../local/spatialdata/meta/templates/meta.py | 2 +- modules/local/utility/Dockerfile | 11 +++++ .../main.nf | 21 +++------ .../baysor_run_transcripts_parquet/main.nf | 23 ++++------ .../main.nf | 45 ++++++------------- .../main.nf | 43 +++++++----------- .../spatialdata_write_meta_merge/main.nf | 7 +-- .../utils_nfcore_spatialxe_pipeline/main.nf | 6 +++ 11 files changed, 84 insertions(+), 96 deletions(-) create mode 100644 modules/local/utility/Dockerfile diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index a8b797b3..43669112 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -15,3 +15,18 @@ export_plots: true disable_version_detection: true log_filesize_limit: 5000000000 # 5GB + +sp: + xenium/cell_feature_matrix: + fn: "*/cell_feature_matrix.h5" + xenium/cells: + fn: "*/cells.parquet" + xenium/experiment: + fn: "*/experiment.xenium" + num_lines: 50 + xenium/metrics: + contents: num_cells_detected + fn: "*/metrics_summary.csv" + num_lines: 5 + xenium/transcripts: + fn: "*/transcripts.parquet" diff --git a/modules/local/baysor/run/main.nf b/modules/local/baysor/run/main.nf index 2344fdcd..485059fd 100644 --- a/modules/local/baysor/run/main.nf +++ b/modules/local/baysor/run/main.nf @@ -31,11 +31,13 @@ process BAYSOR_RUN { def scaling_factor = scale ? "--scale=${scale}": "" """ + mkdir -p ${prefix} + baysor run \\ ${transcripts} \\ ${prior_seg} \\ ${scaling_factor} \\ - --output=${prefix} \\ + --output="${prefix}/segmentation.csv" \\ --config=${config} \\ --plot \\ --polygon-format=GeometryCollectionLegacy \\ diff --git a/modules/local/spatialdata/meta/main.nf b/modules/local/spatialdata/meta/main.nf index 8f39c802..2916cb9c 100644 --- a/modules/local/spatialdata/meta/main.nf +++ b/modules/local/spatialdata/meta/main.nf @@ -20,9 +20,6 @@ process SPATIALDATA_META { exit 1, "SPATIALDATA_META module does not support Conda. Please use Docker / Singularity / Podman instead." } - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" - template 'meta.py' stub: diff --git a/modules/local/spatialdata/meta/templates/meta.py b/modules/local/spatialdata/meta/templates/meta.py index dc23dcdf..fca9ac88 100755 --- a/modules/local/spatialdata/meta/templates/meta.py +++ b/modules/local/spatialdata/meta/templates/meta.py @@ -12,7 +12,7 @@ def main(): spatialdata_bundle = "${spatialdata_bundle}" xenium_bundle = "${xenium_bundle}" output_path = "${meta.id}" - metadata = "${meta.id}" + metadata = "${meta}" output = "spatialdata_meta" sdata = sd.read_zarr(f"{spatialdata_bundle}") diff --git a/modules/local/utility/Dockerfile b/modules/local/utility/Dockerfile new file mode 100644 index 00000000..79213ebb --- /dev/null +++ b/modules/local/utility/Dockerfile @@ -0,0 +1,11 @@ +FROM mambaorg/micromamba:1.5.10-noble +COPY --chown=$MAMBA_USER:$MAMBA_USER conda.yml /tmp/conda.yml +RUN micromamba install -y -n base -f /tmp/conda.yml \ + && micromamba install -y -n base conda-forge::procps-ng \ + && micromamba env export --name base --explicit > environment.lock \ + && echo ">> CONDA_LOCK_START" \ + && cat environment.lock \ + && echo "<< CONDA_LOCK_END" \ + && micromamba clean -a -y +USER root +ENV PATH="$MAMBA_ROOT_PREFIX/bin:$PATH" diff --git a/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf b/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf index 6c958417..b7b57efc 100644 --- a/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf +++ b/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf @@ -22,10 +22,6 @@ workflow BAYSOR_RUN_PRIOR_SEGMENTATION_MASK { ch_transcripts = Channel.empty() - ch_segmentation = Channel.empty() - ch_polygons2d = Channel.empty() - ch_htmls = Channel.empty() - ch_redefined_bundle = Channel.empty() ch_coordinate_space = Channel.value("microns") @@ -58,20 +54,21 @@ workflow BAYSOR_RUN_PRIOR_SEGMENTATION_MASK { ) ch_versions = ch_versions.mix( BAYSOR_RUN.out.versions ) + // run xeniumranger import-segmentation ch_segmentation = BAYSOR_RUN.out.segmentation - ch_just_segmentation = ch_segmentation.map { - _meta, segmentation -> return [ segmentation ] + ch_segmentation_csv = ch_segmentation.map { _meta, seg_csv, _seg_json -> + return [ seg_csv ] + } + ch_polygons2d = ch_segmentation.map { _meta, _seg_csv, seg_json -> + return [ seg_json ] } - ch_polygons2d = BAYSOR_RUN.out.polygons2d - ch_htmls = BAYSOR_RUN.out.htmls - // run xeniumranger import-segmentation XENIUMRANGER_IMPORT_SEGMENTATION ( ch_bundle_path, [], [], [], - ch_just_segmentation, + ch_segmentation_csv, ch_polygons2d, ch_coordinate_space ) @@ -81,10 +78,6 @@ workflow BAYSOR_RUN_PRIOR_SEGMENTATION_MASK { emit: - segmentation = ch_segmentation // channel: [ val(meta), ["segmentation.csv"] ] - polygons2d = ch_polygons2d // channel: [ ["segmentation_polygons_2d.json"] ] - htmls = ch_htmls // channel: [ ["*.html"] ] - coordinate_space = ch_coordinate_space // channel: [ "microns" ] redefined_bundle = ch_redefined_bundle // channel: [ val(meta), ["redefined-xenium-bundle"] ] diff --git a/subworkflows/local/baysor_run_transcripts_parquet/main.nf b/subworkflows/local/baysor_run_transcripts_parquet/main.nf index 2c4f6294..1bce08cf 100644 --- a/subworkflows/local/baysor_run_transcripts_parquet/main.nf +++ b/subworkflows/local/baysor_run_transcripts_parquet/main.nf @@ -23,14 +23,10 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET { ch_transcripts = Channel.empty() // ch_splits_csv = Channel.empty() - ch_segmentation = Channel.empty() - ch_polygons2d = Channel.empty() - ch_htmls = Channel.empty() - ch_redefined_bundle = Channel.empty() ch_coordinate_space = Channel.value("microns") - + // TODO: run baysor in parallel - next release issue // generate splits // SPLIT_TRANSCRIPTS ( // ch_transcripts_parquet, @@ -87,15 +83,16 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET { ) ch_versions = ch_versions.mix ( BAYSOR_RUN.out.versions ) + + // run xeniumranger import-segmentation ch_segmentation = BAYSOR_RUN.out.segmentation - ch_segmentation_csv = ch_segmentation.map { - _meta, segmentation -> return [ segmentation ] + ch_segmentation_csv = ch_segmentation.map { _meta, seg_csv, _seg_json -> + return [ seg_csv ] + } + ch_polygons2d = ch_segmentation.map { _meta, _seg_csv, seg_json -> + return [ seg_json ] } - ch_polygons2d = BAYSOR_RUN.out.polygons2d - ch_htmls = BAYSOR_RUN.out.htmls - - // run xeniumranger import-segmentation XENIUMRANGER_IMPORT_SEGMENTATION ( ch_bundle_path, [], @@ -111,10 +108,6 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET { emit: - segmentation = ch_segmentation // channel: [ val(meta), ["segmentation.csv"] ] - polygons2d = ch_polygons2d // channel: [ ["segmentation_polygons_2d.json"] ] - htmls = ch_htmls // channel: [ ["*.html"] ] - coordinate_space = ch_coordinate_space // channel: [ ["microns"] ] redefined_bundle = ch_redefined_bundle // 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 f0cb4871..dc158beb 100644 --- a/subworkflows/local/cellpose_baysor_import_segmentation/main.nf +++ b/subworkflows/local/cellpose_baysor_import_segmentation/main.nf @@ -3,9 +3,9 @@ // include { RESOLIFT } from '../../../modules/local/resolift/main' +include { BAYSOR_RUN } from '../../../modules/local/baysor/run/main' include { CELLPOSE as CELLPOSE_CELLS } from '../../../modules/nf-core/cellpose/main' include { CELLPOSE as CELLPOSE_NUCLEI } from '../../../modules/nf-core/cellpose/main' -include { BAYSOR_RUN } from '../../../modules/local/baysor/run/main' include { BAYSOR_PREPROCESS_TRANSCRIPTS } from '../../../modules/local/baysor/preprocess/main' include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' @@ -21,17 +21,8 @@ workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { main: ch_versions = Channel.empty() - ch_image = Channel.empty() - ch_polygons = Channel.empty() - ch_segmentation = Channel.empty() ch_transcripts = Channel.empty() ch_filtered_transcripts = Channel.empty() - ch_cellpose_cells_mask = Channel.empty() - ch_cellpose_nuclei_mask = Channel.empty() - ch_cellpose_cells_cells = Channel.empty() - ch_cellpose_nuclei_cells = Channel.empty() - ch_cellpose_cells_flows = Channel.empty() - ch_cellpose_nuclei_flows = Channel.empty() ch_coordinate_space = Channel.value("microns") cellpose_model = params.cellpose_model ? (Channel.fromPath(params.cellpose_model, checkIfExists: true)) : [] @@ -50,19 +41,19 @@ workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { } - // run cellpose on the enhanced tiff + // run cellpose on the morphology (enhanced) tiff if ( params.cell_segmentation_only ) { CELLPOSE_CELLS ( ch_image, cellpose_model, 'cells' ) ch_versions = ch_versions.mix( CELLPOSE_CELLS.out.versions ) - ch_cellpose_cells_cells = CELLPOSE_CELLS.out.cells.map { + _ch_cellpose_cells_cells = CELLPOSE_CELLS.out.cells.map { _meta, cells -> return [ cells ] } ch_cellpose_cells_mask = CELLPOSE_CELLS.out.mask.map { _meta, mask -> return [ mask ] } - ch_cellpose_cells_flows = CELLPOSE_CELLS.out.flows.map { + _ch_cellpose_cells_flows = CELLPOSE_CELLS.out.flows.map { _meta, flows -> return [ flows ] } @@ -73,13 +64,13 @@ workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { CELLPOSE_NUCLEI ( ch_image, 'nuclei', 'nuclei' ) ch_versions = ch_versions.mix( CELLPOSE_NUCLEI.out.versions ) - ch_cellpose_nuclei_cells = CELLPOSE_NUCLEI.out.cells.map { + _ch_cellpose_nuclei_cells = CELLPOSE_NUCLEI.out.cells.map { _meta, cells -> return [ cells ] } ch_cellpose_nuclei_mask = CELLPOSE_NUCLEI.out.mask.map { _meta, mask -> return [ mask ] } - ch_cellpose_nuclei_flows = CELLPOSE_NUCLEI.out.flows.map { + _ch_cellpose_nuclei_flows = CELLPOSE_NUCLEI.out.flows.map { _meta, flows -> return [ flows ] } @@ -130,35 +121,27 @@ workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { // run import-segmentation with baysor outs - ch_segmentation = BAYSOR_RUN.out.segmentation.map { - _meta, segmentation -> return [ segmentation ] + ch_segmentation = BAYSOR_RUN.out.segmentation + ch_segmentation_csv = ch_segmentation.map { _meta, seg_csv, _seg_json -> + return [ seg_csv ] + } + ch_polygons2d = ch_segmentation.map { _meta, _seg_csv, seg_json -> + return [ seg_json ] } - ch_polygons = BAYSOR_RUN.out.polygons2d - XENIUMRANGER_IMPORT_SEGMENTATION ( ch_bundle_path, [], [], [], - ch_segmentation, - ch_polygons, + ch_segmentation_csv, + ch_polygons2d, ch_coordinate_space ) ch_versions = ch_versions.mix ( XENIUMRANGER_IMPORT_SEGMENTATION.out.versions ) emit: - cells_mask = ch_cellpose_cells_mask // channel: [ val(meta), [ "*masks.tif" ] ] - cells_flows = ch_cellpose_cells_flows // channel: [ val(meta), [ "*flows.tif" ] ] - cells_cells = ch_cellpose_cells_cells // channel: [ val(meta), [ "*seg.npy" ] ] - nuclei_mask = ch_cellpose_nuclei_mask // channel: [ val(meta), [ "*masks.tif" ] ] - nuclei_flows = ch_cellpose_nuclei_flows // channel: [ val(meta), [ "*flows.tif" ] ] - nuclei_cells = ch_cellpose_nuclei_cells // channel: [ val(meta), [ "*seg.npy" ] ] - - segmentation = ch_segmentation // channel: [ val(meta), [ *segmentation.csv ] ] - polygons2d = ch_polygons // channel: [ val(meta), [ *segmentation_polygons_2d.json ] ] - coordinate_space = ch_coordinate_space // channel: [ val("microns") ] redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.bundle // 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 b41bc334..2e6685e6 100644 --- a/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf +++ b/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf @@ -17,13 +17,8 @@ workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { main: ch_versions = Channel.empty() - ch_image = Channel.empty() - ch_cellpose_cells_mask = Channel.empty() ch_cellpose_nuclei_mask = Channel.empty() - ch_cellpose_cells_cells = Channel.empty() - ch_cellpose_nuclei_cells = Channel.empty() - ch_cellpose_cells_flows = Channel.empty() - ch_cellpose_nuclei_flows = Channel.empty() + ch_cellpose_cells_mask = Channel.empty() ch_coordinate_space = Channel.value("pixels") cellpose_model = params.cellpose_model ? (Channel.fromPath(params.cellpose_model, checkIfExists: true)) : [] @@ -43,34 +38,37 @@ workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { } // run cellpose on morphology tiff - if ( !params.nucleus_segmentation_only ) { + if ( params.cell_segmentation_only ) { CELLPOSE_CELLS ( ch_image, cellpose_model, 'cells' ) ch_versions = ch_versions.mix( CELLPOSE_CELLS.out.versions ) - ch_cellpose_cells_cells = CELLPOSE_CELLS.out.cells.map { + _ch_cellpose_cells_cells = CELLPOSE_CELLS.out.cells.map { _meta, cells -> return [ cells ] } ch_cellpose_cells_mask = CELLPOSE_CELLS.out.mask.map { _meta, mask -> return [ mask ] } - ch_cellpose_cells_flows = CELLPOSE_CELLS.out.flows.map { + _ch_cellpose_cells_flows = CELLPOSE_CELLS.out.flows.map { _meta, flows -> return [ flows ] } } - CELLPOSE_NUCLEI ( ch_image, 'nuclei', 'nuclei' ) - ch_versions = ch_versions.mix( CELLPOSE_NUCLEI.out.versions ) + if ( params.nucleus_segmentation_only ) { - ch_cellpose_nuclei_cells = CELLPOSE_NUCLEI.out.cells.map { - _meta, cells -> return [ cells ] - } - ch_cellpose_nuclei_mask = CELLPOSE_NUCLEI.out.mask.map { - _meta, mask -> return [ mask ] - } - ch_cellpose_nuclei_flows = CELLPOSE_NUCLEI.out.flows.map { - _meta, flows -> return [ flows ] + CELLPOSE_NUCLEI ( ch_image, 'nuclei', 'nuclei' ) + ch_versions = ch_versions.mix( CELLPOSE_NUCLEI.out.versions ) + + _ch_cellpose_nuclei_cells = CELLPOSE_NUCLEI.out.cells.map { + _meta, cells -> return [ cells ] + } + ch_cellpose_nuclei_mask = CELLPOSE_NUCLEI.out.mask.map { + _meta, mask -> return [ mask ] + } + _ch_cellpose_nuclei_flows = CELLPOSE_NUCLEI.out.flows.map { + _meta, flows -> return [ flows ] + } } // run import-segmentation with cellpose results @@ -103,13 +101,6 @@ workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { emit: - cells_mask = ch_cellpose_cells_mask // channel: [ val(meta), [ "*masks.tif" ] ] - cells_flows = ch_cellpose_cells_flows // channel: [ val(meta), [ "*flows.tif" ] ] - cells_cells = ch_cellpose_cells_cells // channel: [ val(meta), [ "*seg.npy" ] ] - nuclei_mask = ch_cellpose_nuclei_mask // channel: [ val(meta), [ "*masks.tif" ] ] - nuclei_flows = ch_cellpose_nuclei_flows // channel: [ val(meta), [ "*flows.tif" ] ] - nuclei_cells = ch_cellpose_nuclei_cells // channel: [ val(meta), [ "*seg.npy" ] ] - coordinate_space = ch_coordinate_space // channel: [ ["pixels"] ] redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.bundle // channel: [ val(meta), ["redefined-xenium-bundle"] ] diff --git a/subworkflows/local/spatialdata_write_meta_merge/main.nf b/subworkflows/local/spatialdata_write_meta_merge/main.nf index ed5b5798..fc53a282 100644 --- a/subworkflows/local/spatialdata_write_meta_merge/main.nf +++ b/subworkflows/local/spatialdata_write_meta_merge/main.nf @@ -62,17 +62,14 @@ workflow SPATIALDATA_WRITE_META_MERGE { // merge raw & redefined spatialdata objects SPATIALDATA_MERGE_RAW_REDEFINED ( - SPATIALDATA_WRITE_RAW_BUNDLE.out.spatialdata.combine(ch_redefined_bundle, by: 0) + SPATIALDATA_WRITE_RAW_BUNDLE.out.spatialdata.combine( ch_redefined_bundle, by: 0 ) ) ch_versions = ch_versions.mix ( SPATIALDATA_MERGE_RAW_REDEFINED.out.versions ) // write metadata with spatialdata object - ch_just_bundle_path = ch_bundle_path.map { - _meta, bundle -> return [ bundle ] - } SPATIALDATA_META ( - SPATIALDATA_MERGE_RAW_REDEFINED.out.merged_bundle.combine(ch_just_bundle_path, by: 0) + SPATIALDATA_MERGE_RAW_REDEFINED.out.merged_bundle.combine( ch_bundle_path, by: 0 ) ) ch_versions = ch_versions.mix ( SPATIALDATA_META.out.versions ) diff --git a/subworkflows/local/utils_nfcore_spatialxe_pipeline/main.nf b/subworkflows/local/utils_nfcore_spatialxe_pipeline/main.nf index aff748f2..184f4ab0 100644 --- a/subworkflows/local/utils_nfcore_spatialxe_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_spatialxe_pipeline/main.nf @@ -164,6 +164,12 @@ workflow PIPELINE_COMPLETION { // def validateInputParameters() { + // check if the samplesheet provided with the test config is assets/samplesheet.csv + if ( workflow.profile.contains('test') && params.input != "${projectDir}/assets/samplesheet.csv" ) { + log.error "❌ Error: Use the samplesheet at: ${projectDir}/assets/samplesheet.csv with `--input` when running the pipeline in test profile." + exit 1 + } + // check if the segmentation method provided is valid for a mode if ( params.mode == 'image' && params.method ) { if ( !params.image_seg_methods.contains(params.method) ) { From 3f0f2336ae58f6a0199dedd97f5f3359364bb2f9 Mon Sep 17 00:00:00 2001 From: Sameesh Kher Date: Mon, 22 Sep 2025 15:47:21 +0000 Subject: [PATCH 04/12] more changes for multi-sample support --- modules/nf-core/cellpose/cellpose.diff | 52 ++++- modules/nf-core/cellpose/main.nf | 20 +- .../xeniumranger/import-segmentation/main.nf | 21 +- .../xeniumranger-import-segmentation.diff | 40 +++- modules/nf-core/xeniumranger/relabel/main.nf | 2 +- .../relabel/xeniumranger-relabel.diff | 15 +- .../nf-core/xeniumranger/resegment/main.nf | 2 +- .../resegment/xeniumranger-resegment.diff | 15 +- nextflow.config | 3 + nextflow_schema.json | 15 ++ .../main.nf | 34 +-- .../baysor_run_transcripts_parquet/main.nf | 32 +-- .../main.nf | 31 +-- .../local/proseg_preset_proseg2baysor/main.nf | 31 +-- workflows/spatialxe.nf | 193 +++++++++--------- 15 files changed, 313 insertions(+), 193 deletions(-) diff --git a/modules/nf-core/cellpose/cellpose.diff b/modules/nf-core/cellpose/cellpose.diff index 0267f42c..0f62b54d 100644 --- a/modules/nf-core/cellpose/cellpose.diff +++ b/modules/nf-core/cellpose/cellpose.diff @@ -2,7 +2,7 @@ Changes in component 'nf-core/cellpose' Changes in 'cellpose/main.nf': --- modules/nf-core/cellpose/main.nf +++ modules/nf-core/cellpose/main.nf -@@ -6,11 +6,13 @@ +@@ -6,12 +6,14 @@ input: tuple val(meta), path(image) @@ -11,23 +11,59 @@ Changes in 'cellpose/main.nf': + val(maskname) output: - tuple val(meta), path("*masks.tif") , emit: mask - tuple val(meta), path("*flows.tif") , emit: flows, optional: true -+ tuple val(meta), path("*seg.npy") , emit: cells, optional: true - path "versions.yml" , emit: versions +- tuple val(meta), path("*masks.tif") , emit: mask +- tuple val(meta), path("*flows.tif") , emit: flows, optional: true +- path "versions.yml" , emit: versions ++ tuple val(meta), path("${meta.id}/*masks.tif"), emit: mask ++ tuple val(meta), path("${meta.id}/*flows.tif"), emit: flows, optional: true ++ tuple val(meta), path("${meta.id}/*seg.npy") , emit: cells, optional: true ++ path "versions.yml" , emit: versions when: -@@ -32,6 +34,7 @@ + task.ext.when == null || task.ext.when +@@ -27,29 +29,38 @@ + """ + export OMP_NUM_THREADS=${task.cpus} + export MKL_NUM_THREADS=${task.cpus} ++ export NPY_PROMOTION_STATE=legacy + cellpose \\ + --image_path $image \\ --save_tif \\ $model_command \\ $args -+ mv *masks.tif morphology.ome_${maskname}_masks.tif ++ mkdir -p ${prefix} ++ mv *masks.tif ${prefix}/morphology.ome_${maskname}_masks.tif ++ cat <<-END_VERSIONS > versions.yml "${task.process}": + cellpose: \$(cellpose --version | awk 'NR==2 {print \$3}') + END_VERSIONS + """ ++ + stub: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "I did not manage to create a cellpose module in Conda that works in all OSes. Please use Docker / Singularity / Podman instead." + } ++ + def prefix = task.ext.prefix ?: "${meta.id}" + def name = image.name + def base = name.lastIndexOf('.') != -1 ? name[0..name.lastIndexOf('.') - 1] : name ++ + """ ++ mkdir -p ${prefix} ++ touch ${prefix}/morphology.ome_${maskname}_masks.tif + touch ${base}_cp_masks.tif + +- cat <<-END_VERSIONS > versions.yml ++ cat <<-END_VERSIONS > versions.yml + "${task.process}": + cellpose: \$(cellpose --version | awk 'NR==2 {print \$3}') + END_VERSIONS 'modules/nf-core/cellpose/meta.yml' is unchanged 'modules/nf-core/cellpose/tests/main.nf.test' is unchanged -'modules/nf-core/cellpose/tests/nextflow_wflows.config' is unchanged 'modules/nf-core/cellpose/tests/main.nf.test.snap' is unchanged +'modules/nf-core/cellpose/tests/nextflow_wflows.config' is unchanged ************************************************************ diff --git a/modules/nf-core/cellpose/main.nf b/modules/nf-core/cellpose/main.nf index e19bd00f..696a2da0 100644 --- a/modules/nf-core/cellpose/main.nf +++ b/modules/nf-core/cellpose/main.nf @@ -10,10 +10,10 @@ process CELLPOSE { val(maskname) output: - tuple val(meta), path("*masks.tif") , emit: mask - tuple val(meta), path("*flows.tif") , emit: flows, optional: true - tuple val(meta), path("*seg.npy") , emit: cells, optional: true - path "versions.yml" , emit: versions + tuple val(meta), path("${meta.id}/*masks.tif"), emit: mask + tuple val(meta), path("${meta.id}/*flows.tif"), emit: flows, optional: true + tuple val(meta), path("${meta.id}/*seg.npy") , emit: cells, optional: true + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -29,30 +29,38 @@ process CELLPOSE { """ export OMP_NUM_THREADS=${task.cpus} export MKL_NUM_THREADS=${task.cpus} + export NPY_PROMOTION_STATE=legacy cellpose \\ --image_path $image \\ --save_tif \\ $model_command \\ $args - mv *masks.tif morphology.ome_${maskname}_masks.tif + + mkdir -p ${prefix} + mv *masks.tif ${prefix}/morphology.ome_${maskname}_masks.tif cat <<-END_VERSIONS > versions.yml "${task.process}": cellpose: \$(cellpose --version | awk 'NR==2 {print \$3}') END_VERSIONS """ + stub: // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "I did not manage to create a cellpose module in Conda that works in all OSes. Please use Docker / Singularity / Podman instead." } + def prefix = task.ext.prefix ?: "${meta.id}" def name = image.name def base = name.lastIndexOf('.') != -1 ? name[0..name.lastIndexOf('.') - 1] : name + """ + mkdir -p ${prefix} + touch ${prefix}/morphology.ome_${maskname}_masks.tif touch ${base}_cp_masks.tif - cat <<-END_VERSIONS > versions.yml + cat <<-END_VERSIONS > versions.yml "${task.process}": cellpose: \$(cellpose --version | awk 'NR==2 {print \$3}') END_VERSIONS diff --git a/modules/nf-core/xeniumranger/import-segmentation/main.nf b/modules/nf-core/xeniumranger/import-segmentation/main.nf index 1dc7702b..f60b3dee 100644 --- a/modules/nf-core/xeniumranger/import-segmentation/main.nf +++ b/modules/nf-core/xeniumranger/import-segmentation/main.nf @@ -5,17 +5,18 @@ process XENIUMRANGER_IMPORT_SEGMENTATION { container "nf-core/xeniumranger:3.1.1" input: - tuple val(meta), path(xenium_bundle) - path(coordinate_transform) - path(nuclei) - path(cells) - path(transcript_assignment) - path(viz_polygons) - val(units) + tuple val(meta), + path(xenium_bundle), + path(coordinate_transform), + path(nuclei), + path(cells), + path(transcript_assignment), + path(viz_polygons), + val(units) output: tuple val(meta), path("${meta.id}/outs"), emit: bundle - path("versions.yml") , emit: versions + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -69,9 +70,11 @@ process XENIUMRANGER_IMPORT_SEGMENTATION { if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "XENIUMRANGER_IMPORT-SEGMENTATION module does not support Conda. Please use Docker / Singularity / Podman instead." } + def prefix = task.ext.prefix ?: "${meta.id}" + """ - mkdir -p "${prefix}/outs/" + mkdir -p "${prefix}/outs" touch "${prefix}/outs/fake_file.txt" cat <<-END_VERSIONS > versions.yml diff --git a/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff b/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff index 18f220fe..c1748b2d 100644 --- a/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff +++ b/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff @@ -2,7 +2,7 @@ Changes in component 'nf-core/xeniumranger/import-segmentation' Changes in 'xeniumranger/import-segmentation/main.nf': --- modules/nf-core/xeniumranger/import-segmentation/main.nf +++ modules/nf-core/xeniumranger/import-segmentation/main.nf -@@ -2,20 +2,20 @@ +@@ -2,20 +2,21 @@ tag "$meta.id" label 'process_high' @@ -10,24 +10,31 @@ Changes in 'xeniumranger/import-segmentation/main.nf': + container "nf-core/xeniumranger:3.1.1" input: - tuple val(meta), path(xenium_bundle) +- tuple val(meta), path(xenium_bundle) - val(expansion_distance) - path(coordinate_transform) - path(nuclei) - path(cells) - path(transcript_assignment) - path(viz_polygons) -+ val(units) +- path(coordinate_transform) +- path(nuclei) +- path(cells) +- path(transcript_assignment) +- path(viz_polygons) ++ tuple val(meta), ++ path(xenium_bundle), ++ path(coordinate_transform), ++ path(nuclei), ++ path(cells), ++ path(transcript_assignment), ++ path(viz_polygons), ++ val(units) output: - tuple val(meta), path("**/outs/**"), emit: outs - path "versions.yml", emit: versions + tuple val(meta), path("${meta.id}/outs"), emit: bundle -+ path("versions.yml") , emit: versions ++ path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when -@@ -29,32 +29,33 @@ +@@ -29,32 +30,33 @@ def prefix = task.ext.prefix ?: "${meta.id}" // image based segmentation options @@ -75,6 +82,19 @@ Changes in 'xeniumranger/import-segmentation/main.nf': ${args} cat <<-END_VERSIONS > versions.yml +@@ -68,9 +70,11 @@ + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "XENIUMRANGER_IMPORT-SEGMENTATION module does not support Conda. Please use Docker / Singularity / Podman instead." + } ++ + def prefix = task.ext.prefix ?: "${meta.id}" ++ + """ +- mkdir -p "${prefix}/outs/" ++ mkdir -p "${prefix}/outs" + touch "${prefix}/outs/fake_file.txt" + + cat <<-END_VERSIONS > versions.yml Changes in 'xeniumranger/import-segmentation/meta.yml': --- modules/nf-core/xeniumranger/import-segmentation/meta.yml diff --git a/modules/nf-core/xeniumranger/relabel/main.nf b/modules/nf-core/xeniumranger/relabel/main.nf index 40459f8e..e500fa08 100644 --- a/modules/nf-core/xeniumranger/relabel/main.nf +++ b/modules/nf-core/xeniumranger/relabel/main.nf @@ -45,7 +45,7 @@ process XENIUMRANGER_RELABEL { } def prefix = task.ext.prefix ?: "${meta.id}" """ - mkdir -p "${prefix}/outs/" + mkdir -p "${prefix}/outs" touch "${prefix}/outs/fake_file.txt" cat <<-END_VERSIONS > versions.yml diff --git a/modules/nf-core/xeniumranger/relabel/xeniumranger-relabel.diff b/modules/nf-core/xeniumranger/relabel/xeniumranger-relabel.diff index 33766acc..a5a3afbb 100644 --- a/modules/nf-core/xeniumranger/relabel/xeniumranger-relabel.diff +++ b/modules/nf-core/xeniumranger/relabel/xeniumranger-relabel.diff @@ -1,5 +1,4 @@ Changes in component 'nf-core/xeniumranger/relabel' -'modules/nf-core/xeniumranger/relabel/meta.yml' is unchanged Changes in 'xeniumranger/relabel/main.nf': --- modules/nf-core/xeniumranger/relabel/main.nf +++ modules/nf-core/xeniumranger/relabel/main.nf @@ -22,9 +21,19 @@ Changes in 'xeniumranger/relabel/main.nf': when: task.ext.when == null || task.ext.when +@@ -45,7 +45,7 @@ + } + def prefix = task.ext.prefix ?: "${meta.id}" + """ +- mkdir -p "${prefix}/outs/" ++ mkdir -p "${prefix}/outs" + touch "${prefix}/outs/fake_file.txt" + + cat <<-END_VERSIONS > versions.yml +'modules/nf-core/xeniumranger/relabel/meta.yml' is unchanged +'modules/nf-core/xeniumranger/relabel/tests/main.nf.test' is unchanged 'modules/nf-core/xeniumranger/relabel/tests/main.nf.test.snap' is unchanged -'modules/nf-core/xeniumranger/relabel/tests/tags.yml' is unchanged 'modules/nf-core/xeniumranger/relabel/tests/nextflow.config' is unchanged -'modules/nf-core/xeniumranger/relabel/tests/main.nf.test' is unchanged +'modules/nf-core/xeniumranger/relabel/tests/tags.yml' is unchanged ************************************************************ diff --git a/modules/nf-core/xeniumranger/resegment/main.nf b/modules/nf-core/xeniumranger/resegment/main.nf index 4d035cde..cdeef0db 100644 --- a/modules/nf-core/xeniumranger/resegment/main.nf +++ b/modules/nf-core/xeniumranger/resegment/main.nf @@ -52,7 +52,7 @@ process XENIUMRANGER_RESEGMENT { } def prefix = task.ext.prefix ?: "${meta.id}" """ - mkdir -p "${prefix}/outs/" + mkdir -p "${prefix}/outs" touch "${prefix}/outs/fake_file.txt" cat <<-END_VERSIONS > versions.yml diff --git a/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff b/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff index 4d7dc325..24c817e2 100644 --- a/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff +++ b/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff @@ -1,5 +1,4 @@ Changes in component 'nf-core/xeniumranger/resegment' -'modules/nf-core/xeniumranger/resegment/meta.yml' is unchanged Changes in 'xeniumranger/resegment/main.nf': --- modules/nf-core/xeniumranger/resegment/main.nf +++ modules/nf-core/xeniumranger/resegment/main.nf @@ -50,9 +49,19 @@ Changes in 'xeniumranger/resegment/main.nf': ${boundary_stain} \\ ${interior_stain} \\ --localcores=${task.cpus} \\ +@@ -59,7 +52,7 @@ + } + def prefix = task.ext.prefix ?: "${meta.id}" + """ +- mkdir -p "${prefix}/outs/" ++ mkdir -p "${prefix}/outs" + touch "${prefix}/outs/fake_file.txt" + + cat <<-END_VERSIONS > versions.yml +'modules/nf-core/xeniumranger/resegment/meta.yml' is unchanged +'modules/nf-core/xeniumranger/resegment/tests/main.nf.test' is unchanged 'modules/nf-core/xeniumranger/resegment/tests/main.nf.test.snap' is unchanged -'modules/nf-core/xeniumranger/resegment/tests/tags.yml' is unchanged 'modules/nf-core/xeniumranger/resegment/tests/nextflow.config' is unchanged -'modules/nf-core/xeniumranger/resegment/tests/main.nf.test' is unchanged +'modules/nf-core/xeniumranger/resegment/tests/tags.yml' is unchanged ************************************************************ diff --git a/nextflow.config b/nextflow.config index 534a9fd1..388d6140 100644 --- a/nextflow.config +++ b/nextflow.config @@ -19,6 +19,9 @@ params { alignment_csv = null // image alignment file format a 3x3 transformation matrix, where the last row is [0,0,1] cellpose_model = null // custom cellpose model to use for running or starting training segmentation_mask = null // prior segmentation mask + probes_fasta = null // Fasta file for the probe sequences used in the xenium experiment + reference_annotations = null // Path to the genomic features (.gff) and fasta (.fa) files used as reference annotations + gene_synonyms = null // Gene synonyms that may have been counted as off-targets but simply differ in name // execution specific sharpen_tiff = false // wether to sharpen the morphology-focus tiff diff --git a/nextflow_schema.json b/nextflow_schema.json index ee9641ef..5c5e8bc4 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -63,6 +63,21 @@ "description": "Prior segmentation mask from other segmentation methods.", "format": "file-path" }, + "probes_fasta": { + "type": "string", + "description": "Fasta file for the probe sequences used in the xenium experiment.", + "format": "file-path" + }, + "reference_annotations": { + "type": "string", + "description": "Path to the directory containing genomic features (.gff) and fasta (.fa) files used as reference annotations.", + "format": "file-path" + }, + "gene_synonyms": { + "type": "string", + "description": "Gene synonyms that may have been counted as off-targets but simply differ in name.", + "format": "file-path" + }, "email": { "type": "string", "description": "Email address for completion summary.", diff --git a/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf b/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf index b7b57efc..def0918e 100644 --- a/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf +++ b/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf @@ -54,25 +54,27 @@ workflow BAYSOR_RUN_PRIOR_SEGMENTATION_MASK { ) ch_versions = ch_versions.mix( BAYSOR_RUN.out.versions ) - // run xeniumranger import-segmentation - ch_segmentation = BAYSOR_RUN.out.segmentation - ch_segmentation_csv = ch_segmentation.map { _meta, seg_csv, _seg_json -> - return [ seg_csv ] - } - ch_polygons2d = ch_segmentation.map { _meta, _seg_csv, seg_json -> - return [ seg_json ] - } + // run import-segmentation with baysor outs + ch_imp_seg_inputs = ch_bundle_path + .combine(BAYSOR_RUN.out.segmentation[1], by:0) + .combine(BAYSOR_RUN.out.segmentation[2], by:0) + .map { + meta, bundle, segmentation_csv, polygons2d -> tuple ( + meta, // meta + bundle, // bundle + [], // coordinate_transform + [], // nuclei + [], // cells + segmentation_csv, // transcript_assignment + polygons2d, // viz_polygons + ch_coordinate_space.val // units + ) + } XENIUMRANGER_IMPORT_SEGMENTATION ( - ch_bundle_path, - [], - [], - [], - ch_segmentation_csv, - ch_polygons2d, - ch_coordinate_space + ch_imp_seg_inputs ) - ch_versions = ch_versions.mix( XENIUMRANGER_IMPORT_SEGMENTATION.out.versions ) + ch_versions = ch_versions.mix ( XENIUMRANGER_IMPORT_SEGMENTATION.out.versions ) ch_redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.bundle diff --git a/subworkflows/local/baysor_run_transcripts_parquet/main.nf b/subworkflows/local/baysor_run_transcripts_parquet/main.nf index 1bce08cf..d0e9cf5d 100644 --- a/subworkflows/local/baysor_run_transcripts_parquet/main.nf +++ b/subworkflows/local/baysor_run_transcripts_parquet/main.nf @@ -13,7 +13,7 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET { take: ch_bundle_path // channel: [ val(meta), ["xenium-bundle"] ] - ch_transcripts_parquet // channel: [ val(meta), ["transcripts.csv.parquet"] ] + ch_transcripts_parquet // channel: [ val(meta), ["transcripts.parquet"] ] ch_config // channel: ["path-to-xenium.toml"] main: @@ -85,22 +85,24 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET { // run xeniumranger import-segmentation - ch_segmentation = BAYSOR_RUN.out.segmentation - ch_segmentation_csv = ch_segmentation.map { _meta, seg_csv, _seg_json -> - return [ seg_csv ] - } - ch_polygons2d = ch_segmentation.map { _meta, _seg_csv, seg_json -> - return [ seg_json ] - } + ch_imp_seg_inputs = ch_bundle_path + .combine(BAYSOR_RUN.out.segmentation[1], by:0) + .combine(BAYSOR_RUN.out.segmentation[2], by:0) + .map { + meta, bundle, segmentation_csv, polygons2d -> tuple ( + meta, // meta + bundle, // bundle + [], // coordinate_transform + [], // nuclei + [], // cells + segmentation_csv, // transcript_assignment + polygons2d, // viz_polygons + ch_coordinate_space.val // units + ) + } XENIUMRANGER_IMPORT_SEGMENTATION ( - ch_bundle_path, - [], - [], - [], - ch_segmentation_csv, - ch_polygons2d, - ch_coordinate_space + ch_imp_seg_inputs ) ch_versions = ch_versions.mix( XENIUMRANGER_IMPORT_SEGMENTATION.out.versions ) diff --git a/subworkflows/local/cellpose_baysor_import_segmentation/main.nf b/subworkflows/local/cellpose_baysor_import_segmentation/main.nf index dc158beb..a93bf8a7 100644 --- a/subworkflows/local/cellpose_baysor_import_segmentation/main.nf +++ b/subworkflows/local/cellpose_baysor_import_segmentation/main.nf @@ -22,6 +22,7 @@ workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { ch_versions = Channel.empty() ch_transcripts = Channel.empty() + ch_imp_seg_inputs = Channel.empty() ch_filtered_transcripts = Channel.empty() ch_coordinate_space = Channel.value("microns") @@ -121,22 +122,24 @@ workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { // run import-segmentation with baysor outs - ch_segmentation = BAYSOR_RUN.out.segmentation - ch_segmentation_csv = ch_segmentation.map { _meta, seg_csv, _seg_json -> - return [ seg_csv ] - } - ch_polygons2d = ch_segmentation.map { _meta, _seg_csv, seg_json -> - return [ seg_json ] - } + ch_imp_seg_inputs = ch_bundle_path + .combine(BAYSOR_RUN.out.segmentation[1], by:0) + .combine(BAYSOR_RUN.out.segmentation[2], by:0) + .map { + meta, bundle, segmentation_csv, polygons2d -> tuple ( + meta, // meta + bundle, // bundle + [], // coordinate_transform + [], // nuclei + [], // cells + segmentation_csv, // transcript_assignment + polygons2d, // viz_polygons + ch_coordinate_space.val // units + ) + } XENIUMRANGER_IMPORT_SEGMENTATION ( - ch_bundle_path, - [], - [], - [], - ch_segmentation_csv, - ch_polygons2d, - ch_coordinate_space + ch_imp_seg_inputs ) ch_versions = ch_versions.mix ( XENIUMRANGER_IMPORT_SEGMENTATION.out.versions ) diff --git a/subworkflows/local/proseg_preset_proseg2baysor/main.nf b/subworkflows/local/proseg_preset_proseg2baysor/main.nf index f7e25fc8..aeab71d8 100644 --- a/subworkflows/local/proseg_preset_proseg2baysor/main.nf +++ b/subworkflows/local/proseg_preset_proseg2baysor/main.nf @@ -22,26 +22,31 @@ workflow PROSEG_PRESET_PROSEG2BAYSOR { PROSEG ( ch_transcripts_parquet ) ch_versions = ch_versions.mix( PROSEG.out.versions ) + // run proseg-to-baysor on the data generated with the proseg run PROSEG2BAYSOR ( PROSEG.out.seg_outs ) ch_versions = ch_versions.mix( PROSEG2BAYSOR.out.versions ) - ch_metadata = PROSEG2BAYSOR.out.xr_metadata.map { - _meta, trans_meta -> return [ trans_meta ] - } - ch_polygons = PROSEG2BAYSOR.out.xr_polygons.map { - _meta, polygons -> return [ polygons ] - } // run xeniumranger import-segmentation + ch_imp_seg_inputs = ch_bundle_path + .combine(PROSEG2BAYSOR.out.xr_metadata, by: 0) + .combine(PROSEG2BAYSOR.out.xr_polygons, by: 0) + .map { + meta, bundle, metadata, polygons2d -> tuple ( + meta, // meta + bundle, // bundle + [], // coordinate_transform + [], // nuclei + [], // cells + metadata, // transcript_assignment + polygons2d, // viz_polygons + ch_coordinate_space.val // units + ) + } + XENIUMRANGER_IMPORT_SEGMENTATION ( - ch_bundle_path, - [], - [], - [], - ch_metadata, - ch_polygons, - ch_coordinate_space + ch_imp_seg_inputs ) ch_versions = ch_versions.mix( XENIUMRANGER_IMPORT_SEGMENTATION.out.versions ) diff --git a/workflows/spatialxe.nf b/workflows/spatialxe.nf index 7ebd9aca..18f7ac25 100644 --- a/workflows/spatialxe.nf +++ b/workflows/spatialxe.nf @@ -40,7 +40,7 @@ include { XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE } from '../subworkflo include { SPATIALDATA_WRITE_META_MERGE } from '../subworkflows/local/spatialdata_write_meta_merge/main' // TODO qc layer subworkflows - +include { OPT_FLIP_TRACK_STAT } from '../subworkflows/local/opt_flip_track_stat/main' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -61,21 +61,23 @@ workflow SPATIALXE { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - ch_versions = Channel.empty() - - ch_input = Channel.empty() - ch_bundle = Channel.empty() - ch_config = Channel.empty() - ch_features = Channel.empty() - ch_raw_bundle = Channel.empty() - ch_gene_panel = Channel.empty() - ch_bundle_path = Channel.empty() - ch_multiqc_files = Channel.empty() - ch_morphology_image = Channel.empty() - ch_redefined_bundle = Channel.empty() - ch_coordinate_space = Channel.empty() - ch_transcripts_parquet = Channel.empty() - + ch_versions = Channel.empty() + + ch_input = Channel.empty() + ch_bundle = Channel.empty() + ch_config = Channel.empty() + ch_features = Channel.empty() + ch_raw_bundle = Channel.empty() + ch_gene_panel = Channel.empty() + ch_bundle_path = Channel.empty() + ch_gene_synonyms = Channel.empty() + ch_multiqc_files = Channel.empty() + ch_morphology_image = Channel.empty() + ch_redefined_bundle = Channel.empty() + ch_coordinate_space = Channel.empty() + ch_panel_probes_fasta = Channel.empty() + ch_transcripts_parquet = Channel.empty() + ch_reference_annotations = Channel.empty() /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -162,6 +164,30 @@ workflow SPATIALXE { ) } + // get panel probes fasta for off-target-probe tracking + if ( params.probes_fasta ) { + ch_panel_probes_fasta = Channel.fromPath ( + params.probes_fasta, + checkIfExists: true + ) + } + + // get reference annotation files (gff,fa) for off-target-probe tracking + if ( params.reference_annotations ) { + ch_reference_annotations = Channel.fromPath ( + params.reference_annotations, + checkIfExists: true + ) + } + + // get gene synonyms for off-target-probe tracking + if ( params.gene_synonyms ) { + ch_gene_synonyms = Channel.fromPath ( + params.gene_synonyms, + checkIfExists: true + ) + } + // get gene_panel.json if provided with --gene_panel, sets relabel_genes to true if (( params.gene_panel )) { @@ -216,7 +242,6 @@ workflow SPATIALXE { ) } - /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SPATIALXE - XENIUMRANGER LAYER @@ -253,52 +278,47 @@ workflow SPATIALXE { ch_coordinate_space = CELLPOSE_BAYSOR_IMPORT_SEGMENTATION.out.coordinate_space } - // check it the provided method is part of the methods list - if ( params.method in params.image_seg_methods ) { - - // run xeniumranger resegment with morphology_ome.tif - if ( params.method == 'xeniumranger' ) { + // run xeniumranger resegment with morphology_ome.tif + if ( params.method == 'xeniumranger' ) { - XENIUMRANGER_RESEGMENT_MORPHOLOGY_OME_TIF ( - ch_bundle_path - ) - ch_redefined_bundle = XENIUMRANGER_RESEGMENT_MORPHOLOGY_OME_TIF.out.redefined_bundle - ch_coordinate_space = XENIUMRANGER_RESEGMENT_MORPHOLOGY_OME_TIF.out.coordinate_space - } - - // run baysor run with morphology_ome.tif - if ( params.method == 'baysor' ) { - - if ( params.segmentation_mask ) { - BAYSOR_RUN_PRIOR_SEGMENTATION_MASK ( - ch_bundle_path, - ch_transcripts_parquet, - ch_segmentation_mask, - ch_config - ) - } else { - BAYSOR_RUN_PRIOR_SEGMENTATION_MASK ( - ch_bundle_path, - ch_transcripts_parquet, - [], - ch_config - ) - } - ch_redefined_bundle = BAYSOR_RUN_PRIOR_SEGMENTATION_MASK.out.redefined_bundle - ch_coordinate_space = BAYSOR_RUN_PRIOR_SEGMENTATION_MASK.out.coordinate_space - } + XENIUMRANGER_RESEGMENT_MORPHOLOGY_OME_TIF ( + ch_bundle_path + ) + ch_redefined_bundle = XENIUMRANGER_RESEGMENT_MORPHOLOGY_OME_TIF.out.redefined_bundle + ch_coordinate_space = XENIUMRANGER_RESEGMENT_MORPHOLOGY_OME_TIF.out.coordinate_space + } - // run cellpose on the morphology_ome.tif - if ( params.method == 'cellpose' ) { + // run baysor run with morphology_ome.tif + if ( params.method == 'baysor' ) { - CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF ( - ch_morphology_image, - ch_bundle_path + if ( params.segmentation_mask ) { + BAYSOR_RUN_PRIOR_SEGMENTATION_MASK ( + ch_bundle_path, + ch_transcripts_parquet, + ch_segmentation_mask, + ch_config + ) + } else { + BAYSOR_RUN_PRIOR_SEGMENTATION_MASK ( + ch_bundle_path, + ch_transcripts_parquet, + [], + ch_config ) - ch_redefined_bundle = CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF.out.redefined_bundle - ch_coordinate_space = CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF.out.coordinate_space } + ch_redefined_bundle = BAYSOR_RUN_PRIOR_SEGMENTATION_MASK.out.redefined_bundle + ch_coordinate_space = BAYSOR_RUN_PRIOR_SEGMENTATION_MASK.out.coordinate_space + } + // run cellpose on the morphology_ome.tif + if ( params.method == 'cellpose' ) { + + CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF ( + ch_morphology_image, + ch_bundle_path + ) + ch_redefined_bundle = CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF.out.redefined_bundle + ch_coordinate_space = CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF.out.coordinate_space } } @@ -309,8 +329,8 @@ workflow SPATIALXE { */ if ( params.mode == 'coordinate' ) { - // trigger the default transcripts-based workflow if no method is specified - if ( !params.method ) { + // run proseg with transcripts.parquet if method = proseg or is not provided (default) + if ( !params.method || params.method == 'proseg') { PROSEG_PRESET_PROSEG2BAYSOR ( ch_bundle_path, @@ -321,49 +341,34 @@ workflow SPATIALXE { } - // check it the provided method is part of the methods list - if ( params.method in params.transcript_seg_methods ) { - - // run proseg with transcripts.parquet - if ( params.method == 'proseg') { - - PROSEG_PRESET_PROSEG2BAYSOR ( - ch_bundle_path, - ch_transcripts_parquet - ) - ch_redefined_bundle = PROSEG_PRESET_PROSEG2BAYSOR.out.redefined_bundle - ch_coordinate_space = PROSEG_PRESET_PROSEG2BAYSOR.out.coordinate_space + // run segger with transcripts.parquet + if ( params.method == 'segger' ) { - } - - // run segger with transcripts.parquet - if ( params.method == 'segger' ) { - - SEGGER_CREATE_TRAIN_PREDICT ( - ch_bundle_path, - ch_transcripts_parquet - ) - ch_redefined_bundle = SEGGER_CREATE_TRAIN_PREDICT.out.redefined_bundle - ch_coordinate_space = SEGGER_CREATE_TRAIN_PREDICT.out.coordinate_space - - } + SEGGER_CREATE_TRAIN_PREDICT ( + ch_bundle_path, + ch_transcripts_parquet + ) + ch_redefined_bundle = SEGGER_CREATE_TRAIN_PREDICT.out.redefined_bundle + ch_coordinate_space = SEGGER_CREATE_TRAIN_PREDICT.out.coordinate_space - // run baysor with transcripts.parquet - if ( params.method == 'baysor' ) { + } - BAYSOR_RUN_TRANSCRIPTS_PARQUET ( - ch_bundle_path, - ch_transcripts_parquet, - ch_config - ) - ch_redefined_bundle = BAYSOR_RUN_TRANSCRIPTS_PARQUET.out.redefined_bundle - ch_coordinate_space = BAYSOR_RUN_TRANSCRIPTS_PARQUET.out.coordinate_space - } + // run baysor with transcripts.parquet + if ( params.method == 'baysor' ) { + BAYSOR_RUN_TRANSCRIPTS_PARQUET ( + ch_bundle_path, + ch_transcripts_parquet, + ch_config + ) + ch_redefined_bundle = BAYSOR_RUN_TRANSCRIPTS_PARQUET.out.redefined_bundle + ch_coordinate_space = BAYSOR_RUN_TRANSCRIPTS_PARQUET.out.coordinate_space } + } + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SPATIALXE - SPATIALDATA / METADATA LAYER From 0c855ca7047b4359628e58f6c67ce3fa0ae66fa2 Mon Sep 17 00:00:00 2001 From: Sameesh Kher Date: Mon, 22 Sep 2025 23:42:59 +0000 Subject: [PATCH 05/12] more fixes for multisample support --- nextflow.config | 2 +- nextflow_schema.json | 3 +- .../main.nf | 7 +- .../main.nf | 50 +++++++--- .../local/proseg_preset_proseg2baysor/main.nf | 10 +- .../local/segger_create_train_predict/main.nf | 70 ++++++------- .../main.nf | 99 +++++++++++++------ .../main.nf | 24 +++-- workflows/spatialxe.nf | 62 ++++++------ 9 files changed, 198 insertions(+), 129 deletions(-) diff --git a/nextflow.config b/nextflow.config index 388d6140..de804e34 100644 --- a/nextflow.config +++ b/nextflow.config @@ -15,7 +15,7 @@ params { mode = null // run the pipeline either in `image` or `coordinate` or `segfree` or `preview` modes method = null // name of the method to run for image or coordinate or segfree approaches gene_panel = null // path to gene panel json file if `relabel_genes` is true - qupath_polygons = null // polygon segmentation results in GeoJSON format + qupath_polygons = null // Path to qupath segmentation results in GeoJSON format alignment_csv = null // image alignment file format a 3x3 transformation matrix, where the last row is [0,0,1] cellpose_model = null // custom cellpose model to use for running or starting training segmentation_mask = null // prior segmentation mask diff --git a/nextflow_schema.json b/nextflow_schema.json index 5c5e8bc4..d6449899 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -46,7 +46,8 @@ }, "qupath_polygons": { "type": "string", - "description": "Polygon segmentation results in GeoJSON format from QuPath." + "description": "Path to qupath segmentation file in GeoJSON format.", + "format": "file-path" }, "alignment_csv": { "type": "string", diff --git a/subworkflows/local/cellpose_baysor_import_segmentation/main.nf b/subworkflows/local/cellpose_baysor_import_segmentation/main.nf index a93bf8a7..f4f526ea 100644 --- a/subworkflows/local/cellpose_baysor_import_segmentation/main.nf +++ b/subworkflows/local/cellpose_baysor_import_segmentation/main.nf @@ -123,10 +123,11 @@ workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { // run import-segmentation with baysor outs ch_imp_seg_inputs = ch_bundle_path - .combine(BAYSOR_RUN.out.segmentation[1], by:0) - .combine(BAYSOR_RUN.out.segmentation[2], by:0) + .combine(BAYSOR_RUN.out.segmentation, by: 0) .map { - meta, bundle, segmentation_csv, polygons2d -> tuple ( + meta, bundle, segmentation_outs -> + def ( _meta, segmentation_csv, polygons2d ) = segmentation_outs + tuple ( meta, // meta bundle, // bundle [], // coordinate_transform diff --git a/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf b/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf index 2e6685e6..5224180d 100644 --- a/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf +++ b/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf @@ -17,6 +17,7 @@ workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { main: ch_versions = Channel.empty() + ch_imp_seg_inputs = Channel.empty() ch_cellpose_nuclei_mask = Channel.empty() ch_cellpose_cells_mask = Channel.empty() ch_coordinate_space = Channel.value("pixels") @@ -53,6 +54,8 @@ workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { _meta, flows -> return [ flows ] } + + } if ( params.nucleus_segmentation_only ) { @@ -74,27 +77,46 @@ workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { // run import-segmentation with cellpose results if ( params.nucleus_segmentation_only ) { + ch_imp_seg_inputs = ch_bundle_path + .combine(CELLPOSE_NUCLEI.out.cells, by:0) + .map { + meta, bundle, nuclei_seg -> tuple ( + meta, // meta + bundle, // bundle + [], // coordinate_transform + nuclei_seg, // nuclei + [], // cells + [], // transcript_assignment + [], // viz_polygons + ch_coordinate_space.val // units + ) + } + XENIUMRANGER_IMPORT_SEGMENTATION ( - ch_bundle_path, - [], - ch_cellpose_nuclei_mask, - [], - [], - [], - ch_coordinate_space + ch_imp_seg_inputs ) ch_versions = ch_versions.mix( XENIUMRANGER_IMPORT_SEGMENTATION.out.versions ) } else { + ch_imp_seg_inputs = ch_bundle_path + .combine(CELLPOSE_CELLS.out.cells, by:0) + .combine(CELLPOSE_NUCLEI.out.cells, by:0) + .map { + meta, bundle, cells_seg, nuclei_seg -> tuple ( + meta, // meta + bundle, // bundle + [], // coordinate_transform + nuclei_seg, // nuclei + cells_seg, // cells + [], // transcript_assignment + [], // viz_polygons + ch_coordinate_space.val // units + ) + } + XENIUMRANGER_IMPORT_SEGMENTATION ( - ch_bundle_path, - [], - ch_cellpose_nuclei_mask, - ch_cellpose_cells_mask, - [], - [], - ch_coordinate_space + ch_imp_seg_inputs ) ch_versions = ch_versions.mix( XENIUMRANGER_IMPORT_SEGMENTATION.out.versions ) } diff --git a/subworkflows/local/proseg_preset_proseg2baysor/main.nf b/subworkflows/local/proseg_preset_proseg2baysor/main.nf index aeab71d8..d0314e26 100644 --- a/subworkflows/local/proseg_preset_proseg2baysor/main.nf +++ b/subworkflows/local/proseg_preset_proseg2baysor/main.nf @@ -20,18 +20,18 @@ workflow PROSEG_PRESET_PROSEG2BAYSOR { // run proseg with the xenium format PROSEG ( ch_transcripts_parquet ) - ch_versions = ch_versions.mix( PROSEG.out.versions ) + ch_versions = ch_versions.mix ( PROSEG.out.versions ) // run proseg-to-baysor on the data generated with the proseg run PROSEG2BAYSOR ( PROSEG.out.seg_outs ) - ch_versions = ch_versions.mix( PROSEG2BAYSOR.out.versions ) + ch_versions = ch_versions.mix ( PROSEG2BAYSOR.out.versions ) // run xeniumranger import-segmentation ch_imp_seg_inputs = ch_bundle_path - .combine(PROSEG2BAYSOR.out.xr_metadata, by: 0) - .combine(PROSEG2BAYSOR.out.xr_polygons, by: 0) + .combine( PROSEG2BAYSOR.out.xr_metadata, by: 0 ) + .combine( PROSEG2BAYSOR.out.xr_polygons, by: 0 ) .map { meta, bundle, metadata, polygons2d -> tuple ( meta, // meta @@ -48,7 +48,7 @@ workflow PROSEG_PRESET_PROSEG2BAYSOR { XENIUMRANGER_IMPORT_SEGMENTATION ( ch_imp_seg_inputs ) - ch_versions = ch_versions.mix( XENIUMRANGER_IMPORT_SEGMENTATION.out.versions ) + ch_versions = ch_versions.mix ( XENIUMRANGER_IMPORT_SEGMENTATION.out.versions ) emit: diff --git a/subworkflows/local/segger_create_train_predict/main.nf b/subworkflows/local/segger_create_train_predict/main.nf index f0a95414..52423e0d 100644 --- a/subworkflows/local/segger_create_train_predict/main.nf +++ b/subworkflows/local/segger_create_train_predict/main.nf @@ -63,41 +63,41 @@ workflow SEGGER_CREATE_TRAIN_PREDICT { // run xeniumranger import-segmentation - cells = ch_updated_bundle.map { _meta, bundle -> - return [ bundle + "/cells.zarr.zip" ] - } - - if ( params.nucleus_segmentation_only ) { - - XENIUMRANGER_IMPORT_SEGMENTATION ( - ch_updated_bundle, - [], - cells, - cells, - [], - [], - ch_coordinate_space - ) - ch_redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.bundle - - ch_versions = ch_versions.mix ( XENIUMRANGER_IMPORT_SEGMENTATION.out.versions ) - - } else { - - XENIUMRANGER_IMPORT_SEGMENTATION ( - ch_updated_bundle, - [], - [], - cells, - [], - [], - ch_coordinate_space - ) - ch_redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.bundle - - ch_versions = ch_versions.mix ( XENIUMRANGER_IMPORT_SEGMENTATION.out.versions ) - - } + // cells = ch_updated_bundle.map { _meta, bundle -> + // return [ bundle + "/cells.zarr.zip" ] + // } + + // if ( params.nucleus_segmentation_only ) { + + // XENIUMRANGER_IMPORT_SEGMENTATION ( + // ch_updated_bundle, + // [], + // cells, + // cells, + // [], + // [], + // ch_coordinate_space + // ) + // ch_redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.bundle + + // ch_versions = ch_versions.mix ( XENIUMRANGER_IMPORT_SEGMENTATION.out.versions ) + + // } else { + + // XENIUMRANGER_IMPORT_SEGMENTATION ( + // ch_updated_bundle, + // [], + // [], + // cells, + // [], + // [], + // ch_coordinate_space + // ) + // ch_redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.bundle + + // ch_versions = ch_versions.mix ( XENIUMRANGER_IMPORT_SEGMENTATION.out.versions ) + + // } emit: diff --git a/subworkflows/local/xeniumranger_import_segmentation_redefine_bundle/main.nf b/subworkflows/local/xeniumranger_import_segmentation_redefine_bundle/main.nf index e0c9df09..b19b4529 100644 --- a/subworkflows/local/xeniumranger_import_segmentation_redefine_bundle/main.nf +++ b/subworkflows/local/xeniumranger_import_segmentation_redefine_bundle/main.nf @@ -17,23 +17,32 @@ workflow XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE { ch_versions = Channel.empty() ch_redefined_bundle = Channel.empty() - ch_coordinate_space = Channel.empty("pixels") + ch_coordinate_space = Channel.empty() cells = ch_bundle_path.map { - _meta, bundle -> return [ bundle + "/cells.zarr.zip" ] + meta, bundle -> return [ meta, bundle + "/cells.zarr.zip" ] } // scenario - 1 change nuclear expansion distance / create a nucleus-only count matrix(--expansion_distance=0) if ( params.expansion_distance == 0 || params.expansion_distance != 5 ) { + ch_coordinate_space = "microns" + ch_imp_seg_inputs = ch_bundle_path + .combine(cells, by:0) + .map { + meta, bundle, cells_zarr -> tuple ( + meta, // meta + bundle, // bundle + [], // coordinate_transform + cells_zarr, // nuclei + [], // cells + [], // transcript_assignment + [], // viz_polygons + ch_coordinate_space.val // units + ) + } IMP_SEG_COUNT_MATRIX_EXP_DISTANCE ( - ch_bundle_path, - [], - cells, - [], - [], - [], - ch_coordinate_space + ch_imp_seg_inputs ) ch_redefined_bundle = IMP_SEG_COUNT_MATRIX_EXP_DISTANCE.out.bundle @@ -43,14 +52,24 @@ workflow XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE { // scenario - 2 polygon input - geojson format (from QuPath) if ( params.qupath_polygons && params.nucleus_segmentation_only ) { + ch_coordinate_space = "microns" + ch_imp_seg_inputs = ch_bundle_path + .combine(params.qupath_polygons) + .map { + meta, bundle, polygons_geojson -> tuple ( + meta, // meta + bundle, // bundle + [], // coordinate_transform + polygons_geojson, // nuclei + [], // cells + [], // transcript_assignment + [], // viz_polygons + ch_coordinate_space.val // units + ) + } + IMP_SEG_POLYGON_GEOJSON_INPUT ( - ch_bundle_path, - [], - params.qupath_polygons, - [], - [], - [], - ch_coordinate_space + ch_imp_seg_inputs ) ch_redefined_bundle = IMP_SEG_POLYGON_GEOJSON_INPUT.out.bundle @@ -58,14 +77,24 @@ workflow XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE { } else if ( params.qupath_polygons ) { + ch_coordinate_space = "microns" + ch_imp_seg_inputs = ch_bundle_path + .combine(params.qupath_polygons) + .map { + meta, bundle, polygons_geojson -> tuple ( + meta, // meta + bundle, // bundle + [], // coordinate_transform + polygons_geojson, // nuclei + polygons_geojson, // cells + [], // transcript_assignment + [], // viz_polygons + ch_coordinate_space.val // units + ) + } + IMP_SEG_POLYGON_GEOJSON_INPUT ( - ch_bundle_path, - [], - params.qupath_polygons, - params.qupath_polygons, - [], - [], - ch_coordinate_space + ch_imp_seg_inputs ) ch_redefined_bundle = IMP_SEG_POLYGON_GEOJSON_INPUT.out.bundle @@ -80,14 +109,24 @@ workflow XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE { // scenario 5 - transformation matrix input if ( params.qupath_polygons && params.alignment_csv ) { + ch_imp_seg_inputs = ch_bundle_path + .combine(params.qupath_polygins) + .combine(params.alignment_csv) + .map { + meta, bundle, polygons_geojson, alignment_csv -> tuple ( + meta, // meta + bundle, // bundle + alignment_csv, // coordinate_transform + polygons_geojson, // nuclei + polygons_geojson, // cells + [], // transcript_assignment + [], // viz_polygons + ch_coordinate_space.val // units + ) + } + IMP_SEG_TRANS_MATRIX_INPUT ( - ch_bundle_path, - params.alignment_csv, - params.qupath_polygons, - params.qupath_polygons, - [], - [], - ch_coordinate_space + ch_imp_seg_inputs ) ch_redefined_bundle = IMP_SEG_TRANS_MATRIX_INPUT.out.bundle diff --git a/subworkflows/local/xeniumranger_resegment_morphology_ome_tif/main.nf b/subworkflows/local/xeniumranger_resegment_morphology_ome_tif/main.nf index ba81cc51..bea27214 100644 --- a/subworkflows/local/xeniumranger_resegment_morphology_ome_tif/main.nf +++ b/subworkflows/local/xeniumranger_resegment_morphology_ome_tif/main.nf @@ -30,14 +30,24 @@ workflow XENIUMRANGER_RESEGMENT_MORPHOLOGY_OME_TIF { // adjust the nuclear expansion distance without altering nuclei detection if ( params.nucleus_segmentation_only ) { + ch_imp_seg_inputs = ch_bundle_path + .combine(XENIUMRANGER_RESEGMENT.out.bundle, by:0) + .combine(cells) + .map { + meta, bundle, cells_zarr -> tuple ( + meta, // meta + bundle, // bundle + [], // coordinate_transform + cells_zarr, // nuclei + [], // cells + [], // transcript_assignment + [], // viz_polygons + ch_coordinate_space.val // units + ) + } + XENIUMRANGER_IMPORT_SEGMENTATION ( - XENIUMRANGER_RESEGMENT.out.bundle, - [], - cells, - [], - [], - [], - ch_coordinate_space + ch_imp_seg_inputs ) ch_versions = ch_versions.mix( XENIUMRANGER_IMPORT_SEGMENTATION.out.versions ) diff --git a/workflows/spatialxe.nf b/workflows/spatialxe.nf index 18f7ac25..6ac5a11e 100644 --- a/workflows/spatialxe.nf +++ b/workflows/spatialxe.nf @@ -70,6 +70,7 @@ workflow SPATIALXE { ch_raw_bundle = Channel.empty() ch_gene_panel = Channel.empty() ch_bundle_path = Channel.empty() + ch_qupath_polygons = Channel.empty() ch_gene_synonyms = Channel.empty() ch_multiqc_files = Channel.empty() ch_morphology_image = Channel.empty() @@ -139,13 +140,13 @@ workflow SPATIALXE { ch_config = Channel.fromPath ( "${projectDir}/assets/config/xenium.toml", checkIfExists: true - ) + ).flatten() // get segmentation mask if provided with --segmentation_mask for the baysor method if ( params.segmentation_mask ) { ch_segmentation_mask = Channel.fromPath ( params.segmentation_mask, checkIfExists: true - ) + ).flatten() } // get a list of features if provided with the --features for the ficture method @@ -153,7 +154,7 @@ workflow SPATIALXE { ch_features = Channel.fromPath ( params.features, checkIfExists: true - ) + ).flatten() } // get custom cellpose model if provided with the --cellpose_model for the cellpose method @@ -161,7 +162,7 @@ workflow SPATIALXE { ch_features = Channel.fromPath ( params.cellpose_model, checkIfExists: true - ) + ).flatten() } // get panel probes fasta for off-target-probe tracking @@ -169,15 +170,15 @@ workflow SPATIALXE { ch_panel_probes_fasta = Channel.fromPath ( params.probes_fasta, checkIfExists: true - ) + ).flatten() } // get reference annotation files (gff,fa) for off-target-probe tracking if ( params.reference_annotations ) { ch_reference_annotations = Channel.fromPath ( - params.reference_annotations, + "${params.reference_annotations}/*.{fa,gff}".toString(), checkIfExists: true - ) + ).flatten() } // get gene synonyms for off-target-probe tracking @@ -185,7 +186,15 @@ workflow SPATIALXE { ch_gene_synonyms = Channel.fromPath ( params.gene_synonyms, checkIfExists: true - ) + ).flatten() + } + + // get qupath ploygons + if ( params.qupath_polygons ) { + ch_qupath_polygons = Channel.fromPath ( + "${params.qupath_polygons}/*.geojson", + checkIfExists: true + ).flatten() } // get gene_panel.json if provided with --gene_panel, sets relabel_genes to true @@ -195,7 +204,7 @@ workflow SPATIALXE { ch_gene_panel = Channel.fromPath ( params.gene_panel, checkIfExists: true - ) + ).flatten() } else { @@ -329,7 +338,7 @@ workflow SPATIALXE { */ if ( params.mode == 'coordinate' ) { - // run proseg with transcripts.parquet if method = proseg or is not provided (default) + // run proseg with transcripts.parquet if method = proseg or is not provided (default workflow) if ( !params.method || params.method == 'proseg') { PROSEG_PRESET_PROSEG2BAYSOR ( @@ -400,8 +409,8 @@ workflow SPATIALXE { */ if ( params.mode == 'segfree' ) { - // trigger the default segfree workflow if no method is specified - if ( !params.method ) { + // trigger the default segfree workflow if no method or if the method is baysor + if ( !params.method || params.method == 'baysor' ) { BAYSOR_GENERATE_SEGFREE ( ch_transcripts_parquet, @@ -409,26 +418,13 @@ workflow SPATIALXE { ) } - // check it the provided method is part of the methods list - if ( params.method in params.segfree_methods ) { + // run ficture with transcripts.parquet + if ( params.method == 'ficture' ) { - // run baysor with transcripts.parquet - if ( params.method == 'baysor' ) { - - BAYSOR_GENERATE_SEGFREE ( - ch_transcripts_parquet, - ch_config - ) - } - - // run ficture with transcripts.parquet - if ( params.method == 'ficture' ) { - - FICTURE_PREPROCESS_MODEL ( - ch_transcripts_parquet, - ch_features - ) - } + FICTURE_PREPROCESS_MODEL ( + ch_transcripts_parquet, + ch_features + ) } } @@ -453,7 +449,7 @@ workflow SPATIALXE { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ ch_multiqc_config = Channel.fromPath ( - "$projectDir/assets/multiqc_config.yml", + "${projectDir}/assets/multiqc_config.yml", checkIfExists: true ) @@ -477,7 +473,7 @@ workflow SPATIALXE { ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file( params.multiqc_methods_description, checkIfExists: true ) : - file( "$projectDir/assets/methods_description_template.yml", checkIfExists: true ) + file( "${projectDir}/assets/methods_description_template.yml", checkIfExists: true ) ch_methods_description = Channel.value ( methodsDescriptionText ( ch_multiqc_custom_methods_description ) From 700844db1b52c61e32007c922888430db9522f27 Mon Sep 17 00:00:00 2001 From: Sameesh Kher Date: Tue, 23 Sep 2025 00:20:59 +0000 Subject: [PATCH 06/12] removed indexing --- .../local/baysor_run_prior_segmentation_mask/main.nf | 7 ++++--- .../local/baysor_run_transcripts_parquet/main.nf | 7 ++++--- .../cellpose_resolift_morphology_ome_tif/main.nf | 5 +++-- .../main.nf | 12 ++++++++---- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf b/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf index def0918e..62987e72 100644 --- a/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf +++ b/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf @@ -56,10 +56,11 @@ workflow BAYSOR_RUN_PRIOR_SEGMENTATION_MASK { // run import-segmentation with baysor outs ch_imp_seg_inputs = ch_bundle_path - .combine(BAYSOR_RUN.out.segmentation[1], by:0) - .combine(BAYSOR_RUN.out.segmentation[2], by:0) + .combine(BAYSOR_RUN.out.segmentation, by: 0) .map { - meta, bundle, segmentation_csv, polygons2d -> tuple ( + meta, bundle, segmentation_outs -> + def ( _meta, segmentation_csv, polygons2d ) = segmentation_outs + tuple ( meta, // meta bundle, // bundle [], // coordinate_transform diff --git a/subworkflows/local/baysor_run_transcripts_parquet/main.nf b/subworkflows/local/baysor_run_transcripts_parquet/main.nf index d0e9cf5d..9d18893e 100644 --- a/subworkflows/local/baysor_run_transcripts_parquet/main.nf +++ b/subworkflows/local/baysor_run_transcripts_parquet/main.nf @@ -86,10 +86,11 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET { // run xeniumranger import-segmentation ch_imp_seg_inputs = ch_bundle_path - .combine(BAYSOR_RUN.out.segmentation[1], by:0) - .combine(BAYSOR_RUN.out.segmentation[2], by:0) + .combine(BAYSOR_RUN.out.segmentation, by: 0) .map { - meta, bundle, segmentation_csv, polygons2d -> tuple ( + meta, bundle, segmentation_outs -> + def ( _meta, segmentation_csv, polygons2d ) = segmentation_outs + tuple ( meta, // meta bundle, // bundle [], // coordinate_transform diff --git a/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf b/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf index 5224180d..6e0f2e8e 100644 --- a/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf +++ b/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf @@ -78,9 +78,10 @@ workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { if ( params.nucleus_segmentation_only ) { ch_imp_seg_inputs = ch_bundle_path - .combine(CELLPOSE_NUCLEI.out.cells, by:0) + .combine(CELLPOSE_NUCLEI.out.cells, by: 0) .map { - meta, bundle, nuclei_seg -> tuple ( + meta, bundle, nuclei_seg -> + tuple ( meta, // meta bundle, // bundle [], // coordinate_transform diff --git a/subworkflows/local/xeniumranger_import_segmentation_redefine_bundle/main.nf b/subworkflows/local/xeniumranger_import_segmentation_redefine_bundle/main.nf index b19b4529..fd534b3b 100644 --- a/subworkflows/local/xeniumranger_import_segmentation_redefine_bundle/main.nf +++ b/subworkflows/local/xeniumranger_import_segmentation_redefine_bundle/main.nf @@ -29,7 +29,8 @@ workflow XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE { ch_imp_seg_inputs = ch_bundle_path .combine(cells, by:0) .map { - meta, bundle, cells_zarr -> tuple ( + meta, bundle, cells_zarr -> + tuple ( meta, // meta bundle, // bundle [], // coordinate_transform @@ -56,7 +57,8 @@ workflow XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE { ch_imp_seg_inputs = ch_bundle_path .combine(params.qupath_polygons) .map { - meta, bundle, polygons_geojson -> tuple ( + meta, bundle, polygons_geojson -> + tuple ( meta, // meta bundle, // bundle [], // coordinate_transform @@ -81,7 +83,8 @@ workflow XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE { ch_imp_seg_inputs = ch_bundle_path .combine(params.qupath_polygons) .map { - meta, bundle, polygons_geojson -> tuple ( + meta, bundle, polygons_geojson -> + tuple ( meta, // meta bundle, // bundle [], // coordinate_transform @@ -113,7 +116,8 @@ workflow XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE { .combine(params.qupath_polygins) .combine(params.alignment_csv) .map { - meta, bundle, polygons_geojson, alignment_csv -> tuple ( + meta, bundle, polygons_geojson, alignment_csv -> + tuple ( meta, // meta bundle, // bundle alignment_csv, // coordinate_transform From 85331d401f5372068c3e247ab5c0b79cbe98cb88 Mon Sep 17 00:00:00 2001 From: Sameesh Kher Date: Tue, 23 Sep 2025 13:09:20 +0000 Subject: [PATCH 07/12] handled output path prefix --- modules.json | 9 ++++++--- modules/local/baysor/create_dataset/main.nf | 4 ++-- modules/local/baysor/preprocess/main.nf | 4 ++-- modules/local/baysor/preview/main.nf | 2 +- modules/local/baysor/run/main.nf | 6 +++--- modules/local/baysor/segfree/main.nf | 8 +++++--- modules/local/proseg/preset/main.nf | 6 +++--- modules/local/proseg/proseg2baysor/main.nf | 6 +++--- modules/local/resolift/main.nf | 4 ++-- modules/local/spatialdata/merge/main.nf | 4 ++-- modules/local/spatialdata/meta/main.nf | 4 ++-- modules/local/spatialdata/write/main.nf | 4 ++-- modules/local/utility/segger2xr/main.nf | 4 ++-- .../spatialconverter/parquet_to_csv/main.nf | 5 +++-- .../local/utility/split_transcripts/main.nf | 17 ++++++++++++---- .../templates/split_transcripts.py | 6 ++++-- modules/nf-core/cellpose/cellpose.diff | 20 ++++++++++++++----- modules/nf-core/cellpose/main.nf | 12 +++++------ modules/nf-core/opt/flip/main.nf | 4 ++-- modules/nf-core/opt/flip/opt-flip.diff | 20 +++++++++++++++++++ modules/nf-core/opt/stat/main.nf | 4 ++-- modules/nf-core/opt/stat/opt-stat.diff | 20 +++++++++++++++++++ modules/nf-core/opt/track/main.nf | 4 ++-- modules/nf-core/opt/track/opt-track.diff | 20 +++++++++++++++++++ .../xeniumranger/import-segmentation/main.nf | 4 ++-- .../xeniumranger-import-segmentation.diff | 4 ++-- modules/nf-core/xeniumranger/relabel/main.nf | 2 +- .../relabel/xeniumranger-relabel.diff | 2 +- .../nf-core/xeniumranger/resegment/main.nf | 2 +- .../resegment/xeniumranger-resegment.diff | 2 +- 30 files changed, 150 insertions(+), 63 deletions(-) create mode 100644 modules/nf-core/opt/flip/opt-flip.diff create mode 100644 modules/nf-core/opt/stat/opt-stat.diff create mode 100644 modules/nf-core/opt/track/opt-track.diff diff --git a/modules.json b/modules.json index 9cff4eec..aad699b5 100644 --- a/modules.json +++ b/modules.json @@ -19,17 +19,20 @@ "opt/flip": { "branch": "master", "git_sha": "66d5baa4e9b6ac3ab95e84f88709b8e3ebf4b62b", - "installed_by": ["modules"] + "installed_by": ["modules"], + "patch": "modules/nf-core/opt/flip/opt-flip.diff" }, "opt/stat": { "branch": "master", "git_sha": "66d5baa4e9b6ac3ab95e84f88709b8e3ebf4b62b", - "installed_by": ["modules"] + "installed_by": ["modules"], + "patch": "modules/nf-core/opt/stat/opt-stat.diff" }, "opt/track": { "branch": "master", "git_sha": "66d5baa4e9b6ac3ab95e84f88709b8e3ebf4b62b", - "installed_by": ["modules"] + "installed_by": ["modules"], + "patch": "modules/nf-core/opt/track/opt-track.diff" }, "untar": { "branch": "master", diff --git a/modules/local/baysor/create_dataset/main.nf b/modules/local/baysor/create_dataset/main.nf index 2e1cf670..6db53a90 100644 --- a/modules/local/baysor/create_dataset/main.nf +++ b/modules/local/baysor/create_dataset/main.nf @@ -9,8 +9,8 @@ process BAYSOR_CREATE_DATASET { val(sample_fraction) output: - tuple val(meta), path("${meta.id}/sampled_transcripts.csv"), emit: sampled_transcripts - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/sampled_transcripts.csv"), emit: sampled_transcripts + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/baysor/preprocess/main.nf b/modules/local/baysor/preprocess/main.nf index 8e14ccac..a5bedbd5 100644 --- a/modules/local/baysor/preprocess/main.nf +++ b/modules/local/baysor/preprocess/main.nf @@ -14,8 +14,8 @@ process BAYSOR_PREPROCESS_TRANSCRIPTS { output: tuple val(meta), - path("${meta.id}/filtered_transcripts.parquet"), emit: transcripts_parquet - path("versions.yml") , emit: versions + path("${prefix}/filtered_transcripts.parquet"), emit: transcripts_parquet + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/baysor/preview/main.nf b/modules/local/baysor/preview/main.nf index a641d468..b62b7fe4 100644 --- a/modules/local/baysor/preview/main.nf +++ b/modules/local/baysor/preview/main.nf @@ -9,7 +9,7 @@ process BAYSOR_PREVIEW { path(config) output: - tuple val(meta), path("${meta.id}/preview.html"), emit: preview_html + tuple val(meta), path("${prefix}/preview.html"), emit: preview_html path("versions.yml") , emit: versions when: diff --git a/modules/local/baysor/run/main.nf b/modules/local/baysor/run/main.nf index 485059fd..d93c040c 100644 --- a/modules/local/baysor/run/main.nf +++ b/modules/local/baysor/run/main.nf @@ -12,9 +12,9 @@ process BAYSOR_RUN { output: tuple val(meta), - path("${meta.id}/segmentation.csv"), - path("${meta.id}/segmentation_polygons_2d.json"), emit: segmentation - path("versions.yml") , emit: versions + path("${prefix}/segmentation.csv"), + path("${prefix}/segmentation_polygons_2d.json"), emit: segmentation + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/baysor/segfree/main.nf b/modules/local/baysor/segfree/main.nf index 24e96928..32cd1cf3 100644 --- a/modules/local/baysor/segfree/main.nf +++ b/modules/local/baysor/segfree/main.nf @@ -9,8 +9,8 @@ process BAYSOR_SEGFREE { path(config) output: - tuple val(meta), path("ncvs.loom"), emit: ncvs - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/ncvs.loom"), emit: ncvs + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -25,10 +25,12 @@ process BAYSOR_SEGFREE { def prefix = task.ext.prefix ?: "${meta.id}" """ + mkdir -p ${prefix} + baysor segfree \\ ${transcripts} \\ --config ${config} \\ - --output=${prefix} \\ + --output=${prefix}/ncvs.loom \\ ${args} cat <<-END_VERSIONS > versions.yml diff --git a/modules/local/proseg/preset/main.nf b/modules/local/proseg/preset/main.nf index cca3e853..ce64b7f0 100644 --- a/modules/local/proseg/preset/main.nf +++ b/modules/local/proseg/preset/main.nf @@ -9,9 +9,9 @@ process PROSEG { output: tuple val(meta), - path("${meta.id}/cell-polygons.geojson.gz"), - path("${meta.id}/transcript-metadata.csv.gz"), emit: seg_outs - path("versions.yml") , emit: versions + path("${prefix}/cell-polygons.geojson.gz"), + path("${prefix}/transcript-metadata.csv.gz"), emit: seg_outs + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/proseg/proseg2baysor/main.nf b/modules/local/proseg/proseg2baysor/main.nf index dae2ef98..ada63c7d 100644 --- a/modules/local/proseg/proseg2baysor/main.nf +++ b/modules/local/proseg/proseg2baysor/main.nf @@ -8,9 +8,9 @@ process PROSEG2BAYSOR { tuple val(meta), path(cell_polygons), path(transcript_metadata) output: - tuple val(meta), path("${meta.id}/cell-polygons.geojson") , emit: xr_polygons - tuple val(meta), path("${meta.id}/transcript-metadata.csv"), emit: xr_metadata - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/cell-polygons.geojson") , emit: xr_polygons + tuple val(meta), path("${prefix}/transcript-metadata.csv"), emit: xr_metadata + path("versions.yml") , emit: versions script: // Exit if running this module with -profile conda / -profile mamba diff --git a/modules/local/resolift/main.nf b/modules/local/resolift/main.nf index c7467c92..3ab86cf6 100644 --- a/modules/local/resolift/main.nf +++ b/modules/local/resolift/main.nf @@ -9,8 +9,8 @@ process RESOLIFT { output: tuple val(meta), - path("${meta.id}/morphology.ome.enhanced.tiff"), emit: enhanced_tiff - path("versions.yml") , emit: versions + path("${prefix}/morphology.ome.enhanced.tiff"), emit: enhanced_tiff + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/spatialdata/merge/main.nf b/modules/local/spatialdata/merge/main.nf index 55a227c9..db2403d6 100644 --- a/modules/local/spatialdata/merge/main.nf +++ b/modules/local/spatialdata/merge/main.nf @@ -8,8 +8,8 @@ process SPATIALDATA_MERGE { tuple val(meta), path(raw_bundle, stageAs: "*"), path(redefined_bundle, stageAs: "*") output: - tuple val(meta), path("${meta.id}/spatialdata_merged"), emit: merged_bundle - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/spatialdata_merged"), emit: merged_bundle + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/spatialdata/meta/main.nf b/modules/local/spatialdata/meta/main.nf index 2916cb9c..aa5d7ac4 100644 --- a/modules/local/spatialdata/meta/main.nf +++ b/modules/local/spatialdata/meta/main.nf @@ -8,8 +8,8 @@ process SPATIALDATA_META { tuple val(meta), path(spatialdata_bundle, stageAs: "*"), path(xenium_bundle, stageAs: "*") output: - tuple val(meta), path("${meta.id}/spatialdata_meta"), emit: metadata - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/spatialdata_meta"), emit: metadata + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/spatialdata/write/main.nf b/modules/local/spatialdata/write/main.nf index 7beb6786..723a5bee 100644 --- a/modules/local/spatialdata/write/main.nf +++ b/modules/local/spatialdata/write/main.nf @@ -11,8 +11,8 @@ process SPATIALDATA_WRITE { val(coordinate_space) output: - tuple val(meta), path("${meta.id}/${outputfolder}"), emit: spatialdata - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/${outputfolder}"), emit: spatialdata + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/utility/segger2xr/main.nf b/modules/local/utility/segger2xr/main.nf index 15e50835..63dcdad6 100644 --- a/modules/local/utility/segger2xr/main.nf +++ b/modules/local/utility/segger2xr/main.nf @@ -8,8 +8,8 @@ process SEGGER2XR { tuple val(meta), path(transcripts) output: - tuple val(meta), path("${meta.id}/transcripts.parquet"), emit: transcripts_parquet - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/transcripts.parquet"), emit: transcripts_parquet + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/utility/spatialconverter/parquet_to_csv/main.nf b/modules/local/utility/spatialconverter/parquet_to_csv/main.nf index 9d2d0fca..4a75fd24 100644 --- a/modules/local/utility/spatialconverter/parquet_to_csv/main.nf +++ b/modules/local/utility/spatialconverter/parquet_to_csv/main.nf @@ -9,8 +9,8 @@ process PARQUET_TO_CSV { val(extension) output: - tuple val(meta), path("${meta.id}/*.csv*"), emit: transcripts_csv - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/*.csv*"), emit: transcripts_csv + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -20,6 +20,7 @@ process PARQUET_TO_CSV { if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "PARQUET_TO_CSV module does not support Conda. Please use Docker / Singularity / Podman instead." } + def prefix = task.ext.prefix ?: "${meta.id}" template 'parquet_to_csv.py' diff --git a/modules/local/utility/split_transcripts/main.nf b/modules/local/utility/split_transcripts/main.nf index f24773d4..29632736 100644 --- a/modules/local/utility/split_transcripts/main.nf +++ b/modules/local/utility/split_transcripts/main.nf @@ -2,7 +2,7 @@ process SPLIT_TRANSCRIPTS { tag "$meta.id" label 'process_low' - container "ghcr.io/scverse/spatialdata:spatialdata0.3.0_spatialdata-io0.1.7_spatialdata-plot0.2.9" + container "community.wave.seqera.io/library/pip_pandas:5c59aaec7d5d4750" input: tuple val(meta), path(transcripts) @@ -10,22 +10,31 @@ process SPLIT_TRANSCRIPTS { val(y_bins) output: - tuple val(meta), path("splits.csv"), emit: splits_csv - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/splits.csv"), emit: splits_csv + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when script: + // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "SPLIT_TRANSCRIPTS module does not support Conda. Please use Docker / Singularity / Podman instead." } + def prefix = task.ext.prefix ?: "${meta.id}" template 'split_transcripts.py' stub: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "SPLIT_TRANSCRIPTS module does not support Conda. Please use Docker / Singularity / Podman instead." + } + def prefix = task.ext.prefix ?: "${meta.id}" """ - touch ${transcripts}.parquet + mkdir -p ${prefix} + touch "${prefix}/${transcripts}.parquet" + cat <<-END_VERSIONS > versions.yml "${task.process}": baysor_split_parquet: "1.0.0" diff --git a/modules/local/utility/split_transcripts/templates/split_transcripts.py b/modules/local/utility/split_transcripts/templates/split_transcripts.py index 9392b16f..dea42502 100644 --- a/modules/local/utility/split_transcripts/templates/split_transcripts.py +++ b/modules/local/utility/split_transcripts/templates/split_transcripts.py @@ -49,7 +49,8 @@ def generate_version_yml() -> None: def main( transcripts: str, x_bins: int = 10, - y_bins: int = 10 + y_bins: int = 10, + prefix: str = "" ) -> None: """ Generate splits @@ -61,7 +62,7 @@ def main( tiles_df = make_tiles(df, x_bins, y_bins) # save parquet file - tiles_df.to_csv("splits.csv", index=False) + tiles_df.to_csv(f"{prefix}/splits.csv", index=False) # generate version yml generate_version_yml() @@ -74,5 +75,6 @@ def main( transcripts: str = "${transcripts}" x_bins: int = "${x_bins}" y_bins: int = "${y_bins}" + prefix: str = "${prefix}" main(transcripts=transcripts, x_bins=x_bins, y_bins=y_bins) diff --git a/modules/nf-core/cellpose/cellpose.diff b/modules/nf-core/cellpose/cellpose.diff index 0f62b54d..ee24bf20 100644 --- a/modules/nf-core/cellpose/cellpose.diff +++ b/modules/nf-core/cellpose/cellpose.diff @@ -14,13 +14,22 @@ Changes in 'cellpose/main.nf': - tuple val(meta), path("*masks.tif") , emit: mask - tuple val(meta), path("*flows.tif") , emit: flows, optional: true - path "versions.yml" , emit: versions -+ tuple val(meta), path("${meta.id}/*masks.tif"), emit: mask -+ tuple val(meta), path("${meta.id}/*flows.tif"), emit: flows, optional: true -+ tuple val(meta), path("${meta.id}/*seg.npy") , emit: cells, optional: true -+ path "versions.yml" , emit: versions ++ tuple val(meta), path("${prefix}/*masks.tif"), emit: mask ++ tuple val(meta), path("${prefix}/*flows.tif"), emit: flows, optional: true ++ tuple val(meta), path("${prefix}/*seg.npy") , emit: cells, optional: true ++ path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when +@@ -19,7 +21,7 @@ + script: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { +- error "I did not manage to create a cellpose module in Conda that works in all OSes. Please use Docker / Singularity / Podman instead." ++ error "CELLPOSE module does not support conda. Please use Docker / Singularity / Podman instead." + } + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" @@ -27,29 +29,38 @@ """ export OMP_NUM_THREADS=${task.cpus} @@ -44,7 +53,8 @@ Changes in 'cellpose/main.nf': stub: // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { - error "I did not manage to create a cellpose module in Conda that works in all OSes. Please use Docker / Singularity / Podman instead." +- error "I did not manage to create a cellpose module in Conda that works in all OSes. Please use Docker / Singularity / Podman instead." ++ error "CELLPOSE module does not support conda. Please use Docker / Singularity / Podman instead." } + def prefix = task.ext.prefix ?: "${meta.id}" diff --git a/modules/nf-core/cellpose/main.nf b/modules/nf-core/cellpose/main.nf index 696a2da0..9b815096 100644 --- a/modules/nf-core/cellpose/main.nf +++ b/modules/nf-core/cellpose/main.nf @@ -10,10 +10,10 @@ process CELLPOSE { val(maskname) output: - tuple val(meta), path("${meta.id}/*masks.tif"), emit: mask - tuple val(meta), path("${meta.id}/*flows.tif"), emit: flows, optional: true - tuple val(meta), path("${meta.id}/*seg.npy") , emit: cells, optional: true - path "versions.yml" , emit: versions + tuple val(meta), path("${prefix}/*masks.tif"), emit: mask + tuple val(meta), path("${prefix}/*flows.tif"), emit: flows, optional: true + tuple val(meta), path("${prefix}/*seg.npy") , emit: cells, optional: true + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -21,7 +21,7 @@ process CELLPOSE { script: // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { - error "I did not manage to create a cellpose module in Conda that works in all OSes. Please use Docker / Singularity / Podman instead." + error "CELLPOSE module does not support conda. Please use Docker / Singularity / Podman instead." } def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" @@ -48,7 +48,7 @@ process CELLPOSE { stub: // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { - error "I did not manage to create a cellpose module in Conda that works in all OSes. Please use Docker / Singularity / Podman instead." + error "CELLPOSE module does not support conda. Please use Docker / Singularity / Podman instead." } def prefix = task.ext.prefix ?: "${meta.id}" diff --git a/modules/nf-core/opt/flip/main.nf b/modules/nf-core/opt/flip/main.nf index fa98c4f0..cb0ef65f 100644 --- a/modules/nf-core/opt/flip/main.nf +++ b/modules/nf-core/opt/flip/main.nf @@ -9,8 +9,8 @@ process OPT_FLIP { tuple val(meta2), path(ref_annot_gff), path(ref_annot_fa) output: - tuple val(meta), path("${meta.id}/fwd_oriented.fa"), emit: fwd_oriented_fa - path "versions.yml" , emit: versions + tuple val(meta), path("${prefix}/fwd_oriented.fa"), emit: fwd_oriented_fa + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/nf-core/opt/flip/opt-flip.diff b/modules/nf-core/opt/flip/opt-flip.diff new file mode 100644 index 00000000..4ffda377 --- /dev/null +++ b/modules/nf-core/opt/flip/opt-flip.diff @@ -0,0 +1,20 @@ +Changes in component 'nf-core/opt/flip' +Changes in 'opt/flip/main.nf': +--- modules/nf-core/opt/flip/main.nf ++++ modules/nf-core/opt/flip/main.nf +@@ -9,8 +9,8 @@ + tuple val(meta2), path(ref_annot_gff), path(ref_annot_fa) + + output: +- tuple val(meta), path("${meta.id}/fwd_oriented.fa"), emit: fwd_oriented_fa +- path "versions.yml" , emit: versions ++ tuple val(meta), path("${prefix}/fwd_oriented.fa"), emit: fwd_oriented_fa ++ path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + +'modules/nf-core/opt/flip/meta.yml' is unchanged +'modules/nf-core/opt/flip/tests/main.nf.test' is unchanged +'modules/nf-core/opt/flip/tests/main.nf.test.snap' is unchanged +************************************************************ diff --git a/modules/nf-core/opt/stat/main.nf b/modules/nf-core/opt/stat/main.nf index b4e2875e..bd0b0225 100644 --- a/modules/nf-core/opt/stat/main.nf +++ b/modules/nf-core/opt/stat/main.nf @@ -10,8 +10,8 @@ process OPT_STAT { path(gene_synonyms) output: - tuple val(meta), path("${meta.id}/collapsed_summary.tsv"), emit: summary - path "versions.yml" , emit: versions + tuple val(meta), path("${prefix}/collapsed_summary.tsv"), emit: summary + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/nf-core/opt/stat/opt-stat.diff b/modules/nf-core/opt/stat/opt-stat.diff new file mode 100644 index 00000000..b1c612d4 --- /dev/null +++ b/modules/nf-core/opt/stat/opt-stat.diff @@ -0,0 +1,20 @@ +Changes in component 'nf-core/opt/stat' +Changes in 'opt/stat/main.nf': +--- modules/nf-core/opt/stat/main.nf ++++ modules/nf-core/opt/stat/main.nf +@@ -10,8 +10,8 @@ + path(gene_synonyms) + + output: +- tuple val(meta), path("${meta.id}/collapsed_summary.tsv"), emit: summary +- path "versions.yml" , emit: versions ++ tuple val(meta), path("${prefix}/collapsed_summary.tsv"), emit: summary ++ path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + +'modules/nf-core/opt/stat/meta.yml' is unchanged +'modules/nf-core/opt/stat/tests/main.nf.test' is unchanged +'modules/nf-core/opt/stat/tests/main.nf.test.snap' is unchanged +************************************************************ diff --git a/modules/nf-core/opt/track/main.nf b/modules/nf-core/opt/track/main.nf index fc99a3e5..c6bffaf7 100644 --- a/modules/nf-core/opt/track/main.nf +++ b/modules/nf-core/opt/track/main.nf @@ -9,8 +9,8 @@ process OPT_TRACK { tuple val(meta2), path(ref_annot_gff), path(ref_annot_fa) output: - tuple val(meta), path("${meta.id}/probe2targets.tsv"), emit: probes2target - path "versions.yml" , emit: versions + tuple val(meta), path("${prefix}/probe2targets.tsv"), emit: probes2target + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/nf-core/opt/track/opt-track.diff b/modules/nf-core/opt/track/opt-track.diff new file mode 100644 index 00000000..b1a2a9ca --- /dev/null +++ b/modules/nf-core/opt/track/opt-track.diff @@ -0,0 +1,20 @@ +Changes in component 'nf-core/opt/track' +Changes in 'opt/track/main.nf': +--- modules/nf-core/opt/track/main.nf ++++ modules/nf-core/opt/track/main.nf +@@ -9,8 +9,8 @@ + tuple val(meta2), path(ref_annot_gff), path(ref_annot_fa) + + output: +- tuple val(meta), path("${meta.id}/probe2targets.tsv"), emit: probes2target +- path "versions.yml" , emit: versions ++ tuple val(meta), path("${prefix}/probe2targets.tsv"), emit: probes2target ++ path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + +'modules/nf-core/opt/track/meta.yml' is unchanged +'modules/nf-core/opt/track/tests/main.nf.test' is unchanged +'modules/nf-core/opt/track/tests/main.nf.test.snap' is unchanged +************************************************************ diff --git a/modules/nf-core/xeniumranger/import-segmentation/main.nf b/modules/nf-core/xeniumranger/import-segmentation/main.nf index f60b3dee..a884886c 100644 --- a/modules/nf-core/xeniumranger/import-segmentation/main.nf +++ b/modules/nf-core/xeniumranger/import-segmentation/main.nf @@ -15,8 +15,8 @@ process XENIUMRANGER_IMPORT_SEGMENTATION { val(units) output: - tuple val(meta), path("${meta.id}/outs"), emit: bundle - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/outs"), emit: bundle + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff b/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff index c1748b2d..0c2c7755 100644 --- a/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff +++ b/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff @@ -29,8 +29,8 @@ Changes in 'xeniumranger/import-segmentation/main.nf': output: - tuple val(meta), path("**/outs/**"), emit: outs - path "versions.yml", emit: versions -+ tuple val(meta), path("${meta.id}/outs"), emit: bundle -+ path("versions.yml") , emit: versions ++ tuple val(meta), path("${prefix}/outs"), emit: bundle ++ path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/nf-core/xeniumranger/relabel/main.nf b/modules/nf-core/xeniumranger/relabel/main.nf index e500fa08..b4f11f10 100644 --- a/modules/nf-core/xeniumranger/relabel/main.nf +++ b/modules/nf-core/xeniumranger/relabel/main.nf @@ -9,7 +9,7 @@ process XENIUMRANGER_RELABEL { path(gene_panel) output: - tuple val(meta), path("${meta.id}/outs"), emit: bundle + tuple val(meta), path("${prefix}/outs"), emit: bundle path("versions.yml") , emit: versions when: diff --git a/modules/nf-core/xeniumranger/relabel/xeniumranger-relabel.diff b/modules/nf-core/xeniumranger/relabel/xeniumranger-relabel.diff index a5a3afbb..3963a558 100644 --- a/modules/nf-core/xeniumranger/relabel/xeniumranger-relabel.diff +++ b/modules/nf-core/xeniumranger/relabel/xeniumranger-relabel.diff @@ -16,7 +16,7 @@ Changes in 'xeniumranger/relabel/main.nf': output: - tuple val(meta), path("**/outs/**"), emit: outs - path "versions.yml", emit: versions -+ tuple val(meta), path("${meta.id}/outs"), emit: bundle ++ tuple val(meta), path("${prefix}/outs"), emit: bundle + path("versions.yml") , emit: versions when: diff --git a/modules/nf-core/xeniumranger/resegment/main.nf b/modules/nf-core/xeniumranger/resegment/main.nf index cdeef0db..76babbe1 100644 --- a/modules/nf-core/xeniumranger/resegment/main.nf +++ b/modules/nf-core/xeniumranger/resegment/main.nf @@ -8,7 +8,7 @@ process XENIUMRANGER_RESEGMENT { tuple val(meta), path(xenium_bundle) output: - tuple val(meta), path("${meta.id}/outs"), emit: bundle + tuple val(meta), path("${prefix}/outs"), emit: bundle path("versions.yml") , emit: versions when: diff --git a/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff b/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff index 24c817e2..085822c6 100644 --- a/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff +++ b/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff @@ -19,7 +19,7 @@ Changes in 'xeniumranger/resegment/main.nf': output: - tuple val(meta), path("**/outs/**"), emit: outs - path "versions.yml", emit: versions -+ tuple val(meta), path("${meta.id}/outs"), emit: bundle ++ tuple val(meta), path("${prefix}/outs"), emit: bundle + path("versions.yml") , emit: versions when: From e08e2d4979da7415cae055b58ad40fb876927595 Mon Sep 17 00:00:00 2001 From: Sameesh Kher Date: Tue, 23 Sep 2025 16:26:25 +0000 Subject: [PATCH 08/12] reverting changes --- conf/modules.config | 20 +++++++++++++++++++ modules/local/baysor/create_dataset/main.nf | 4 ++-- modules/local/baysor/preprocess/main.nf | 4 ++-- modules/local/baysor/preview/main.nf | 2 +- modules/local/baysor/run/main.nf | 6 +++--- modules/local/baysor/segfree/main.nf | 4 ++-- modules/local/proseg/preset/main.nf | 4 ++-- modules/local/proseg/proseg2baysor/main.nf | 4 ++-- modules/local/resolift/main.nf | 4 ++-- modules/local/spatialdata/merge/main.nf | 4 ++-- modules/local/spatialdata/meta/main.nf | 4 ++-- modules/local/spatialdata/write/main.nf | 4 ++-- modules/local/utility/segger2xr/main.nf | 4 ++-- .../spatialconverter/parquet_to_csv/main.nf | 4 ++-- .../local/utility/split_transcripts/main.nf | 4 ++-- modules/nf-core/cellpose/main.nf | 8 ++++---- modules/nf-core/opt/flip/main.nf | 4 ++-- modules/nf-core/opt/stat/main.nf | 4 ++-- modules/nf-core/opt/track/main.nf | 4 ++-- .../xeniumranger/import-segmentation/main.nf | 4 ++-- .../xeniumranger-import-segmentation.diff | 4 ++-- modules/nf-core/xeniumranger/relabel/main.nf | 2 +- .../nf-core/xeniumranger/resegment/main.nf | 2 +- .../resegment/xeniumranger-resegment.diff | 2 +- .../baysor_run_transcripts_parquet/main.nf | 3 +-- 25 files changed, 66 insertions(+), 47 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 232e504b..57ecf36c 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -152,4 +152,24 @@ process { ext.args = { "--diameter 9 --channel_axis 0 --save_flows" } } + withName: OPT_FLIP { + publishDir = [ + path: { "${params.outdir}/opt/flip" }, + mode: params.publish_dir_mode, + ] + } + + withName: OPT_TRACK { + publishDir = [ + path: { "${params.outdir}/opt/track" }, + mode: params.publish_dir_mode, + ] + } + + withName: OPT_STAT { + publishDir = [ + path: { "${params.outdir}/opt/stat" }, + mode: params.publish_dir_mode, + ] + } } diff --git a/modules/local/baysor/create_dataset/main.nf b/modules/local/baysor/create_dataset/main.nf index 6db53a90..2e1cf670 100644 --- a/modules/local/baysor/create_dataset/main.nf +++ b/modules/local/baysor/create_dataset/main.nf @@ -9,8 +9,8 @@ process BAYSOR_CREATE_DATASET { val(sample_fraction) output: - tuple val(meta), path("${prefix}/sampled_transcripts.csv"), emit: sampled_transcripts - path("versions.yml") , emit: versions + tuple val(meta), path("${meta.id}/sampled_transcripts.csv"), emit: sampled_transcripts + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/baysor/preprocess/main.nf b/modules/local/baysor/preprocess/main.nf index a5bedbd5..8e14ccac 100644 --- a/modules/local/baysor/preprocess/main.nf +++ b/modules/local/baysor/preprocess/main.nf @@ -14,8 +14,8 @@ process BAYSOR_PREPROCESS_TRANSCRIPTS { output: tuple val(meta), - path("${prefix}/filtered_transcripts.parquet"), emit: transcripts_parquet - path("versions.yml") , emit: versions + path("${meta.id}/filtered_transcripts.parquet"), emit: transcripts_parquet + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/baysor/preview/main.nf b/modules/local/baysor/preview/main.nf index b62b7fe4..a641d468 100644 --- a/modules/local/baysor/preview/main.nf +++ b/modules/local/baysor/preview/main.nf @@ -9,7 +9,7 @@ process BAYSOR_PREVIEW { path(config) output: - tuple val(meta), path("${prefix}/preview.html"), emit: preview_html + tuple val(meta), path("${meta.id}/preview.html"), emit: preview_html path("versions.yml") , emit: versions when: diff --git a/modules/local/baysor/run/main.nf b/modules/local/baysor/run/main.nf index d93c040c..485059fd 100644 --- a/modules/local/baysor/run/main.nf +++ b/modules/local/baysor/run/main.nf @@ -12,9 +12,9 @@ process BAYSOR_RUN { output: tuple val(meta), - path("${prefix}/segmentation.csv"), - path("${prefix}/segmentation_polygons_2d.json"), emit: segmentation - path("versions.yml") , emit: versions + path("${meta.id}/segmentation.csv"), + path("${meta.id}/segmentation_polygons_2d.json"), emit: segmentation + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/baysor/segfree/main.nf b/modules/local/baysor/segfree/main.nf index 32cd1cf3..830de65e 100644 --- a/modules/local/baysor/segfree/main.nf +++ b/modules/local/baysor/segfree/main.nf @@ -9,8 +9,8 @@ process BAYSOR_SEGFREE { path(config) output: - tuple val(meta), path("${prefix}/ncvs.loom"), emit: ncvs - path("versions.yml") , emit: versions + tuple val(meta), path("${meta.id}/ncvs.loom"), emit: ncvs + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/proseg/preset/main.nf b/modules/local/proseg/preset/main.nf index ce64b7f0..be8faed9 100644 --- a/modules/local/proseg/preset/main.nf +++ b/modules/local/proseg/preset/main.nf @@ -9,8 +9,8 @@ process PROSEG { output: tuple val(meta), - path("${prefix}/cell-polygons.geojson.gz"), - path("${prefix}/transcript-metadata.csv.gz"), emit: seg_outs + path("${meta.id}/cell-polygons.geojson.gz"), + path("${meta.id}/transcript-metadata.csv.gz"), emit: seg_outs path("versions.yml") , emit: versions when: diff --git a/modules/local/proseg/proseg2baysor/main.nf b/modules/local/proseg/proseg2baysor/main.nf index ada63c7d..09e9e3d6 100644 --- a/modules/local/proseg/proseg2baysor/main.nf +++ b/modules/local/proseg/proseg2baysor/main.nf @@ -8,8 +8,8 @@ process PROSEG2BAYSOR { tuple val(meta), path(cell_polygons), path(transcript_metadata) output: - tuple val(meta), path("${prefix}/cell-polygons.geojson") , emit: xr_polygons - tuple val(meta), path("${prefix}/transcript-metadata.csv"), emit: xr_metadata + tuple val(meta), path("${meta.id}/cell-polygons.geojson") , emit: xr_polygons + tuple val(meta), path("${meta.id}/transcript-metadata.csv"), emit: xr_metadata path("versions.yml") , emit: versions script: diff --git a/modules/local/resolift/main.nf b/modules/local/resolift/main.nf index 3ab86cf6..c7467c92 100644 --- a/modules/local/resolift/main.nf +++ b/modules/local/resolift/main.nf @@ -9,8 +9,8 @@ process RESOLIFT { output: tuple val(meta), - path("${prefix}/morphology.ome.enhanced.tiff"), emit: enhanced_tiff - path("versions.yml") , emit: versions + path("${meta.id}/morphology.ome.enhanced.tiff"), emit: enhanced_tiff + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/spatialdata/merge/main.nf b/modules/local/spatialdata/merge/main.nf index db2403d6..55a227c9 100644 --- a/modules/local/spatialdata/merge/main.nf +++ b/modules/local/spatialdata/merge/main.nf @@ -8,8 +8,8 @@ process SPATIALDATA_MERGE { tuple val(meta), path(raw_bundle, stageAs: "*"), path(redefined_bundle, stageAs: "*") output: - tuple val(meta), path("${prefix}/spatialdata_merged"), emit: merged_bundle - path("versions.yml") , emit: versions + tuple val(meta), path("${meta.id}/spatialdata_merged"), emit: merged_bundle + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/spatialdata/meta/main.nf b/modules/local/spatialdata/meta/main.nf index aa5d7ac4..2916cb9c 100644 --- a/modules/local/spatialdata/meta/main.nf +++ b/modules/local/spatialdata/meta/main.nf @@ -8,8 +8,8 @@ process SPATIALDATA_META { tuple val(meta), path(spatialdata_bundle, stageAs: "*"), path(xenium_bundle, stageAs: "*") output: - tuple val(meta), path("${prefix}/spatialdata_meta"), emit: metadata - path("versions.yml") , emit: versions + tuple val(meta), path("${meta.id}/spatialdata_meta"), emit: metadata + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/spatialdata/write/main.nf b/modules/local/spatialdata/write/main.nf index 723a5bee..7beb6786 100644 --- a/modules/local/spatialdata/write/main.nf +++ b/modules/local/spatialdata/write/main.nf @@ -11,8 +11,8 @@ process SPATIALDATA_WRITE { val(coordinate_space) output: - tuple val(meta), path("${prefix}/${outputfolder}"), emit: spatialdata - path("versions.yml") , emit: versions + tuple val(meta), path("${meta.id}/${outputfolder}"), emit: spatialdata + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/utility/segger2xr/main.nf b/modules/local/utility/segger2xr/main.nf index 63dcdad6..15e50835 100644 --- a/modules/local/utility/segger2xr/main.nf +++ b/modules/local/utility/segger2xr/main.nf @@ -8,8 +8,8 @@ process SEGGER2XR { tuple val(meta), path(transcripts) output: - tuple val(meta), path("${prefix}/transcripts.parquet"), emit: transcripts_parquet - path("versions.yml") , emit: versions + tuple val(meta), path("${meta.id}/transcripts.parquet"), emit: transcripts_parquet + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/utility/spatialconverter/parquet_to_csv/main.nf b/modules/local/utility/spatialconverter/parquet_to_csv/main.nf index 4a75fd24..1637717e 100644 --- a/modules/local/utility/spatialconverter/parquet_to_csv/main.nf +++ b/modules/local/utility/spatialconverter/parquet_to_csv/main.nf @@ -9,8 +9,8 @@ process PARQUET_TO_CSV { val(extension) output: - tuple val(meta), path("${prefix}/*.csv*"), emit: transcripts_csv - path("versions.yml") , emit: versions + tuple val(meta), path("${meta.id}/*.csv*"), emit: transcripts_csv + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/utility/split_transcripts/main.nf b/modules/local/utility/split_transcripts/main.nf index 29632736..5f89d9d1 100644 --- a/modules/local/utility/split_transcripts/main.nf +++ b/modules/local/utility/split_transcripts/main.nf @@ -10,8 +10,8 @@ process SPLIT_TRANSCRIPTS { val(y_bins) output: - tuple val(meta), path("${prefix}/splits.csv"), emit: splits_csv - path("versions.yml") , emit: versions + tuple val(meta), path("${meta.id}/splits.csv"), emit: splits_csv + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/nf-core/cellpose/main.nf b/modules/nf-core/cellpose/main.nf index 9b815096..b6cd71c4 100644 --- a/modules/nf-core/cellpose/main.nf +++ b/modules/nf-core/cellpose/main.nf @@ -10,10 +10,10 @@ process CELLPOSE { val(maskname) output: - tuple val(meta), path("${prefix}/*masks.tif"), emit: mask - tuple val(meta), path("${prefix}/*flows.tif"), emit: flows, optional: true - tuple val(meta), path("${prefix}/*seg.npy") , emit: cells, optional: true - path "versions.yml" , emit: versions + tuple val(meta), path("${meta.id}/*masks.tif"), emit: mask + tuple val(meta), path("${meta.id}/*flows.tif"), emit: flows, optional: true + tuple val(meta), path("${meta.id}/*seg.npy") , emit: cells, optional: true + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/nf-core/opt/flip/main.nf b/modules/nf-core/opt/flip/main.nf index cb0ef65f..fa98c4f0 100644 --- a/modules/nf-core/opt/flip/main.nf +++ b/modules/nf-core/opt/flip/main.nf @@ -9,8 +9,8 @@ process OPT_FLIP { tuple val(meta2), path(ref_annot_gff), path(ref_annot_fa) output: - tuple val(meta), path("${prefix}/fwd_oriented.fa"), emit: fwd_oriented_fa - path "versions.yml" , emit: versions + tuple val(meta), path("${meta.id}/fwd_oriented.fa"), emit: fwd_oriented_fa + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/nf-core/opt/stat/main.nf b/modules/nf-core/opt/stat/main.nf index bd0b0225..85d74a24 100644 --- a/modules/nf-core/opt/stat/main.nf +++ b/modules/nf-core/opt/stat/main.nf @@ -10,8 +10,8 @@ process OPT_STAT { path(gene_synonyms) output: - tuple val(meta), path("${prefix}/collapsed_summary.tsv"), emit: summary - path "versions.yml" , emit: versions + tuple val(meta), path("${meta.id}/collapsed_summary.tsv"), emit: summary + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/nf-core/opt/track/main.nf b/modules/nf-core/opt/track/main.nf index c6bffaf7..fc99a3e5 100644 --- a/modules/nf-core/opt/track/main.nf +++ b/modules/nf-core/opt/track/main.nf @@ -9,8 +9,8 @@ process OPT_TRACK { tuple val(meta2), path(ref_annot_gff), path(ref_annot_fa) output: - tuple val(meta), path("${prefix}/probe2targets.tsv"), emit: probes2target - path "versions.yml" , emit: versions + tuple val(meta), path("${meta.id}/probe2targets.tsv"), emit: probes2target + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/nf-core/xeniumranger/import-segmentation/main.nf b/modules/nf-core/xeniumranger/import-segmentation/main.nf index a884886c..1fce274e 100644 --- a/modules/nf-core/xeniumranger/import-segmentation/main.nf +++ b/modules/nf-core/xeniumranger/import-segmentation/main.nf @@ -15,8 +15,8 @@ process XENIUMRANGER_IMPORT_SEGMENTATION { val(units) output: - tuple val(meta), path("${prefix}/outs"), emit: bundle - path("versions.yml") , emit: versions + tuple val(meta), path("${meta.id}/outs"), emit: bundle + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff b/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff index 0c2c7755..d4e402f6 100644 --- a/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff +++ b/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff @@ -29,8 +29,8 @@ Changes in 'xeniumranger/import-segmentation/main.nf': output: - tuple val(meta), path("**/outs/**"), emit: outs - path "versions.yml", emit: versions -+ tuple val(meta), path("${prefix}/outs"), emit: bundle -+ path("versions.yml") , emit: versions ++ tuple val(meta), path("${meta.id}/outs"), emit: bundle ++ path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/nf-core/xeniumranger/relabel/main.nf b/modules/nf-core/xeniumranger/relabel/main.nf index b4f11f10..e500fa08 100644 --- a/modules/nf-core/xeniumranger/relabel/main.nf +++ b/modules/nf-core/xeniumranger/relabel/main.nf @@ -9,7 +9,7 @@ process XENIUMRANGER_RELABEL { path(gene_panel) output: - tuple val(meta), path("${prefix}/outs"), emit: bundle + tuple val(meta), path("${meta.id}/outs"), emit: bundle path("versions.yml") , emit: versions when: diff --git a/modules/nf-core/xeniumranger/resegment/main.nf b/modules/nf-core/xeniumranger/resegment/main.nf index 76babbe1..cdeef0db 100644 --- a/modules/nf-core/xeniumranger/resegment/main.nf +++ b/modules/nf-core/xeniumranger/resegment/main.nf @@ -8,7 +8,7 @@ process XENIUMRANGER_RESEGMENT { tuple val(meta), path(xenium_bundle) output: - tuple val(meta), path("${prefix}/outs"), emit: bundle + tuple val(meta), path("${meta.id}/outs"), emit: bundle path("versions.yml") , emit: versions when: diff --git a/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff b/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff index 085822c6..24c817e2 100644 --- a/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff +++ b/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff @@ -19,7 +19,7 @@ Changes in 'xeniumranger/resegment/main.nf': output: - tuple val(meta), path("**/outs/**"), emit: outs - path "versions.yml", emit: versions -+ tuple val(meta), path("${prefix}/outs"), emit: bundle ++ tuple val(meta), path("${meta.id}/outs"), emit: bundle + path("versions.yml") , emit: versions when: diff --git a/subworkflows/local/baysor_run_transcripts_parquet/main.nf b/subworkflows/local/baysor_run_transcripts_parquet/main.nf index 9d18893e..d24c1a1a 100644 --- a/subworkflows/local/baysor_run_transcripts_parquet/main.nf +++ b/subworkflows/local/baysor_run_transcripts_parquet/main.nf @@ -88,8 +88,7 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET { ch_imp_seg_inputs = ch_bundle_path .combine(BAYSOR_RUN.out.segmentation, by: 0) .map { - meta, bundle, segmentation_outs -> - def ( _meta, segmentation_csv, polygons2d ) = segmentation_outs + meta, bundle, segmentation_csv, polygons2d -> tuple ( meta, // meta bundle, // bundle From 40b1c0daa938d3857cf9a9fc8d5a768b28e8e85b Mon Sep 17 00:00:00 2001 From: Sameesh Kher Date: Tue, 23 Sep 2025 22:43:51 +0000 Subject: [PATCH 09/12] sample buffering and other minor changes --- nextflow.config | 4 ++++ nextflow_schema.json | 10 ++++++++++ workflows/spatialxe.nf | 17 +++++++++++++---- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/nextflow.config b/nextflow.config index de804e34..98d12f5f 100644 --- a/nextflow.config +++ b/nextflow.config @@ -81,6 +81,10 @@ params { max_multiqc_email_size = '25.MB' multiqc_methods_description = null + // pipeline dev and testing option + buffer_samples = false // process one sample at a time from the multi-sample samplesheet + buffer_size = 0 // buffer size 0 means no buffering of samples + // Boilerplate options outdir = null publish_dir_mode = 'copy' diff --git a/nextflow_schema.json b/nextflow_schema.json index d6449899..2f539844 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -259,6 +259,16 @@ "type": "boolean", "description": "Whether to use connected components for grouping transcripts without direct nucleus association", "default": false + }, + "buffer_samples": { + "type": "boolean", + "description": "Process only one sample at a time from a multi-sample samplesheet.", + "default": false + }, + "buffer_size": { + "type": "integer", + "description": "Number of sample(s) to process at a time from a multi-sample samplesheet. Works if buffered_samples is true.", + "default": 0 } } }, diff --git a/workflows/spatialxe.nf b/workflows/spatialxe.nf index 6ac5a11e..4f8d40c0 100644 --- a/workflows/spatialxe.nf +++ b/workflows/spatialxe.nf @@ -107,10 +107,19 @@ workflow SPATIALXE { } .set { ch_input } - } else { - - // for all other profile runs - ch_input = ch_samplesheet + } else { // for all other profile runs + + // check if samples are buffered + if ( params.buffer_samples ) { + ch_input = ch_samplesheet.buffer ( size: params.buffer_size ) + .map + { buffered_sample -> + def (meta, bundle, tif) = buffered_sample[0] + tuple(meta, bundle, tif) + } + } else { + ch_input = ch_samplesheet + } } // path to bundle input From b44b561867952c18072467d08406f93f1c2036e7 Mon Sep 17 00:00:00 2001 From: Sameesh Kher Date: Wed, 24 Sep 2025 01:14:13 +0000 Subject: [PATCH 10/12] sample buffering and other channel fixes for baysor --- modules/local/baysor/run/main.nf | 9 +-- modules/nf-core/cellpose/main.nf | 1 + nextflow.config | 3 +- nextflow_schema.json | 2 +- .../main.nf | 24 +++++-- .../baysor_run_transcripts_parquet/main.nf | 43 ++++------- .../main.nf | 71 +++++++++++-------- .../main.nf | 41 ++--------- 8 files changed, 85 insertions(+), 109 deletions(-) diff --git a/modules/local/baysor/run/main.nf b/modules/local/baysor/run/main.nf index 485059fd..aab444db 100644 --- a/modules/local/baysor/run/main.nf +++ b/modules/local/baysor/run/main.nf @@ -5,10 +5,11 @@ process BAYSOR_RUN { container "khersameesh24/baysor:0.7.1" input: - tuple val(meta), path(transcripts) - path(prior_segmentation) - path(config) - val(scale) + tuple val(meta), + path(transcripts), + path(prior_segmentation), + path(config), + val(scale) output: tuple val(meta), diff --git a/modules/nf-core/cellpose/main.nf b/modules/nf-core/cellpose/main.nf index b6cd71c4..31e6bde2 100644 --- a/modules/nf-core/cellpose/main.nf +++ b/modules/nf-core/cellpose/main.nf @@ -58,6 +58,7 @@ process CELLPOSE { """ mkdir -p ${prefix} touch ${prefix}/morphology.ome_${maskname}_masks.tif + touch ${prefix}/morphology.ome_${maskname}_seg.npy touch ${base}_cp_masks.tif cat <<-END_VERSIONS > versions.yml diff --git a/nextflow.config b/nextflow.config index 98d12f5f..4ac065c8 100644 --- a/nextflow.config +++ b/nextflow.config @@ -83,7 +83,8 @@ params { // pipeline dev and testing option buffer_samples = false // process one sample at a time from the multi-sample samplesheet - buffer_size = 0 // buffer size 0 means no buffering of samples + buffer_size = 1 // buffer size 0 means no buffering of samples + restrict_concurrency = false // // Boilerplate options outdir = null diff --git a/nextflow_schema.json b/nextflow_schema.json index 2f539844..3b99eea2 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -268,7 +268,7 @@ "buffer_size": { "type": "integer", "description": "Number of sample(s) to process at a time from a multi-sample samplesheet. Works if buffered_samples is true.", - "default": 0 + "default": 1 } } }, diff --git a/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf b/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf index 62987e72..ebef6af4 100644 --- a/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf +++ b/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf @@ -45,15 +45,25 @@ workflow BAYSOR_RUN_PRIOR_SEGMENTATION_MASK { ch_transcripts = ch_transcripts_parquet } - // run baysor with morphology.tiff - BAYSOR_RUN ( - ch_transcripts, - ch_segmentation_mask, - ch_config, - 30 - ) + + // run baysor with prior segmentation mask + ch_baysor_input = ch_transcripts + .combine(ch_segmentation_mask) + .combine(ch_config) + .map { meta, transcripts, mask, config -> + tuple ( + meta, // meta + transcripts, // transcripts + mask, // prior_segmentation + config, // config + 30 // scale + ) + } + + BAYSOR_RUN ( ch_baysor_input ) ch_versions = ch_versions.mix( BAYSOR_RUN.out.versions ) + // run import-segmentation with baysor outs ch_imp_seg_inputs = ch_bundle_path .combine(BAYSOR_RUN.out.segmentation, by: 0) diff --git a/subworkflows/local/baysor_run_transcripts_parquet/main.nf b/subworkflows/local/baysor_run_transcripts_parquet/main.nf index d24c1a1a..d09827bb 100644 --- a/subworkflows/local/baysor_run_transcripts_parquet/main.nf +++ b/subworkflows/local/baysor_run_transcripts_parquet/main.nf @@ -27,31 +27,6 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET { ch_coordinate_space = Channel.value("microns") // TODO: run baysor in parallel - next release issue - // generate splits - // SPLIT_TRANSCRIPTS ( - // ch_transcripts_parquet, - // params.x_bins, - // params.y_bins - // ) - // ch_versions = ch_versions.mix ( SPLIT_TRANSCRIPTS.out.versions ) - - // ch_splits_csv = SPLIT_TRANSCRIPTS.out.splits_csv - - - // Set splits.csv into tuple queue channel - // Channel - // ch_splits_csv - // .flatMap { meta, splits_file -> - // splits_file.splitCsv(header: true).collect { row -> - // tuple(meta, row.tile_id, row.x_min, row.x_max, row.y_min, row.y_max) - // } - // } - // .set { ch_splits } // channel: [ val(tile_id), val(x_min), val(x_max), val(y_min), val(y_max) ] - - - //Add in sample path for each split value - // transcripts_input = ch_transcripts_parquet.combine(ch_splits, by: 0) - // filter transcripts.parquet based on thresholds if ( params.filter_transcripts ) { @@ -75,12 +50,18 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET { // run baysor with the filtered transcripts.parquet - BAYSOR_RUN ( - ch_transcripts, - [], - ch_config, - 30 - ) + ch_baysor_input = ch_transcripts + .combine(ch_config) + .map { meta, transcripts, config -> + tuple ( + meta, // meta + transcripts, // transcripts + [], // prior_segmentation + config, // config + 30 // scale + ) + } + BAYSOR_RUN ( ch_baysor_input ) ch_versions = ch_versions.mix ( BAYSOR_RUN.out.versions ) diff --git a/subworkflows/local/cellpose_baysor_import_segmentation/main.nf b/subworkflows/local/cellpose_baysor_import_segmentation/main.nf index f4f526ea..dda337e5 100644 --- a/subworkflows/local/cellpose_baysor_import_segmentation/main.nf +++ b/subworkflows/local/cellpose_baysor_import_segmentation/main.nf @@ -42,22 +42,13 @@ workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { } + // run cellpose on the morphology (enhanced) tiff if ( params.cell_segmentation_only ) { CELLPOSE_CELLS ( ch_image, cellpose_model, 'cells' ) ch_versions = ch_versions.mix( CELLPOSE_CELLS.out.versions ) - _ch_cellpose_cells_cells = CELLPOSE_CELLS.out.cells.map { - _meta, cells -> return [ cells ] - } - ch_cellpose_cells_mask = CELLPOSE_CELLS.out.mask.map { - _meta, mask -> return [ mask ] - } - _ch_cellpose_cells_flows = CELLPOSE_CELLS.out.flows.map { - _meta, flows -> return [ flows ] - } - } if ( params.nucleus_segmentation_only ) { @@ -65,16 +56,6 @@ workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { CELLPOSE_NUCLEI ( ch_image, 'nuclei', 'nuclei' ) ch_versions = ch_versions.mix( CELLPOSE_NUCLEI.out.versions ) - _ch_cellpose_nuclei_cells = CELLPOSE_NUCLEI.out.cells.map { - _meta, cells -> return [ cells ] - } - ch_cellpose_nuclei_mask = CELLPOSE_NUCLEI.out.mask.map { - _meta, mask -> return [ mask ] - } - _ch_cellpose_nuclei_flows = CELLPOSE_NUCLEI.out.flows.map { - _meta, flows -> return [ flows ] - } - } @@ -103,19 +84,54 @@ workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { if ( params.nucleus_segmentation_only ) { // run baysor with nuclei mask - BAYSOR_RUN ( ch_transcripts, ch_cellpose_nuclei_mask, ch_config, 30 ) + ch_baysor_input = ch_transcripts + .combine(CELLPOSE_NUCLEI.out.mask, by: 0) + .combine(ch_config) + .map { meta, transcripts, mask, config -> + tuple ( + meta, // meta + transcripts, // transcripts + mask, // prior_segmentation + config, // config + 30 // scale + ) + } + BAYSOR_RUN ( ch_baysor_input ) ch_versions = ch_versions.mix ( BAYSOR_RUN.out.versions ) } else if ( params.cell_segmentation_only ) { // run baysor with cell mask - BAYSOR_RUN ( ch_transcripts, ch_cellpose_cells_mask, ch_config, 30 ) + ch_baysor_input = ch_transcripts + .combine(CELLPOSE_CELLS.out.mask, by: 0) + .combine(ch_config) + .map { meta, transcripts, mask, config -> + tuple ( + meta, // meta + transcripts, // transcripts + mask, // prior_segmentation + config, // config + 30 // scale + ) + } + BAYSOR_RUN ( ch_baysor_input ) ch_versions = ch_versions.mix ( BAYSOR_RUN.out.versions ) } else { - // run baysor with cell mask - BAYSOR_RUN ( ch_transcripts, [], ch_config, 30 ) + // run baysor without cell/nuclei mask + ch_baysor_input = ch_transcripts + .combine(ch_config) + .map { meta, transcripts, config -> + tuple ( + meta, // meta + transcripts, // transcripts + [], // prior_segmentation + config, // config + 30 // scale + ) + } + BAYSOR_RUN ( ch_baysor_input ) ch_versions = ch_versions.mix ( BAYSOR_RUN.out.versions ) } @@ -125,8 +141,7 @@ workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { ch_imp_seg_inputs = ch_bundle_path .combine(BAYSOR_RUN.out.segmentation, by: 0) .map { - meta, bundle, segmentation_outs -> - def ( _meta, segmentation_csv, polygons2d ) = segmentation_outs + meta, bundle, segmentation_csv, polygons2d -> tuple ( meta, // meta bundle, // bundle @@ -139,9 +154,7 @@ workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { ) } - XENIUMRANGER_IMPORT_SEGMENTATION ( - ch_imp_seg_inputs - ) + XENIUMRANGER_IMPORT_SEGMENTATION ( ch_imp_seg_inputs ) ch_versions = ch_versions.mix ( XENIUMRANGER_IMPORT_SEGMENTATION.out.versions ) emit: diff --git a/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf b/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf index 6e0f2e8e..5d5216aa 100644 --- a/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf +++ b/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf @@ -18,8 +18,6 @@ workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { ch_versions = Channel.empty() ch_imp_seg_inputs = Channel.empty() - ch_cellpose_nuclei_mask = Channel.empty() - ch_cellpose_cells_mask = Channel.empty() ch_coordinate_space = Channel.value("pixels") cellpose_model = params.cellpose_model ? (Channel.fromPath(params.cellpose_model, checkIfExists: true)) : [] @@ -39,40 +37,12 @@ workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { } // run cellpose on morphology tiff - if ( params.cell_segmentation_only ) { + CELLPOSE_CELLS ( ch_image, cellpose_model, 'cells' ) + ch_versions = ch_versions.mix( CELLPOSE_CELLS.out.versions ) - CELLPOSE_CELLS ( ch_image, cellpose_model, 'cells' ) - ch_versions = ch_versions.mix( CELLPOSE_CELLS.out.versions ) + CELLPOSE_NUCLEI ( ch_image, 'nuclei', 'nuclei' ) + ch_versions = ch_versions.mix( CELLPOSE_NUCLEI.out.versions ) - _ch_cellpose_cells_cells = CELLPOSE_CELLS.out.cells.map { - _meta, cells -> return [ cells ] - } - ch_cellpose_cells_mask = CELLPOSE_CELLS.out.mask.map { - _meta, mask -> return [ mask ] - } - _ch_cellpose_cells_flows = CELLPOSE_CELLS.out.flows.map { - _meta, flows -> return [ flows ] - } - - - - } - - if ( params.nucleus_segmentation_only ) { - - CELLPOSE_NUCLEI ( ch_image, 'nuclei', 'nuclei' ) - ch_versions = ch_versions.mix( CELLPOSE_NUCLEI.out.versions ) - - _ch_cellpose_nuclei_cells = CELLPOSE_NUCLEI.out.cells.map { - _meta, cells -> return [ cells ] - } - ch_cellpose_nuclei_mask = CELLPOSE_NUCLEI.out.mask.map { - _meta, mask -> return [ mask ] - } - _ch_cellpose_nuclei_flows = CELLPOSE_NUCLEI.out.flows.map { - _meta, flows -> return [ flows ] - } - } // run import-segmentation with cellpose results if ( params.nucleus_segmentation_only ) { @@ -92,7 +62,6 @@ workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { ch_coordinate_space.val // units ) } - XENIUMRANGER_IMPORT_SEGMENTATION ( ch_imp_seg_inputs ) @@ -115,7 +84,7 @@ workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { ch_coordinate_space.val // units ) } - + ch_imp_seg_inputs.view() XENIUMRANGER_IMPORT_SEGMENTATION ( ch_imp_seg_inputs ) From 3c6c1b3ca1fa8430e7e1660d5192ee54193ee9c4 Mon Sep 17 00:00:00 2001 From: Sameesh Kher Date: Wed, 24 Sep 2025 01:25:40 +0000 Subject: [PATCH 11/12] linting fix --- nextflow.config | 2 +- nextflow_schema.json | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/nextflow.config b/nextflow.config index 4ac065c8..69554676 100644 --- a/nextflow.config +++ b/nextflow.config @@ -84,7 +84,7 @@ params { // pipeline dev and testing option buffer_samples = false // process one sample at a time from the multi-sample samplesheet buffer_size = 1 // buffer size 0 means no buffering of samples - restrict_concurrency = false // + restrict_concurrency = false // restrict running certain process in parallel // Boilerplate options outdir = null diff --git a/nextflow_schema.json b/nextflow_schema.json index 3b99eea2..f52d053d 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -269,6 +269,11 @@ "type": "integer", "description": "Number of sample(s) to process at a time from a multi-sample samplesheet. Works if buffered_samples is true.", "default": 1 + }, + "restrict_concurrency": { + "type": "boolean", + "description": "Restrict parallelizing a process. Eg. restrict running cellpose cell and nuclei segmentation together if the resources are limited.", + "default": false } } }, From f6165eb6231ff860a6b3917b352408d94f0c9602 Mon Sep 17 00:00:00 2001 From: Sameesh Kher Date: Wed, 24 Sep 2025 16:25:17 +0000 Subject: [PATCH 12/12] minor changes for filepath prefix --- conf/modules.config | 2 ++ modules/local/baysor/create_dataset/main.nf | 8 +++--- modules/local/baysor/preprocess/main.nf | 8 +++--- modules/local/baysor/preview/main.nf | 8 +++--- modules/local/baysor/run/main.nf | 10 +++---- modules/local/baysor/segfree/main.nf | 6 ++--- modules/local/proseg/preset/main.nf | 8 +++--- modules/local/proseg/proseg2baysor/main.nf | 8 +++--- modules/local/resolift/main.nf | 8 +++--- modules/local/segger/create_dataset/main.nf | 6 ++--- modules/local/segger/predict/main.nf | 11 ++++---- modules/local/segger/train/main.nf | 8 +++--- modules/local/spatialdata/merge/main.nf | 8 +++--- modules/local/spatialdata/meta/main.nf | 8 +++--- modules/local/spatialdata/write/main.nf | 8 +++--- modules/nf-core/cellpose/cellpose.diff | 11 +++++--- modules/nf-core/cellpose/main.nf | 12 ++++----- modules/nf-core/opt/flip/main.nf | 15 +++++++---- modules/nf-core/opt/flip/opt-flip.diff | 26 +++++++++++++++++++ modules/nf-core/opt/stat/main.nf | 14 ++++++---- modules/nf-core/opt/stat/opt-stat.diff | 25 ++++++++++++++++++ modules/nf-core/opt/track/main.nf | 13 ++++++---- modules/nf-core/opt/track/opt-track.diff | 23 ++++++++++++++++ .../xeniumranger/import-segmentation/main.nf | 8 +++--- .../xeniumranger-import-segmentation.diff | 15 +++++++---- modules/nf-core/xeniumranger/relabel/main.nf | 9 ++++--- .../relabel/xeniumranger-relabel.diff | 19 +++++++++++--- .../nf-core/xeniumranger/resegment/main.nf | 9 ++++--- .../resegment/xeniumranger-resegment.diff | 23 ++++++++++------ .../main.nf | 15 +++++------ workflows/spatialxe.nf | 7 ----- 31 files changed, 234 insertions(+), 125 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 57ecf36c..42875673 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -32,6 +32,7 @@ process { path: "${params.outdir}/xeniumranger/resegment", mode: params.publish_dir_mode ] + ext.prefix = {"${meta.id}"} } withName: XENIUMRANGER_IMPORT_SEGMENTATION { @@ -39,6 +40,7 @@ process { path: "${params.outdir}/xeniumranger/import_segementation", mode: params.publish_dir_mode ] + ext.prefix = {"${meta.id}"} } withName: FICTURE_PREPROCESS { diff --git a/modules/local/baysor/create_dataset/main.nf b/modules/local/baysor/create_dataset/main.nf index 2e1cf670..c3daf0e0 100644 --- a/modules/local/baysor/create_dataset/main.nf +++ b/modules/local/baysor/create_dataset/main.nf @@ -9,8 +9,8 @@ process BAYSOR_CREATE_DATASET { val(sample_fraction) output: - tuple val(meta), path("${meta.id}/sampled_transcripts.csv"), emit: sampled_transcripts - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/sampled_transcripts.csv"), emit: sampled_transcripts + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -21,7 +21,7 @@ process BAYSOR_CREATE_DATASET { error "BAYSOR_CREATE_DATASET module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" template 'create_dataset.py' @@ -31,7 +31,7 @@ process BAYSOR_CREATE_DATASET { error "BAYSOR_CREATE_DATASET module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix} diff --git a/modules/local/baysor/preprocess/main.nf b/modules/local/baysor/preprocess/main.nf index 8e14ccac..aaf9d378 100644 --- a/modules/local/baysor/preprocess/main.nf +++ b/modules/local/baysor/preprocess/main.nf @@ -14,8 +14,8 @@ process BAYSOR_PREPROCESS_TRANSCRIPTS { output: tuple val(meta), - path("${meta.id}/filtered_transcripts.parquet"), emit: transcripts_parquet - path("versions.yml") , emit: versions + path("${prefix}/filtered_transcripts.parquet"), emit: transcripts_parquet + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -26,7 +26,7 @@ process BAYSOR_PREPROCESS_TRANSCRIPTS { error "BAYSOR_PREPROCESS_TRANSCRIPTS module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" template 'preprocess_transcripts.py' @@ -36,7 +36,7 @@ process BAYSOR_PREPROCESS_TRANSCRIPTS { error "BAYSOR_PREPROCESS_TRANSCRIPTS module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix} diff --git a/modules/local/baysor/preview/main.nf b/modules/local/baysor/preview/main.nf index a641d468..3b7582aa 100644 --- a/modules/local/baysor/preview/main.nf +++ b/modules/local/baysor/preview/main.nf @@ -9,8 +9,8 @@ process BAYSOR_PREVIEW { path(config) output: - tuple val(meta), path("${meta.id}/preview.html"), emit: preview_html - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/preview.html"), emit: preview_html + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -22,7 +22,7 @@ process BAYSOR_PREVIEW { } def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix} @@ -46,7 +46,7 @@ process BAYSOR_PREVIEW { error "BAYSOR_PREVIEW module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix} diff --git a/modules/local/baysor/run/main.nf b/modules/local/baysor/run/main.nf index aab444db..94c8adf3 100644 --- a/modules/local/baysor/run/main.nf +++ b/modules/local/baysor/run/main.nf @@ -13,9 +13,9 @@ process BAYSOR_RUN { output: tuple val(meta), - path("${meta.id}/segmentation.csv"), - path("${meta.id}/segmentation_polygons_2d.json"), emit: segmentation - path("versions.yml") , emit: versions + path("${prefix}/segmentation.csv"), + path("${prefix}/segmentation_polygons_2d.json"), emit: segmentation + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -27,9 +27,9 @@ process BAYSOR_RUN { } def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" def prior_seg = "${prior_segmentation}" ? "${prior_segmentation}" : "" def scaling_factor = scale ? "--scale=${scale}": "" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix} @@ -56,7 +56,7 @@ process BAYSOR_RUN { error "BAYSOR_RUN module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix} diff --git a/modules/local/baysor/segfree/main.nf b/modules/local/baysor/segfree/main.nf index 830de65e..62d4554e 100644 --- a/modules/local/baysor/segfree/main.nf +++ b/modules/local/baysor/segfree/main.nf @@ -9,7 +9,7 @@ process BAYSOR_SEGFREE { path(config) output: - tuple val(meta), path("${meta.id}/ncvs.loom"), emit: ncvs + tuple val(meta), path("${prefix}/ncvs.loom"), emit: ncvs path("versions.yml") , emit: versions when: @@ -22,7 +22,7 @@ process BAYSOR_SEGFREE { } def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix} @@ -45,7 +45,7 @@ process BAYSOR_SEGFREE { error "BAYSOR_SEGFREE module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix} diff --git a/modules/local/proseg/preset/main.nf b/modules/local/proseg/preset/main.nf index be8faed9..3c7e1441 100644 --- a/modules/local/proseg/preset/main.nf +++ b/modules/local/proseg/preset/main.nf @@ -9,8 +9,8 @@ process PROSEG { output: tuple val(meta), - path("${meta.id}/cell-polygons.geojson.gz"), - path("${meta.id}/transcript-metadata.csv.gz"), emit: seg_outs + path("${prefix}/cell-polygons.geojson.gz"), + path("${prefix}/transcript-metadata.csv.gz"), emit: seg_outs path("versions.yml") , emit: versions when: @@ -23,7 +23,7 @@ process PROSEG { } def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" // check for platform values if ( !(params.format in ['xenium', 'cosmx', 'merscope']) ) { @@ -59,7 +59,7 @@ process PROSEG { error "PROSEG module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix}/ diff --git a/modules/local/proseg/proseg2baysor/main.nf b/modules/local/proseg/proseg2baysor/main.nf index 09e9e3d6..d9a9b404 100644 --- a/modules/local/proseg/proseg2baysor/main.nf +++ b/modules/local/proseg/proseg2baysor/main.nf @@ -8,8 +8,8 @@ process PROSEG2BAYSOR { tuple val(meta), path(cell_polygons), path(transcript_metadata) output: - tuple val(meta), path("${meta.id}/cell-polygons.geojson") , emit: xr_polygons - tuple val(meta), path("${meta.id}/transcript-metadata.csv"), emit: xr_metadata + tuple val(meta), path("${prefix}/cell-polygons.geojson") , emit: xr_polygons + tuple val(meta), path("${prefix}/transcript-metadata.csv"), emit: xr_metadata path("versions.yml") , emit: versions script: @@ -19,7 +19,7 @@ process PROSEG2BAYSOR { } def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix} @@ -44,7 +44,7 @@ process PROSEG2BAYSOR { error "PROSEG2BAYSOR module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix} diff --git a/modules/local/resolift/main.nf b/modules/local/resolift/main.nf index c7467c92..be75100a 100644 --- a/modules/local/resolift/main.nf +++ b/modules/local/resolift/main.nf @@ -9,8 +9,8 @@ process RESOLIFT { output: tuple val(meta), - path("${meta.id}/morphology.ome.enhanced.tiff"), emit: enhanced_tiff - path("versions.yml") , emit: versions + path("${prefix}/morphology.ome.enhanced.tiff"), emit: enhanced_tiff + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -22,7 +22,7 @@ process RESOLIFT { } def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix} @@ -43,7 +43,7 @@ process RESOLIFT { if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "RESOLIFT module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix} diff --git a/modules/local/segger/create_dataset/main.nf b/modules/local/segger/create_dataset/main.nf index f109fd31..29057344 100644 --- a/modules/local/segger/create_dataset/main.nf +++ b/modules/local/segger/create_dataset/main.nf @@ -8,7 +8,7 @@ process SEGGER_CREATE_DATASET { tuple val(meta), path(base_dir) output: - tuple val(meta), path("${meta.id}"), emit: datasetdir + tuple val(meta), path("${prefix}/"), emit: datasetdir path("versions.yml") , emit: versions when: @@ -21,8 +21,8 @@ process SEGGER_CREATE_DATASET { } def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" def script_path = "/workspace/segger_dev/src/segger/cli/create_dataset_fast.py" + prefix = task.ext.prefix ?: "${meta.id}" // check for platform values if ( !(params.format in ['xenium']) ) { @@ -51,7 +51,7 @@ process SEGGER_CREATE_DATASET { error "SEGGER_CREATE_DATASET module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix}/ diff --git a/modules/local/segger/predict/main.nf b/modules/local/segger/predict/main.nf index cc63dc90..3e08a803 100644 --- a/modules/local/segger/predict/main.nf +++ b/modules/local/segger/predict/main.nf @@ -9,11 +9,10 @@ process SEGGER_PREDICT { path(models_dir) path(transcripts) - output: - tuple val(meta), path("${meta.id}/benchmarks_dir") , emit: benchmarks - tuple val(meta), path("${meta.id}/benchmarks_dir/*/segger_transcripts.parquet"), emit: transcripts - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/benchmarks_dir") , emit: benchmarks + tuple val(meta), path("${prefix}/benchmarks_dir/*/segger_transcripts.parquet"), emit: transcripts + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -25,8 +24,8 @@ process SEGGER_PREDICT { } def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" def script_path = "/workspace/segger_dev/src/segger/cli/predict_fast.py" + prefix = task.ext.prefix ?: "${meta.id}" """ python3 ${script_path} \\ @@ -52,7 +51,7 @@ process SEGGER_PREDICT { error "SEGGER_PREDICT module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p "${prefix}/benchmarks_dir" diff --git a/modules/local/segger/train/main.nf b/modules/local/segger/train/main.nf index 8ca932c7..70448258 100644 --- a/modules/local/segger/train/main.nf +++ b/modules/local/segger/train/main.nf @@ -8,8 +8,8 @@ process SEGGER_TRAIN { tuple val(meta), path(dataset_dir) output: - tuple val(meta), path("${meta.id}/trained_models"), emit: trained_models - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/trained_models"), emit: trained_models + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -21,8 +21,8 @@ process SEGGER_TRAIN { } def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" def script_path = "/workspace/segger_dev/src/segger/cli/train_model.py" + prefix = task.ext.prefix ?: "${meta.id}" """ python3 ${script_path} \\ @@ -48,7 +48,7 @@ process SEGGER_TRAIN { error "SEGGER_TRAIN module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix}/trained_models/ diff --git a/modules/local/spatialdata/merge/main.nf b/modules/local/spatialdata/merge/main.nf index 55a227c9..fc552b75 100644 --- a/modules/local/spatialdata/merge/main.nf +++ b/modules/local/spatialdata/merge/main.nf @@ -8,8 +8,8 @@ process SPATIALDATA_MERGE { tuple val(meta), path(raw_bundle, stageAs: "*"), path(redefined_bundle, stageAs: "*") output: - tuple val(meta), path("${meta.id}/spatialdata_merged"), emit: merged_bundle - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/spatialdata_merged"), emit: merged_bundle + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -21,7 +21,7 @@ process SPATIALDATA_MERGE { } def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" template 'merge.py' @@ -31,7 +31,7 @@ process SPATIALDATA_MERGE { exit 1, "SPATIALDATA_WRITE module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p "${prefix}/spatialdata_merged/" diff --git a/modules/local/spatialdata/meta/main.nf b/modules/local/spatialdata/meta/main.nf index 2916cb9c..b197bc1c 100644 --- a/modules/local/spatialdata/meta/main.nf +++ b/modules/local/spatialdata/meta/main.nf @@ -8,8 +8,8 @@ process SPATIALDATA_META { tuple val(meta), path(spatialdata_bundle, stageAs: "*"), path(xenium_bundle, stageAs: "*") output: - tuple val(meta), path("${meta.id}/spatialdata_meta"), emit: metadata - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/spatialdata_meta"), emit: metadata + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -20,6 +20,8 @@ process SPATIALDATA_META { exit 1, "SPATIALDATA_META module does not support Conda. Please use Docker / Singularity / Podman instead." } + prefix = task.ext.prefix ?: "${meta.id}" + template 'meta.py' stub: @@ -28,7 +30,7 @@ process SPATIALDATA_META { exit 1, "SPATIALDATA_META module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p "${prefix}/spatialdata_meta/" diff --git a/modules/local/spatialdata/write/main.nf b/modules/local/spatialdata/write/main.nf index 7beb6786..7816ba68 100644 --- a/modules/local/spatialdata/write/main.nf +++ b/modules/local/spatialdata/write/main.nf @@ -11,8 +11,8 @@ process SPATIALDATA_WRITE { val(coordinate_space) output: - tuple val(meta), path("${meta.id}/${outputfolder}"), emit: spatialdata - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/${outputfolder}"), emit: spatialdata + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -23,7 +23,7 @@ process SPATIALDATA_WRITE { exit 1, "SPATIALDATA_WRITE module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" template 'write.py' @@ -33,8 +33,8 @@ process SPATIALDATA_WRITE { exit 1, "SPATIALDATA_WRITE module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" def outdir = "${outputfolder}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p "${prefix}/${outdir}" diff --git a/modules/nf-core/cellpose/cellpose.diff b/modules/nf-core/cellpose/cellpose.diff index ee24bf20..b4f73e87 100644 --- a/modules/nf-core/cellpose/cellpose.diff +++ b/modules/nf-core/cellpose/cellpose.diff @@ -21,7 +21,7 @@ Changes in 'cellpose/main.nf': when: task.ext.when == null || task.ext.when -@@ -19,7 +21,7 @@ +@@ -19,37 +21,47 @@ script: // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { @@ -29,8 +29,9 @@ Changes in 'cellpose/main.nf': + error "CELLPOSE module does not support conda. Please use Docker / Singularity / Podman instead." } def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" -@@ -27,29 +29,38 @@ +- def prefix = task.ext.prefix ?: "${meta.id}" + def model_command = model ? "--pretrained_model $model" : "" ++ prefix = task.ext.prefix ?: "${meta.id}" """ export OMP_NUM_THREADS=${task.cpus} export MKL_NUM_THREADS=${task.cpus} @@ -56,14 +57,16 @@ Changes in 'cellpose/main.nf': - error "I did not manage to create a cellpose module in Conda that works in all OSes. Please use Docker / Singularity / Podman instead." + error "CELLPOSE module does not support conda. Please use Docker / Singularity / Podman instead." } +- def prefix = task.ext.prefix ?: "${meta.id}" + - def prefix = task.ext.prefix ?: "${meta.id}" def name = image.name def base = name.lastIndexOf('.') != -1 ? name[0..name.lastIndexOf('.') - 1] : name ++ prefix = task.ext.prefix ?: "${meta.id}" + """ + mkdir -p ${prefix} + touch ${prefix}/morphology.ome_${maskname}_masks.tif ++ touch ${prefix}/morphology.ome_${maskname}_seg.npy touch ${base}_cp_masks.tif - cat <<-END_VERSIONS > versions.yml diff --git a/modules/nf-core/cellpose/main.nf b/modules/nf-core/cellpose/main.nf index 31e6bde2..272f3475 100644 --- a/modules/nf-core/cellpose/main.nf +++ b/modules/nf-core/cellpose/main.nf @@ -10,10 +10,10 @@ process CELLPOSE { val(maskname) output: - tuple val(meta), path("${meta.id}/*masks.tif"), emit: mask - tuple val(meta), path("${meta.id}/*flows.tif"), emit: flows, optional: true - tuple val(meta), path("${meta.id}/*seg.npy") , emit: cells, optional: true - path "versions.yml" , emit: versions + tuple val(meta), path("${prefix}/*masks.tif"), emit: mask + tuple val(meta), path("${prefix}/*flows.tif"), emit: flows, optional: true + tuple val(meta), path("${prefix}/*seg.npy") , emit: cells, optional: true + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -24,8 +24,8 @@ process CELLPOSE { error "CELLPOSE module does not support conda. Please use Docker / Singularity / Podman instead." } def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" def model_command = model ? "--pretrained_model $model" : "" + prefix = task.ext.prefix ?: "${meta.id}" """ export OMP_NUM_THREADS=${task.cpus} export MKL_NUM_THREADS=${task.cpus} @@ -51,9 +51,9 @@ process CELLPOSE { error "CELLPOSE module does not support conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" def name = image.name def base = name.lastIndexOf('.') != -1 ? name[0..name.lastIndexOf('.') - 1] : name + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix} diff --git a/modules/nf-core/opt/flip/main.nf b/modules/nf-core/opt/flip/main.nf index fa98c4f0..66be07d0 100644 --- a/modules/nf-core/opt/flip/main.nf +++ b/modules/nf-core/opt/flip/main.nf @@ -9,8 +9,8 @@ process OPT_FLIP { tuple val(meta2), path(ref_annot_gff), path(ref_annot_fa) output: - tuple val(meta), path("${meta.id}/fwd_oriented.fa"), emit: fwd_oriented_fa - path "versions.yml" , emit: versions + tuple val(meta), path("${prefix}/fwd_oriented.fa"), emit: fwd_oriented_fa + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -20,8 +20,9 @@ process OPT_FLIP { if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "OPT_FLIP module does not support Conda. Please use Docker / Singularity / Podman instead." } + def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ opt \\ @@ -40,8 +41,12 @@ process OPT_FLIP { """ stub: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "OPT_FLIP module does not support Conda. Please use Docker / Singularity / Podman instead." + } + + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix} diff --git a/modules/nf-core/opt/flip/opt-flip.diff b/modules/nf-core/opt/flip/opt-flip.diff index 4ffda377..f1ac73fb 100644 --- a/modules/nf-core/opt/flip/opt-flip.diff +++ b/modules/nf-core/opt/flip/opt-flip.diff @@ -13,6 +13,32 @@ Changes in 'opt/flip/main.nf': when: task.ext.when == null || task.ext.when +@@ -20,8 +20,9 @@ + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "OPT_FLIP module does not support Conda. Please use Docker / Singularity / Podman instead." + } ++ + def args = task.ext.args ?: '' +- def prefix = task.ext.prefix ?: "${meta.id}" ++ prefix = task.ext.prefix ?: "${meta.id}" + + """ + opt \\ +@@ -40,8 +41,12 @@ + """ + + stub: +- def args = task.ext.args ?: '' +- def prefix = task.ext.prefix ?: "${meta.id}" ++ // Exit if running this module with -profile conda / -profile mamba ++ if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { ++ error "OPT_FLIP module does not support Conda. Please use Docker / Singularity / Podman instead." ++ } ++ ++ prefix = task.ext.prefix ?: "${meta.id}" + + """ + mkdir -p ${prefix} 'modules/nf-core/opt/flip/meta.yml' is unchanged 'modules/nf-core/opt/flip/tests/main.nf.test' is unchanged diff --git a/modules/nf-core/opt/stat/main.nf b/modules/nf-core/opt/stat/main.nf index 85d74a24..e8de5860 100644 --- a/modules/nf-core/opt/stat/main.nf +++ b/modules/nf-core/opt/stat/main.nf @@ -10,8 +10,8 @@ process OPT_STAT { path(gene_synonyms) output: - tuple val(meta), path("${meta.id}/collapsed_summary.tsv"), emit: summary - path "versions.yml" , emit: versions + tuple val(meta), path("${prefix}/collapsed_summary.tsv"), emit: summary + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -22,8 +22,8 @@ process OPT_STAT { error "OPT_STAT module does not support Conda. Please use Docker / Singularity / Podman instead." } def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" def synonyms = gene_synonyms ? "-s ${gene_synonyms}": "" + prefix = task.ext.prefix ?: "${meta.id}" """ opt \\ @@ -41,8 +41,12 @@ process OPT_STAT { """ stub: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "OPT_STAT module does not support Conda. Please use Docker / Singularity / Podman instead." + } + + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix} diff --git a/modules/nf-core/opt/stat/opt-stat.diff b/modules/nf-core/opt/stat/opt-stat.diff index b1c612d4..63a743ba 100644 --- a/modules/nf-core/opt/stat/opt-stat.diff +++ b/modules/nf-core/opt/stat/opt-stat.diff @@ -13,6 +13,31 @@ Changes in 'opt/stat/main.nf': when: task.ext.when == null || task.ext.when +@@ -22,8 +22,8 @@ + error "OPT_STAT module does not support Conda. Please use Docker / Singularity / Podman instead." + } + def args = task.ext.args ?: '' +- def prefix = task.ext.prefix ?: "${meta.id}" + def synonyms = gene_synonyms ? "-s ${gene_synonyms}": "" ++ prefix = task.ext.prefix ?: "${meta.id}" + + """ + opt \\ +@@ -41,8 +41,12 @@ + """ + + stub: +- def args = task.ext.args ?: '' +- def prefix = task.ext.prefix ?: "${meta.id}" ++ // Exit if running this module with -profile conda / -profile mamba ++ if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { ++ error "OPT_STAT module does not support Conda. Please use Docker / Singularity / Podman instead." ++ } ++ ++ prefix = task.ext.prefix ?: "${meta.id}" + + """ + mkdir -p ${prefix} 'modules/nf-core/opt/stat/meta.yml' is unchanged 'modules/nf-core/opt/stat/tests/main.nf.test' is unchanged diff --git a/modules/nf-core/opt/track/main.nf b/modules/nf-core/opt/track/main.nf index fc99a3e5..ff92645e 100644 --- a/modules/nf-core/opt/track/main.nf +++ b/modules/nf-core/opt/track/main.nf @@ -9,8 +9,8 @@ process OPT_TRACK { tuple val(meta2), path(ref_annot_gff), path(ref_annot_fa) output: - tuple val(meta), path("${meta.id}/probe2targets.tsv"), emit: probes2target - path "versions.yml" , emit: versions + tuple val(meta), path("${prefix}/probe2targets.tsv"), emit: probes2target + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -21,7 +21,7 @@ process OPT_TRACK { error "OPT_TRACK module does not support Conda. Please use Docker / Singularity / Podman instead." } def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ opt \\ @@ -41,8 +41,11 @@ process OPT_TRACK { """ stub: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "OPT_TRACK module does not support Conda. Please use Docker / Singularity / Podman instead." + } + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p ${prefix} diff --git a/modules/nf-core/opt/track/opt-track.diff b/modules/nf-core/opt/track/opt-track.diff index b1a2a9ca..5f8d9420 100644 --- a/modules/nf-core/opt/track/opt-track.diff +++ b/modules/nf-core/opt/track/opt-track.diff @@ -13,6 +13,29 @@ Changes in 'opt/track/main.nf': when: task.ext.when == null || task.ext.when +@@ -21,7 +21,7 @@ + error "OPT_TRACK module does not support Conda. Please use Docker / Singularity / Podman instead." + } + def args = task.ext.args ?: '' +- def prefix = task.ext.prefix ?: "${meta.id}" ++ prefix = task.ext.prefix ?: "${meta.id}" + + """ + opt \\ +@@ -41,8 +41,11 @@ + """ + + stub: +- def args = task.ext.args ?: '' +- def prefix = task.ext.prefix ?: "${meta.id}" ++ // Exit if running this module with -profile conda / -profile mamba ++ if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { ++ error "OPT_TRACK module does not support Conda. Please use Docker / Singularity / Podman instead." ++ } ++ prefix = task.ext.prefix ?: "${meta.id}" + + """ + mkdir -p ${prefix} 'modules/nf-core/opt/track/meta.yml' is unchanged 'modules/nf-core/opt/track/tests/main.nf.test' is unchanged diff --git a/modules/nf-core/xeniumranger/import-segmentation/main.nf b/modules/nf-core/xeniumranger/import-segmentation/main.nf index 1fce274e..985a709e 100644 --- a/modules/nf-core/xeniumranger/import-segmentation/main.nf +++ b/modules/nf-core/xeniumranger/import-segmentation/main.nf @@ -15,8 +15,8 @@ process XENIUMRANGER_IMPORT_SEGMENTATION { val(units) output: - tuple val(meta), path("${meta.id}/outs"), emit: bundle - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/outs"), emit: bundle + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -27,7 +27,7 @@ process XENIUMRANGER_IMPORT_SEGMENTATION { error "XENIUMRANGER_IMPORT-SEGMENTATION module does not support Conda. Please use Docker / Singularity / Podman instead." } def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" // image based segmentation options def coord_transform = coordinate_transform ? "--coordinate-transform=\"${coordinate_transform}\"": "" @@ -71,7 +71,7 @@ process XENIUMRANGER_IMPORT_SEGMENTATION { error "XENIUMRANGER_IMPORT-SEGMENTATION module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p "${prefix}/outs" diff --git a/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff b/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff index d4e402f6..57550231 100644 --- a/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff +++ b/modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff @@ -29,13 +29,17 @@ Changes in 'xeniumranger/import-segmentation/main.nf': output: - tuple val(meta), path("**/outs/**"), emit: outs - path "versions.yml", emit: versions -+ tuple val(meta), path("${meta.id}/outs"), emit: bundle -+ path("versions.yml") , emit: versions ++ tuple val(meta), path("${prefix}/outs"), emit: bundle ++ path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when -@@ -29,32 +30,33 @@ - def prefix = task.ext.prefix ?: "${meta.id}" +@@ -26,35 +27,36 @@ + error "XENIUMRANGER_IMPORT-SEGMENTATION module does not support Conda. Please use Docker / Singularity / Podman instead." + } + def args = task.ext.args ?: '' +- def prefix = task.ext.prefix ?: "${meta.id}" ++ prefix = task.ext.prefix ?: "${meta.id}" // image based segmentation options - def expansion_distance = expansion_distance ? "--expansion-distance=\"${expansion_distance}\"": "" // expansion distance (default - 5, range - 0 - 100) @@ -86,8 +90,9 @@ Changes in 'xeniumranger/import-segmentation/main.nf': if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "XENIUMRANGER_IMPORT-SEGMENTATION module does not support Conda. Please use Docker / Singularity / Podman instead." } +- def prefix = task.ext.prefix ?: "${meta.id}" + - def prefix = task.ext.prefix ?: "${meta.id}" ++ prefix = task.ext.prefix ?: "${meta.id}" + """ - mkdir -p "${prefix}/outs/" diff --git a/modules/nf-core/xeniumranger/relabel/main.nf b/modules/nf-core/xeniumranger/relabel/main.nf index e500fa08..03d55d9f 100644 --- a/modules/nf-core/xeniumranger/relabel/main.nf +++ b/modules/nf-core/xeniumranger/relabel/main.nf @@ -9,8 +9,8 @@ process XENIUMRANGER_RELABEL { path(gene_panel) output: - tuple val(meta), path("${meta.id}/outs"), emit: bundle - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/outs"), emit: bundle + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -21,7 +21,7 @@ process XENIUMRANGER_RELABEL { error "XENIUMRANGER_RELABEL module does not support Conda. Please use Docker / Singularity / Podman instead." } def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" """ xeniumranger relabel \\ @@ -43,7 +43,8 @@ process XENIUMRANGER_RELABEL { if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "XENIUMRANGER_RELABEL module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" + """ mkdir -p "${prefix}/outs" touch "${prefix}/outs/fake_file.txt" diff --git a/modules/nf-core/xeniumranger/relabel/xeniumranger-relabel.diff b/modules/nf-core/xeniumranger/relabel/xeniumranger-relabel.diff index 3963a558..3e7f3adb 100644 --- a/modules/nf-core/xeniumranger/relabel/xeniumranger-relabel.diff +++ b/modules/nf-core/xeniumranger/relabel/xeniumranger-relabel.diff @@ -17,13 +17,26 @@ Changes in 'xeniumranger/relabel/main.nf': - tuple val(meta), path("**/outs/**"), emit: outs - path "versions.yml", emit: versions + tuple val(meta), path("${prefix}/outs"), emit: bundle -+ path("versions.yml") , emit: versions ++ path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when -@@ -45,7 +45,7 @@ +@@ -21,7 +21,7 @@ + error "XENIUMRANGER_RELABEL module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + def args = task.ext.args ?: '' +- def prefix = task.ext.prefix ?: "${meta.id}" ++ prefix = task.ext.prefix ?: "${meta.id}" + + """ + xeniumranger relabel \\ +@@ -43,9 +43,10 @@ + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "XENIUMRANGER_RELABEL module does not support Conda. Please use Docker / Singularity / Podman instead." + } +- def prefix = task.ext.prefix ?: "${meta.id}" ++ prefix = task.ext.prefix ?: "${meta.id}" ++ """ - mkdir -p "${prefix}/outs/" + mkdir -p "${prefix}/outs" diff --git a/modules/nf-core/xeniumranger/resegment/main.nf b/modules/nf-core/xeniumranger/resegment/main.nf index cdeef0db..839aacaf 100644 --- a/modules/nf-core/xeniumranger/resegment/main.nf +++ b/modules/nf-core/xeniumranger/resegment/main.nf @@ -8,8 +8,8 @@ process XENIUMRANGER_RESEGMENT { tuple val(meta), path(xenium_bundle) output: - tuple val(meta), path("${meta.id}/outs"), emit: bundle - path("versions.yml") , emit: versions + tuple val(meta), path("${prefix}/outs"), emit: bundle + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -20,7 +20,7 @@ process XENIUMRANGER_RESEGMENT { error "XENIUMRANGER_RESEGMENT module does not support Conda. Please use Docker / Singularity / Podman instead." } def args = task.ext.args ?: "" - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" // Do not use boundary stain in analysis, but keep default interior stain and DAPI def boundary_stain = "${params.boundary_stain}" ? "": "--boundary-stain=disable" @@ -50,7 +50,8 @@ process XENIUMRANGER_RESEGMENT { if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "XENIUMRANGER_RESEGMENT module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" + """ mkdir -p "${prefix}/outs" touch "${prefix}/outs/fake_file.txt" diff --git a/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff b/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff index 24c817e2..9fffaf5a 100644 --- a/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff +++ b/modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff @@ -19,18 +19,21 @@ Changes in 'xeniumranger/resegment/main.nf': output: - tuple val(meta), path("**/outs/**"), emit: outs - path "versions.yml", emit: versions -+ tuple val(meta), path("${meta.id}/outs"), emit: bundle -+ path("versions.yml") , emit: versions ++ tuple val(meta), path("${prefix}/outs"), emit: bundle ++ path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when -@@ -26,20 +22,17 @@ +@@ -24,22 +20,19 @@ + error "XENIUMRANGER_RESEGMENT module does not support Conda. Please use Docker / Singularity / Podman instead." + } def args = task.ext.args ?: "" - def prefix = task.ext.prefix ?: "${meta.id}" - +- def prefix = task.ext.prefix ?: "${meta.id}" +- - def expansion_distance = expansion_distance ? "--expansion-distance=\"${expansion_distance}\"": "" - def dapi_filter = dapi_filter ? "--dapi-filter=\"${dapi_filter}\"": "" -- ++ prefix = task.ext.prefix ?: "${meta.id}" + // Do not use boundary stain in analysis, but keep default interior stain and DAPI - def boundary_stain = boundary_stain ? "--boundary-stain=disable": "" + def boundary_stain = "${params.boundary_stain}" ? "": "--boundary-stain=disable" @@ -49,9 +52,13 @@ Changes in 'xeniumranger/resegment/main.nf': ${boundary_stain} \\ ${interior_stain} \\ --localcores=${task.cpus} \\ -@@ -59,7 +52,7 @@ +@@ -57,9 +50,10 @@ + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "XENIUMRANGER_RESEGMENT module does not support Conda. Please use Docker / Singularity / Podman instead." } - def prefix = task.ext.prefix ?: "${meta.id}" +- def prefix = task.ext.prefix ?: "${meta.id}" ++ prefix = task.ext.prefix ?: "${meta.id}" ++ """ - mkdir -p "${prefix}/outs/" + mkdir -p "${prefix}/outs" diff --git a/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf b/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf index ebef6af4..9aa4c94c 100644 --- a/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf +++ b/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf @@ -23,7 +23,7 @@ workflow BAYSOR_RUN_PRIOR_SEGMENTATION_MASK { ch_transcripts = Channel.empty() ch_redefined_bundle = Channel.empty() - ch_coordinate_space = Channel.value("microns") + ch_coordinate_space = Channel.value("pixels") // filter transcripts.parquet based on thresholds if ( params.filter_transcripts ) { @@ -59,7 +59,6 @@ workflow BAYSOR_RUN_PRIOR_SEGMENTATION_MASK { 30 // scale ) } - BAYSOR_RUN ( ch_baysor_input ) ch_versions = ch_versions.mix( BAYSOR_RUN.out.versions ) @@ -68,20 +67,18 @@ workflow BAYSOR_RUN_PRIOR_SEGMENTATION_MASK { ch_imp_seg_inputs = ch_bundle_path .combine(BAYSOR_RUN.out.segmentation, by: 0) .map { - meta, bundle, segmentation_outs -> - def ( _meta, segmentation_csv, polygons2d ) = segmentation_outs + meta, bundle, _segmentation_csv, polygons2d -> tuple ( meta, // meta bundle, // bundle [], // coordinate_transform - [], // nuclei - [], // cells - segmentation_csv, // transcript_assignment - polygons2d, // viz_polygons + polygons2d, // nuclei + polygons2d, // cells + [], // transcript_assignment + [], // viz_polygons ch_coordinate_space.val // units ) } - XENIUMRANGER_IMPORT_SEGMENTATION ( ch_imp_seg_inputs ) diff --git a/workflows/spatialxe.nf b/workflows/spatialxe.nf index 4f8d40c0..c3e83be5 100644 --- a/workflows/spatialxe.nf +++ b/workflows/spatialxe.nf @@ -316,13 +316,6 @@ workflow SPATIALXE { ch_segmentation_mask, ch_config ) - } else { - BAYSOR_RUN_PRIOR_SEGMENTATION_MASK ( - ch_bundle_path, - ch_transcripts_parquet, - [], - ch_config - ) } ch_redefined_bundle = BAYSOR_RUN_PRIOR_SEGMENTATION_MASK.out.redefined_bundle ch_coordinate_space = BAYSOR_RUN_PRIOR_SEGMENTATION_MASK.out.coordinate_space