From 99401e7b47485fa7ea3d66b251d7f6e84abd3a4f Mon Sep 17 00:00:00 2001 From: Sameesh Kher Date: Thu, 23 Oct 2025 11:28:03 +0000 Subject: [PATCH 1/2] Pending changes exported from your codespace --- assets/samplesheet.csv | 2 +- conf/test.config | 4 + conf/test_coordinate_mode.config | 31 +++ conf/test_image_mode.config | 31 +++ conf/test_preview_mode.config | 31 +++ conf/test_segfree_mode.config | 31 +++ modules.json | 54 +++-- .../spatialconverter/parquet_to_csv/main.nf | 12 +- .../templates/parquet_to_csv.py | 23 ++- modules/nf-core/untar/main.nf | 1 + modules/nf-core/untar/untar.diff | 7 +- .../local/baysor_generate_preview/main.nf | 3 +- .../main.nf | 28 +-- .../utils_nfcore_spatialxe_pipeline/main.nf | 47 +++-- tests/.nftignore | 2 + tests/coordinate_mode.nf.test | 36 ++++ tests/coordinate_mode.nf.test.snap | 115 +++++++++++ tests/default.nf.test.snap | 191 ++++-------------- tests/image_mode.nf.test | 36 ++++ tests/image_mode.nf.test.snap | 43 ++++ tests/nextflow.config | 9 + tests/preview_mode.nf.test | 36 ++++ tests/preview_mode.nf.test.snap | 59 ++++++ tests/segfree_mode.nf.test | 36 ++++ tests/segfree_mode.nf.test.snap | 46 +++++ workflows/spatialxe.nf | 85 ++++++-- 26 files changed, 766 insertions(+), 233 deletions(-) create mode 100644 conf/test_coordinate_mode.config create mode 100644 conf/test_image_mode.config create mode 100644 conf/test_preview_mode.config create mode 100644 conf/test_segfree_mode.config create mode 100644 tests/coordinate_mode.nf.test create mode 100644 tests/coordinate_mode.nf.test.snap create mode 100644 tests/image_mode.nf.test create mode 100644 tests/image_mode.nf.test.snap create mode 100644 tests/preview_mode.nf.test create mode 100644 tests/preview_mode.nf.test.snap create mode 100644 tests/segfree_mode.nf.test create mode 100644 tests/segfree_mode.nf.test.snap diff --git a/assets/samplesheet.csv b/assets/samplesheet.csv index f89b075..f5710da 100644 --- a/assets/samplesheet.csv +++ b/assets/samplesheet.csv @@ -1,2 +1,2 @@ sample,bundle,image -Xenium_Prime_Mouse_Ileum_tiny_outs,https://raw.githubusercontent.com/nf-core/test-datasets/spatialxe/Xenium_Prime_Mouse_Ileum_tiny_outs.tar.gz, +test_run,https://raw.githubusercontent.com/nf-core/test-datasets/spatialxe/xenium_bundle.tar.gz diff --git a/conf/test.config b/conf/test.config index 1f04370..9ce1d3c 100644 --- a/conf/test.config +++ b/conf/test.config @@ -18,6 +18,10 @@ process { time: '2.h', ] + withName: UNTAR { + ext.prefix = "test_run" + } + } params { diff --git a/conf/test_coordinate_mode.config b/conf/test_coordinate_mode.config new file mode 100644 index 0000000..1f04370 --- /dev/null +++ b/conf/test_coordinate_mode.config @@ -0,0 +1,31 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Nextflow config file for running minimal tests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Defines input files and everything required to run a fast and simple pipeline test. + + Use as follows: + nextflow run nf-core/spatialxe -profile test, --mode --outdir + +---------------------------------------------------------------------------------------- +*/ + +process { + + resourceLimits = [ + cpus: 4, + memory: '15.GB', + time: '2.h', + ] + +} + +params { + config_profile_name = 'Test profile' + config_profile_description = 'Minimal test dataset to check pipeline function' + + // Input data + input = "${projectDir}/assets/samplesheet.csv" + outdir = 'results' + mode = 'coordinate' +} diff --git a/conf/test_image_mode.config b/conf/test_image_mode.config new file mode 100644 index 0000000..31ef719 --- /dev/null +++ b/conf/test_image_mode.config @@ -0,0 +1,31 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Nextflow config file for running minimal tests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Defines input files and everything required to run a fast and simple pipeline test. + + Use as follows: + nextflow run nf-core/spatialxe -profile test, --mode --outdir + +---------------------------------------------------------------------------------------- +*/ + +process { + + resourceLimits = [ + cpus: 4, + memory: '15.GB', + time: '2.h', + ] + +} + +params { + config_profile_name = 'Test profile' + config_profile_description = 'Minimal test dataset to check pipeline function' + + // Input data + input = "${projectDir}/assets/samplesheet.csv" + outdir = 'results' + mode = 'image' +} diff --git a/conf/test_preview_mode.config b/conf/test_preview_mode.config new file mode 100644 index 0000000..f56ac91 --- /dev/null +++ b/conf/test_preview_mode.config @@ -0,0 +1,31 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Nextflow config file for running minimal tests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Defines input files and everything required to run a fast and simple pipeline test. + + Use as follows: + nextflow run nf-core/spatialxe -profile test, --mode --outdir + +---------------------------------------------------------------------------------------- +*/ + +process { + + resourceLimits = [ + cpus: 4, + memory: '15.GB', + time: '2.h', + ] + +} + +params { + config_profile_name = 'Test profile' + config_profile_description = 'Minimal test dataset to check pipeline function' + + // Input data + input = "${projectDir}/assets/samplesheet.csv" + outdir = 'results' + mode = 'preview' +} diff --git a/conf/test_segfree_mode.config b/conf/test_segfree_mode.config new file mode 100644 index 0000000..1cf5308 --- /dev/null +++ b/conf/test_segfree_mode.config @@ -0,0 +1,31 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Nextflow config file for running minimal tests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Defines input files and everything required to run a fast and simple pipeline test. + + Use as follows: + nextflow run nf-core/spatialxe -profile test, --mode --outdir + +---------------------------------------------------------------------------------------- +*/ + +process { + + resourceLimits = [ + cpus: 4, + memory: '15.GB', + time: '2.h', + ] + +} + +params { + config_profile_name = 'Test profile' + config_profile_description = 'Minimal test dataset to check pipeline function' + + // Input data + input = "${projectDir}/assets/samplesheet.csv" + outdir = 'results' + mode = 'segfree' +} diff --git a/modules.json b/modules.json index 686d4cc..40c2bce 100644 --- a/modules.json +++ b/modules.json @@ -8,59 +8,79 @@ "cellpose": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/cellpose/cellpose.diff" }, "multiqc": { "branch": "master", "git_sha": "e10b76ca0c66213581bec2833e30d31f239dec0b", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "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", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/untar/untar.diff" }, "unzip": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "xeniumranger/import-segmentation": { "branch": "master", "git_sha": "b5e1891a88491d8731b5e68e22bd907726caec4a", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/xeniumranger/import-segmentation/xeniumranger-import-segmentation.diff" }, "xeniumranger/relabel": { "branch": "master", "git_sha": "b5e1891a88491d8731b5e68e22bd907726caec4a", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/xeniumranger/relabel/xeniumranger-relabel.diff" }, "xeniumranger/resegment": { "branch": "master", "git_sha": "b5e1891a88491d8731b5e68e22bd907726caec4a", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/xeniumranger/resegment/xeniumranger-resegment.diff" } } @@ -70,20 +90,26 @@ "utils_nextflow_pipeline": { "branch": "master", "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] }, "utils_nfcore_pipeline": { "branch": "master", "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] }, "utils_nfschema_plugin": { "branch": "master", "git_sha": "4b406a74dc0449c0401ed87d5bfff4252fd277fd", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] } } } } } -} +} \ No newline at end of file diff --git a/modules/local/utility/spatialconverter/parquet_to_csv/main.nf b/modules/local/utility/spatialconverter/parquet_to_csv/main.nf index 1637717..2f3175c 100644 --- a/modules/local/utility/spatialconverter/parquet_to_csv/main.nf +++ b/modules/local/utility/spatialconverter/parquet_to_csv/main.nf @@ -2,15 +2,15 @@ process PARQUET_TO_CSV { tag "$meta.id" label 'process_low' - container "community.wave.seqera.io/library/pip_pandas:5c59aaec7d5d4750" + container "community.wave.seqera.io/library/pandas_procs_pyarrow_pip_pruned:a01d9a7721ecb2b7" input: tuple val(meta), path(transcripts) 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,9 +20,9 @@ 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}" + prefix = task.ext.prefix ?: "${meta.id}" - template 'parquet_to_csv.py' + template('parquet_to_csv.py') stub: // Exit if running this module with -profile conda / -profile mamba @@ -30,7 +30,7 @@ process PARQUET_TO_CSV { error "PARQUET_TO_CSV 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/utility/spatialconverter/parquet_to_csv/templates/parquet_to_csv.py b/modules/local/utility/spatialconverter/parquet_to_csv/templates/parquet_to_csv.py index 9ca97dc..7ea2d06 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 @@ -1,18 +1,19 @@ #!/usr/bin/env python + import pandas as pd from pathlib import Path -def convert_parquet ( - transcripts: Path, - extension: str = '.csv', - prefix: str = "" +def convert_parquet( + transcripts: Path, + extension: str = '.csv', + prefix: str = "" ) -> None: - df = pd.read_parquet(transcripts, engine = 'pyarrow') + df = pd.read_parquet(transcripts, engine='pyarrow') - prefix.mkdir(parents=True, exist_ok=True) + Path(prefix).mkdir(parents=True, exist_ok=True) if extension == ".gz": output = transcripts.replace(".parquet", ".csv.gz") @@ -31,13 +32,13 @@ def convert_parquet ( prefix: str = "${meta.id}" # generate transcripts.csv(.gz) - convert_parquet ( + convert_parquet( transcripts=transcripts, extension=extension, prefix=prefix ) - #Output versions.yml - with open("versions.yml", "w") as f: - f.write('"${task.process}":\\n') - f.write('spatialconverter: "v0.0.1"\\n') + # Output versions.yml + with open("versions.yml", "w", encoding='utf-8') as fobj: + fobj.write('"${task.process}":\\n') + fobj.write('spatialconverter: "v0.0.1"\\n') diff --git a/modules/nf-core/untar/main.nf b/modules/nf-core/untar/main.nf index 550d857..1e21cac 100644 --- a/modules/nf-core/untar/main.nf +++ b/modules/nf-core/untar/main.nf @@ -56,6 +56,7 @@ process UNTAR { touch ${prefix}/morphology.ome.tif touch ${prefix}/transcripts.parquet touch ${prefix}/gene_panel.json + touch ${prefix}/experiment.xenium ## Dry-run untaring the archive to get the files and place all in prefix if [[ \$(tar -taf ${archive} | grep -o -P "^.*?\\/" | uniq | wc -l) -eq 1 ]]; then diff --git a/modules/nf-core/untar/untar.diff b/modules/nf-core/untar/untar.diff index 7076b9d..1f30a33 100644 --- a/modules/nf-core/untar/untar.diff +++ b/modules/nf-core/untar/untar.diff @@ -1,21 +1,22 @@ Changes in component 'nf-core/untar' -'modules/nf-core/untar/environment.yml' is unchanged +'modules/nf-core/untar/meta.yml' is unchanged Changes in 'untar/main.nf': --- modules/nf-core/untar/main.nf +++ modules/nf-core/untar/main.nf -@@ -53,6 +53,10 @@ +@@ -53,6 +53,11 @@ prefix = task.ext.prefix ?: (meta.id ? "${meta.id}" : archive.toString().replaceFirst(/\.[^\.]+(.gz)?$/, "")) """ mkdir ${prefix} + touch ${prefix}/morphology.ome.tif + touch ${prefix}/transcripts.parquet + touch ${prefix}/gene_panel.json ++ touch ${prefix}/experiment.xenium + ## Dry-run untaring the archive to get the files and place all in prefix if [[ \$(tar -taf ${archive} | grep -o -P "^.*?\\/" | uniq | wc -l) -eq 1 ]]; then for i in `tar -tf ${archive}`; -'modules/nf-core/untar/meta.yml' is unchanged +'modules/nf-core/untar/environment.yml' is unchanged 'modules/nf-core/untar/tests/main.nf.test' is unchanged 'modules/nf-core/untar/tests/main.nf.test.snap' is unchanged ************************************************************ diff --git a/subworkflows/local/baysor_generate_preview/main.nf b/subworkflows/local/baysor_generate_preview/main.nf index 0c07a84..8db0d93 100644 --- a/subworkflows/local/baysor_generate_preview/main.nf +++ b/subworkflows/local/baysor_generate_preview/main.nf @@ -26,7 +26,8 @@ workflow BAYSOR_GENERATE_PREVIEW { ch_versions = ch_versions.mix(BAYSOR_CREATE_DATASET.out.versions) // run baysor preview if param - generate_preview is true - ch_baysor_preview_input = ch_transcripts_parquet + ch_sampled_transcripts = BAYSOR_CREATE_DATASET.out.sampled_transcripts + ch_baysor_preview_input = ch_sampled_transcripts .combine(ch_config) .map { meta, transcripts, config -> tuple( diff --git a/subworkflows/local/cellpose_baysor_import_segmentation/main.nf b/subworkflows/local/cellpose_baysor_import_segmentation/main.nf index 02d9ec6..b524250 100644 --- a/subworkflows/local/cellpose_baysor_import_segmentation/main.nf +++ b/subworkflows/local/cellpose_baysor_import_segmentation/main.nf @@ -2,22 +2,22 @@ // Run the cellpose, baysor and import-segmentation flow // -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_PREPROCESS_TRANSCRIPTS } from '../../../modules/local/baysor/preprocess/main' -include { RESIZE_TIF } from '../../../modules/local/utility/resize_tif/main' -include { GET_TRANSCRIPTS_COORDINATES } from '../../../modules/local/utility/get_coordinates/main' +include { 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_PREPROCESS_TRANSCRIPTS } from '../../../modules/local/baysor/preprocess/main' +include { RESIZE_TIF } from '../../../modules/local/utility/resize_tif/main' +include { GET_TRANSCRIPTS_COORDINATES } from '../../../modules/local/utility/get_coordinates/main' include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { take: - ch_morphology_image // channel: [ val(meta), ["path-to-morphology.ome.tif"] ] - ch_bundle_path // channel: [ val(meta), ["path-to-xenium-bundle"] ] - ch_transcripts_parquet // channel: [ val(meta), ["path-to-transcripts.parquet"] ] - ch_experiment_metadata // channel: [ ["path-to-experiment.xenium"] ] - ch_config // channel: ["path-to-xenium.toml"] + ch_morphology_image // channel: [ val(meta), ["path-to-morphology.ome.tif"] ] + ch_bundle_path // channel: [ val(meta), ["path-to-xenium-bundle"] ] + ch_transcripts_parquet // channel: [ val(meta), ["path-to-transcripts.parquet"] ] + ch_experiment_metadata // channel: [ ["path-to-experiment.xenium"] ] + ch_config // channel: ["path-to-xenium.toml"] main: @@ -186,7 +186,7 @@ workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { ch_versions = ch_versions.mix(XENIUMRANGER_IMPORT_SEGMENTATION.out.versions) emit: - coordinate_space = ch_coordinate_space // channel: [ val("microns") ] + coordinate_space = ch_coordinate_space // channel: [ val("microns") ] redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.bundle // channel: [ val(meta), ["redefined-xenium-bundle"] ] - versions = ch_versions // channel: [ versions.yml ] + versions = ch_versions // channel: [ versions.yml ] } diff --git a/subworkflows/local/utils_nfcore_spatialxe_pipeline/main.nf b/subworkflows/local/utils_nfcore_spatialxe_pipeline/main.nf index 8280098..792aeb4 100644 --- a/subworkflows/local/utils_nfcore_spatialxe_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_spatialxe_pipeline/main.nf @@ -94,7 +94,7 @@ workflow PIPELINE_INITIALISATION { // Custom validation for pipeline parameters // validateInputParameters() - log.info("INFO Pipeline parameters validated ✅ ") + log.info("✅ Pipeline parameters validated.") // // Create channel from input file provided through params.input @@ -107,7 +107,7 @@ workflow PIPELINE_INITIALISATION { } .set { ch_samplesheet } - log.info("INFO Samplesheet fields validated ✅ ") + log.info("✅ Samplesheet validated.") } catch (Exception e) { @@ -243,11 +243,8 @@ def validateInputParameters() { // def validateXeniumBundle(ch_samplesheet) { - // define xenium bundle directory structure - def xenium_bundle = [ - "analysis.tar.gz", - "analysis.zarr.zip", - "analysis_summary.html", + // define xenium bundle directory structure - required files + def bundle_required_files = [ "cell_boundaries.csv.gz", "cell_boundaries.parquet", "cell_feature_matrix.h5", @@ -267,6 +264,13 @@ def validateXeniumBundle(ch_samplesheet) { "transcripts.zarr.zip", ] + // bundle optional files + def bundle_optional_files = [ + "analysis.tar.gz", + "analysis.zarr.zip", + "analysis_summary.html" + ] + // get bundle path def ch_bundle_path = ch_samplesheet.map { _meta, bundle, _image -> def bundle_path = file( @@ -285,25 +289,42 @@ def validateXeniumBundle(ch_samplesheet) { if (ch_bundle_path.map { it.exists() }) { ch_bundle_path.map { path -> - def missing_files = [] + def missing_required_files = [] + def missing_optional_files = [] - def allExist = xenium_bundle.every { filename -> + def requiredExist = bundle_required_files.every { filename -> def fullPath = file("${path}/${filename}") if (!fullPath.exists()) { - missing_files.add(filename) + missing_required_files.add(filename) return false } return true } + // raise error if required files are missing + if (!requiredExist) { + log.error("❌ Missing file(s) at bundle path provided in the samplesheet: ${missing_required_files}") + exit(1) + } - if (!allExist) { - log.error("❌ Missing file(s) at bundle path provided in the samplesheet: ${missing_files}") + def optionalExist = bundle_optional_files.every { filename -> + def fullPath = file("${path}/${filename}") + if (!fullPath.exists()) { + missing_optional_files.add(filename) + return false + } + return true + } + // log message if optional files are missing + if (!optionalExist) { + log.warn("⚠️ Missing optional file(s) at bundle path provided in the samplesheet: ${missing_optional_files}") exit(1) } + + } } else { - log.info("INFO Xenium bundle validated ✅ \n") + log.info("✅ Xenium bundle validated.\n") } } diff --git a/tests/.nftignore b/tests/.nftignore index e42e03d..057e660 100644 --- a/tests/.nftignore +++ b/tests/.nftignore @@ -9,3 +9,5 @@ multiqc/multiqc_data/llms-full.txt multiqc/multiqc_plots/{svg,pdf,png}/*.{svg,pdf,png} multiqc/multiqc_report.html pipeline_info/*.{html,json,txt,yml} +**/untar/** +**/proseg/** diff --git a/tests/coordinate_mode.nf.test b/tests/coordinate_mode.nf.test new file mode 100644 index 0000000..b6240f3 --- /dev/null +++ b/tests/coordinate_mode.nf.test @@ -0,0 +1,36 @@ +nextflow_pipeline { + + name "Test pipeline for the `coordinate` mode, test run the proseg subworkflow" + script "../main.nf" + tag "pipeline" + config "../conf/test_coordinate_mode.config" + + test("-profile test") { + + options "-stub" + + when { + params { + outdir = "$outputDir" + } + } + + then { + // stable_name: All files + folders in ${params.outdir}/ with a stable name + def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}']) + // stable_path: All files in ${params.outdir}/ with stable content + def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') + assertAll( + { assert workflow.success}, + { assert snapshot( + // pipeline versions.yml file for multiqc from which Nextflow version is removed because we test pipelines on multiple Nextflow versions + removeNextflowVersion("$outputDir/pipeline_info/nf_core_spatialxe_software_mqc_versions.yml"), + // All stable path name, with a relative path + stable_name, + // All files with stable contents + stable_path + ).match() } + ) + } + } +} diff --git a/tests/coordinate_mode.nf.test.snap b/tests/coordinate_mode.nf.test.snap new file mode 100644 index 0000000..22fe762 --- /dev/null +++ b/tests/coordinate_mode.nf.test.snap @@ -0,0 +1,115 @@ +{ + "-profile test": { + "content": [ + { + "UNTAR": { + "untar": 1.34 + }, + "Workflow": { + "nf-core/spatialxe": "v1.0dev" + } + }, + [ + "multiqc", + "multiqc/multiqc_data", + "multiqc/multiqc_plots", + "multiqc/multiqc_report.html", + "pipeline_info", + "pipeline_info/nf_core_spatialxe_software_mqc_versions.yml", + "proseg", + "proseg/preset", + "proseg/preset/test_run", + "proseg/preset/test_run/cell-polygons.geojson.gz", + "proseg/preset/test_run/transcript-metadata.csv.gz", + "proseg/preset/versions.yml", + "proseg/proseg2baysor", + "proseg/proseg2baysor/test_run", + "proseg/proseg2baysor/test_run/cell-polygons.geojson", + "proseg/proseg2baysor/test_run/transcript-metadata.csv", + "proseg/proseg2baysor/versions.yml", + "spatialdata", + "spatialdata/merge", + "spatialdata/merge/test_run", + "spatialdata/merge/test_run/spatialdata_merged", + "spatialdata/merge/test_run/spatialdata_merged/fake_file.txt", + "spatialdata/merge/versions.yml", + "spatialdata/meta", + "spatialdata/meta/test_run", + "spatialdata/meta/test_run/spatialdata_meta", + "spatialdata/meta/test_run/spatialdata_meta/fake_file.txt", + "spatialdata/meta/versions.yml", + "spatialdata/write", + "spatialdata/write/test_run", + "spatialdata/write/test_run/spatialdata_raw", + "spatialdata/write/test_run/spatialdata_raw/fake_file.txt", + "spatialdata/write/test_run/spatialdata_redefined", + "spatialdata/write/test_run/spatialdata_redefined/fake_file.txt", + "spatialdata/write/versions.yml", + "untar", + "untar/test_run", + "untar/test_run/experiment.xenium", + "untar/test_run/gene_panel.json", + "untar/test_run/morphology.ome.tif", + "untar/test_run/transcripts.parquet", + "xeniumranger", + "xeniumranger/import_segementation", + "xeniumranger/import_segementation/test_run", + "xeniumranger/import_segementation/test_run/outs", + "xeniumranger/import_segementation/test_run/outs/fake_file.txt", + "xeniumranger/import_segementation/versions.yml" + ], + [ + { + "directory": false, + "file": true, + "freeSpace": 6039748608, + "canonicalPath": "/workspaces/spatialxe/.nf-test/tests/488e86689a494e1614a97a76fbae8637/output/proseg/preset/test_run/cell-polygons.geojson.gz", + "usableSpace": 4304994304, + "hidden": false, + "totalSpace": 33636024320, + "path": "/workspaces/spatialxe/.nf-test/tests/488e86689a494e1614a97a76fbae8637/output/proseg/preset/test_run/cell-polygons.geojson.gz", + "name": "cell-polygons.geojson.gz", + "absolute": true, + "absolutePath": "/workspaces/spatialxe/.nf-test/tests/488e86689a494e1614a97a76fbae8637/output/proseg/preset/test_run/cell-polygons.geojson.gz", + "parent": "/workspaces/spatialxe/.nf-test/tests/488e86689a494e1614a97a76fbae8637/output/proseg/preset/test_run" + }, + { + "directory": false, + "file": true, + "freeSpace": 6039748608, + "canonicalPath": "/workspaces/spatialxe/.nf-test/tests/488e86689a494e1614a97a76fbae8637/output/proseg/preset/test_run/transcript-metadata.csv.gz", + "usableSpace": 4304994304, + "hidden": false, + "totalSpace": 33636024320, + "path": "/workspaces/spatialxe/.nf-test/tests/488e86689a494e1614a97a76fbae8637/output/proseg/preset/test_run/transcript-metadata.csv.gz", + "name": "transcript-metadata.csv.gz", + "absolute": true, + "absolutePath": "/workspaces/spatialxe/.nf-test/tests/488e86689a494e1614a97a76fbae8637/output/proseg/preset/test_run/transcript-metadata.csv.gz", + "parent": "/workspaces/spatialxe/.nf-test/tests/488e86689a494e1614a97a76fbae8637/output/proseg/preset/test_run" + }, + "versions.yml:md5,ac3abfa01bfd5b6102495845cdc1b768", + "cell-polygons.geojson:md5,d41d8cd98f00b204e9800998ecf8427e", + "transcript-metadata.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,66d4df69da12a0f8425f221f94afe76b", + "fake_file.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,9010b5ed380b88a5b20ca6dae73345cb", + "fake_file.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,1dfc19eaa8a0746f17aad700d797e323", + "fake_file.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "fake_file.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,5ffb7137a403934431ca87be7ad84968", + "experiment.xenium:md5,d41d8cd98f00b204e9800998ecf8427e", + "gene_panel.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "morphology.ome.tif:md5,d41d8cd98f00b204e9800998ecf8427e", + "transcripts.parquet:md5,d41d8cd98f00b204e9800998ecf8427e", + "fake_file.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,a65b627a1324c7f6255ed5e47fef71a4" + ] + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.04.8" + }, + "timestamp": "2025-10-23T09:20:49.255521686" + } +} \ No newline at end of file diff --git a/tests/default.nf.test.snap b/tests/default.nf.test.snap index 87ff4b4..6422334 100644 --- a/tests/default.nf.test.snap +++ b/tests/default.nf.test.snap @@ -18,93 +18,74 @@ "pipeline_info/nf_core_spatialxe_software_mqc_versions.yml", "proseg", "proseg/preset", - "proseg/preset/Xenium_Prime_Mouse_Ileum_tiny_outs", - "proseg/preset/Xenium_Prime_Mouse_Ileum_tiny_outs/cell-polygons.geojson.gz", - "proseg/preset/Xenium_Prime_Mouse_Ileum_tiny_outs/transcript-metadata.csv.gz", + "proseg/preset/test_run", + "proseg/preset/test_run/cell-polygons.geojson.gz", + "proseg/preset/test_run/transcript-metadata.csv.gz", "proseg/preset/versions.yml", "proseg/proseg2baysor", - "proseg/proseg2baysor/Xenium_Prime_Mouse_Ileum_tiny_outs", - "proseg/proseg2baysor/Xenium_Prime_Mouse_Ileum_tiny_outs/cell-polygons.geojson", - "proseg/proseg2baysor/Xenium_Prime_Mouse_Ileum_tiny_outs/transcript-metadata.csv", + "proseg/proseg2baysor/test_run", + "proseg/proseg2baysor/test_run/cell-polygons.geojson", + "proseg/proseg2baysor/test_run/transcript-metadata.csv", "proseg/proseg2baysor/versions.yml", "spatialdata", "spatialdata/merge", - "spatialdata/merge/Xenium_Prime_Mouse_Ileum_tiny_outs", - "spatialdata/merge/Xenium_Prime_Mouse_Ileum_tiny_outs/spatialdata_merged", - "spatialdata/merge/Xenium_Prime_Mouse_Ileum_tiny_outs/spatialdata_merged/fake_file.txt", + "spatialdata/merge/test_run", + "spatialdata/merge/test_run/spatialdata_merged", + "spatialdata/merge/test_run/spatialdata_merged/fake_file.txt", "spatialdata/merge/versions.yml", "spatialdata/meta", - "spatialdata/meta/Xenium_Prime_Mouse_Ileum_tiny_outs", - "spatialdata/meta/Xenium_Prime_Mouse_Ileum_tiny_outs/spatialdata_meta", - "spatialdata/meta/Xenium_Prime_Mouse_Ileum_tiny_outs/spatialdata_meta/fake_file.txt", + "spatialdata/meta/test_run", + "spatialdata/meta/test_run/spatialdata_meta", + "spatialdata/meta/test_run/spatialdata_meta/fake_file.txt", "spatialdata/meta/versions.yml", "spatialdata/write", - "spatialdata/write/Xenium_Prime_Mouse_Ileum_tiny_outs", - "spatialdata/write/Xenium_Prime_Mouse_Ileum_tiny_outs/spatialdata_raw", - "spatialdata/write/Xenium_Prime_Mouse_Ileum_tiny_outs/spatialdata_raw/fake_file.txt", - "spatialdata/write/Xenium_Prime_Mouse_Ileum_tiny_outs/spatialdata_redefined", - "spatialdata/write/Xenium_Prime_Mouse_Ileum_tiny_outs/spatialdata_redefined/fake_file.txt", + "spatialdata/write/test_run", + "spatialdata/write/test_run/spatialdata_raw", + "spatialdata/write/test_run/spatialdata_raw/fake_file.txt", + "spatialdata/write/test_run/spatialdata_redefined", + "spatialdata/write/test_run/spatialdata_redefined/fake_file.txt", "spatialdata/write/versions.yml", "untar", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/.end-of-run", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/analysis.tar.gz", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/analysis.zarr.zip", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/analysis_summary.html", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/aux_outputs.tar.gz", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/cell_boundaries.csv.gz", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/cell_boundaries.parquet", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/cell_feature_matrix.h5", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/cell_feature_matrix.tar.gz", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/cell_feature_matrix.zarr.zip", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/cells.csv.gz", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/cells.parquet", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/cells.zarr.zip", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/experiment.xenium", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/gene_panel.json", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/metrics_summary.csv", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/morphology.ome.tif", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/morphology_focus", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/morphology_focus/morphology_focus_0000.ome.tif", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/nucleus_boundaries.csv.gz", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/nucleus_boundaries.parquet", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/transcripts.parquet", - "untar/Xenium_Prime_Mouse_Ileum_tiny_outs/transcripts.zarr.zip", + "untar/test_run", + "untar/test_run/experiment.xenium", + "untar/test_run/gene_panel.json", + "untar/test_run/morphology.ome.tif", + "untar/test_run/transcripts.parquet", "xeniumranger", "xeniumranger/import_segementation", - "xeniumranger/import_segementation/Xenium_Prime_Mouse_Ileum_tiny_outs", - "xeniumranger/import_segementation/Xenium_Prime_Mouse_Ileum_tiny_outs/outs", - "xeniumranger/import_segementation/Xenium_Prime_Mouse_Ileum_tiny_outs/outs/fake_file.txt", + "xeniumranger/import_segementation/test_run", + "xeniumranger/import_segementation/test_run/outs", + "xeniumranger/import_segementation/test_run/outs/fake_file.txt", "xeniumranger/import_segementation/versions.yml" ], [ { "directory": false, "file": true, - "freeSpace": 7060684800, - "canonicalPath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/proseg/preset/Xenium_Prime_Mouse_Ileum_tiny_outs/cell-polygons.geojson.gz", - "usableSpace": 5325930496, + "freeSpace": 6039023616, + "canonicalPath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/proseg/preset/test_run/cell-polygons.geojson.gz", + "usableSpace": 4304269312, "hidden": false, "totalSpace": 33636024320, - "path": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/proseg/preset/Xenium_Prime_Mouse_Ileum_tiny_outs/cell-polygons.geojson.gz", + "path": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/proseg/preset/test_run/cell-polygons.geojson.gz", "name": "cell-polygons.geojson.gz", "absolute": true, - "absolutePath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/proseg/preset/Xenium_Prime_Mouse_Ileum_tiny_outs/cell-polygons.geojson.gz", - "parent": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/proseg/preset/Xenium_Prime_Mouse_Ileum_tiny_outs" + "absolutePath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/proseg/preset/test_run/cell-polygons.geojson.gz", + "parent": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/proseg/preset/test_run" }, { "directory": false, "file": true, - "freeSpace": 7060684800, - "canonicalPath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/proseg/preset/Xenium_Prime_Mouse_Ileum_tiny_outs/transcript-metadata.csv.gz", - "usableSpace": 5325930496, + "freeSpace": 6039023616, + "canonicalPath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/proseg/preset/test_run/transcript-metadata.csv.gz", + "usableSpace": 4304269312, "hidden": false, "totalSpace": 33636024320, - "path": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/proseg/preset/Xenium_Prime_Mouse_Ileum_tiny_outs/transcript-metadata.csv.gz", + "path": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/proseg/preset/test_run/transcript-metadata.csv.gz", "name": "transcript-metadata.csv.gz", "absolute": true, - "absolutePath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/proseg/preset/Xenium_Prime_Mouse_Ileum_tiny_outs/transcript-metadata.csv.gz", - "parent": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/proseg/preset/Xenium_Prime_Mouse_Ileum_tiny_outs" + "absolutePath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/proseg/preset/test_run/transcript-metadata.csv.gz", + "parent": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/proseg/preset/test_run" }, "versions.yml:md5,ac3abfa01bfd5b6102495845cdc1b768", "cell-polygons.geojson:md5,d41d8cd98f00b204e9800998ecf8427e", @@ -117,106 +98,10 @@ "fake_file.txt:md5,d41d8cd98f00b204e9800998ecf8427e", "fake_file.txt:md5,d41d8cd98f00b204e9800998ecf8427e", "versions.yml:md5,5ffb7137a403934431ca87be7ad84968", - ".end-of-run:md5,d41d8cd98f00b204e9800998ecf8427e", - { - "directory": false, - "file": true, - "freeSpace": 7060684800, - "canonicalPath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs/analysis.tar.gz", - "usableSpace": 5325930496, - "hidden": false, - "totalSpace": 33636024320, - "path": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs/analysis.tar.gz", - "name": "analysis.tar.gz", - "absolute": true, - "absolutePath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs/analysis.tar.gz", - "parent": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs" - }, - "analysis.zarr.zip:md5,d41d8cd98f00b204e9800998ecf8427e", - "analysis_summary.html:md5,d41d8cd98f00b204e9800998ecf8427e", - { - "directory": false, - "file": true, - "freeSpace": 7060684800, - "canonicalPath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs/aux_outputs.tar.gz", - "usableSpace": 5325930496, - "hidden": false, - "totalSpace": 33636024320, - "path": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs/aux_outputs.tar.gz", - "name": "aux_outputs.tar.gz", - "absolute": true, - "absolutePath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs/aux_outputs.tar.gz", - "parent": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs" - }, - { - "directory": false, - "file": true, - "freeSpace": 7060684800, - "canonicalPath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs/cell_boundaries.csv.gz", - "usableSpace": 5325930496, - "hidden": false, - "totalSpace": 33636024320, - "path": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs/cell_boundaries.csv.gz", - "name": "cell_boundaries.csv.gz", - "absolute": true, - "absolutePath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs/cell_boundaries.csv.gz", - "parent": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs" - }, - "cell_boundaries.parquet:md5,d41d8cd98f00b204e9800998ecf8427e", - "cell_feature_matrix.h5:md5,d41d8cd98f00b204e9800998ecf8427e", - { - "directory": false, - "file": true, - "freeSpace": 7060684800, - "canonicalPath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs/cell_feature_matrix.tar.gz", - "usableSpace": 5325930496, - "hidden": false, - "totalSpace": 33636024320, - "path": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs/cell_feature_matrix.tar.gz", - "name": "cell_feature_matrix.tar.gz", - "absolute": true, - "absolutePath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs/cell_feature_matrix.tar.gz", - "parent": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs" - }, - "cell_feature_matrix.zarr.zip:md5,d41d8cd98f00b204e9800998ecf8427e", - { - "directory": false, - "file": true, - "freeSpace": 7060684800, - "canonicalPath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs/cells.csv.gz", - "usableSpace": 5325930496, - "hidden": false, - "totalSpace": 33636024320, - "path": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs/cells.csv.gz", - "name": "cells.csv.gz", - "absolute": true, - "absolutePath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs/cells.csv.gz", - "parent": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs" - }, - "cells.parquet:md5,d41d8cd98f00b204e9800998ecf8427e", - "cells.zarr.zip:md5,d41d8cd98f00b204e9800998ecf8427e", "experiment.xenium:md5,d41d8cd98f00b204e9800998ecf8427e", "gene_panel.json:md5,d41d8cd98f00b204e9800998ecf8427e", - "metrics_summary.csv:md5,d41d8cd98f00b204e9800998ecf8427e", "morphology.ome.tif:md5,d41d8cd98f00b204e9800998ecf8427e", - "morphology_focus_0000.ome.tif:md5,d41d8cd98f00b204e9800998ecf8427e", - { - "directory": false, - "file": true, - "freeSpace": 7060684800, - "canonicalPath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs/nucleus_boundaries.csv.gz", - "usableSpace": 5325930496, - "hidden": false, - "totalSpace": 33636024320, - "path": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs/nucleus_boundaries.csv.gz", - "name": "nucleus_boundaries.csv.gz", - "absolute": true, - "absolutePath": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs/nucleus_boundaries.csv.gz", - "parent": "/workspaces/spatialxe/.nf-test/tests/114eea5799d89b6db58311660eae3dd6/output/untar/Xenium_Prime_Mouse_Ileum_tiny_outs" - }, - "nucleus_boundaries.parquet:md5,d41d8cd98f00b204e9800998ecf8427e", "transcripts.parquet:md5,d41d8cd98f00b204e9800998ecf8427e", - "transcripts.zarr.zip:md5,d41d8cd98f00b204e9800998ecf8427e", "fake_file.txt:md5,d41d8cd98f00b204e9800998ecf8427e", "versions.yml:md5,a65b627a1324c7f6255ed5e47fef71a4" ] @@ -225,6 +110,6 @@ "nf-test": "0.9.3", "nextflow": "25.04.8" }, - "timestamp": "2025-10-21T22:48:37.355835323" + "timestamp": "2025-10-23T09:21:17.04547356" } } \ No newline at end of file diff --git a/tests/image_mode.nf.test b/tests/image_mode.nf.test new file mode 100644 index 0000000..dec9ada --- /dev/null +++ b/tests/image_mode.nf.test @@ -0,0 +1,36 @@ +nextflow_pipeline { + + name "Test pipeline for the `image` mode, test run the cellpose->baysor subworkflow" + script "../main.nf" + tag "pipeline" + config "../conf/test_image_mode.config" + + test("-profile test") { + + options "-stub" + + when { + params { + outdir = "$outputDir" + } + } + + then { + // stable_name: All files + folders in ${params.outdir}/ with a stable name + def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}']) + // stable_path: All files in ${params.outdir}/ with stable content + def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') + assertAll( + { assert workflow.success}, + { assert snapshot( + // pipeline versions.yml file for multiqc from which Nextflow version is removed because we test pipelines on multiple Nextflow versions + removeNextflowVersion("$outputDir/pipeline_info/nf_core_spatialxe_software_mqc_versions.yml"), + // All stable path name, with a relative path + stable_name, + // All files with stable contents + stable_path + ).match() } + ) + } + } +} diff --git a/tests/image_mode.nf.test.snap b/tests/image_mode.nf.test.snap new file mode 100644 index 0000000..1649ae3 --- /dev/null +++ b/tests/image_mode.nf.test.snap @@ -0,0 +1,43 @@ +{ + "-profile test": { + "content": [ + { + "UNTAR": { + "untar": 1.34 + }, + "Workflow": { + "nf-core/spatialxe": "v1.0dev" + } + }, + [ + "pipeline_info", + "pipeline_info/nf_core_spatialxe_software_mqc_versions.yml", + "spatialdata", + "spatialdata/write", + "spatialdata/write/test_run", + "spatialdata/write/test_run/spatialdata_raw", + "spatialdata/write/test_run/spatialdata_raw/fake_file.txt", + "spatialdata/write/versions.yml", + "untar", + "untar/test_run", + "untar/test_run/experiment.xenium", + "untar/test_run/gene_panel.json", + "untar/test_run/morphology.ome.tif", + "untar/test_run/transcripts.parquet" + ], + [ + "fake_file.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,9fa55401a0e7ec94baad557178917eb9", + "experiment.xenium:md5,d41d8cd98f00b204e9800998ecf8427e", + "gene_panel.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "morphology.ome.tif:md5,d41d8cd98f00b204e9800998ecf8427e", + "transcripts.parquet:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.04.8" + }, + "timestamp": "2025-10-23T09:23:33.998171371" + } +} \ No newline at end of file diff --git a/tests/nextflow.config b/tests/nextflow.config index 21d5c00..5106381 100644 --- a/tests/nextflow.config +++ b/tests/nextflow.config @@ -12,3 +12,12 @@ params { } aws.client.anonymous = true // fixes S3 access issues on self-hosted runners + +process { + + resourceLimits = [ + cpus: 4, + memory: '15.GB', + ] + +} \ No newline at end of file diff --git a/tests/preview_mode.nf.test b/tests/preview_mode.nf.test new file mode 100644 index 0000000..39fbb8c --- /dev/null +++ b/tests/preview_mode.nf.test @@ -0,0 +1,36 @@ +nextflow_pipeline { + + name "Test pipeline for the `preview` mode, test run the basyor-preview subworkflow" + script "../main.nf" + tag "pipeline" + config "../conf/test_preview_mode.config" + + test("-profile test") { + + options "-stub" + + when { + params { + outdir = "$outputDir" + } + } + + then { + // stable_name: All files + folders in ${params.outdir}/ with a stable name + def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}']) + // stable_path: All files in ${params.outdir}/ with stable content + def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') + assertAll( + { assert workflow.success}, + { assert snapshot( + // pipeline versions.yml file for multiqc from which Nextflow version is removed because we test pipelines on multiple Nextflow versions + removeNextflowVersion("$outputDir/pipeline_info/nf_core_spatialxe_software_mqc_versions.yml"), + // All stable path name, with a relative path + stable_name, + // All files with stable contents + stable_path + ).match() } + ) + } + } +} diff --git a/tests/preview_mode.nf.test.snap b/tests/preview_mode.nf.test.snap new file mode 100644 index 0000000..a6b4d0c --- /dev/null +++ b/tests/preview_mode.nf.test.snap @@ -0,0 +1,59 @@ +{ + "-profile test": { + "content": [ + { + "UNTAR": { + "untar": 1.34 + }, + "Workflow": { + "nf-core/spatialxe": "v1.0dev" + } + }, + [ + "baysor", + "baysor/create_dataset", + "baysor/create_dataset/test_run", + "baysor/create_dataset/test_run/sampled_transcripts.csv", + "baysor/create_dataset/versions.yml", + "baysor/preview", + "baysor/preview/test_run", + "baysor/preview/test_run/preview.html", + "baysor/preview/versions.yml", + "multiqc", + "multiqc/multiqc_data", + "multiqc/multiqc_plots", + "multiqc/multiqc_report.html", + "pipeline_info", + "pipeline_info/nf_core_spatialxe_software_mqc_versions.yml", + "spatialconverter", + "spatialconverter/parquet_to_csv", + "spatialconverter/parquet_to_csv/test_run", + "spatialconverter/parquet_to_csv/test_run/transcripts.parquet.csv", + "spatialconverter/parquet_to_csv/versions.yml", + "untar", + "untar/test_run", + "untar/test_run/experiment.xenium", + "untar/test_run/gene_panel.json", + "untar/test_run/morphology.ome.tif", + "untar/test_run/transcripts.parquet" + ], + [ + "sampled_transcripts.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,ba06b22355a650c8b7118fcbc171162b", + "preview.html:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,dc0516ae9a452f7949e0e2e65b0201b0", + "transcripts.parquet.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,b7a26f2cff61d87a77f2db813dbc851a", + "experiment.xenium:md5,d41d8cd98f00b204e9800998ecf8427e", + "gene_panel.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "morphology.ome.tif:md5,d41d8cd98f00b204e9800998ecf8427e", + "transcripts.parquet:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.04.8" + }, + "timestamp": "2025-10-23T09:23:50.987857992" + } +} \ No newline at end of file diff --git a/tests/segfree_mode.nf.test b/tests/segfree_mode.nf.test new file mode 100644 index 0000000..ece296b --- /dev/null +++ b/tests/segfree_mode.nf.test @@ -0,0 +1,36 @@ +nextflow_pipeline { + + name "Test pipeline" + script "../main.nf" + tag "pipeline" + config "../conf/test_segfree_mode.config" + + test("-profile test") { + + options "-stub" + + when { + params { + outdir = "$outputDir" + } + } + + then { + // stable_name: All files + folders in ${params.outdir}/ with a stable name + def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}']) + // stable_path: All files in ${params.outdir}/ with stable content + def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') + assertAll( + { assert workflow.success}, + { assert snapshot( + // pipeline versions.yml file for multiqc from which Nextflow version is removed because we test pipelines on multiple Nextflow versions + removeNextflowVersion("$outputDir/pipeline_info/nf_core_spatialxe_software_mqc_versions.yml"), + // All stable path name, with a relative path + stable_name, + // All files with stable contents + stable_path + ).match() } + ) + } + } +} diff --git a/tests/segfree_mode.nf.test.snap b/tests/segfree_mode.nf.test.snap new file mode 100644 index 0000000..e8614a4 --- /dev/null +++ b/tests/segfree_mode.nf.test.snap @@ -0,0 +1,46 @@ +{ + "-profile test": { + "content": [ + { + "UNTAR": { + "untar": 1.34 + }, + "Workflow": { + "nf-core/spatialxe": "v1.0dev" + } + }, + [ + "baysor", + "baysor/segfree", + "baysor/segfree/test_run", + "baysor/segfree/test_run/ncvs.loom", + "baysor/segfree/versions.yml", + "multiqc", + "multiqc/multiqc_data", + "multiqc/multiqc_plots", + "multiqc/multiqc_report.html", + "pipeline_info", + "pipeline_info/nf_core_spatialxe_software_mqc_versions.yml", + "untar", + "untar/test_run", + "untar/test_run/experiment.xenium", + "untar/test_run/gene_panel.json", + "untar/test_run/morphology.ome.tif", + "untar/test_run/transcripts.parquet" + ], + [ + "ncvs.loom:md5,d41d8cd98f00b204e9800998ecf8427e", + "versions.yml:md5,63bed288b51a17ff6d425b7920ae7f13", + "experiment.xenium:md5,d41d8cd98f00b204e9800998ecf8427e", + "gene_panel.json:md5,d41d8cd98f00b204e9800998ecf8427e", + "morphology.ome.tif:md5,d41d8cd98f00b204e9800998ecf8427e", + "transcripts.parquet:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.04.8" + }, + "timestamp": "2025-10-23T09:24:05.726126177" + } +} \ No newline at end of file diff --git a/workflows/spatialxe.nf b/workflows/spatialxe.nf index 14bc65a..5c84b74 100644 --- a/workflows/spatialxe.nf +++ b/workflows/spatialxe.nf @@ -6,6 +6,8 @@ // multiqc include { MULTIQC } from '../modules/nf-core/multiqc/main' +include { MULTIQC as MULTIQC_PRE_XR_RUN } from '../modules/nf-core/multiqc/main' +include { MULTIQC as MULTIQC_POST_XR_RUN } from '../modules/nf-core/multiqc/main' include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline' // nf-core functionality @@ -72,6 +74,7 @@ workflow SPATIALXE { ch_exp_metadata = Channel.empty() ch_gene_synonyms = Channel.empty() ch_multiqc_files = Channel.empty() + ch_multiqc_report = Channel.empty() ch_qupath_polygons = Channel.empty() ch_morphology_image = Channel.empty() ch_redefined_bundle = Channel.empty() @@ -79,6 +82,8 @@ workflow SPATIALXE { ch_panel_probes_fasta = Channel.empty() ch_transcripts_parquet = Channel.empty() ch_reference_annotations = Channel.empty() + ch_multiqc_pre_xr_report = Channel.empty() + ch_multiqc_post_xr_report = Channel.empty() /* @@ -127,6 +132,12 @@ workflow SPATIALXE { // path to bundle input ch_bundle_path = ch_input.map { meta, bundle, _image -> + + def bundle_path = file(bundle) + if( !bundle_path.exists() ) { + log.error("❌ Check if the path to the xenium bundle exists.") + exit(1) + } return [meta, bundle] } @@ -438,8 +449,6 @@ workflow SPATIALXE { } - - /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SPATIALXE - SEGMENTATION-FREE LAYER @@ -528,23 +537,65 @@ workflow SPATIALXE { ) ) - // get all files from the redefined bundle - ch_redefined_bundle_files = ch_redefined_bundle.flatMap { _meta, path -> - file("${path}/*") - } + if (params.mode == 'image' || params.mode == 'coordinate') { - ch_multiqc_files = ch_multiqc_files.mix(ch_redefined_bundle_files.flatten()) + // get all files from the raw bundle + ch_raw_bundle_files = ch_bundle.flatMap { _meta, path -> + file("${path}/*") + } - MULTIQC( - ch_multiqc_files.collect(), - ch_multiqc_config.toList(), - ch_multiqc_custom_config.toList(), - ch_multiqc_logo.toList(), - [], - [], - ) + ch_multiqc_files = ch_multiqc_files.mix(ch_raw_bundle_files.flatten()) + + MULTIQC_PRE_XR_RUN ( + ch_multiqc_files.collect(), + ch_multiqc_config.toList(), + ch_multiqc_custom_config.toList(), + ch_multiqc_logo.toList(), + [], + [], + ) + ch_multiqc_pre_xr_report = MULTIQC_PRE_XR_RUN.out.report.toList() + + // get all files from the redefined bundle + ch_redefined_bundle_files = ch_redefined_bundle.flatMap { _meta, path -> + file("${path}/*") + } + + ch_multiqc_files = ch_multiqc_files.mix(ch_redefined_bundle_files.flatten()) + + MULTIQC_POST_XR_RUN ( + ch_multiqc_files.collect(), + ch_multiqc_config.toList(), + ch_multiqc_custom_config.toList(), + ch_multiqc_logo.toList(), + [], + [], + ) + ch_multiqc_post_xr_report = MULTIQC_POST_XR_RUN.out.report.toList() + + } else { + + ch_raw_bundle_path = ch_input.map { _meta, path, _image -> + return [path] + } + + ch_multiqc_files = ch_multiqc_files.mix(ch_raw_bundle_path.flatten()) + + MULTIQC ( + ch_multiqc_files.collect(), + ch_multiqc_config.toList(), + ch_multiqc_custom_config.toList(), + ch_multiqc_logo.toList(), + [], + [], + ) + ch_multiqc_report = MULTIQC.out.report.toList() + + } emit: - multiqc_report = MULTIQC.out.report.toList() // channel: /path/to/multiqc_report.html - versions = ch_versions // channel: [ path(versions.yml) ] + multiqc_pre_xr_report = ch_multiqc_pre_xr_report // channel: /path/to/multiqc_report.html + multiqc_post_xr_report = ch_multiqc_post_xr_report // channel: /path/to/multiqc_report.html + multiqc_report = ch_multiqc_report // channel: /path/to/multiqc_report.html + versions = ch_versions // channel: [ path(versions.yml) ] } From 547d9f1cb51a150ae5496d90909cd488abac467b Mon Sep 17 00:00:00 2001 From: khersameesh24 Date: Sat, 25 Oct 2025 23:23:27 +0200 Subject: [PATCH 2/2] added support for baysor preview html in multiqc report --- conf/modules.config | 18 ++++++ modules/local/baysor/preview/main.nf | 5 +- modules/local/utility/clean_html/main.nf | 43 +++++++++++++++ .../clean_html/templates/clean_html.py | 55 +++++++++++++++++++ modules/local/utility/get_coordinates/main.nf | 2 +- nextflow.config | 2 +- .../local/baysor_generate_preview/main.nf | 15 +++-- workflows/spatialxe.nf | 31 +++++++---- 8 files changed, 149 insertions(+), 22 deletions(-) create mode 100644 modules/local/utility/clean_html/main.nf create mode 100644 modules/local/utility/clean_html/templates/clean_html.py diff --git a/conf/modules.config b/conf/modules.config index 7f4a87b..3c13b56 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -27,6 +27,24 @@ process { ] } + withName: MULTIQC_PRE_XR_RUN { + ext.args = { params.multiqc_title ? "--title \"${params.multiqc_title}\"" : '' } + publishDir = [ + path: { "${params.outdir}/multiqc/raw_bundle" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, + ] + } + + withName: MULTIQC_POST_XR_RUN { + ext.args = { params.multiqc_title ? "--title \"${params.multiqc_title}\"" : '' } + publishDir = [ + path: { "${params.outdir}/multiqc/redefined_bundle" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, + ] + } + withName: XENIUMRANGER_RESEGMENT { publishDir = [ path: "${params.outdir}/xeniumranger/resegment", diff --git a/modules/local/baysor/preview/main.nf b/modules/local/baysor/preview/main.nf index d910d54..a35548b 100644 --- a/modules/local/baysor/preview/main.nf +++ b/modules/local/baysor/preview/main.nf @@ -29,10 +29,9 @@ process BAYSOR_PREVIEW { baysor preview \\ ${transcripts} \\ --config ${config} \\ + --output ${prefix}/preview.html ${args} - mv preview.html ${prefix}/preview.html - cat <<-END_VERSIONS > versions.yml "${task.process}": baysor: 0.7.1 @@ -49,7 +48,7 @@ process BAYSOR_PREVIEW { """ mkdir -p ${prefix} - touch "${prefix}/preview.html" + touch ${prefix}/preview.html cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/utility/clean_html/main.nf b/modules/local/utility/clean_html/main.nf new file mode 100644 index 0000000..3218224 --- /dev/null +++ b/modules/local/utility/clean_html/main.nf @@ -0,0 +1,43 @@ +process CLEAN_PREVIEW_HTML { + tag "${meta.id}" + label 'process_low' + + container "community.wave.seqera.io/library/beautifulsoup4_procs:3f09125465990b35" + + input: + tuple val(meta), path(preview_html) + + output: + tuple val(meta), path("${prefix}/preview_mqc.html"), emit: mqc_html + 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("CLEAN_HTML module does not support Conda. Please use Docker / Singularity / Podman instead.") + } + + prefix = task.ext.prefix ?: "${meta.id}" + + template('clean_html.py') + + stub: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error("CLEAN_HTML module does not support Conda. Please use Docker / Singularity / Podman instead.") + } + prefix = task.ext.prefix ?: "${meta.id}" + + """ + mkdir -p ${prefix} + touch ${prefix}/preview_mqc.html + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + CLEAN_HTML: "1.0.0" + END_VERSIONS + """ +} diff --git a/modules/local/utility/clean_html/templates/clean_html.py b/modules/local/utility/clean_html/templates/clean_html.py new file mode 100644 index 0000000..521d28d --- /dev/null +++ b/modules/local/utility/clean_html/templates/clean_html.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 + +from bs4 import BeautifulSoup +from pathlib import Path + +def clean_preview_html(input_html, output_mqc_html, height=800): + """ + 1. Cleans the Baysor preview HTML by removing the
containing +

