5. Cell-type Deconvolution#
Pipeline phase: Phase 3.5b
What you will learn:
Understand the deconvolution module API
Prepare a reference scRNA-seq AnnData
Extract reference profiles with
extract_reference_profilesCall
deconvolutionwith a supported backendInspect
obsm['cell_type_proportions']andobs['{method}_argmax']
Backends supported: cell2location, tangram, destvi
Install: pip install sc-tools[deconvolution]
Note: This tutorial shows the API interface and expected data shapes. Running a full deconvolution requires a GPU-enabled machine with the optional
[deconvolution]extras installed. The code cells below are illustrative; they will raiseImportErrorwithout those extras.
import numpy as np
import pandas as pd
import anndata as ad
import sc_tools.tl as tl
Prepare spatial AnnData (target)#
The spatial AnnData must have raw counts in adata.X and spatial coordinates
in adata.obsm['spatial']. The library_id column in adata.obs is used
for per-library batching to avoid OOM on large datasets.
np.random.seed(99)
n_spots, n_genes = 300, 200
gene_names = [f"GENE_{i}" for i in range(n_genes)]
row, col = np.divmod(np.arange(n_spots), 20)
spatial_coords = np.column_stack([col * 100.0, row * 100.0])
spatial_adata = ad.AnnData(
X=np.random.poisson(5, size=(n_spots, n_genes)).astype(float),
obs={"library_id": [f"lib_{i % 2}" for i in range(n_spots)]},
obsm={"spatial": spatial_coords},
)
spatial_adata.var_names = gene_names
print("Spatial AnnData:", spatial_adata)
Prepare reference scRNA-seq AnnData#
The reference must have:
Raw counts in
adata.XCell-type labels in
adata.obs['celltype']Overlapping gene names with the spatial AnnData
n_cells = 500
cell_types = ["Epithelial", "Macrophage", "T_cell", "Fibroblast", "Endothelial"]
ref_adata = ad.AnnData(
X=np.random.poisson(3, size=(n_cells, n_genes)).astype(float),
obs={"celltype": pd.Categorical([cell_types[i % len(cell_types)] for i in range(n_cells)])},
)
ref_adata.var_names = gene_names
print("Reference AnnData:", ref_adata)
print("Cell types:", ref_adata.obs["celltype"].value_counts().to_dict())
Extract reference profiles#
extract_reference_profiles computes per-cell-type mean expression profiles
optimized for Cell2location (negative binomial regression model).
It handles memory-efficient batch processing for large reference datasets.
# In a real run (with scvi-tools installed):
# inf_aver = tl.extract_reference_profiles(
# ref_adata,
# celltype_col="celltype",
# batch_key=None,
# use_gpu=False, # set True on GPU machine
# )
# print("Reference profiles shape:", inf_aver.shape)
# Simulated output shape for illustration:
print("Expected inf_aver shape: (n_genes, n_celltypes) =", (n_genes, len(cell_types)))
Run deconvolution#
The deconvolution function accepts backend="cell2location", "tangram", or "destvi".
It processes each library_id separately to avoid OOM on large spatial datasets.
# In a real run:
# tl.deconvolution(
# spatial_adata,
# reference=ref_adata,
# celltype_col="celltype",
# backend="cell2location",
# library_key="library_id",
# use_gpu=False,
# max_epochs=100,
# )
# After deconvolution, the following are populated:
# - spatial_adata.obsm['cell_type_proportions'] -- shape (n_spots, n_celltypes)
# - spatial_adata.obs['cell2location_argmax'] -- dominant cell type per spot
print("Output: obsm['cell_type_proportions'] shape = (n_spots, n_celltypes)")
print("Output: obs['cell2location_argmax'] = dominant cell type per spot")
Inspect proportions (synthetic example)#
# Simulate deconvolution output for illustration
proportions = np.random.dirichlet(np.ones(len(cell_types)), size=n_spots)
spatial_adata.obsm["cell_type_proportions"] = pd.DataFrame(
proportions, index=spatial_adata.obs_names, columns=cell_types
)
spatial_adata.obs["cell2location_argmax"] = pd.Categorical(
spatial_adata.obsm["cell_type_proportions"].idxmax(axis=1)
)
print("Proportions (first 3 spots):")
print(spatial_adata.obsm["cell_type_proportions"].head(3).round(3).to_string())
print("\nDominant cell type distribution:")
print(spatial_adata.obs["cell2location_argmax"].value_counts())
Save and downstream use#
# Save method-specific checkpoint
spatial_adata.write_h5ad("results/adata.deconvolution.cell2location.h5ad")
# Spatial plots (Phase 5)
import sc_tools.pl as pl
pl.spatial.plot_spatial_continuous(
spatial_adata,
key="cell_type_proportions",
column="Macrophage",
library_id="lib_0",
)
For project-specific deconvolution scripts see:
projects/visium/ggo_visium/scripts/run_deconvolution.pyprojects/visium_hd/robin/scripts/run_deconvolution.py