Skip to content

Commit 10bec30

Browse files
authored
Merge pull request #49 from nf-core/local-module-proseg
Local module proseg
2 parents f8c08e4 + ee3a6f0 commit 10bec30

File tree

5 files changed

+290
-0
lines changed

5 files changed

+290
-0
lines changed

modules/local/proseg/main.nf

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
process PROSEG {
2+
tag "$meta.id"
3+
label 'process_high'
4+
5+
container "nf-core/proseg:1.1.8"
6+
7+
input:
8+
tuple val(meta), path(transcripts)
9+
10+
output:
11+
tuple val(meta), path("cell-polygons.geojson.gz"), emit: cell_polygons_2d
12+
path("expected-counts.csv.gz"), emit: expected_counts
13+
path("cell-metadata.csv.gz"), emit: cell_metadata
14+
path("transcript-metadata.csv.gz"), emit: transcript_metadata
15+
path("gene-metadata.csv.gz"), emit: gene_metadata
16+
path("rates.csv.gz"), emit: rates
17+
path("cell-polygons-layers.geojson.gz"), emit: cell_polygons_layers
18+
path("cell-hulls.geojson.gz"), emit: cell_hulls
19+
path("versions.yml"), emit: versions
20+
21+
when:
22+
task.ext.when == null || task.ext.when
23+
24+
script:
25+
// Exit if running this module with -profile conda / -profile mamba
26+
if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) {
27+
error "PROSEG module does not support Conda. Please use Docker / Singularity / Podman instead."
28+
}
29+
def args = task.ext.args ?: ''
30+
def prefix = task.ext.prefix ?: "${meta.id}"
31+
def platform = preset ? "${params.preset}" : ""
32+
33+
// check for preset values
34+
if (!(platform in ['xenium', 'cosmx', 'merscope'])) {
35+
error "${platform} is an invalid platform (preset) type. Please specify xenium, cosmx, or merscope"
36+
}
37+
38+
"""
39+
proseg \\
40+
--${preset} \\
41+
${transcripts} \\
42+
--nthreads ${task.cpus} \\
43+
--output-expected-counts expected-counts.csv.gz \\
44+
--output-cell-metadata cell-metadata.csv.gz \\
45+
--output-transcript-metadata transcript-metadata.csv.gz \\
46+
--output-gene-metadata gene-metadata.csv.gz \\
47+
--output-rates rates.csv.gz \\
48+
--output-cell-polygons cell-polygons.geojson.gz \\
49+
--output-cell-polygon-layers cell-polygons-layers.geojson.gz \\
50+
--output-cell-hulls cell-hulls.geojson.gz \\
51+
${args}
52+
53+
cat <<-END_VERSIONS > versions.yml
54+
"${task.process}":
55+
proseg: \$(proseg --version | sed 's/proseg //')
56+
END_VERSIONS
57+
"""
58+
59+
stub:
60+
// Exit if running this module with -profile conda / -profile mamba
61+
if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) {
62+
error "PROSEG module does not support Conda. Please use Docker / Singularity / Podman instead."
63+
}
64+
def args = task.ext.args ?: ''
65+
def prefix = task.ext.prefix ?: "${meta.id}"
66+
67+
"""
68+
touch expected-counts.csv.gz
69+
touch cell-metadata.csv.gz
70+
touch transcript-metadata.csv.gz
71+
touch gene-metadata.csv.gz
72+
touch rates.csv.gz
73+
touch cell-polygons.geojson.gz
74+
touch cell-polygons-layers.geojson.gz
75+
touch cell-hulls.geojson.gz
76+
77+
cat <<-END_VERSIONS > versions.yml
78+
"${task.process}":
79+
proseg: \$(proseg --version | sed 's/proseg //')
80+
END_VERSIONS
81+
"""
82+
}