Content

and the
    list. + 2. Inlines the cleaned HTML directly into a MultiQC _mqc.html wrapper. + """ + input_html = Path(input_html) + output_mqc_html = Path(prefix)/output_mqc_html + output_mqc_html.parent.mkdir(parents=True, exist_ok=True) + + # Step 1: Clean the HTML + with open(input_html, 'r') as f: + soup = BeautifulSoup(f, 'html.parser') + + for div in soup.find_all('div'): + h2 = div.find('h2') + ul = div.find('ul') + if h2 and h2.get_text(strip=True) == 'Content' and ul: + div.decompose() + + # Change all

    to

    + for h1 in soup.find_all('h1'): + h1.name = 'h3' + + cleaned_html_content = str(soup) + + # Step 2: Wrap and inline into MultiQC _mqc.html + wrapper_content = f""" + +{cleaned_html_content} +""" + + with open(output_mqc_html, 'w') as f: + f.write(wrapper_content) + + +if __name__ == '__main__': + preview_html = "${preview_html}" + output_html = "preview_mqc.html" + prefix = "${prefix}" + + clean_preview_html( + preview_html, + output_html + ) + + #Output versions.yml + with open("versions.yml", "w") as f: + f.write('"${task.process}":\\n') + f.write('CLEAN_PREVIEW_HTML: "1.0.0"\\n') diff --git a/modules/local/utility/get_coordinates/main.nf b/modules/local/utility/get_coordinates/main.nf index 87eee09..60ba76c 100644 --- a/modules/local/utility/get_coordinates/main.nf +++ b/modules/local/utility/get_coordinates/main.nf @@ -8,7 +8,7 @@ process GET_TRANSCRIPTS_COORDINATES { tuple val(meta), path(transcripts) output: - tuple val(meta), stdout(), emit: transcript_coordinates + stdout() path ("versions.yml"), emit: versions when: diff --git a/nextflow.config b/nextflow.config index 89a88a3..f07f70f 100644 --- a/nextflow.config +++ b/nextflow.config @@ -132,7 +132,7 @@ profiles { nextflow.enable.configProcessNamesValidation = true } conda { - conda.enabled = true + conda.enabled = false docker.enabled = false singularity.enabled = false podman.enabled = false diff --git a/subworkflows/local/baysor_generate_preview/main.nf b/subworkflows/local/baysor_generate_preview/main.nf index 8db0d93..672f28c 100644 --- a/subworkflows/local/baysor_generate_preview/main.nf +++ b/subworkflows/local/baysor_generate_preview/main.nf @@ -4,6 +4,7 @@ include { BAYSOR_PREVIEW } from '../../../modules/local/baysor/preview/main' include { BAYSOR_CREATE_DATASET } from '../../../modules/local/baysor/create_dataset/main' +include { CLEAN_PREVIEW_HTML } from '../../../modules/local/utility/clean_html/main' include { PARQUET_TO_CSV } from '../../../modules/local/utility/spatialconverter/parquet_to_csv/main' workflow BAYSOR_GENERATE_PREVIEW { @@ -13,8 +14,8 @@ workflow BAYSOR_GENERATE_PREVIEW { main: - ch_versions = Channel.empty() - ch_preview_html = Channel.empty() + ch_versions = Channel.empty() + ch_preview_mqc_html = Channel.empty() // run parquet to csv @@ -39,9 +40,13 @@ workflow BAYSOR_GENERATE_PREVIEW { BAYSOR_PREVIEW(ch_baysor_preview_input) ch_versions = ch_versions.mix(BAYSOR_PREVIEW.out.versions) - ch_preview_html = BAYSOR_PREVIEW.out.preview_html + // clean the preview html file generated + CLEAN_PREVIEW_HTML(BAYSOR_PREVIEW.out.preview_html) + ch_versions = ch_versions.mix(CLEAN_PREVIEW_HTML.out.versions) + + ch_preview_mqc_html = CLEAN_PREVIEW_HTML.out.mqc_html emit: - preview_html = ch_preview_html // channel: [ val(meta), ["preview.html"] ] - versions = ch_versions // channel: [ versions.yml ] + preview_html = ch_preview_mqc_html // channel: [ val(meta), ["preview_mqc.html"] ] + versions = ch_versions // channel: [ versions.yml ] } diff --git a/workflows/spatialxe.nf b/workflows/spatialxe.nf index 5c84b74..3c29300 100644 --- a/workflows/spatialxe.nf +++ b/workflows/spatialxe.nf @@ -71,6 +71,7 @@ workflow SPATIALXE { ch_raw_bundle = Channel.empty() ch_gene_panel = Channel.empty() ch_bundle_path = Channel.empty() + ch_preview_html = Channel.empty() ch_exp_metadata = Channel.empty() ch_gene_synonyms = Channel.empty() ch_multiqc_files = Channel.empty() @@ -293,6 +294,7 @@ workflow SPATIALXE { ch_transcripts_parquet, ch_config, ) + ch_preview_html = BAYSOR_GENERATE_PREVIEW.out.preview_html } /* @@ -539,12 +541,11 @@ workflow SPATIALXE { if (params.mode == 'image' || params.mode == 'coordinate') { - // get all files from the raw bundle - ch_raw_bundle_files = ch_bundle.flatMap { _meta, path -> - file("${path}/*") + // get path to the raw bundle + ch_just_bundle_path = ch_bundle_path.map { + _meta, bundle_path -> return [bundle_path] } - - ch_multiqc_files = ch_multiqc_files.mix(ch_raw_bundle_files.flatten()) + ch_multiqc_files = ch_multiqc_files.mix(ch_just_bundle_path.flatten()) MULTIQC_PRE_XR_RUN ( ch_multiqc_files.collect(), @@ -556,12 +557,12 @@ workflow SPATIALXE { ) ch_multiqc_pre_xr_report = MULTIQC_PRE_XR_RUN.out.report.toList() - // get all files from the redefined bundle - ch_redefined_bundle_files = ch_redefined_bundle.flatMap { _meta, path -> - file("${path}/*") + // get path to the redefined bundle + ch_just_redefined_bundle_path = ch_redefined_bundle.map { + _meta, bundle_path -> return [bundle_path] } - ch_multiqc_files = ch_multiqc_files.mix(ch_redefined_bundle_files.flatten()) + ch_multiqc_files = ch_multiqc_files.mix(ch_just_redefined_bundle_path.flatten()) MULTIQC_POST_XR_RUN ( ch_multiqc_files.collect(), @@ -575,11 +576,17 @@ workflow SPATIALXE { } else { - ch_raw_bundle_path = ch_input.map { _meta, path, _image -> - return [path] + // get path to the raw bundle + ch_just_bundle_path = ch_bundle_path.map { + _meta, bundle_path -> return [bundle_path] } + ch_multiqc_files = ch_multiqc_files.mix(ch_just_bundle_path.flatten()) - ch_multiqc_files = ch_multiqc_files.mix(ch_raw_bundle_path.flatten()) + // get the preview html file if preview mode is run + ch_just_preview_html = ch_preview_html.map { _meta, preview_html -> + return [preview_html] + } + ch_multiqc_files = ch_multiqc_files.mix(ch_just_preview_html.flatten()) MULTIQC ( ch_multiqc_files.collect(),