Skip to content

Commit 85284ec

Browse files
authored
Merge pull request #17 from openproblems-bio/dev
Dev
2 parents a900549 + f81a15f commit 85284ec

File tree

5 files changed

+205
-1
lines changed

5 files changed

+205
-1
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
__merge__: /src/api/comp_method_cell_type_annotation.yaml
2+
3+
name: moscot
4+
label: "MOSCOT"
5+
summary: "Mapping of annotations from single-cell to spatial using moscot"
6+
description: "Mapping of annotations from single-cell to spatial using moscot"
7+
links:
8+
documentation: "https://moscot.readthedocs.io"
9+
repository: "https://github.com/theislab/moscot"
10+
references:
11+
doi: "10.1038/s41586-024-08453-2"
12+
13+
arguments:
14+
# TODO: alpha check range [0.7, 0.8, 0.9]
15+
# TODO: tau_a=tau_b check range [0.1, 0.2, 0.3] (seems only to work with tau=1 on our data)
16+
# TODO: rank depends on data set size, rank=5000 for 300k cells and down to rank=500 minimum (seems only to work with rank=-1 on our data)
17+
- name: --alpha
18+
required: false
19+
direction: input
20+
type: double
21+
default: 0.8
22+
- name: --epsilon
23+
required: false
24+
direction: input
25+
type: double
26+
default: 0.01
27+
- name: --tau
28+
required: false
29+
direction: input
30+
type: double
31+
default: 1.0
32+
- name: --rank
33+
required: false
34+
direction: input
35+
type: integer
36+
default: -1
37+
- name: --mapping_mode
38+
required: false
39+
direction: input
40+
type: string
41+
choices: ["sum", "max"]
42+
default: "max"
43+
44+
resources:
45+
- type: python_script
46+
path: script.py
47+
48+
engines:
49+
- type: docker
50+
image: openproblems/base_python:1.0.0
51+
setup:
52+
- type: python
53+
pypi: [numpy, anndata, scanpy, moscot, flax, diffrax]
54+
- type: native
55+
56+
runners:
57+
- type: executable
58+
- type: nextflow
59+
directives:
60+
label: [ midtime, midcpu, midmem ]
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#!/usr/bin/env python3
2+
3+
import numpy as np
4+
import anndata as ad
5+
import scanpy as sc
6+
7+
import moscot as mt
8+
from moscot.problems.space import MappingProblem
9+
10+
## VIASH START
11+
par = {
12+
'input_spatial_normalized_counts': 'resources_test/task_ist_preprocessing/mouse_brain_combined/spatial_normalized_counts.h5ad',
13+
'input_scrnaseq_reference': 'resources_test/task_ist_preprocessing/mouse_brain_combined/scrnaseq_reference.h5ad',
14+
'output': 'spatial_with_celltypes.h5ad',
15+
'celltype_key': 'cell_type',
16+
'alpha': 0.8,
17+
'epsilon': 0.01,
18+
'tau': 1.0,
19+
'rank': -1,
20+
'mapping_mode': 'max',
21+
}
22+
meta = {
23+
'name': 'moscot',
24+
}
25+
## VIASH END
26+
27+
# Optional parameter check: For this specific annotation method the par['input_spatial_normalized_counts'] and par['input_scrnaseq_reference'] are required
28+
assert par['input_spatial_normalized_counts'] is not None, 'Spatial input is required for this annotation method.'
29+
assert par['input_scrnaseq_reference'] is not None, 'Single cell input is required for this annotation method.'
30+
31+
# Read input
32+
adata_sc = ad.read_h5ad(par['input_scrnaseq_reference'])
33+
adata_sp = ad.read_h5ad(par['input_spatial_normalized_counts'])
34+
35+
# Check for normalized layer and centroid information
36+
assert "normalized" in adata_sc.layers.keys(), 'Layer "normalized" is required for single-cell anndata'
37+
assert "normalized" in adata_sp.layers.keys(), 'Layer "normalized" is required for spatial anndata'
38+
assert "centroid_x" in adata_sp.obs and "centroid_y" in adata_sp.obs, '"Observation level columns "centroid_x" and "centroid_y" are required for spatial anndata'
39+
40+
# Use normalized layer and create spatial obsm
41+
adata_sc.X = adata_sc.layers["normalized"]
42+
adata_sp.X = adata_sp.layers["normalized"]
43+
adata_sp.obsm["spatial"] = adata_sp.obs[["centroid_x", "centroid_y"]].to_numpy()
44+
45+
# Define mapping problem
46+
mp = MappingProblem(adata_sc=adata_sc, adata_sp=adata_sp)
47+
48+
mp = mp.prepare(
49+
sc_attr={"attr": "layers", "key": "normalized"},
50+
xy_callback="local-pca",
51+
)
52+
53+
mp = mp.solve(
54+
alpha=par['alpha'],
55+
epsilon=par['epsilon'],
56+
tau_a=par['tau'],
57+
tau_b=par['tau'],
58+
rank=par['rank'],
59+
)
60+
61+
# Map annotations
62+
anno_map_max = mp.annotation_mapping(
63+
mapping_mode=par['mapping_mode'],
64+
annotation_label=par['celltype_key'],
65+
source="src",
66+
forward=False,
67+
)
68+
adata_sp.obs[par['celltype_key']] = anno_map_max[par['celltype_key']].values
69+
70+
# Write output
71+
adata_sp.write_h5ad(par['output'])
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
__merge__: /src/api/comp_method_cell_type_annotation.yaml
2+
3+
name: tacco
4+
label: "Tacco"
5+
summary: "Annotate cell types using Tacco"
6+
description: "Annotate cell types using Tacco"
7+
links:
8+
documentation: "https://simonwm.github.io/tacco/"
9+
repository: "https://github.com/simonwm/tacco"
10+
references:
11+
doi: "10.1038/s41587-023-01657-3"
12+
13+
resources:
14+
- type: python_script
15+
path: script.py
16+
17+
engines:
18+
- type: docker
19+
image: openproblems/base_python:1.0.0
20+
setup:
21+
- type: python
22+
pypi: [anndata, numpy, tacco]
23+
- type: native
24+
25+
runners:
26+
- type: executable
27+
- type: nextflow
28+
directives:
29+
label: [ midtime, midcpu, midmem ]
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/usr/bin/env python3
2+
3+
import anndata as ad
4+
import numpy as np
5+
import tacco
6+
7+
## VIASH START
8+
par = {
9+
'input_spatial_normalized_counts': 'resources_test/task_ist_preprocessing/mouse_brain_combined/spatial_normalized_counts.h5ad',
10+
'input_scrnaseq_reference': 'resources_test/task_ist_preprocessing/mouse_brain_combined/scrnaseq_reference.h5ad',
11+
'output': 'spatial_with_celltypes.h5ad',
12+
'celltype_key': 'cell_type',
13+
}
14+
meta = {
15+
'name': 'tacco',
16+
}
17+
## VIASH END
18+
19+
# Optional parameter check: For this specific annotation method the par['input_spatial_normalized_counts'] and par['input_scrnaseq_reference'] are required
20+
assert par['input_spatial_normalized_counts'] is not None, 'Spatial input is required for this annotation method.'
21+
assert par['input_scrnaseq_reference'] is not None, 'Single cell input is required for this annotation method.'
22+
23+
# Read input
24+
adata_sp = ad.read_h5ad(par['input_spatial_normalized_counts'])
25+
adata_sc = ad.read_h5ad(par['input_scrnaseq_reference'])
26+
27+
# Switch to raw counts
28+
adata_sp.X = adata_sp.layers['counts']
29+
adata_sc.X = adata_sc.layers['counts']
30+
31+
# Run tacco
32+
cell_type_assignment = tacco.tl.annotate(
33+
adata=adata_sp,
34+
reference=adata_sc,
35+
annotation_key=par['celltype_key']
36+
)
37+
38+
# Tacco stores the cell type proportions in a n_obs x n_celltypes matrix, so we have to extract the celltype with highest consensus
39+
cell_types = cell_type_assignment.columns
40+
highest_score_idx = np.argmax(cell_type_assignment, axis=1)
41+
adata_sp.obs[par['celltype_key']] = cell_types[highest_score_idx]
42+
43+
# Write output
44+
adata_sp.write_h5ad(par['output'])

0 commit comments

Comments
 (0)