modules/local/proseg/meta.yml

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
name: "proseg"
2+
description: Probabilistic cell segmentation for in situ spatial transcriptomics
3+
keywords:
4+
- segmentation
5+
- cell segmentation
6+
- spatialomics
7+
- probabilistic segmentation
8+
- in situ spatial transcriptomics
9+
tools:
10+
- "proseg":
11+
description: "Proseg (probabilistic segmentation) is a cell segmentation method for in situ spatial transcriptomics. Xenium, CosMx, and MERSCOPE platforms are currently supported."
12+
homepage: "https://github.com/dcjones/proseg/tree/main"
13+
documentation: "https://github.com/dcjones/proseg/blob/main/README.md"
14+
tool_dev_url: "https://github.com/dcjones/proseg"
15+
doi: ""
16+
licence: ["GNU Public License"]
17+
18+
input:
19+
- - meta:
20+
type: map
21+
description: |
22+
Groovy Map containing run information
23+
e.g. `[ id:'run_id']`
24+
- transcripts:
25+
type: file
26+
description: |
27+
File containing the transcript position
28+
pattern: "transcripts.csv.gz"
29+
30+
output:
31+
- - meta:
32+
type: map
33+
description: |
34+
Groovy Map containing run information
35+
e.g. `[ id:'run_id']`
36+
- cell_polygons:
37+
type: file
38+
description: 2D polygons for each cell in GeoJSON format. These are flattened from 3D
39+
pattern: "cell-polygons.geojson.gz"
40+
- - expected_counts:
41+
type: file
42+
description: cell-by-gene count matrix
43+
pattern: "expected-counts.csv.gz"
44+
- - cell_metadata:
45+
type: file
46+
description: Cell centroids, volume, and other information
47+
pattern: "cell-metadata.csv.gz"
48+
- - transcript_metadata:
49+
type: file
50+
description: Transcript ids, genes, revised positions, assignment probability
51+
pattern: "transcript-metadata.csv.gz"
52+
- - gene_metadata:
53+
type: file
54+
description: Per-gene summary statistics
55+
pattern: "gene-metadata.csv.gz"
56+
- - rates:
57+
type: file
58+
description: Cell-by-gene Poisson rate parameters
59+
pattern: "rates.csv.gz"
60+
- - cell_polygon_layers:
61+
type: file
62+
description: A separate, non-overlapping cell polygon for each z-layer, preserving 3D segmentation
63+
pattern: "cell-polygons-layers.geojson.gz"
64+
- - cell_hulls:
65+
type: file
66+
description: Convex hulls around assigned transcripts
67+
pattern: "cell-hulls.geojson.gz"
68+
- - versions:
69+
type: file
70+
description: File containing software versions
71+
pattern: "versions.yml"
72+
73+
authors:
74+
- "@khersameesh24"
75+
maintainers:
76+
- "@khersameesh24"
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
process PROSEG2BAYSOR {
2+
tag "$meta.id"
3+
label 'process_high'
4+
5+
container "nf-core/proseg:1.1.8"
6+
7+
input:
8+
path(transcript_metadata)
9+
path(cell_polygons)
10+
11+
output:
12+
path("xr-transcript-metadata.csv"), emit: xr_metadata
13+
path("xr-cell-polygons.geojson"), emit: xr_polygons
14+
15+
script:
16+
// Exit if running this module with -profile conda / -profile mamba
17+
if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) {
18+
error "PROSEG2BAYSOR (preprocess) module does not support Conda. Please use Docker / Singularity / Podman instead."
19+
}
20+
21+
"""
22+
proseg-to-baysor \
23+
${transcript_metadata} \
24+
${cell_polygons} \
25+
--output-transcript-metadata xr-transcript-metadata.csv \
26+
--output-cell-polygons xr-cell-polygons.geojson
27+
28+
cat <<-END_VERSIONS > versions.yml
29+
"${task.process}":
30+
proseg: \$(proseg --version | sed 's/proseg //')
31+
END_VERSIONS
32+
33+
"""
34+
35+
stub:
36+
// Exit if running this module with -profile conda / -profile mamba
37+
if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) {
38+
error "PROSEG module does not support Conda. Please use Docker / Singularity / Podman instead."
39+
}
40+
def args = task.ext.args ?: ''
41+
def prefix = task.ext.prefix ?: "${meta.id}"
42+
43+
"""
44+
touch xr-transcript-metadata.csv
45+
touch xr-cell-polygons.geojson
46+
47+
cat <<-END_VERSIONS > versions.yml
48+
"${task.process}":
49+
proseg: \$(proseg --version | sed 's/proseg //')
50+
END_VERSIONS
51+
"""
52+
}
53+
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
nextflow_process {
2+
3+
name "Test Process PROSEG"
4+
script "../main.nf"
5+
process "PROSEG"
6+
7+
tag "modules"
8+
tag "modules_nfcore"
9+
tag "proseg"
10+
tag "segmentation"
11+
tag "cell_segmentation"
12+
13+
14+
setup {
15+
run("UNZIP") {
16+
script "modules/nf-core/unzip/main.nf"
17+
process {
18+
"""
19+
input[0] = [[], file('https://raw.githubusercontent.com/nf-core/test-datasets/spatialxe/Xenium_Prime_Mouse_Ileum_tiny_outs.zip', checkIfExists: true)]
20+
"""
21+
}
22+
}
23+
}
24+
25+
test("proseg - transcripts.csv") {
26+
27+
when {
28+
process {
29+
"""
30+
input[0] = Channel.of([
31+
[id: "test_run_proseg"],
32+
]).combine(UNZIP.out.unzipped_archive.map { it[1] } + "/transcripts.csv")
33+
"""
34+
}
35+
}
36+
37+
then {
38+
assertAll(
39+
{ assert process.success },
40+
{ assert snapshot(process.out).match() },
41+
{ assert file(process.out.expected_counts.get(0).get(1).find { file(it).name == 'expected-counts.csv.gz' }).exists() },
42+
{ assert file(process.out.cell_metadata.get(0).get(1).find { file(it).name == 'cell-metadata.csv.gz' }).exists() },
43+
{ assert file(process.out.transcript_metadata.get(0).get(1).find { file(it).name == 'transcript-metadata.csv.gz' }).exists() },
44+
{ assert file(process.out.gene_metadata.get(0).get(1).find { file(it).name == 'gene-metadata.csv.gz' }).exists() },
45+
{ assert file(process.out.rates.get(0).get(1).find { file(it).name == 'rates.csv.gz' }).exists() },
46+
{ assert file(process.out.cell_polygons.get(0).get(1).find { file(it).name == 'cell-polygons.geojson.gz' }).exists() },
47+
{ assert file(process.out.cell_polygons_layers.get(0).get(1).find { file(it).name == 'cell-polygons-layers.geojson.gz' }).exists() },
48+
{ assert file(process.out.cell-hulls.get(0).get(1).find { file(it).name == 'cell-hulls.geojson.gz' }).exists() },
49+
)
50+
}
51+
52+
}
53+
54+
test("proseg stub") {
55+
56+
options "-stub"
57+
58+
when {
59+
process {
60+
"""
61+
input[0] = Channel.of([
62+
[id: "test_run_proseg"],
63+
]).combine(UNZIP.out.unzipped_archive.map { it[1] } + "/transcripts.csv")
64+
"""
65+
}
66+
}
67+
68+
then {
69+
assertAll(
70+
{ assert process.success },
71+
{ assert snapshot(process.out).match() }
72+
)
73+
}
74+
75+
}
76+
77+
}

modules/local/proseg/tests/tags.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
proseg:
2+
- "modules/nf-core/proseg/**"

0 commit comments

Comments
 (0)