Composition#
Second of five demonstration notebooks – this one covers composition plots: stacked_barplots,
stacked_barplots_multi_meta, composition_heatmap, and abundance_bubble_grid.
Data: the same PDAC atlas subset used throughout this set of notebooks (Lucarelli et al., https://doi.org/10.64898/2026.03.19.712924). See Embeddings for UMAP-based plots, Overview for dataset overview plots, or API Reference for the complete parameter reference.
import anndata as ad
import scanpy as sc
import scplotkit as spk
sc.settings.verbosity = 1
ATLAS_PATH = "/data/Daniele/atlases/final_versions_topublish/Human_subsampled.zarr"
Load the atlas#
adata = ad.read_zarr(ATLAS_PATH)
adata
AnnData object with n_obs × n_vars = 100000 × 39041
obs: 'Sample_ID', 'Condition', 'Treatment', 'TreatmentType', 'TreatmentStatus', 'Tissue', 'Sex', 'Dataset', 'Technology', 'Level_1', 'Level_2', 'Level_3', 'Level_4', 'Age', 'Diabetes', 'Is_Core', 'EMT category', 'Dataset_ID', 'Cluster_Names'
var: 'n_cells', 'ensembl_id', 'start', 'end', 'chromosome', 'gene_name_adata_sc', 'highly_variable_adata_sc', 'means_adata_sc', 'dispersions_adata_sc', 'dispersions_norm_adata_sc', 'highly_variable_nbatches_adata_sc', 'highly_variable_intersection_adata_sc', 'n_cells_by_counts_adata_sc', 'mean_counts_adata_sc', 'log1p_mean_counts_adata_sc', 'pct_dropout_by_counts_adata_sc', 'total_counts_adata_sc', 'log1p_total_counts_adata_sc', 'mito_adata_sc', 'n_cells_by_counts_adata_sn', 'mean_counts_adata_sn', 'log1p_mean_counts_adata_sn', 'pct_dropout_by_counts_adata_sn', 'total_counts_adata_sn', 'log1p_total_counts_adata_sn', 'Manual_Genes', 'mt', 'ribo', 'hb'
uns: 'UMAP_0.85', 'Condition_colors', 'Level_3_colors', 'Is_Core_colors', 'neighbors', 'UMAP_0.75', '_scvi_uuid', 'Level_4_colors', '_scvi_manager_uuid', 'Level_2_colors', 'Level_4_All_colors', 'Level_1_colors', 'umap', 'Level_4_Final_colors'
obsm: 'pct_counts_mito', 'X_pca', 'is_outlier_total_counts', 'bin_edges', 'UMAP_0.85', 'log_counts', 'scanvi_extended_atlas_emb', 'scanvi_L4_emb', 'log1p_total_counts', '_scvi_batch', 'scANVI_cross_species', 'level0_leiden_subcluster', 'leiden_0.2_annotation', 'log1p_n_genes_by_counts', 'batch', 'outlier', 'n_genes_by_counts', 'EMT_score_DL', 'n_genes', 'total_counts', 'leiden', 'UMAP_0.75', 'total_counts_mito', 'X_umap', 'MALAT1_lognorm', 'Global_Leiden', 'infercnv_score_malignant', 'leiden_0.5', 'leiden_0.2', 'UMAP_0.95', 'leiden_subcluster', 'EMT score', 'cnv_score_abs', 'log1p_total_counts_mito', 'scANVI_emb_final', 'n_counts', 'mt_frac', 'infercnv_score_malignant_refined', 'empty_droplet', '_scvi_labels'
layers: 'log_norm', 'counts', 'raw'
obsp: 'connectivities', 'distances'
Set up the plotter#
config = spk.PlotConfig({
"palettes": {
"Level_2": {
"Lymphoid": "#1f78b4",
"Malignant Cell": "#e31a1c",
"Stromal Cell": "#33a02c",
"Myeloid": "#ff7f00",
"Endothelial Cell": "#6a3d9a",
"Exocrine Cell": "#b15928",
"Endocrine Cell": "#a6cee3",
},
"TreatmentStatus": {"Untreated": "#4daf4a", "Treated": "#984ea3"},
}
})
plotter = spk.ScPlotter(config=config, output_dir="figures")
stacked_barplots#
Stacked bars of cell-type proportion per sample; every call already returns "basic", "clustered", and
(if order_by_column is given) "clustered_grouped" variants. Two demonstrations: the full atlas ordered
and clustered by treatment status, and a subset to one lineage with a custom palette.
figs = plotter.stacked_barplots(
adata,
level_column="Level_2",
sample_column="Sample_ID",
order_by_column="TreatmentStatus",
figsize=(10, 6),
)
figs["clustered_grouped"]
Subset to the myeloid compartment only (subset_level/subset_value), at Level_3 resolution, with a
custom palette for its four subtypes.
figs = plotter.stacked_barplots(
adata,
level_column="Level_3",
sample_column="Sample_ID",
subset_level="Level_2",
subset_value="Myeloid",
palette={
"Macrophage": "#d95f02",
"Dendritic Cell": "#7570b3",
"Neutrophil": "#e7298a",
"Monocyte": "#66a61e",
},
figsize=(10, 6),
save_name_prefix="myeloid_composition",
)
figs["clustered"]
stacked_barplots_multi_meta#
Like stacked_barplots, with extra color-coded metadata strips drawn below the bars. Two demonstrations:
two strips (treatment status + sex) over the full atlas, and a subset to the lymphoid compartment ordered by
treatment status.
plotter.stacked_barplots_multi_meta(
adata,
level_column="Level_2",
sample_column="Sample_ID",
metadata_columns=["TreatmentStatus", "Sex"],
figsize=(10, 6),
)
Subset to the lymphoid compartment at Level_3 resolution, ordered by TreatmentStatus (also drawn as its
own metadata strip) with Sex as a second strip.
figs = plotter.stacked_barplots_multi_meta(
adata,
level_column="Level_3",
sample_column="Sample_ID",
subset_level="Level_2",
subset_value="Lymphoid",
order_by_column="TreatmentStatus",
metadata_columns=["Sex"],
figsize=(10, 6),
save_name_prefix="lymphoid_composition_multi_meta",
)
figs["clustered_grouped"]
Figure saved to: figures/compositional_plot_multi_meta/lymphoid_composition_multi_meta_basic.png
Figure saved to: figures/compositional_plot_multi_meta/lymphoid_composition_multi_meta_clustered.png
Figure saved to: figures/compositional_plot_multi_meta/lymphoid_composition_multi_meta_clustered_grouped.png
composition_heatmap#
Clustered heatmap of cell-type proportion per sample. Two demonstrations: the default colormap with a
TreatmentStatus color strip, and a different colormap on a lineage subset.
plotter.composition_heatmap(
adata,
level_column="Level_3",
sample_column="Sample_ID",
order_by_column="TreatmentStatus",
figsize=(10, 8),
save_name="composition_heatmap",
)
cmap="rocket" (a seaborn colormap), subset to the stromal compartment at Level_4.
plotter.composition_heatmap(
adata,
level_column="Level_4",
sample_column="Sample_ID",
subset_level="Level_2",
subset_value="Stromal Cell",
cmap="rocket",
figsize=(10, 4),
save_name="composition_heatmap_stromal",
)
abundance_bubble_grid#
Dot grid of cell counts per (cell type, sample) pair – dot area encodes count, and gaps are drawn as faint
open rings rather than left blank. Two demonstrations: the default styling over the whole atlas, and a subset
with a custom dot_color and a larger max_size.
plotter.abundance_bubble_grid(
adata,
level_column="Level_2",
sample_column="Sample_ID",
save_name="level2_by_sample",
)
Subset to the stromal compartment at Level_4, with a custom dot_color.
Next steps#
See Overview for overview plots, or API Reference for the full parameter reference of every function used here.