diff --git a/README.md b/README.md index dc6ca02..f544174 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,12 @@ ## Introduction -**nf-core/mcmicro** is a bioinformatics pipeline that ... +> **Warning:** +> We are currently in the process of porting the original MCMICRO to nf-core. This pipeline is therefore in active development. + +**nf-core/mcmicro** is a nextflow pipeline for processing highly-multiplexed imaging data, as produced by technologies such as Cycif, MIBI, CODEX, SeqIF among others. + +If you want to run the original MCMICRO pipeline outside of nf-core, please see . -1. Read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/)) -2. Present QC for raw reads ([`MultiQC`](http://multiqc.info/)) - -## Usage + -Now, you can run the pipeline using: + -```bash + :::warning Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those @@ -69,19 +71,19 @@ provided by the `-c` Nextflow option can be used to provide any configuration _* see [docs](https://nf-co.re/usage/configuration#custom-configuration-files). ::: -For more details and further functionality, please refer to the [usage documentation](https://nf-co.re/mcmicro/usage) and the [parameter documentation](https://nf-co.re/mcmicro/parameters). + -## Pipeline output + -## Credits + @@ -98,6 +100,8 @@ For further information or help, don't hesitate to get in touch on the [Slack `# +If you use nf-core/mcmicro for your analysis, please cite it using the following article: [Schapiro et al. 2022 Nat. Methods](https://www.nature.com/articles/s41592-021-01308-y) + An extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file. You can cite the `nf-core` publication as follows: diff --git a/bin/check_samplesheet.py b/bin/check_samplesheet.py index 4a758fe..9199613 100755 --- a/bin/check_samplesheet.py +++ b/bin/check_samplesheet.py @@ -24,17 +24,21 @@ class RowChecker: """ - VALID_FORMATS = ( - ".fq.gz", - ".fastq.gz", + VALID_IMAGE_FORMATS = ( + ".tiff", + ".tif" + ) + + VALID_MARKER_FORMATS = ( + ".csv" ) def __init__( self, sample_col="sample", - first_col="fastq_1", - second_col="fastq_2", - single_col="single_end", + first_col="image", + second_col="marker", + #single_col="single_end", **kwargs, ): """ @@ -43,20 +47,20 @@ def __init__( Args: sample_col (str): The name of the column that contains the sample name (default "sample"). - first_col (str): The name of the column that contains the first (or only) - FASTQ file path (default "fastq_1"). - second_col (str): The name of the column that contains the second (if any) - FASTQ file path (default "fastq_2"). - single_col (str): The name of the new column that will be inserted and - records whether the sample contains single- or paired-end sequencing - reads (default "single_end"). + first_col (str): The name of the column that contains the channel name + (default "channel"). + second_col (str): The name of the column that contains the image file + image file path (default "tiff"). + #single_col (str): The name of the new column that will be inserted and + # records whether the sample contains single- or paired-end sequencing + # reads (default "single_end"). """ super().__init__(**kwargs) self._sample_col = sample_col self._first_col = first_col self._second_col = second_col - self._single_col = single_col + #self._single_col = single_col self._seen = set() self.modified = [] @@ -72,7 +76,7 @@ def validate_and_transform(self, row): self._validate_sample(row) self._validate_first(row) self._validate_second(row) - self._validate_pair(row) + #self._validate_pair(row) self._seen.add((row[self._sample_col], row[self._first_col])) self.modified.append(row) @@ -84,50 +88,59 @@ def _validate_sample(self, row): row[self._sample_col] = row[self._sample_col].replace(" ", "_") def _validate_first(self, row): - """Assert that the first FASTQ entry is non-empty and has the right format.""" + """Assert that the image entry has the right format if it exists.""" if len(row[self._first_col]) <= 0: - raise AssertionError("At least the first FASTQ file is required.") - self._validate_fastq_format(row[self._first_col]) + raise AssertionError("Image required.") + self._validate_image_format(row[self._first_col]) def _validate_second(self, row): - """Assert that the second FASTQ entry has the right format if it exists.""" - if len(row[self._second_col]) > 0: - self._validate_fastq_format(row[self._second_col]) - - def _validate_pair(self, row): - """Assert that read pairs have the same file extension. Report pair status.""" - if row[self._first_col] and row[self._second_col]: - row[self._single_col] = False - first_col_suffix = Path(row[self._first_col]).suffixes[-2:] - second_col_suffix = Path(row[self._second_col]).suffixes[-2:] - if first_col_suffix != second_col_suffix: - raise AssertionError("FASTQ pairs must have the same file extensions.") - else: - row[self._single_col] = True - - def _validate_fastq_format(self, filename): - """Assert that a given filename has one of the expected FASTQ extensions.""" - if not any(filename.endswith(extension) for extension in self.VALID_FORMATS): + """Assert that the image entry has the right format if it exists.""" + if len(row[self._second_col]) <= 0: + raise AssertionError("Marker required.") + self._validate_marker_format(row[self._second_col]) + + # def _validate_pair(self, row): + # """Assert that read pairs have the same file extension. Report pair status.""" + # if row[self._first_col] and row[self._second_col]: + # row[self._single_col] = False + # first_col_suffix = Path(row[self._first_col]).suffixes[-2:] + # second_col_suffix = Path(row[self._second_col]).suffixes[-2:] + # if first_col_suffix != second_col_suffix: + # raise AssertionError("FASTQ pairs must have the same file extensions.") + # else: + # row[self._single_col] = True + + def _validate_image_format(self, filename): + """Assert that a given filename has image extension.""" + if not any(filename.endswith(extension) for extension in self.VALID_IMAGE_FORMATS): + raise AssertionError( + f"The image file has an unrecognized extension: {filename}\n" + f"It should be one of: {', '.join(self.VALID_IMAGE_FORMATS)}" + ) + + def _validate_marker_format(self, filename): + """Assert that a given filename has marker extension.""" + if not any(filename.endswith(extension) for extension in self.VALID_MARKER_FORMATS): raise AssertionError( - f"The FASTQ file has an unrecognized extension: {filename}\n" - f"It should be one of: {', '.join(self.VALID_FORMATS)}" + f"The marker file has an unrecognized extension: {filename}\n" + f"It should be one of: {', '.join(self.VALID_MARKER_FORMATS)}" ) def validate_unique_samples(self): """ - Assert that the combination of sample name and FASTQ filename is unique. + Assert that the combination of sample name and image filename is unique. In addition to the validation, also rename all samples to have a suffix of _T{n}, where n is the - number of times the same sample exist, but with different FASTQ files, e.g., multiple runs per experiment. + number of times the same sample exist, but with different image files, e.g., multiple runs per experiment. """ if len(self._seen) != len(self.modified): - raise AssertionError("The pair of sample name and FASTQ must be unique.") + raise AssertionError("The pair of channel and image must be unique.") seen = Counter() for row in self.modified: sample = row[self._sample_col] seen[sample] += 1 - row[self._sample_col] = f"{sample}_T{seen[sample]}" + #row[self._sample_col] = f"{sample}_T{seen[sample]}" def read_head(handle, num_lines=10): @@ -166,8 +179,8 @@ def check_samplesheet(file_in, file_out): """ Check that the tabular samplesheet has the structure expected by nf-core pipelines. - Validate the general shape of the table, expected columns, and each row. Also add - an additional column which records whether one or two FASTQ reads were found. + Validate the general shape of the table, expected columns, and each row. + # Also add an additional column which records whether one or two FASTQ reads were found. Args: file_in (pathlib.Path): The given tabular samplesheet. The format can be either @@ -179,16 +192,16 @@ def check_samplesheet(file_in, file_out): This function checks that the samplesheet follows the following structure, see also the `viral recon samplesheet`_:: - sample,fastq_1,fastq_2 - SAMPLE_PE,SAMPLE_PE_RUN1_1.fastq.gz,SAMPLE_PE_RUN1_2.fastq.gz - SAMPLE_PE,SAMPLE_PE_RUN2_1.fastq.gz,SAMPLE_PE_RUN2_2.fastq.gz - SAMPLE_SE,SAMPLE_SE_RUN1_1.fastq.gz, + sample,ffp,dfp + SAMPLE,001,exemplar-001-cycle-08.ome.tiff,markers.csv + SAMPLE,001,exemplar-001-cycle-07.ome.tiff,markers.csv + SAMPLE,001,exemplar-001-cycle-06.ome.tiff,markers.csv - .. _viral recon samplesheet: - https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv + #.. _viral recon samplesheet: + # https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv """ - required_columns = {"sample", "fastq_1", "fastq_2"} + required_columns = {"sample", "image", "marker"} # See https://docs.python.org/3.9/library/csv.html#id3 to read up on `newline=""`. with file_in.open(newline="") as in_handle: reader = csv.DictReader(in_handle, dialect=sniff_format(in_handle)) @@ -207,7 +220,7 @@ def check_samplesheet(file_in, file_out): sys.exit(1) checker.validate_unique_samples() header = list(reader.fieldnames) - header.insert(1, "single_end") + #header.insert(1, "single_end") # See https://docs.python.org/3.9/library/csv.html#id3 to read up on `newline=""`. with file_out.open(mode="w", newline="") as out_handle: writer = csv.DictWriter(out_handle, header, delimiter=",") diff --git a/conf/modules.config b/conf/modules.config index 39e8138..e837ac6 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -26,10 +26,6 @@ process { ] } - withName: FASTQC { - ext.args = '--quiet' - } - withName: CUSTOM_DUMPSOFTWAREVERSIONS { publishDir = [ path: { "${params.outdir}/pipeline_info" }, diff --git a/lib/WorkflowMain.groovy b/lib/WorkflowMain.groovy index ac0dace..5ad7823 100755 --- a/lib/WorkflowMain.groovy +++ b/lib/WorkflowMain.groovy @@ -52,6 +52,7 @@ class WorkflowMain { // // Get attribute from genome config file e.g. fasta // + /* public static Object getGenomeAttribute(params, attribute) { if (params.genomes && params.genome && params.genomes.containsKey(params.genome)) { if (params.genomes[ params.genome ].containsKey(attribute)) { @@ -60,4 +61,5 @@ class WorkflowMain { } return null } + */ } diff --git a/lib/WorkflowMcmicro.groovy b/lib/WorkflowMcmicro.groovy index 54ee5e1..68deb04 100755 --- a/lib/WorkflowMcmicro.groovy +++ b/lib/WorkflowMcmicro.groovy @@ -10,15 +10,16 @@ class WorkflowMcmicro { // // Check and validate parameters // + /* public static void initialise(params, log) { genomeExistsError(params, log) - if (!params.fasta) { Nextflow.error "Genome fasta file not specified with e.g. '--fasta genome.fa' or via a detectable config file." } } + */ // // Get workflow summary for MultiQC @@ -109,6 +110,7 @@ class WorkflowMcmicro { // // Exit pipeline if incorrect --genome key provided // + /* private static void genomeExistsError(params, log) { if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { def error_string = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + @@ -119,4 +121,5 @@ class WorkflowMcmicro { Nextflow.error(error_string) } } + */ } diff --git a/modules.json b/modules.json index a34d175..dba694f 100644 --- a/modules.json +++ b/modules.json @@ -5,19 +5,54 @@ "https://github.com/nf-core/modules.git": { "modules": { "nf-core": { + "ashlar": { + "branch": "master", + "git_sha": "97b7dc798a002688b6304a453da932b2144727b1", + "installed_by": ["modules"] + }, + "backsub": { + "branch": "master", + "git_sha": "240937a2a9c30298110753292be041188891f2cb", + "installed_by": ["modules"] + }, + "basicpy": { + "branch": "master", + "git_sha": "716ef3019b66772a817b417078edce2f7b337858", + "installed_by": ["modules"] + }, + "cellpose": { + "branch": "master", + "git_sha": "716ef3019b66772a817b417078edce2f7b337858", + "installed_by": ["modules"] + }, "custom/dumpsoftwareversions": { "branch": "master", - "git_sha": "911696ea0b62df80e900ef244d7867d177971f73", + "git_sha": "05c280924b6c768d484c7c443dad5e605c4ff4b4", + "installed_by": ["modules"] + }, + "deepcell/mesmer": { + "branch": "master", + "git_sha": "b9829e1064382745d8dff7f1d74d2138d2864f71", "installed_by": ["modules"] }, "fastqc": { "branch": "master", - "git_sha": "bd8092b67b5103bdd52e300f75889442275c3117", + "git_sha": "9a4517e720bc812e95b56d23d15a1653b6db4f53", + "installed_by": ["modules"] + }, + "mcquant": { + "branch": "master", + "git_sha": "b9829e1064382745d8dff7f1d74d2138d2864f71", "installed_by": ["modules"] }, "multiqc": { "branch": "master", - "git_sha": "911696ea0b62df80e900ef244d7867d177971f73", + "git_sha": "a6e11ac655e744f7ebc724be669dd568ffdc0e80", + "installed_by": ["modules"] + }, + "scimap/mcmicro": { + "branch": "master", + "git_sha": "ebb27711cd5f4de921244bfa81c676504072d31c", "installed_by": ["modules"] } } diff --git a/modules/nf-core/ashlar/main.nf b/modules/nf-core/ashlar/main.nf new file mode 100644 index 0000000..2316b02 --- /dev/null +++ b/modules/nf-core/ashlar/main.nf @@ -0,0 +1,52 @@ +process ASHLAR { + tag '$meta.id' + label 'process_single' + + conda "bioconda::ashlar=1.17.0" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/ashlar:1.17.0--pyh5e36f6f_0' : + 'biocontainers/ashlar:1.17.0--pyh5e36f6f_0' }" + + input: + tuple val(meta), path(images) + path(opt_dfp) + path(opt_ffp) + + output: + tuple val(meta), path("*.ome.tif"), emit: tif + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def dfp = opt_dfp ? "--dfp $opt_dfp" : "" + def ffp = opt_ffp ? "--ffp $opt_ffp" : "" + def num_files = images instanceof List ? images.size() : 1 + def opt_dfp_size = opt_dfp instanceof List ? opt_dfp.size() : 1 + def opt_ffp_size = opt_ffp instanceof List ? opt_ffp.size() : 1 + def dfp_validated = (opt_dfp_size == 0 || opt_dfp_size == 1 || opt_dfp_size == num_files) ? true : false + def ffp_validated = (opt_ffp_size == 0 || opt_ffp_size == 1 || opt_ffp_size == num_files) ? true : false + + if ( !dfp_validated ) { error "Please input only zero, one, or N dfp files, where N is the number of input images" } + if ( !ffp_validated ) { error "Please input only zero, one, or N ffp files, where N is the number of input images" } + + """ + + ashlar \\ + -o ${prefix}.ome.tif \\ + $images \\ + $args \\ + $dfp \\ + $ffp + + sed -i -E 's/UUID="urn:uuid:[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12}"/ /g' ${prefix}.ome.tif + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + ashlar: \$(ashlar --version 2>&1 | sed 's/^.*ashlar //; s/Using.*\$//' ) + END_VERSIONS + """ +} diff --git a/modules/nf-core/ashlar/meta.yml b/modules/nf-core/ashlar/meta.yml new file mode 100644 index 0000000..244e972 --- /dev/null +++ b/modules/nf-core/ashlar/meta.yml @@ -0,0 +1,42 @@ +name: "ashlar" +description: Alignment by Simultaneous Harmonization of Layer/Adjacency Registration +keywords: + - image_processing + - alignment + - registration +tools: + - "ashlar": + description: "Alignment by Simultaneous Harmonization of Layer/Adjacency Registration" + homepage: "https://labsyspharm.github.io/ashlar/" + documentation: "https://labsyspharm.github.io/ashlar/" + doi: "10.1093/bioinformatics/btac544" + licence: ["MIT"] + +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - images: + type: file + description: Overlapping tile image data in formats from most commercial microscopes + pattern: "*.{ome.tiff,ome.tif,rcpnl,btf,nd2,tiff,tif,czi}" +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - tif: + type: file + description: A pyramidal, tiled OME-TIFF file created from input images. + pattern: "*.ome.tif" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + +authors: + - "@RobJY" + - "@jmuhlich" diff --git a/modules/nf-core/backsub/main.nf b/modules/nf-core/backsub/main.nf new file mode 100644 index 0000000..2d24277 --- /dev/null +++ b/modules/nf-core/backsub/main.nf @@ -0,0 +1,46 @@ +process BACKSUB { + tag "$meta.id" + label 'process_single' + + container "ghcr.io/schapirolabor/background_subtraction:v0.3.4" + + input: + tuple val(meta) , path(image) + tuple val(meta2), path(markerfile) + + output: + tuple val(meta), path("${prefix}.backsub.ome.tif"), emit: backsub_tif + tuple val(meta2), path("*.csv") , emit: markerout + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + prefix = task.ext.prefix ?: "${meta.id}" + """ + python3 /background_subtraction/background_sub.py \ + -o "${prefix}.backsub.ome.tif" \ + -mo markers_bs.csv \ + -r $image \ + -m $markerfile \ + $args + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + backsub: \$(python3 /background_subtraction/background_sub.py --version | sed 's/v//g') + END_VERSIONS + """ + + stub: + prefix = task.ext.prefix ?: "${meta.id}" + """ + touch "${prefix}.backsub.ome.tif" + touch "markers_bs.csv" + cat <<-END_VERSIONS > versions.yml + "${task.process}": + backsub: \$(python3 /background_subtraction/background_sub.py --version | sed 's/v//g') + END_VERSIONS + """ +} diff --git a/modules/nf-core/backsub/meta.yml b/modules/nf-core/backsub/meta.yml new file mode 100644 index 0000000..4464502 --- /dev/null +++ b/modules/nf-core/backsub/meta.yml @@ -0,0 +1,72 @@ +name: "backsub" +description: Pixel-by-pixel channel subtraction scaled by exposure times of pre-stitched `tif` images. +keywords: + - background + - cycif + - autofluorescence + - image_analysis + - mcmicro + - highly_multiplexed_imaging + +tools: + - "backsub": + description: "Module for pixel-by-pixel channel subtraction scaled by exposure times" + homepage: "https://github.com/SchapiroLabor/Background_subtraction" + documentation: "https://github.com/SchapiroLabor/Background_subtraction/blob/master/README.md" + tool_dev_url: "https://github.com/SchapiroLabor/Background_subtraction" + licence: "MIT licence" + +input: + # Only when we have meta + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + + - image: + type: file + description: Multi-channel image file + pattern: "*.{tif,tiff}" + + - meta2: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + + - markerfile: + type: file + description: Marker file with channel names, exposure times, and specified background to subtract (and remove to exclude channels from output) + pattern: "*.csv" + +output: + #Only when we have meta + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + + - backsub_tif: + type: file + description: Background corrected pyramidal ome.tif + pattern: "*.{tif}" + + - meta2: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + + - markerout: + type: file + description: Marker file adjusted to match the background corrected image + pattern: "*.{csv}" +authors: + - "@kbestak" diff --git a/modules/nf-core/basicpy/main.nf b/modules/nf-core/basicpy/main.nf new file mode 100644 index 0000000..cfcf9ac --- /dev/null +++ b/modules/nf-core/basicpy/main.nf @@ -0,0 +1,48 @@ +process BASICPY { + tag "$meta.id" + label 'process_single' + + container "docker.io/yfukai/basicpy-docker-mcmicro:0.2.1" + + input: + tuple val(meta), path(image) + + output: + tuple val(meta), path("*.tiff"), emit: fields + 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 "Basicpy module does not support Conda. Please use Docker / Singularity instead." + } + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def VERSION = "1.0.1" // WARN: Version information not provided by tool on CLI. Please update this string when bumping + """ + /opt/main.py -i $image -o . $args + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + basicpy:: $VERSION + END_VERSIONS + """ + + stub: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "Basicpy module does not support Conda. Please use Docker / Singularity instead." + } + """ + touch ${prefix}.-dfp.tiff + touch ${prefix}.-dfp.tiff + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + basicpy:: $VERSION + END_VERSIONS + """ +} diff --git a/modules/nf-core/basicpy/meta.yml b/modules/nf-core/basicpy/meta.yml new file mode 100644 index 0000000..1415178 --- /dev/null +++ b/modules/nf-core/basicpy/meta.yml @@ -0,0 +1,47 @@ +name: "basicpy" +description: BaSiCPy is a python package for background and shading correction of optical microscopy images. It is developed based on the Matlab version of BaSiC tool with major improvements in the algorithm. +keywords: + - illumiation_correction + - background_correction + - microscopy + - imaging +tools: + - "basicpy": + description: "BaSiCPy is a python package for background and shading correction of optical microscopy images. It is developed based on the Matlab version of BaSiC tool with major improvements in the algorithm. The container of this tool needs to be initialized with an empty Entrypoint. See the nextflow.config of the tests for details." + homepage: "https://github.com/peng-lab/BaSiCPy" + documentation: "https://basicpy.readthedocs.io/en/latest/index.html" + tool_dev_url: "https://github.com/peng-lab/BaSiCPy" + doi: 10.1038/ncomms14836 + licence: "MIT License" + +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + + - image: + type: file + description: Tiff file to be used for dark and flat field illumination correction + pattern: "*.{tiff,tif}" + +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + + - fields: + type: file + description: Tiff fields for dark and flat field illumination correction + pattern: "*.{tiff,tif}" + +authors: + - "@FloWuenne" diff --git a/modules/nf-core/cellpose/main.nf b/modules/nf-core/cellpose/main.nf new file mode 100644 index 0000000..a2b2206 --- /dev/null +++ b/modules/nf-core/cellpose/main.nf @@ -0,0 +1,56 @@ +process CELLPOSE { + tag "$meta.id" + label 'process_medium' + + container "docker.io/biocontainers/cellpose:2.1.1_cv2" + + input: + tuple val(meta), path(image) + path(model) + + output: + tuple val(meta), path("*masks.tif"), emit: mask + 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 "I did not manage to create a cellpose module in Conda that works in all OSes. 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" : "" + def VERSION = '2.1.1' + """ + cellpose \ + --image_path $image \ + --save_tif \ + --verbose \ + $model_command \ + $args + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + cellpose: $VERSION + 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 VERSION = "2.1.1" // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. + """ + touch ${prefix}_cp_masks.tif + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + cellpose: $VERSION + END_VERSIONS + """ + +} diff --git a/modules/nf-core/cellpose/meta.yml b/modules/nf-core/cellpose/meta.yml new file mode 100644 index 0000000..b452f57 --- /dev/null +++ b/modules/nf-core/cellpose/meta.yml @@ -0,0 +1,46 @@ +name: "cellpose" +description: cellpose segments cells in images +keywords: + - segmentation + - image + - cellpose +tools: + - "cellpose": + description: "cellpose is an anatomical segmentation algorithm written in Python 3 by Carsen Stringer and Marius Pachitariu" + homepage: "https://github.com/MouseLand/cellpose" + documentation: "https://cellpose.readthedocs.io/en/latest/command.html" + tool_dev_url: "https://github.com/MouseLand/cellpose" + doi: 10.1038/s41592-022-01663-4 + licence: "BSD 3-Clause" + +input: + - meta: + type: map + description: | + Groovy Map containing sample information + (sample id) + - image: + type: file + description: tif file for ready for segmentation + pattern: "*.{tif,tiff}" + - model: + type: file + description: Optional input file. Cellpose 2 model trained by user using human-in-the-loop approach. + +output: + - meta: + type: map + description: | + Groovy Map containing sample information + [sample id] + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + - mask: + type: file + description: labelled mask output from cellpose in tif format + pattern: "*.{tif, tiff}" + +authors: + - "@josenimo" diff --git a/modules/nf-core/custom/dumpsoftwareversions/main.nf b/modules/nf-core/custom/dumpsoftwareversions/main.nf index ebc8727..c9d014b 100644 --- a/modules/nf-core/custom/dumpsoftwareversions/main.nf +++ b/modules/nf-core/custom/dumpsoftwareversions/main.nf @@ -2,10 +2,10 @@ process CUSTOM_DUMPSOFTWAREVERSIONS { label 'process_single' // Requires `pyyaml` which does not have a dedicated container but is in the MultiQC container - conda "bioconda::multiqc=1.14" + conda "bioconda::multiqc=1.15" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.14--pyhdfd78af_0' : - 'biocontainers/multiqc:1.14--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.15--pyhdfd78af_0' : + 'biocontainers/multiqc:1.15--pyhdfd78af_0' }" input: path versions diff --git a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py index e55b8d4..da03340 100755 --- a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py +++ b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py @@ -4,11 +4,10 @@ """Provide functions to merge multiple versions.yml files.""" +import yaml import platform from textwrap import dedent -import yaml - def _make_versions_html(versions): """Generate a tabular HTML output of all versions for MultiQC.""" diff --git a/modules/nf-core/deepcell/mesmer/main.nf b/modules/nf-core/deepcell/mesmer/main.nf new file mode 100644 index 0000000..56d96c5 --- /dev/null +++ b/modules/nf-core/deepcell/mesmer/main.nf @@ -0,0 +1,39 @@ +process DEEPCELL_MESMER { + tag "$meta.id" + label 'process_single' + + container "docker.io/vanvalenlab/deepcell-applications:0.4.1" + + input: + tuple val(meta) , path(img) + tuple val(meta2), path(membrane_img) + + // Output a .tif image, don't touch versions + output: + tuple val(meta), path("mask.tif"), emit: mask + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def membrane_command = membrane_img ? "--membrane-image $membrane_img" : "" + def VERSION = "0.4.0" + + """ + python /usr/src/app/run_app.py mesmer \ + --squeeze \ + --nuclear-image $img \ + --output-directory . \ + --output-name mask.tif \ + $membrane_command \ + $args + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + deepcell_mesmer:: $VERSION + END_VERSIONS + """ +} diff --git a/modules/nf-core/deepcell/mesmer/meta.yml b/modules/nf-core/deepcell/mesmer/meta.yml new file mode 100644 index 0000000..49fd391 --- /dev/null +++ b/modules/nf-core/deepcell/mesmer/meta.yml @@ -0,0 +1,49 @@ +name: "deepcell_mesmer" +description: Deepcell/mesmer segmentation for whole-cell +keywords: + - imaging + - spatial_omics + - segmentation +tools: + - "mesmer": + description: "Deep cell is a collection of tools to segment imaging data" + homepage: "https://github.com/vanvalenlab/deepcell-tf" + documentation: "https://github.com/vanvalenlab/intro-to-deepcell/tree/master/pretrained_models" + tool_dev_url: "https://githu/b.com/vanvalenlab/deepcell-tf" + doi: 10.1038/s41587-021-01094-0 + licence: "APACHE2" + +input: + # Only when we have meta + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + # We always need to have an image of the tissue. (That's the whole point fo cell segmentation) + - img: + type: file + description: Multichannel image file + pattern: "*.{tiff,tif,h5,hdf5}" + +output: + #Only when we have meta + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + # + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + + - mask: + type: file + description: File containing the mask. + pattern: "*.{tif, tiff}" + +authors: + - "@migueLib" + - "@chiarasch" diff --git a/modules/nf-core/fastqc/meta.yml b/modules/nf-core/fastqc/meta.yml deleted file mode 100644 index 4da5bb5..0000000 --- a/modules/nf-core/fastqc/meta.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: fastqc -description: Run FastQC on sequenced reads -keywords: - - quality control - - qc - - adapters - - fastq -tools: - - fastqc: - description: | - FastQC gives general quality metrics about your reads. - It provides information about the quality score distribution - across your reads, the per base sequence content (%A/C/G/T). - You get information about adapter contamination and other - overrepresented sequences. - homepage: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/ - documentation: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/ - licence: ["GPL-2.0-only"] -input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - reads: - type: file - description: | - List of input FastQ files of size 1 and 2 for single-end and paired-end data, - respectively. -output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - html: - type: file - description: FastQC report - pattern: "*_{fastqc.html}" - - zip: - type: file - description: FastQC report archive - pattern: "*_{fastqc.zip}" - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" -authors: - - "@drpatelh" - - "@grst" - - "@ewels" - - "@FelixKrueger" diff --git a/modules/nf-core/mcquant/main.nf b/modules/nf-core/mcquant/main.nf new file mode 100644 index 0000000..bc0eedf --- /dev/null +++ b/modules/nf-core/mcquant/main.nf @@ -0,0 +1,49 @@ +process MCQUANT { + tag "$meta.id" + label 'process_single' + + // WARN: Version information not provided by tool on CLI. Please update version string below when bumping container versions. + container "docker.io/labsyspharm/quantification:1.5.4" + + input: + tuple val(meta), path(image) + tuple val(meta2), path(mask) + tuple val(meta3), path(markerfile) + + output: + tuple val(meta), path("*.csv"), emit: csv + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def VERSION = '1.5.4' // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. + """ + python /app/CommandSingleCellExtraction.py \ + --masks $mask \ + --image $image \ + --channel_names $markerfile \ + --output . \ + $args + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + mcquant: $VERSION + END_VERSIONS + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + def VERSION = '1.5.4' + """ + touch ${prefix}.csv + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + mcquant: $VERSION + END_VERSIONS + """ +} diff --git a/modules/nf-core/mcquant/meta.yml b/modules/nf-core/mcquant/meta.yml new file mode 100644 index 0000000..5400314 --- /dev/null +++ b/modules/nf-core/mcquant/meta.yml @@ -0,0 +1,69 @@ +name: "mcquant" +description: write your description here +keywords: + - quantification + - image_analysis + - mcmicro + - highly_multiplexed_imaging +tools: + - "mcquant": + description: "Module for single-cell data extraction given a segmentation mask and multi-channel image. The CSV structure is aligned with histoCAT output." + homepage: "https://github.com/labsyspharm/quantification" + documentation: "https://github.com/labsyspharm/quantification/blob/master/README.md" + tool_dev_url: "https://github.com/labsyspharm/quantification" + doi: 10.1038/s41592-021-01308-y + licence: "" + +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + + - image: + type: file + description: Multi-channel image file + pattern: "*.{tiff,tif,h5,hdf5}" + + - meta2: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + + - mask: + type: file + description: Labeled segmentation mask for image + pattern: "*.{tiff,tif,h5,hdf5}" + + - meta3: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + + - markerfile: + type: file + description: Marker file with channel names for image to quantify + pattern: "*.{csv}" + +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + + - csv: + type: file + description: Quantified regionprops_table + pattern: "*.{csv}" + +authors: + - "@FloWuenne" diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 1fc387b..65d7dd0 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -1,10 +1,10 @@ process MULTIQC { label 'process_single' - conda "bioconda::multiqc=1.14" + conda "bioconda::multiqc=1.15" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.14--pyhdfd78af_0' : - 'biocontainers/multiqc:1.14--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.15--pyhdfd78af_0' : + 'biocontainers/multiqc:1.15--pyhdfd78af_0' }" input: path multiqc_files, stageAs: "?/*" diff --git a/modules/nf-core/scimap/mcmicro/main.nf b/modules/nf-core/scimap/mcmicro/main.nf new file mode 100644 index 0000000..c8ff4ce --- /dev/null +++ b/modules/nf-core/scimap/mcmicro/main.nf @@ -0,0 +1,35 @@ +process SCIMAP_MCMICRO { + tag "$meta.id" + label 'process_single' + + container "docker.io/labsyspharm/scimap:0.22.0" + + input: + tuple val(meta), path(cellbyfeature) + + output: + tuple val(meta), path("*.csv") , emit: annotedDataCsv, optional:true + tuple val(meta), path("*.h5ad") , emit: annotedDataH5ad, optional:true + 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 "Scimap module does not support Conda. Please use Docker / Singularity / Podman instead." + } + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def VERSION='0.22.0' // WARN: Version information not provided by tool on CLI. Please update this string when bumping + """ + scimap-mcmicro $cellbyfeature -o . + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + scimap: $VERSION + END_VERSIONS + """ + +} diff --git a/modules/nf-core/scimap/mcmicro/meta.yml b/modules/nf-core/scimap/mcmicro/meta.yml new file mode 100644 index 0000000..b4b8086 --- /dev/null +++ b/modules/nf-core/scimap/mcmicro/meta.yml @@ -0,0 +1,54 @@ +name: "scimap_mcmicro" +description: SCIMAP is a suite of tools that enables spatial single-cell analyses +keywords: + - sort + - spatial + - single cell +tools: + - "scimap": + description: "Scimap is a scalable toolkit for analyzing spatial molecular data." + homepage: "https://scimap.xyz/" + documentation: "https://scimap.xyz/All%20Functions/A.%20Pre%20Processing/sm.pp.mcmicro_to_scimap/" + tool_dev_url: "https://github.com/labsyspharm/scimap" + licence: "MIT License" + +input: + # Only when we have meta + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - cellByFeature: + type: file + description: CSV file with cell by feature table + pattern: "*.{csv}" + +output: + #Only when we have meta + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + # + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + - annotedDataCsv: + type: file + description: Sorted CSV file + pattern: "*.{csv}" + - annotedDataH5ad: + type: file + description: Sorted H5AD file + pattern: "*.{h5ad}" + + # - clusterPlot: + # type: file + # description: UPMA plot of the data in pdf file + # pattern: "*.pdf" + +authors: + - "@luiskuhn" diff --git a/nextflow.config b/nextflow.config index 61fe7df..6a02ec1 100644 --- a/nextflow.config +++ b/nextflow.config @@ -12,11 +12,14 @@ params { // TODO nf-core: Specify your pipeline's command line flags // Input options input = null + // References - genome = null - igenomes_base = 's3://ngi-igenomes/igenomes' - igenomes_ignore = false - + //genome = null + //igenomes_base = 's3://ngi-igenomes/igenomes' + //igenomes_ignore = false + + // Illumination options + illumination = false // MultiQC options multiqc_config = null @@ -43,7 +46,7 @@ params { custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" config_profile_contact = null config_profile_url = null - + // Max resource options // Defaults only, expecting to be overwritten @@ -185,11 +188,13 @@ plugins { } // Load igenomes.config if required +/* if (!params.igenomes_ignore) { includeConfig 'conf/igenomes.config' } else { params.genomes = [:] } +*/ // Export these variables to prevent local Python/R libraries from conflicting with those in the container // The JULIA depot path has been adjusted to a fixed path `/usr/local/share/julia` that needs to be used for packages in the container. // See https://apeltzer.github.io/post/03-julia-lang-nextflow/ for details on that. Once we have a common agreement on where to keep Julia packages, this is adjustable. diff --git a/nextflow_schema.json b/nextflow_schema.json index 314dad7..69b2195 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -42,37 +42,6 @@ } } }, - "reference_genome_options": { - "title": "Reference genome options", - "type": "object", - "fa_icon": "fas fa-dna", - "description": "Reference genome related files and options required for the workflow.", - "properties": { - "genome": { - "type": "string", - "description": "Name of iGenomes reference.", - "fa_icon": "fas fa-book", - "help_text": "If using a reference genome configured in the pipeline using iGenomes, use this parameter to give the ID for the reference. This is then used to build the full paths for all required reference genome files e.g. `--genome GRCh38`. \n\nSee the [nf-core website docs](https://nf-co.re/usage/reference_genomes) for more details." - }, - "fasta": { - "type": "string", - "format": "file-path", - "exists": true, - "mimetype": "text/plain", - "pattern": "^\\S+\\.fn?a(sta)?(\\.gz)?$", - "description": "Path to FASTA genome file.", - "help_text": "This parameter is *mandatory* if `--genome` is not specified. If you don't have a BWA index available this will be generated for you automatically. Combine with `--save_reference` to save BWA index for future runs.", - "fa_icon": "far fa-file-code" - }, - "igenomes_ignore": { - "type": "boolean", - "description": "Do not load the iGenomes reference config.", - "fa_icon": "fas fa-ban", - "hidden": true, - "help_text": "Do not load `igenomes.config` when running the pipeline. You may choose this option if you observe clashes between custom parameters and those supplied in `igenomes.config`." - } - } - }, "institutional_config_options": { "title": "Institutional config options", "type": "object", @@ -264,6 +233,10 @@ "description": "Validation of parameters in lenient more.", "hidden": true, "help_text": "Allows string values that are parseable as numbers or booleans. For further information see [JSONSchema docs](https://github.com/everit-org/json-schema#lenient-mode)." + }, + "illumination": { + "type": "boolean", + "default": false } } } @@ -272,9 +245,6 @@ { "$ref": "#/definitions/input_output_options" }, - { - "$ref": "#/definitions/reference_genome_options" - }, { "$ref": "#/definitions/institutional_config_options" }, @@ -284,5 +254,11 @@ { "$ref": "#/definitions/generic_options" } - ] + ], + "properties": { + "validationSchemaIgnoreParams": { + "type": "string", + "default": "genomes" + } + } } diff --git a/subworkflows/local/input_check.nf b/subworkflows/local/input_check.nf index 0aecf87..b271912 100644 --- a/subworkflows/local/input_check.nf +++ b/subworkflows/local/input_check.nf @@ -9,14 +9,26 @@ workflow INPUT_CHECK { samplesheet // file: /path/to/samplesheet.csv main: + + /* + if( params.illumination){ + SAMPLESHEET_CHECK ( samplesheet ) + .csv + .splitCsv ( header:true, sep:',' ) + .map { create_fastq_channel(it) } + .groupTuple(by: [0]) + .map { meta, reads -> [ meta, reads.flatten() ] } + .set { images_merged } + } + */ SAMPLESHEET_CHECK ( samplesheet ) - .csv - .splitCsv ( header:true, sep:',' ) - .map { create_fastq_channel(it) } - .set { reads } + .csv + .splitCsv ( header:true, sep:',' ) + .map { create_fastq_channel(it) } + .set { input } emit: - reads // channel: [ val(meta), [ reads ] ] + input // channel: [ val(meta), [ image ], [ marker ] ] versions = SAMPLESHEET_CHECK.out.versions // channel: [ versions.yml ] } @@ -25,20 +37,25 @@ def create_fastq_channel(LinkedHashMap row) { // create meta map def meta = [:] meta.id = row.sample - meta.single_end = row.single_end.toBoolean() + // meta.tiff = row.single_end.toBoolean() // add path(s) of the fastq file(s) to the meta map - def fastq_meta = [] - if (!file(row.fastq_1).exists()) { - exit 1, "ERROR: Please check input samplesheet -> Read 1 FastQ file does not exist!\n${row.fastq_1}" + //def fastq_meta = [] + if (!file(row.image).exists()) { + exit 1, "ERROR: Please check input samplesheet -> image file does not exist!\n${row.image}" } - if (meta.single_end) { - fastq_meta = [ meta, [ file(row.fastq_1) ] ] - } else { - if (!file(row.fastq_2).exists()) { - exit 1, "ERROR: Please check input samplesheet -> Read 2 FastQ file does not exist!\n${row.fastq_2}" - } - fastq_meta = [ meta, [ file(row.fastq_1), file(row.fastq_2) ] ] + if (!file(row.marker).exists()) { + exit 1, "ERROR: Please check input samplesheet -> image file does not exist!\n${row.marker}" } - return fastq_meta + + // if (meta.single_end) { + // fastq_meta = [ meta, [ file(row.fastq_1) ] ] + // } else { + // if (!file(row.fastq_2).exists()) { + // exit 1, "ERROR: Please check input samplesheet -> Read 2 FastQ file does not exist!\n${row.fastq_2}" + // } + //} + image_meta = [ meta, [ file(row.image) ], [file(row.marker)] ] + + return image_meta } diff --git a/workflows/mcmicro.nf b/workflows/mcmicro.nf index 76f1ead..555cffa 100644 --- a/workflows/mcmicro.nf +++ b/workflows/mcmicro.nf @@ -13,7 +13,7 @@ def summary_params = paramsSummaryMap(workflow) // Print parameter summary log to screen log.info logo + paramsSummaryLog(workflow) + citation -WorkflowMcmicro.initialise(params, log) +//WorkflowMcmicro.initialise(params, log) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -46,7 +46,16 @@ include { INPUT_CHECK } from '../subworkflows/local/input_check' // // MODULE: Installed directly from nf-core/modules // -include { FASTQC } from '../modules/nf-core/fastqc/main' + +//include { ILLUMINATION } from './modules/nf-core/local/illumination.nf' + +include { BASICPY } from '../modules/nf-core/basicpy/main' +include { ASHLAR } from '../modules/nf-core/ashlar/main' +include { BACKSUB } from '../modules/nf-core/backsub/main' +include { CELLPOSE } from '../modules/nf-core/cellpose/main' +include { DEEPCELL_MESMER } from '../modules/nf-core/deepcell/mesmer/main' +include { MCQUANT } from '../modules/nf-core/mcquant/main' +include { SCIMAP_MCMICRO } from '../modules/nf-core/scimap/mcmicro/main' include { MULTIQC } from '../modules/nf-core/multiqc/main' include { CUSTOM_DUMPSOFTWAREVERSIONS } from '../modules/nf-core/custom/dumpsoftwareversions/main' @@ -56,6 +65,12 @@ include { CUSTOM_DUMPSOFTWAREVERSIONS } from '../modules/nf-core/custom/dumpsoft ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +// Manually define inputs here +//image_tuple = tuple([ id:'image' ], '/home/florian/Documents/tmp_data_folder/cycif_tonsil_registered.ome.tif') +//marker_tuple = tuple([ id:'marker'], '/home/florian/Documents/tmp_data_folder/markers.csv') + +ch_input = file(params.input) + // Info required for completion email and summary def multiqc_report = [] @@ -74,13 +89,49 @@ workflow MCMICRO { // See the documentation https://nextflow-io.github.io/nf-validation/samplesheets/fromSamplesheet/ // ! There is currently no tooling to help you write a sample sheet schema - // - // MODULE: Run FastQC - // - FASTQC ( - INPUT_CHECK.out.reads - ) - ch_versions = ch_versions.mix(FASTQC.out.versions.first()) + //ILLUMINATION(mcp.modules['illumination'], raw) + + // sample check here: + ch_input = INPUT_CHECK.out.input + + // Split the original channel into two separate channels + ch_images = ch_input.map { item -> [item[0], item[1]]} + // Mapping and obtaining unique items based on item[2] + ch_markers = ch_input.map { item -> [item[0], item[2]] } + .groupTuple(by: [0]) + .map { sample, markers -> [ sample, markers.flatten().unique() ] } + + /* + if ( params.illumination ) { + BASICPY(ch_images) + ch_tif = BASICPY.out.fields + ch_versions = ch_versions.mix(BASICPY.out.versions) + + ch_dfp = ch_tif.filter { file -> file.name.endsWith('.dfp.tiff') } + ch_ffp = ch_tif.filter { file -> file.name.endsWith('.ffp.tiff') } + } + */ + + ASHLAR(ch_input, [], []) + ch_versions = ch_versions.mix(ASHLAR.out.versions) + + // Run Background Correction + BACKSUB(ASHLAR.out.tif, ch_markers) + ch_versions = ch_versions.mix(BACKSUB.out.versions) + + // Run Segmentation + CELLPOSE(BACKSUB.out.backsub_tif) + ch_versions = ch_versions.mix(CELLPOSE.out.versions) + + // Run Quantification + MCQUANT(BACKSUB.out.backsub_tif, + CELLPOSE.out.mask, + BACKSUB.out.markerout) + ch_versions = ch_versions.mix(MCQUANT.out.versions) + + // Run Reporting + SCIMAP_MCMICRO(MCQUANT.out.csv) + ch_versions = ch_versions.mix(SCIMAP_MCMICRO.out.versions) CUSTOM_DUMPSOFTWAREVERSIONS ( ch_versions.unique().collectFile(name: 'collated_versions.yml') @@ -89,6 +140,7 @@ workflow MCMICRO { // // MODULE: MultiQC // + /* workflow_summary = WorkflowMcmicro.paramsSummaryMultiqc(workflow, summary_params) ch_workflow_summary = Channel.value(workflow_summary) @@ -99,7 +151,6 @@ workflow MCMICRO { ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml')) ch_multiqc_files = ch_multiqc_files.mix(CUSTOM_DUMPSOFTWAREVERSIONS.out.mqc_yml.collect()) - ch_multiqc_files = ch_multiqc_files.mix(FASTQC.out.zip.collect{it[1]}.ifEmpty([])) MULTIQC ( ch_multiqc_files.collect(), @@ -108,6 +159,7 @@ workflow MCMICRO { ch_multiqc_logo.toList() ) multiqc_report = MULTIQC.out.report.toList() + */ } /*