Cross-Condition Analysis#
import plotnine as pn
import scanpy as sc
import matplotlib.pyplot as plt
from partipy.datasets import load_ncM_lupus_data
import decoupler as dc
import partipy as pt
In this vignette, we focus on non-classical monocytes from [PGS+22].
In this study, PBMCs from healthy subjects and from SLE (Systemic lupus erythematosus) patients were analyzed using scRNA-seq.
Here, we use the data to highlight how archetypal analysis can be used in the cross-condition setting. We identify one archetype that is enriched in the disease context, and characterize this archetype.
Load Data#
adata = load_ncM_lupus_data()
adata
AnnData object with n_obs × n_vars = 47819 × 30867
obs: 'library_uuid', 'author_cell_type', 'sample_uuid', 'disease_state', 'donor_id', 'Processing_Cohort', 'ct_cov', 'ind_cov', 'cell_type', 'assay', 'disease', 'sex', 'self_reported_ethnicity', 'development_stage', 'observation_joinid', 'Status'
var: 'feature_is_filtered', 'feature_reference', 'feature_biotype', 'feature_length', 'feature_type'
Check the number of cells we have per condition:
adata.obs.value_counts("Status")
Status
Managed 31268
Healthy 15091
Flare 1460
Name: count, dtype: int64
Quality Control#
We follow the Scanpy tutorial to perform quality control on the dataset.
First, we compute the proportion of counts originating from mitochondrial, ribosomal, and hemoglobin genes:
adata.var["mt"] = adata.var_names.str.startswith("MT-")
adata.var["ribo"] = adata.var_names.str.startswith(("RPS", "RPL"))
adata.var["hb"] = adata.var_names.str.contains(("^HB[^(P)]"))
sc.pp.calculate_qc_metrics(
adata, qc_vars=["mt", "ribo", "hb"], inplace=True, percent_top=[20], log1p=True
)
We can now examine key quality control metrics, including:
The number of genes expressed per cell
The total counts per cell
The percentage of counts originating from mitochondrial genes
sc.pl.violin(
adata,
["total_counts", "n_genes_by_counts", "pct_counts_mt"],
jitter=0.4,
multi_panel=True,
)
To remove low-quality data, we filter out cells with fewer than 100 detected genes and genes that are present in fewer than 3 cells. This ensures that only high-quality cells and genes are retained for downstream analysis.
print(f"Number of cells before filtering: {adata.n_obs} \nNumber of genes before filtering: {adata.n_vars}")
sc.pp.filter_cells(adata, min_genes=100)
sc.pp.filter_genes(adata, min_cells=3)
print(f"Number of cells after filtering of low quality cells: {adata.n_obs} \nNumber of genes after filtering of low quality genes: {adata.n_vars}")
Number of cells before filtering: 47819
Number of genes before filtering: 30867
Number of cells after filtering of low quality cells: 47819
Number of genes after filtering of low quality genes: 18496
Normalization and feature selection#
To ensure comparability across cells, we normalize the data to the median total counts per cell and apply a logarithmic transformation:
sc.pp.normalize_total(adata)
sc.pp.log1p(adata)
Next, we identify highly variable genes, which are key for downstream analysis. We also visualize them to assess their distribution:
sc.pp.highly_variable_genes(adata)
sc.pl.highly_variable_genes(adata)
For the downstream enrichment analysis, we standardize the data by scaling gene expression values:
adata.layers["z_scaled"]= sc.pp.scale(adata.X, max_value=10, copy=True)
Dimension Reduction#
We compute a Principal Component Analysis (PCA) using only highly variable genes to reduce nosie and extract the most meaningful dimensions based on explained variance.
sc.pp.pca(adata, mask_var="highly_variable")
sc.pl.pca_scatter(adata, color="Status")
To determine the optimal number of principal components (PCs) to retain, we inspect their contribution to the total variance:
sc.pl.pca_variance_ratio(adata, n_pcs=50)
Based on this, we select 7 PCs, as the variance explained plateaus beyond this point. For ease of use in downstream analysis, we store the selected number of dimensions of the PCA in adata.uns[“aa_config”] with the following function:
pt.set_obsm(adata=adata, obsm_key="X_pca", n_dimensions=7)
Number of Archetypes#
Next, we need to determine the optimal number of archetypes in our data—essentially, the number of vertices in the polyhedron.
We first assess how much variance is explained for different numbers of archetypes.
The function var_explained_aa() takes the 7D PCA data and calculates the explained variance for a range of archetypes (min_k to max_a). It computes:
The variance explained by each archetype.
The additional variance explained by each successive archetype.
The distance from the projected point to the line of the elbow plot.
An information criteria (IC)
pt.compute_selection_metrics(adata=adata, n_archetypes_list=range(2,10))
The results are stored in:
pt.summarize_aa_metrics(adata)
| k | n_archetypes | n_restarts | seed | varexpl | IC | RSS | |
|---|---|---|---|---|---|---|---|
| 0 | 2 | 2 | 5 | 42 | 0.345126 | 44101.212524 | 219199.375000 |
| 1 | 3 | 3 | 5 | 42 | 0.512452 | 38643.200165 | 163190.234375 |
| 2 | 4 | 4 | 5 | 42 | 0.625245 | 38706.799687 | 125437.351562 |
| 3 | 5 | 5 | 5 | 42 | 0.713459 | 42202.905868 | 95911.164062 |
| 4 | 6 | 6 | 5 | 42 | 0.779241 | 45237.676820 | 73892.960938 |
| 5 | 7 | 7 | 5 | 42 | 0.835723 | 48805.377194 | 54987.296875 |
| 6 | 8 | 8 | 5 | 42 | 0.868597 | 52748.205372 | 43983.996094 |
| 7 | 9 | 9 | 5 | 42 | 0.884990 | 57209.086866 | 38496.464844 |
We visualize the explained variance for different models:
In this plot, the grey line connects the first and last variance explained (EV) values, helping to identify the “elbow” of the black curve.
Visualize the trend of the IC:
This analysis suggests that the best choice is 4-6 archetypes. We decide to use 4 archetypes, as later analyses show that the 5th archetype introduces no new tasks.
n_archetypes = 4
To validate the archetype stability, we apply bootstrapping. We sample the data 25 times and run Archetypal Analysis (AA) on each sample.
pt.compute_bootstrap_variance(adata=adata, n_bootstrap=50, n_archetypes_list=n_archetypes)
The positions of the archetypes and the mean variance per archetype and across all bootstrapped samples can be accessed using pt.get_aa_bootstrap
pt.get_aa_bootstrap(adata, n_archetypes=n_archetypes)
| X_pca_0 | X_pca_1 | X_pca_2 | X_pca_3 | X_pca_4 | X_pca_5 | X_pca_6 | archetype | iter | reference | mean_variance | variance_per_archetype | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | -4.816427 | -3.540382 | 0.685227 | -0.309495 | 0.276425 | 0.018469 | 0.135509 | 0 | 1 | False | 0.822806 | 0.314052 |
| 1 | 0.600345 | 3.903207 | 3.580197 | -1.339453 | 0.443354 | -0.066739 | -0.171309 | 1 | 1 | False | 0.822806 | 1.289679 |
| 2 | -1.430764 | 3.333933 | -3.710526 | 1.043123 | -0.464882 | 0.049811 | -0.021669 | 2 | 1 | False | 0.822806 | 1.267447 |
| 3 | 6.307580 | -2.459274 | -0.703617 | 0.508641 | -0.270054 | -0.187655 | 0.121409 | 3 | 1 | False | 0.822806 | 0.420045 |
| 0 | -3.734222 | -3.449724 | -1.146636 | -1.181680 | 0.387082 | 0.298474 | -0.082064 | 0 | 2 | False | 0.822806 | 0.314052 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 3 | 5.096452 | -2.411780 | 2.652799 | 0.736679 | 0.016161 | -0.178691 | 0.226363 | 3 | 50 | False | 0.822806 | 0.420045 |
| 0 | -4.013512 | -3.654292 | -1.208841 | -0.551198 | 0.161331 | 0.218104 | -0.124733 | 0 | 0 | True | 0.822806 | 0.314052 |
| 1 | -3.962077 | 2.977677 | 3.858459 | 1.793481 | -0.317860 | -0.247827 | 0.572696 | 1 | 0 | True | 0.822806 | 1.289679 |
| 2 | 1.994150 | 3.965207 | -3.145393 | -1.469313 | 0.277546 | -0.147325 | -0.481090 | 2 | 0 | True | 0.822806 | 1.267447 |
| 3 | 6.057837 | -2.123687 | 1.216479 | 0.570489 | -0.240843 | -0.104882 | 0.146785 | 3 | 0 | True | 0.822806 | 0.420045 |
204 rows × 12 columns
We visualize the bootstrapping results to show that the archetypes are mostly stable:
Archetype Analysis and Visualization of the Archetypes#
Now that we’ve determined the number of archetypes, we can investigate the four archetypes in more detail. The coordinates of the archetypes are given in
pt.get_aa_result(adata, n_archetypes=4)["Z"]
array([[-4.0135117 , -3.6542923 , -1.2088412 , -0.5511984 , 0.16133077,
0.21810366, -0.1247327 ],
[-3.9620771 , 2.977677 , 3.8584588 , 1.793481 , -0.31786036,
-0.24782737, 0.57269555],
[ 1.9941503 , 3.9652069 , -3.1453931 , -1.4693129 , 0.2775457 ,
-0.1473254 , -0.4810897 ],
[ 6.0578375 , -2.1236866 , 1.2164787 , 0.570489 , -0.24084304,
-0.10488223, 0.14678527]], dtype=float32)
The RSS is also saved into “AA_results”. We can manually check for the convergence as follows:
plt.plot(pt.get_aa_result(adata, n_archetypes=4)["RSS"])
plt.grid()
plt.xlabel("Iteration", y="Residual Sum of Squares (RSS)")
plt.ylabel("Residual Sum of Squares (RSS)")
plt.yscale("log")
plt.show()
We can visualize the polytope in both 2D and 3D with the coloring representing the disease status. Alternatively, we can color the plot based on a gene with distinct expression across archetypes. For example, using the gene IFI27.
To visualize the polytope in 2D use the following function:
Identify representatives#
To assign tasks to the archetypes, we need to identify cells that are representative of each archetype. To do this, we calculate cell weights for each archetype.
First, we calculate the weights for each cell based on its distance from the archetypes with a Radial Basis Function (RBF) kernel. The length scale of the RBF kernel is automatically set as half the median distance from the data centroid to the archetypes. However, this can also be manually adjusted if needed.
pt.compute_archetype_weights(adata=adata, mode="automatic", result_filters={"n_archetypes": 4})
Applied length scale is 3.06.
The resulting cell weights for e.g. archetype 3 are:
Enrichment Metadata#
With the weights we can now calculate enrichment of interest. Since we have different cell status associated with healthy and disease, we want first to check the enrichment by the disease state and find our archetypes of interest.
meta_enrichment() calcualtes the enrichment of any specified metadata stored in .obs.
status_enrichment = pt.compute_meta_enrichment(adata=adata, meta_col="Status", result_filters={"n_archetypes": 4})
status_enrichment
| Flare | Managed | Healthy | |
|---|---|---|---|
| 0 | 0.234499 | 0.302162 | 0.463339 |
| 1 | 0.161296 | 0.297869 | 0.540835 |
| 2 | 0.329187 | 0.355966 | 0.314847 |
| 3 | 0.557284 | 0.368842 | 0.073874 |
We find ncM with the “Flare” status enriched at an archetype. These results can be visualized in multiple ways:
pt.radarplot_meta_enrichment(status_enrichment)
Functional Enrichment MSigDB#
Next, we compute the archetypes “gene expression” using the z-scaled gene expression data and cell weights to observe differences in gene expression across the archetypes:
archetype_expression = pt.compute_archetype_expression(adata=adata, layer="z_scaled", result_filters={"n_archetypes": 4})
archetype_expression.iloc[:, 20:25]
| TNFRSF4 | SDF4 | B3GALT6 | C1QTNF12 | ENSG00000260179.1 | |
|---|---|---|---|---|---|
| 0 | -257.661762 | -373.689194 | -209.559462 | -382.375408 | -347.789129 |
| 1 | -93.357272 | -17.415676 | -15.345104 | -162.569499 | -164.947694 |
| 2 | -188.547137 | 158.578746 | -103.503072 | -253.325774 | -237.760378 |
| 3 | -249.735386 | 232.526122 | -91.851896 | -257.211882 | -220.419653 |
For functional enrichment, we use Decoupler with Gene Ontology (GO) biological processes. While other collections can be used, it’s recommended to choose those with less broad categories to avoid non-significant results.
We begin by loading the MSigDB resource and filtering for the GO biological processes collection:
msigdb_raw = dc.op.resource("MSigDB")
msigdb = msigdb_raw[msigdb_raw["collection"]=="go_biological_process"]
msigdb = msigdb[~msigdb.duplicated(["geneset", "genesymbol"])]
msigdb = msigdb.rename(columns={"geneset": "source", "genesymbol": "target"})
msigdb
| target | collection | source | |
|---|---|---|---|
| 73 | A1CF | go_biological_process | GOBP_MRNA_METABOLIC_PROCESS |
| 78 | A1CF | go_biological_process | GOBP_EMBRYO_IMPLANTATION |
| 84 | A1CF | go_biological_process | GOBP_MACROMOLECULE_CATABOLIC_PROCESS |
| 87 | A1CF | go_biological_process | GOBP_MRNA_MODIFICATION |
| 88 | A1CF | go_biological_process | GOBP_RNA_PROCESSING |
| ... | ... | ... | ... |
| 5522215 | ZZZ3 | go_biological_process | GOBP_PROTEIN_ACYLATION |
| 5522223 | ZZZ3 | go_biological_process | GOBP_HISTONE_H3_ACETYLATION |
| 5522241 | ZZZ3 | go_biological_process | GOBP_REGULATION_OF_MULTICELLULAR_ORGANISMAL_DE... |
| 5522261 | ZZZ3 | go_biological_process | GOBP_MACROMOLECULE_DEACYLATION |
| 5522262 | ZZZ3 | go_biological_process | GOBP_CELL_CYCLE |
1026039 rows × 3 columns
Next, we run ULM from decoupler on the pseudobulk data using the filtered MSigDB resource. The resulting estimated enrichment scores and p-values are saved in acts_ulm_est and acts_ulm_est_p:
acts_ulm_est, acts_ulm_est_p = dc.mt.ulm(data=archetype_expression,
net=msigdb)
acts_ulm_est
| GOBP_10_FORMYLTETRAHYDROFOLATE_METABOLIC_PROCESS | GOBP_2FE_2S_CLUSTER_ASSEMBLY | GOBP_2_OXOGLUTARATE_METABOLIC_PROCESS | GOBP_3_PHOSPHOADENOSINE_5_PHOSPHOSULFATE_METABOLIC_PROCESS | GOBP_3_UTR_MEDIATED_MRNA_DESTABILIZATION | GOBP_3_UTR_MEDIATED_MRNA_STABILIZATION | GOBP_4FE_4S_CLUSTER_ASSEMBLY | GOBP_5S_CLASS_RRNA_TRANSCRIPTION_BY_RNA_POLYMERASE_III | GOBP_5_PHOSPHORIBOSE_1_DIPHOSPHATE_METABOLIC_PROCESS | GOBP_7_METHYLGUANOSINE_CAP_HYPERMETHYLATION | ... | GOBP_XENOBIOTIC_TRANSPORT | GOBP_XENOBIOTIC_TRANSPORT_ACROSS_BLOOD_BRAIN_BARRIER | GOBP_XENOPHAGY | GOBP_XMP_METABOLIC_PROCESS | GOBP_XYLULOSE_5_PHOSPHATE_METABOLIC_PROCESS | GOBP_ZINC_ION_IMPORT_ACROSS_PLASMA_MEMBRANE | GOBP_ZINC_ION_IMPORT_INTO_ORGANELLE | GOBP_ZINC_ION_TRANSPORT | GOBP_ZYMOGEN_ACTIVATION | GOBP_ZYMOGEN_INHIBITION | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.241079 | 0.672763 | -0.030060 | -0.378506 | -4.176762 | -2.494529 | 0.958651 | 0.367429 | 0.420109 | 0.827908 | ... | -0.331340 | 0.254343 | -3.042813 | -0.080069 | -0.243916 | 0.345404 | 0.474443 | 0.803099 | -2.633981 | -0.253889 |
| 1 | -0.203632 | -1.988812 | -0.867501 | -0.684650 | 4.825518 | 3.437554 | -1.052776 | 0.514176 | 0.050987 | -2.969620 | ... | -0.443198 | 0.131471 | 1.155966 | 0.120715 | -1.416573 | 0.605550 | 0.496199 | 0.463621 | -3.180310 | -0.683561 |
| 2 | 0.427570 | 2.635611 | 1.640959 | 0.700003 | 3.195863 | 3.441391 | 1.481129 | 0.828693 | 1.670545 | 2.539954 | ... | -1.333788 | -0.563798 | 2.112109 | 1.854099 | 2.331447 | 0.442798 | 0.065135 | 0.473911 | 1.780707 | 0.669558 |
| 3 | 0.143610 | 1.260025 | 0.704676 | 0.509149 | 0.084102 | 0.423825 | 0.779055 | 0.459744 | 0.539227 | 2.436380 | ... | -0.889441 | -0.585189 | 2.212209 | -0.407028 | 0.648526 | -0.093672 | 0.179846 | 0.227018 | 4.025651 | 1.801857 |
4 rows × 6910 columns
To identify the top enriched processes for each archetype, we extract the top 20 processes and order them in descending order:
top_processes = pt.extract_enriched_processes(est=acts_ulm_est,
pval=acts_ulm_est_p,
order="desc",
n=20,
p_threshold=0.05)
For example, for the archetype that is enriched in “Flare,” we observe an enrichment of processes related to the immune response to viruses and the response to interferon.
top_processes[arch_idx].round(2)
| Process | 0 | 1 | 2 | 3 | specificity | |
|---|---|---|---|---|---|---|
| 0 | GOBP_NEGATIVE_REGULATION_OF_VIRAL_GENOME_REPLI... | -18.01 | -13.64 | 0.96 | 29.23 | 28.27 |
| 1 | GOBP_NEGATIVE_REGULATION_OF_VIRAL_PROCESS | -20.22 | -12.49 | 4.40 | 28.55 | 24.15 |
| 2 | GOBP_DEFENSE_RESPONSE_TO_SYMBIONT | -19.53 | -8.42 | 5.86 | 27.08 | 21.22 |
| 3 | GOBP_DEFENSE_RESPONSE_TO_OTHER_ORGANISM | -23.68 | -5.96 | 15.31 | 26.25 | 10.94 |
| 4 | GOBP_INNATE_IMMUNE_RESPONSE | -22.05 | -6.81 | 14.06 | 25.93 | 11.87 |
| 5 | GOBP_BIOLOGICAL_PROCESS_INVOLVED_IN_INTERSPECI... | -24.11 | -4.38 | 18.16 | 25.46 | 7.30 |
| 6 | GOBP_RESPONSE_TO_VIRUS | -19.20 | -6.54 | 8.01 | 25.32 | 17.31 |
| 7 | GOBP_DEFENSE_RESPONSE | -24.52 | -4.77 | 16.87 | 24.45 | 7.58 |
| 8 | GOBP_IMMUNE_RESPONSE | -24.45 | -4.96 | 18.72 | 23.54 | 4.82 |
| 9 | GOBP_REGULATION_OF_VIRAL_PROCESS | -19.64 | -9.11 | 9.03 | 23.50 | 14.47 |
| 10 | GOBP_REGULATION_OF_VIRAL_GENOME_REPLICATION | -15.75 | -7.97 | 2.48 | 22.90 | 20.42 |
| 11 | GOBP_RESPONSE_TO_TYPE_I_INTERFERON | -13.37 | -8.37 | 1.30 | 21.88 | 20.57 |
| 12 | GOBP_RESPONSE_TO_INTERFERON_BETA | -12.91 | -11.05 | 2.45 | 20.61 | 18.16 |
| 13 | GOBP_VIRAL_GENOME_REPLICATION | -13.45 | -5.71 | 4.16 | 19.29 | 15.13 |
| 14 | GOBP_INTERFERON_MEDIATED_SIGNALING_PATHWAY | -12.07 | -7.06 | 2.23 | 18.95 | 16.72 |
| 15 | GOBP_VIRAL_LIFE_CYCLE | -15.42 | -6.13 | 8.81 | 18.56 | 9.76 |
| 16 | GOBP_VIRAL_PROCESS | -14.60 | -3.52 | 10.26 | 17.49 | 7.22 |
| 17 | GOBP_NEGATIVE_REGULATION_OF_VIRAL_LIFE_CYCLE | -12.57 | -9.87 | 3.90 | 17.33 | 13.43 |
| 18 | GOBP_REGULATION_OF_RESPONSE_TO_BIOTIC_STIMULUS | -16.03 | -1.83 | 10.50 | 17.15 | 6.65 |
| 19 | GOBP_REGULATION_OF_IMMUNE_RESPONSE | -18.81 | -3.07 | 16.45 | 17.01 | 0.56 |
On the other hand, for the archetype that is enriched in healthy, we see task of upkeeping homeostasis and normal cellular function in the cells.
top_processes[1].round(2)
| Process | 0 | 1 | 2 | 3 | specificity | |
|---|---|---|---|---|---|---|
| 0 | GOBP_CYTOPLASMIC_TRANSLATION | 3.68 | 16.35 | 30.72 | -23.19 | -14.37 |
| 1 | GOBP_POSITIVE_REGULATION_OF_RNA_METABOLIC_PROCESS | -2.70 | 14.80 | 7.49 | 2.44 | 7.32 |
| 2 | GOBP_POSITIVE_REGULATION_OF_MACROMOLECULE_BIOS... | -2.34 | 13.88 | 8.45 | 2.14 | 5.43 |
| 3 | GOBP_POSITIVE_REGULATION_OF_TRANSCRIPTION_BY_R... | -3.80 | 12.60 | 4.82 | 1.21 | 7.78 |
| 4 | GOBP_NEGATIVE_REGULATION_OF_BIOSYNTHETIC_PROCESS | -2.74 | 11.90 | 5.86 | 1.27 | 6.04 |
| 5 | GOBP_NEGATIVE_REGULATION_OF_NUCLEOBASE_CONTAIN... | -2.31 | 11.88 | 4.94 | 1.09 | 6.94 |
| 6 | GOBP_CHROMATIN_ORGANIZATION | 3.59 | 11.15 | 2.17 | -0.47 | 7.56 |
| 7 | GOBP_PEPTIDE_BIOSYNTHETIC_PROCESS | 2.28 | 10.73 | 23.44 | -7.30 | -12.71 |
| 8 | GOBP_NEGATIVE_REGULATION_OF_RNA_BIOSYNTHETIC_P... | -2.34 | 10.65 | 3.71 | 0.89 | 6.94 |
| 9 | GOBP_MRNA_METABOLIC_PROCESS | 2.83 | 10.47 | 8.01 | 3.19 | 2.46 |
| 10 | GOBP_AMIDE_BIOSYNTHETIC_PROCESS | 2.66 | 10.31 | 21.92 | -6.38 | -11.61 |
| 11 | GOBP_CELLULAR_MACROMOLECULE_BIOSYNTHETIC_PROCESS | 2.86 | 10.28 | 19.71 | -5.09 | -9.43 |
| 12 | GOBP_PEPTIDE_METABOLIC_PROCESS | 1.50 | 10.17 | 23.31 | -6.04 | -13.14 |
| 13 | GOBP_NEGATIVE_REGULATION_OF_TRANSCRIPTION_BY_R... | -1.94 | 10.08 | 2.33 | -0.09 | 7.75 |
| 14 | GOBP_REGULATION_OF_MRNA_METABOLIC_PROCESS | 1.15 | 10.00 | 5.62 | -0.58 | 4.38 |
| 15 | GOBP_PHOSPHORYLATION | -3.42 | 9.82 | 5.48 | 2.45 | 4.33 |
| 16 | GOBP_POST_TRANSCRIPTIONAL_REGULATION_OF_GENE_E... | 1.11 | 9.48 | 9.52 | -1.26 | -0.04 |
| 17 | GOBP_HISTONE_MODIFICATION | 2.41 | 9.16 | 2.99 | 1.00 | 6.18 |
| 18 | GOBP_REGULATION_OF_CELLULAR_MACROMOLECULE_BIOS... | 1.17 | 9.12 | 9.17 | -1.65 | -0.04 |
| 19 | GOBP_RNA_PROCESSING | 5.58 | 9.02 | 11.41 | 2.10 | -2.39 |
To identify processes specific to a particular archetype, meaning they are in the top enriched processes of one archetype, we can filter for the highest specificity score, by apply the following function:
specific_processes = pt.extract_specific_processes(est=acts_ulm_est,
pval=acts_ulm_est_p,
n=10,
p_threshold=0.05)
specific_processes[2].round(2)
| Process | 0 | 1 | 2 | 3 | specificity | |
|---|---|---|---|---|---|---|
| 0 | GOBP_PEPTIDE_ANTIGEN_ASSEMBLY_WITH_MHC_CLASS_I... | -27.00 | -17.47 | 47.16 | 6.92 | 40.24 |
| 1 | GOBP_PEPTIDE_ANTIGEN_ASSEMBLY_WITH_MHC_PROTEIN... | -25.15 | -16.37 | 43.50 | 7.42 | 36.08 |
| 2 | GOBP_ANTIGEN_PROCESSING_AND_PRESENTATION_OF_EX... | -23.33 | -16.47 | 38.43 | 9.22 | 29.21 |
| 3 | GOBP_ANTIGEN_PROCESSING_AND_PRESENTATION_OF_PE... | -21.71 | -14.97 | 35.35 | 9.06 | 26.29 |
| 4 | GOBP_ANTIGEN_PROCESSING_AND_PRESENTATION_OF_EX... | -23.43 | -15.77 | 35.55 | 11.36 | 24.20 |
| 5 | GOBP_ANTIGEN_PROCESSING_AND_PRESENTATION_OF_EX... | -22.24 | -14.90 | 33.00 | 11.14 | 21.86 |
| 6 | GOBP_ANTIGEN_PROCESSING_AND_PRESENTATION_OF_PE... | -20.82 | -13.78 | 29.52 | 11.89 | 17.63 |
| 7 | GOBP_IMMUNOGLOBULIN_PRODUCTION_INVOLVED_IN_IMM... | -12.21 | -5.75 | 20.46 | 3.85 | 16.61 |
| 8 | GOBP_DENDRITIC_CELL_ANTIGEN_PROCESSING_AND_PRE... | -13.76 | -7.24 | 20.94 | 5.19 | 15.75 |
| 9 | GOBP_CYTOPLASMIC_TRANSLATION | 3.68 | 16.35 | 30.72 | -23.19 | 14.37 |
For visualization we can plot the obtained results:
pt.barplot_functional_enrichment(top_processes)
Session Info#
import session_info2
print(session_info2.session_info(dependencies=True))
plotnine 0.14.5
pandas 2.2.3
scanpy 1.11.2
matplotlib 3.10.3
partipy 0.0.1
decoupler 2.0.6
anndata 0.11.4
numpy 2.2.6
---- ----
igraph 0.11.8
annotated-types 0.7.0
threadpoolctl 3.6.0
pyparsing 3.2.3
plotly 6.1.2
certifi 2025.4.26 (2025.04.26)
PyYAML 6.0.2
setuptools 80.8.0
tornado 6.5.1
zarr 2.18.7
executing 2.2.0
pyzmq 26.4.0
idna 3.10
urllib3 2.4.0
typing_extensions 4.13.2
Pygments 2.19.1
importlib_metadata 8.7.0
zipp 3.22.0
ipython 9.2.0
pybiomart 0.2.0
pydantic 2.12.0
narwhals 1.41.0
wrapt 1.17.2
parso 0.8.4
cloudpickle 3.1.1
joblib 1.5.1
docrep 0.3.2
tqdm 4.67.1
debugpy 1.8.14
traitlets 5.14.3
stack-data 0.6.3
legendkit 0.3.5
ipykernel 6.29.5
adjustText 1.3.0
pyarrow 20.0.0
seaborn 0.13.2
six 1.17.0
typing-inspection 0.4.2
psutil 7.0.0
wcwidth 0.2.13
future 1.0.0
crc32c 2.7.1
scikit-learn 1.6.1
llvmlite 0.44.0
numcodecs 0.15.1
session-info2 0.1.2
texttable 1.7.0
url-normalize 2.2.1
Deprecated 1.2.18
scipy 1.15.2
colorama 0.4.6
toolz 1.0.0
decorator 5.2.1
mizani 0.13.5
h5py 3.13.0
xgboost 3.0.2
kiwisolver 1.4.8
python-dateutil 2.9.0.post0
appnope 0.1.4
ipywidgets 8.1.7
cycler 0.12.1
pillow 11.2.1
asciitree 0.3.3
marsilea 0.5.3
requests-cache 1.2.1
pydantic_core 2.41.1
comm 0.2.2
jupyter_client 8.6.3
asttokens 3.0.0
matplotlib-inline 0.1.7
pure_eval 0.2.3
jedi 0.19.2
charset-normalizer 3.4.2
platformdirs 4.3.8
requests 2.32.3
pytz 2025.2
numba 0.61.2
legacy-api-wrap 1.4.1
natsort 8.4.0
jupyter_core 5.8.1
packaging 25.0
dask 2024.11.2
patsy 1.0.1
attrs 25.3.0
cattrs 24.1.3
xarray 2024.11.0
prompt_toolkit 3.0.51
statsmodels 0.14.4
dcor 0.6
---- ----
Python 3.11.0 | packaged by conda-forge | (main, Jan 14 2023, 12:26:40) [Clang 14.0.6 ]
OS macOS-15.7.1-arm64-arm-64bit
Updated 2025-10-14 12:27