diff --git a/openproblems/tasks/_batch_integration/batch_integration_embed/api.py b/openproblems/tasks/_batch_integration/batch_integration_embed/api.py index d13a8d0e07..d534551688 100644 --- a/openproblems/tasks/_batch_integration/batch_integration_embed/api.py +++ b/openproblems/tasks/_batch_integration/batch_integration_embed/api.py @@ -23,4 +23,5 @@ def sample_method(adata): """Create sample method output for testing metrics in this task.""" adata.obsm["X_emb"] = adata.obsm["X_uni_pca"] + adata.uns["is_baseline"] = False return adata diff --git a/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/_utils.py b/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/_utils.py deleted file mode 100644 index 8fe3be43aa..0000000000 --- a/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/_utils.py +++ /dev/null @@ -1,5 +0,0 @@ -def _get_split(adata): - uni = adata - uni.obsm["X_pca"] = uni.obsm["X_uni_pca"] - uni.X = uni.layers["log_normalized"] - return (uni, adata) diff --git a/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/ari.py b/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/ari.py index 10822e79ba..9bfe349d12 100644 --- a/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/ari.py +++ b/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/ari.py @@ -1,5 +1,6 @@ from .....tools.decorators import metric from ...batch_integration_graph import metrics as graph_metrics +from .utils import embedding_to_graph """ The Rand index compares the overlap of two clusterings; @@ -16,7 +17,4 @@ @metric(**graph_metrics.ari.metadata) def ari(adata): - from scanpy.pp import neighbors - - neighbors(adata, use_rep="X_emb") - return graph_metrics.ari(adata) + return graph_metrics.ari(embedding_to_graph(adata)) diff --git a/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/cc_score.py b/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/cc_score.py index 8d7ee9101f..4cf7650542 100644 --- a/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/cc_score.py +++ b/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/cc_score.py @@ -1,4 +1,5 @@ from .....tools.decorators import metric +from .utils import get_split """ The cell-cycle conservation score evaluates how well the cell-cycle effect can be @@ -24,13 +25,12 @@ maximize=True, image="openproblems-r-pytorch", ) -def cc_score(adata, test=False): - from ._utils import _get_split +def cc_score(adata): from scib.metrics import cell_cycle try: cc = cell_cycle( - *_get_split(adata), "batch", embed="X_emb", organism=adata.uns["organism"] + *get_split(adata), "batch", embed="X_emb", organism=adata.uns["organism"] ) except ValueError: diff --git a/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/graph_connectivity.py b/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/graph_connectivity.py index e1d2e03cb5..4fc69fe1a2 100644 --- a/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/graph_connectivity.py +++ b/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/graph_connectivity.py @@ -1,5 +1,6 @@ from .....tools.decorators import metric from ...batch_integration_graph import metrics as graph_metrics +from .utils import embedding_to_graph """ The graph connectivity metric assesses whether the kNN graph representation, @@ -22,7 +23,4 @@ @metric(**graph_metrics.graph_connectivity.metadata) def graph_connectivity(adata): - from scanpy.pp import neighbors - - neighbors(adata, use_rep="X_emb") - return graph_metrics.graph_connectivity(adata) + return graph_metrics.graph_connectivity(embedding_to_graph(adata)) diff --git a/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/iso_label_f1.py b/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/iso_label_f1.py index aa2b9cdafe..578bceed26 100644 --- a/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/iso_label_f1.py +++ b/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/iso_label_f1.py @@ -1,5 +1,6 @@ from .....tools.decorators import metric from ...batch_integration_graph import metrics as graph_metrics +from .utils import embedding_to_graph """ We developed two isolated label scores to evaluate how well the data integration methods @@ -27,7 +28,4 @@ @metric(**graph_metrics.isolated_labels_f1.metadata) def isolated_labels_f1(adata): - from scanpy.pp import neighbors - - neighbors(adata, use_rep="X_emb") - return graph_metrics.isolated_labels_f1(adata) + return graph_metrics.isolated_labels_f1(embedding_to_graph(adata)) diff --git a/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/nmi.py b/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/nmi.py index 06fd3dbb5c..71aa9acdb7 100644 --- a/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/nmi.py +++ b/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/nmi.py @@ -1,5 +1,6 @@ from .....tools.decorators import metric from ...batch_integration_graph import metrics as graph_metrics +from .utils import embedding_to_graph """NMI compares the overlap of two clusterings. We used NMI to compare the cell-type labels with Louvain clusters computed on @@ -15,7 +16,4 @@ @metric(**graph_metrics.nmi.metadata) def nmi(adata): - from scanpy.pp import neighbors - - neighbors(adata, use_rep="X_emb") - return graph_metrics.nmi(adata) + return graph_metrics.nmi(embedding_to_graph(adata)) diff --git a/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/pcr.py b/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/pcr.py index 3e68a8ac27..d2a6c011ae 100644 --- a/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/pcr.py +++ b/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/pcr.py @@ -1,4 +1,5 @@ from .....tools.decorators import metric +from .utils import get_split """ Principal component regression, derived from PCA, has previously been used to quantify @@ -22,7 +23,6 @@ image="openproblems-r-pytorch", ) def pcr(adata): - from ._utils import _get_split from scib.metrics import pcr_comparison - return pcr_comparison(*_get_split(adata), "batch", embed="X_emb") + return pcr_comparison(*get_split(adata), "batch", embed="X_emb") diff --git a/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/utils.py b/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/utils.py new file mode 100644 index 0000000000..455e92ec76 --- /dev/null +++ b/openproblems/tasks/_batch_integration/batch_integration_embed/metrics/utils.py @@ -0,0 +1,16 @@ +def embedding_to_graph(adata): + import scanpy as sc + + if adata.uns["is_baseline"] and "neighbors" in adata.uns: + # precomputed; do nothing + return adata + + sc.pp.neighbors(adata, use_rep="X_emb") + return adata + + +def get_split(adata): + uni = adata + uni.obsm["X_pca"] = uni.obsm["X_uni_pca"] + uni.X = uni.layers["log_normalized"] + return (uni, adata) diff --git a/openproblems/tasks/_batch_integration/batch_integration_feature/api.py b/openproblems/tasks/_batch_integration/batch_integration_feature/api.py index 4aabaf94ef..bbf5e2f4bb 100644 --- a/openproblems/tasks/_batch_integration/batch_integration_feature/api.py +++ b/openproblems/tasks/_batch_integration/batch_integration_feature/api.py @@ -29,4 +29,5 @@ def sample_dataset(): def sample_method(adata): """Create sample method output for testing metrics in this task.""" adata.X = adata.X.multiply(2) + adata.uns["is_baseline"] = False return adata diff --git a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/ari.py b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/ari.py index cc0a9541cb..48bef53b28 100644 --- a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/ari.py +++ b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/ari.py @@ -1,5 +1,6 @@ from .....tools.decorators import metric from ...batch_integration_graph import metrics as graph_metrics +from .utils import feature_to_graph """ The Rand index compares the overlap of two clusterings; @@ -16,9 +17,4 @@ @metric(**graph_metrics.ari.metadata) def ari(adata): - from scanpy.pp import neighbors - from scanpy.tl import pca - - adata.obsm["X_emb"] = pca(adata.X) - neighbors(adata, use_rep="X_emb") - return graph_metrics.ari(adata) + return graph_metrics.ari(feature_to_graph(adata)) diff --git a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/cc_score.py b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/cc_score.py index d7bd5730d5..778ac40e29 100644 --- a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/cc_score.py +++ b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/cc_score.py @@ -1,5 +1,6 @@ from .....tools.decorators import metric from ...batch_integration_embed import metrics as embed_metrics +from .utils import feature_to_embedding """ The cell-cycle conservation score evaluates how well the cell-cycle effect can be @@ -20,8 +21,5 @@ @metric(**embed_metrics.cc_score.metadata) -def cc_score(adata, test=False): - from scanpy.tl import pca - - adata.obsm["X_emb"] = pca(adata.X) - return embed_metrics.cc_score(adata) +def cc_score(adata): + return embed_metrics.cc_score(feature_to_embedding(adata)) diff --git a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/graph_connectivity.py b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/graph_connectivity.py index bc7fbba9cc..4289f1174d 100644 --- a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/graph_connectivity.py +++ b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/graph_connectivity.py @@ -1,5 +1,6 @@ from .....tools.decorators import metric from ...batch_integration_graph import metrics as graph_metrics +from .utils import feature_to_graph """ The graph connectivity metric assesses whether the kNN graph representation, @@ -22,9 +23,4 @@ @metric(**graph_metrics.graph_connectivity.metadata) def graph_connectivity(adata): - from scanpy.pp import neighbors - from scanpy.tl import pca - - adata.obsm["X_emb"] = pca(adata.X) - neighbors(adata, use_rep="X_emb") - return graph_metrics.graph_connectivity(adata) + return graph_metrics.graph_connectivity(feature_to_graph(adata)) diff --git a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/iso_label_f1.py b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/iso_label_f1.py index 9e5896c064..048ad0996a 100644 --- a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/iso_label_f1.py +++ b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/iso_label_f1.py @@ -1,5 +1,6 @@ from .....tools.decorators import metric from ...batch_integration_graph import metrics as graph_metrics +from .utils import feature_to_graph """ We developed two isolated label scores to evaluate how well the data integration methods @@ -27,9 +28,4 @@ @metric(**graph_metrics.isolated_labels_f1.metadata) def isolated_labels_f1(adata): - from scanpy.pp import neighbors - from scanpy.tl import pca - - adata.obsm["X_emb"] = pca(adata.X) - neighbors(adata, use_rep="X_emb") - return graph_metrics.isolated_labels_f1(adata) + return graph_metrics.isolated_labels_f1(feature_to_graph(adata)) diff --git a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/iso_label_sil.py b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/iso_label_sil.py index 72ece6686d..9f1e3e1115 100644 --- a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/iso_label_sil.py +++ b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/iso_label_sil.py @@ -1,5 +1,6 @@ from .....tools.decorators import metric from ...batch_integration_embed import metrics as embed_metrics +from .utils import feature_to_embedding """ Isolated cell labels are defined as the labels present in the least number @@ -15,7 +16,4 @@ @metric(**embed_metrics.isolated_labels_sil.metadata) def isolated_labels_sil(adata): - from scanpy.tl import pca - - adata.obsm["X_emb"] = pca(adata.X) - return embed_metrics.isolated_labels_sil(adata) + return embed_metrics.isolated_labels_sil(feature_to_embedding(adata)) diff --git a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/kBET.py b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/kBET.py index 44820545f5..f8ed86d5a7 100644 --- a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/kBET.py +++ b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/kBET.py @@ -1,5 +1,6 @@ from .....tools.decorators import metric from ...batch_integration_embed import metrics as embed_metrics +from .utils import feature_to_embedding """ The kBET algorithm (v.0.99.6, release 4c9dafa) determines whether the label composition @@ -27,7 +28,4 @@ @metric(**embed_metrics.kBET.metadata) def kBET(adata): - from scanpy.tl import pca - - adata.obsm["X_emb"] = pca(adata.X) - return embed_metrics.kBET(adata) + return embed_metrics.kBET(feature_to_embedding(adata)) diff --git a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/nmi.py b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/nmi.py index 3e8e62bde1..21b1cc55ba 100644 --- a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/nmi.py +++ b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/nmi.py @@ -1,5 +1,6 @@ from .....tools.decorators import metric from ...batch_integration_graph import metrics as graph_metrics +from .utils import feature_to_graph """NMI compares the overlap of two clusterings. We used NMI to compare the cell-type labels with Louvain clusters computed on @@ -15,9 +16,4 @@ @metric(**graph_metrics.nmi.metadata) def nmi(adata): - from scanpy.pp import neighbors - from scanpy.tl import pca - - adata.obsm["X_emb"] = pca(adata.X) - neighbors(adata, use_rep="X_emb") - return graph_metrics.nmi(adata) + return graph_metrics.nmi(feature_to_graph(adata)) diff --git a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/pcr.py b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/pcr.py index 8a5d641f37..3a556dbe2f 100644 --- a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/pcr.py +++ b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/pcr.py @@ -1,5 +1,6 @@ from .....tools.decorators import metric from ...batch_integration_embed import metrics as embed_metrics +from .utils import feature_to_embedding """ Principal component regression, derived from PCA, has previously been used to quantify @@ -18,7 +19,4 @@ @metric(**embed_metrics.pcr.metadata) def pcr(adata): - from scanpy.tl import pca - - adata.obsm["X_emb"] = pca(adata.X) - return embed_metrics.pcr(adata) + return embed_metrics.pcr(feature_to_embedding(adata)) diff --git a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/sil_batch.py b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/sil_batch.py index 35f024ca44..ac98714333 100644 --- a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/sil_batch.py +++ b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/sil_batch.py @@ -1,5 +1,6 @@ from .....tools.decorators import metric from ...batch_integration_embed import metrics as embed_metrics +from .utils import feature_to_embedding """ We consider the absolute silhouette width, s(i), on @@ -24,7 +25,4 @@ @metric(**embed_metrics.silhouette_batch.metadata) def silhouette_batch(adata): - from scanpy.tl import pca - - adata.obsm["X_emb"] = pca(adata.X) - return embed_metrics.silhouette_batch(adata) + return embed_metrics.silhouette_batch(feature_to_embedding(adata)) diff --git a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/silhouette.py b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/silhouette.py index aa94c887e0..dcd29a8f71 100644 --- a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/silhouette.py +++ b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/silhouette.py @@ -1,5 +1,6 @@ from .....tools.decorators import metric from ...batch_integration_embed import metrics as embed_metrics +from .utils import feature_to_embedding """ For the bio-conservation score, the ASW was computed on cell identity labels and @@ -12,7 +13,4 @@ @metric(**embed_metrics.silhouette.metadata) def silhouette(adata): - from scanpy.tl import pca - - adata.obsm["X_emb"] = pca(adata.X) - return embed_metrics.silhouette(adata) + return embed_metrics.silhouette(feature_to_embedding(adata)) diff --git a/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/utils.py b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/utils.py new file mode 100644 index 0000000000..d2decfa054 --- /dev/null +++ b/openproblems/tasks/_batch_integration/batch_integration_feature/metrics/utils.py @@ -0,0 +1,18 @@ +from ...batch_integration_embed.metrics.utils import embedding_to_graph + + +def feature_to_embedding(adata): + import scanpy as sc + + if adata.uns["is_baseline"] and "X_emb" in adata.obsm: + # precomputed; do nothing + return adata + + adata.obsm["X_emb"] = sc.pp.pca(adata.X) + return adata + + +def feature_to_graph(adata): + adata = feature_to_embedding(adata) + adata = embedding_to_graph(adata) + return adata diff --git a/openproblems/tools/decorators.py b/openproblems/tools/decorators.py index 3c477a0167..dd2af6e193 100644 --- a/openproblems/tools/decorators.py +++ b/openproblems/tools/decorators.py @@ -85,8 +85,9 @@ def decorator(func): @functools.wraps(func) def apply_method(adata: anndata.AnnData, *args, **kwargs): log.debug("Running {} method".format(func.__name__)) + adata = func(adata, *args, **kwargs) adata.uns["is_baseline"] = is_baseline - return func(adata, *args, **kwargs) + return adata apply_method.metadata = dict( method_name=method_name,