Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code cleanup #99

Merged
merged 4 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion assets/schema_input.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@
"spot_table": {
"type": "string",
"pattern": "^\\S+\\.(txt|tsv)$",
"format": "file-path",
"errorMessage": "Spot table must be provided, has to have shape x,y,z,gene with sep = '\t', cannot contain spaces and must have extension '.txt'"
},
"membrane_image": {
"errorMessage": "Membrane image is optional, and cannot contain spaces and must have extension '.tif' or '.tiff'",
"anyOf": [
{
"type": "string",
"pattern": "^\\S+\\.(tif|tiff)$"
"pattern": "^\\S+\\.(tif|tiff)$",
"format": "file-path"
},
{
"type": "string",
Expand Down
3 changes: 1 addition & 2 deletions modules/local/createanndata.nf
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,12 @@ process CREATE_ANNDATA {
script:
def args = task.ext.args ?: ''
def prefix = task.ext.prefix ?: "${meta.id}"

"""
create_anndata.py \\
--input ${spot2cell} \\
--spatial_cols X_centroid Y_centroid \\
--output ${prefix}.adata \\
$args
${args}

cat <<-END_VERSIONS > versions.yml
"${task.process}":
Expand Down
3 changes: 1 addition & 2 deletions modules/local/createstack.nf
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@ process CREATE_STACK {
script:
def args = task.ext.args ?: ''
def prefix = task.ext.prefix ?: "${meta.id}"

"""
stack.py \\
--input ${image} \\
--output ${prefix}.ome.tif \\
$args
${args}

cat <<-END_VERSIONS > versions.yml
"${task.process}":
Expand Down
10 changes: 4 additions & 6 deletions modules/local/crophdf5.nf
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@ process CROPHDF5 {
task.ext.when == null || task.ext.when

script:
def args = task.ext.args ?: ''
def prefix = task.ext.prefix ?: "${meta.id}"

def args = task.ext.args ?: ''
"""
crop_hdf5.py \\
--input $image_stack \\
--input ${image_stack} \\
--output . \\
--num_channels $num_channels \\
$args
--num_channels ${num_channels} \\
${args}

cat <<-END_VERSIONS > versions.yml
"${task.process}":
Expand Down
13 changes: 5 additions & 8 deletions modules/local/croptiff.nf
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ process CROPTIFF {
container 'ghcr.io/schapirolabor/molkart-local:v0.0.4'

input:
tuple val(meta), path(image_stack)
tuple val(meta), path(crop_summary)
tuple val(meta), path(image_stack), path(crop_summary)

output:
tuple val(meta), path("*.tiff"), emit: crop_tiff
Expand All @@ -17,14 +16,12 @@ process CROPTIFF {
task.ext.when == null || task.ext.when

script:
def args = task.ext.args ?: ''
def prefix = task.ext.prefix ?: "${meta.id}"

def args = task.ext.args ?: ''
"""
crop_tiff.py \\
--input $image_stack \\
--crop_summary $crop_summary \\
$args
--input ${image_stack} \\
--crop_summary ${crop_summary} \\
${args}

cat <<-END_VERSIONS > versions.yml
"${task.process}":
Expand Down
1 change: 0 additions & 1 deletion modules/local/maskfilter.nf
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ process MASKFILTER {
"""

stub:
def args = task.ext.args ?: ''
def prefix = task.ext.prefix ?: "${meta.id}"

"""
Expand Down
13 changes: 6 additions & 7 deletions modules/local/molkartqc.nf
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ process MOLKARTQC{

"""
collect_QC.py \\
--cellxgene $cellxgene_table \\
--spots $spot_table \\
--sample_id $prefix \\
--segmentation_method $segmethod \\
--filterqc $filterqc \\
--cellxgene ${cellxgene_table} \\
--spots ${spot_table} \\
--sample_id ${prefix} \\
--segmentation_method ${segmethod} \\
--filterqc ${filterqc} \\
--outdir . \\
$args
${args}

cat <<-END_VERSIONS > versions.yml
"${task.process}":
Expand All @@ -35,7 +35,6 @@ process MOLKARTQC{
"""

stub:
def args = task.ext.args ?: ''
def prefix = task.ext.prefix ?: "${meta.id}"

"""
Expand Down
8 changes: 3 additions & 5 deletions modules/local/molkartqcpng.nf
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ process MOLKARTQCPNG {

"""
collect_QC.py \\
--png_overview $png \\
--png_overview ${png} \\
--outdir . \\
$args
${args}

cat <<-END_VERSIONS > versions.yml
"${task.process}":
Expand All @@ -29,9 +29,7 @@ process MOLKARTQCPNG {
"""

stub:
def args = task.ext.args ?: ''
def prefix = task.ext.prefix ?: "${meta.id}"

def prefix = task.ext.prefix ?: ( png.name.toString().tokenize('.')[0] )
"""
touch ${prefix}.png

Expand Down
3 changes: 1 addition & 2 deletions modules/local/spot2cell.nf
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ process SPOT2CELL{
container 'ghcr.io/schapirolabor/molkart-local:v0.0.4'

input:
tuple val(meta) , path(spot_table)
tuple val(meta2), path(cell_mask)
tuple val(meta), path(spot_table), path(cell_mask)

output:
tuple val(meta), path("*.csv"), emit: cellxgene_table
Expand Down
10 changes: 4 additions & 6 deletions modules/local/tiffh5convert.nf
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@ process TIFFH5CONVERT {
task.ext.when == null || task.ext.when

script:
def args = task.ext.args ?: ''
def prefix = task.ext.prefix ?: "${meta.id}"

def args = task.ext.args ?: ''
"""
crop_hdf5.py \\
--input $image \\
--input ${image} \\
--output . \\
--num_channels $num_channels \\
$args
--num_channels ${num_channels} \\
${args}

cat <<-END_VERSIONS > versions.yml
"${task.process}":
Expand Down
85 changes: 33 additions & 52 deletions workflows/molkart.nf
Original file line number Diff line number Diff line change
Expand Up @@ -44,31 +44,21 @@ workflow MOLKART {

// stain: "1" denotes membrane, stain: "0" denotes nuclear image
// this is used to preserve the order later
ch_samplesheet
.map {
meta, nuclear, spots, membrane ->
def new_meta = meta.clone()
new_meta.stain = "1"
return membrane != [] ? [new_meta, membrane] : null
//it[3] != [] ? tuple([id:it[0],stain:"1"], it[3]) : null
}.set { membrane_tuple } // if a membrane image is provided, return membrane image channel tuple (meta, path)
membrane_tuple = ch_samplesheet
.filter { it[3] } // filter samples with membrane
.map {meta, _nuclear, _spots, membrane ->
[meta + [stain: '1'], membrane]
}

ch_samplesheet
.map {
meta, nuclear, spots, membrane ->
def new_meta = meta.clone()
new_meta.stain = "0"
return [new_meta, nuclear]
image_tuple = ch_samplesheet
.map {meta, nuclear, _spots, _membrane ->
[meta + [stain: '0'], nuclear]
}
.set { image_tuple } // creates nuclear image channel tuple (meta, path)

ch_samplesheet
.map {
meta, nuclear, spots, membrane ->
def new_meta = meta.clone()
return [meta, spots]
spot_tuple = ch_samplesheet
.map {meta, _nuclear, spots, _membrane ->
[meta, spots]
}
.set { spot_tuple } // creates spot table channel tuple (meta, path)

//
// MODULE: Run Mindagap_mindagap
Expand All @@ -88,27 +78,25 @@ workflow MOLKART {
map_for_stacks = params.skip_clahe ? clahe_in : CLAHE.out.img_clahe

map_for_stacks
.map {
meta, tiff -> [meta.subMap("id"), tiff, meta.stain] // creates a channel containing only the sample id in meta, path to preprocessed image and the stain value ("0" or "1")
}.groupTuple() // combines based on meta
.map { meta, tiff ->
[ meta.subMap("id"), tiff, meta.stain ]
}
.groupTuple(by: 0)
.map { id, tiffs, stains ->
def sorted = [tiffs, stains].transpose().sort { it[1] }
def nuclear = sorted[0]
def membrane = sorted.size() > 1 ? sorted[1] : null
membrane ? [id, nuclear[0], membrane[0]] : [id, nuclear[0]]
}
.set{ grouped_map_stack }

grouped_map_stack.filter { !it[2] } // for rows without a present membrane image, set channel to no_stack
.set{ no_stack }

grouped_map_stack.filter{ it[2] } // for rows where the membrane image is present, create a list of images to be stacked
.map{
meta, paths, stains -> [meta, [paths[0], stains[0]], [paths[1], stains[1]]] // reorganizes to match path and stain
}.map{
meta, stain1, stain2 -> [meta, [stain1, stain2].sort{ it[1] }] // sort by stain index (0 for nuclear, 1 for other)
}.map{
meta, list -> [meta, list[0], list[1]] // sorted will have null as first list
}.map{
it[1][0] != null ? [it[0],it[1][0],it[2][0]] : [it[0],it[2][0]] // if null, only return the valid nuclear path value, otherwise return both nuclear and membrane paths
}.set { grouped_map_stack }

grouped_map_stack.filter{ // for rows without a present membrane image, set channel to no_stack
it[2] == null
}.set{ no_stack }

grouped_map_stack.filter{ // for rows where the membrane image is present, make it compliant with STACK inputs
it[2] != null
}.map{
[it[0],tuple(it[1],it[2])]
id, nuclear, membrane ->
[id, tuple(nuclear, membrane)]
}.set{ create_stack_in }

//
Expand All @@ -130,10 +118,7 @@ workflow MOLKART {
ch_versions = ch_versions.mix(CROPHDF5.out.versions)
// Combine images with crop_summary for making the same training tiff stacks as ilastik
tiff_crop = stack_mix.join(CROPHDF5.out.crop_summary)
CROPTIFF(
tiff_crop.map(it -> tuple(it[0],it[1])),
tiff_crop.map(it -> tuple(it[0],it[2])),
)
CROPTIFF(tiff_crop)
ch_versions = ch_versions.mix(CROPTIFF.out.versions)
MOLKARTQCPNG(CROPTIFF.out.overview.map{
tuple('matchkey', it[1])
Expand Down Expand Up @@ -222,7 +207,7 @@ workflow MOLKART {
}
segmentation_masks.map{
meta, mask, segmentation ->
new_meta = meta.clone()
def new_meta = meta.clone()
new_meta.segmentation = segmentation
[new_meta, mask]
}.set { matched_segmasks }
Expand All @@ -244,16 +229,12 @@ workflow MOLKART {
.combine(filtered_masks, by: 0)
.map {
meta, spots_table, mask, segmethod ->
new_meta = meta.clone()
def new_meta = meta.clone()
new_meta.segmentation = segmethod
[new_meta, spots_table, mask]
}
.set { dedup_spots }

SPOT2CELL(
dedup_spots.map(it -> tuple(it[0],it[1])),
dedup_spots.map(it -> tuple(it[0],it[2]))
)
SPOT2CELL(dedup_spots)
ch_versions = ch_versions.mix(SPOT2CELL.out.versions)

//
Expand Down