diff --git a/CHANGELOG.md b/CHANGELOG.md index f3033975..9c211678 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ * Added `method/limma_removebatcheffect` component (PR #79). +* Added ComBat-Seq method (PR #55). * Added `methods/scmerge2` component (PR #63). ## Minor changes diff --git a/_viash.yaml b/_viash.yaml index f8da6a98..090573ea 100644 --- a/_viash.yaml +++ b/_viash.yaml @@ -130,6 +130,11 @@ authors: info: github: liuwd15 orcid: 0000-0002-5124-9338 + - name: Maximilien Colange + roles: [contributor] + info: + github: EpigeneMax + orcid: 0000-0003-4769-3302 config_mods: | .runners[.type == "nextflow"].config.labels := { lowmem : "memory = 20.Gb", midmem : "memory = 50.Gb", highmem : "memory = 100.Gb", lowcpu : "cpus = 5", midcpu : "cpus = 15", highcpu : "cpus = 30", lowtime : "time = 1.h", midtime : "time = 4.h", hightime : "time = 8.h", veryhightime : "time = 24.h" } diff --git a/src/methods/combat_seq/config.vsh.yaml b/src/methods/combat_seq/config.vsh.yaml new file mode 100644 index 00000000..f8273cfe --- /dev/null +++ b/src/methods/combat_seq/config.vsh.yaml @@ -0,0 +1,52 @@ +__merge__: /src/api/comp_method.yaml +name: combat_seq +label: ComBat-Seq +summary: Adjusting batch effects in RNA-Seq expression data using empirical Bayes + methods +description: | + ComBat-Seq extends the ComBat method for batch correction in RNA-Seq data. + While ComBat assumes normally distributed data, ComBat-Seq uses a negative + binomial distribution to model the data. While initially developed for + RNA-Seq data, ComBat-Seq can be applied to single-cell RNA-Seq data as well. + + The method is implemented in Python as a part of the inmoose package. It is + based on the original R implementation, distributed through the sva package. + +references: + doi: + - 10.1093/nargab/lqaa078 + - 10.1186/s12859-023-05578-5 + +links: + documentation: https://inmoose.readthedocs.io/en/stable/pycombatseq.html + repository: https://github.com/epigenelabs/inmoose + +# Metadata for your component +info: + # Which normalisation method this component prefers to use (required). + preferred_normalization: counts + method_types: [feature] + +# Resources required to run the component +resources: + - type: python_script + path: script.py + - path: /src/utils/read_anndata_partial.py + +engines: + # Specifications for the Docker image for this component. + - type: docker + image: openproblems/base_python:1 + # Add custom dependencies here (optional). For more information, see + # https://viash.io/reference/config/engines/docker/#setup . + setup: + - type: python + pip: inmoose + +runners: + # This platform allows running the component natively + - type: executable + # Allows turning the component into a Nextflow module / pipeline. + - type: nextflow + directives: + label: [midtime,midmem,midcpu] diff --git a/src/methods/combat_seq/script.py b/src/methods/combat_seq/script.py new file mode 100644 index 00000000..f86c06dd --- /dev/null +++ b/src/methods/combat_seq/script.py @@ -0,0 +1,41 @@ +import sys + +import anndata as ad +import numpy as np +from inmoose.pycombat import pycombat_seq +from scipy.sparse import csr_matrix, issparse + +# VIASH START +# Note: this section is auto-generated by viash at runtime. To edit it, make changes +# in config.vsh.yaml and then run `viash config inject config.vsh.yaml`. +par = {"input": "resources_test/.../input.h5ad", "output": "output.h5ad"} +meta = {"name": "combat_seq"} +# VIASH END + +sys.path.append(meta["resources_dir"]) +from read_anndata_partial import read_anndata + +print("Read input", flush=True) +adata = read_anndata(par["input"], X="layers/counts", obs="obs", var="var", uns="uns") + +print("Run Combat-Seq", flush=True) +# pycombat_seq wants a dense genes x cells matrix +counts = (adata.X.toarray() if issparse(adata.X) else adata.X).T.astype(np.double) +corrected_counts = pycombat_seq(counts, adata.obs["batch"]) + +print("Store output", flush=True) +output = ad.AnnData( + obs=adata.obs[[]], + var=adata.var[[]], + uns={ + "dataset_id": adata.uns["dataset_id"], + "normalization_id": adata.uns["normalization_id"], + "method_id": meta["name"], + }, + layers={ + "corrected_counts": csr_matrix(corrected_counts.T), + }, +) + +print("Write output to file", flush=True) +output.write_h5ad(par["output"], compression="gzip") diff --git a/src/workflows/run_benchmark/config.vsh.yaml b/src/workflows/run_benchmark/config.vsh.yaml index 891abab5..ae2be6cc 100644 --- a/src/workflows/run_benchmark/config.vsh.yaml +++ b/src/workflows/run_benchmark/config.vsh.yaml @@ -93,6 +93,7 @@ dependencies: - name: methods/bbknn - name: methods/cellplm - name: methods/combat + - name: methods/combat_seq - name: methods/density_adaptive - name: methods/fadvi - name: methods/geneformer diff --git a/src/workflows/run_benchmark/main.nf b/src/workflows/run_benchmark/main.nf index 4f564571..2f5bf7c9 100644 --- a/src/workflows/run_benchmark/main.nf +++ b/src/workflows/run_benchmark/main.nf @@ -23,6 +23,7 @@ methods = [ args: [model: file("s3://openproblems-work/cache/cellplm-ckpt.zip")] ), combat, + combat_seq, density_adaptive, fadvi, geneformer,