Upstream Steps
This Notebook
Metacell calculation by SEACells (following this tutorial)
import os
import sys
import numpy as np
import pandas as pd
import scanpy as sc
import pickle
#Plotting
import matplotlib.pyplot as plt
import matplotlib
import seaborn as sns
#utils
#import ipynbname
from datetime import datetime
# SeaCell
import SEACells
#import custom functions
sys.path.append('../')
import functions as fn
# Some plotting aesthetics
%matplotlib inline
sns.set_style('ticks')
matplotlib.rcParams['figure.figsize'] = [3.5, 3.5]
matplotlib.rcParams['figure.dpi'] = 100
print("Scanpy version: ", sc.__version__)
print("Pandas version: ", pd.__version__)
print("SEACell version: ", SEACells.__version__)
Scanpy version: 1.10.2 Pandas version: 2.2.2 SEACell version: 0.3.3
sc.settings.verbosity = 3
sc.settings.set_figure_params(dpi=80)
input_file = '../../../../DataDir/ExternalData/SingleCellData/Wang_IITrimester_adata.h5ad'
output_file = '../../../../DataDir/ExternalData/SingleCellData/Wang_IITrimester_adataMetacells.h5ad'
print(datetime.now())
2026-03-11 12:33:22.575161
adata = sc.read(input_file)
adata
AnnData object with n_obs × n_vars = 64500 × 20266
obs: 'Auth_Sample_ID', 'Auth_Estimated_postconceptional_age_in_days', 'Auth_Group', 'Auth_Region', 'Auth_nCount_RNA', 'Auth_nFeature_RNA', 'Auth_ATAC_fragments_in_peaks', 'Auth_Scrublet_doublet_score', 'Auth_S.Score', 'Auth_G2M.Score', 'Auth_Class', 'Auth_Subclass', 'Auth_Type_updated', 'Auth_Cluster', 'Auth_cell_type_ontology_term_id', 'Auth_development_stage_ontology_term_id', 'Auth_donor_id', 'Auth_cell_type', 'Auth_sex', 'Auth_tissue', 'Auth_self_reported_ethnicity', 'Auth_development_stage', 'dataset_id', 'sample_id', 'age', 'stage', 'cell_label', 'brain_region', 'n_genes_by_counts', 'log1p_n_genes_by_counts', 'total_counts', 'log1p_total_counts', 'total_counts_mito', 'log1p_total_counts_mito', 'pct_counts_mito', 'total_counts_ribo', 'log1p_total_counts_ribo', 'pct_counts_ribo', 'log1p_gene_UMI_ratio', 'n_genes', 'n_counts', 'Leiden_02', 'Leiden_04', 'Leiden_06', 'Leiden_Sel'
var: 'gene_name', 'feature_is_filtered', 'feature_name', 'feature_length', 'feature_type', 'EnsembleCode', 'mito', 'ribo', 'n_cells_by_counts', 'mean_counts', 'log1p_mean_counts', 'pct_dropout_by_counts', 'total_counts', 'log1p_total_counts', 'n_cells', 'highly_variable', 'means', 'dispersions', 'dispersions_norm', 'highly_variable_nbatches', 'highly_variable_intersection'
uns: 'Auth_Group_colors', 'Leiden_02', 'Leiden_02_colors', 'Leiden_04', 'Leiden_04_colors', 'Leiden_06', 'Leiden_06_colors', 'Leiden_Sel_colors', 'age_colors', 'brain_region_colors', 'cell_label_colors', 'diffmap_evals', 'draw_graph', 'harmony', 'hvg', 'log1p', 'pca', 'sample_id_colors', 'umap'
obsm: 'X_draw_graph_fa_harmony', 'X_pca', 'X_pca_harmony', 'X_umap_harmony', 'X_umap_nocorr'
varm: 'PCs'
layers: 'counts', 'lognorm'
obsp: 'harmony_connectivities', 'harmony_distances', 'pca_connectivities', 'pca_distances'
adata.obsm
AxisArrays with keys: X_draw_graph_fa_harmony, X_pca, X_pca_harmony, X_umap_harmony, X_umap_nocorr
adata.X
<Compressed Sparse Row sparse matrix of dtype 'float32' with 150008510 stored elements and shape (64500, 20266)>
print(adata.X[40:45, 40:45])
<Compressed Sparse Row sparse matrix of dtype 'float32' with 0 stored elements and shape (5, 5)>
adata.layers['counts']
<Compressed Sparse Row sparse matrix of dtype 'uint16' with 150008510 stored elements and shape (64500, 20266)>
print(adata.layers['counts'][40:45, 40:45])
<Compressed Sparse Row sparse matrix of dtype 'uint16' with 0 stored elements and shape (5, 5)>
sc.pl.scatter(adata, basis='umap_nocorr', color=['sample_id', 'brain_region', 'cell_label'], frameon=False)
sc.pl.scatter(adata, basis='pca_harmony', color=['sample_id', 'brain_region', 'cell_label'], frameon=False)
sc.pl.scatter(adata, basis='umap_harmony', color=['sample_id', 'brain_region', 'cell_label'], frameon=False)
adata.obs.head(3)
| Auth_Sample_ID | Auth_Estimated_postconceptional_age_in_days | Auth_Group | Auth_Region | Auth_nCount_RNA | Auth_nFeature_RNA | Auth_ATAC_fragments_in_peaks | Auth_Scrublet_doublet_score | Auth_S.Score | Auth_G2M.Score | ... | total_counts_ribo | log1p_total_counts_ribo | pct_counts_ribo | log1p_gene_UMI_ratio | n_genes | n_counts | Leiden_02 | Leiden_04 | Leiden_06 | Leiden_Sel | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ARKFrozen-18-PFC_AAACAGCCAAGGTGCA-1 | ARKFrozen-18-PFC | 98 | Second_trimester | PFC | 5071 | 2436 | 6329 | 0.078697 | 0.028415 | -0.040407 | ... | 239 | 5.480639 | 4.716795 | 0.392021 | 2432 | 5067 | 0 | 0 | 0 | 0 |
| ARKFrozen-18-PFC_AAACAGCCACTAAATC-1 | ARKFrozen-18-PFC | 98 | Second_trimester | PFC | 5564 | 2508 | 6727 | 0.118406 | -0.085718 | -0.007773 | ... | 322 | 5.777652 | 5.789284 | 0.371948 | 2506 | 5562 | 1 | 2 | 2 | 2 |
| ARKFrozen-18-PFC_AAACAGCCAGGTTCAC-1 | ARKFrozen-18-PFC | 98 | Second_trimester | PFC | 2191 | 1468 | 3477 | 0.039033 | 0.040728 | 0.065663 | ... | 121 | 4.804021 | 5.527638 | 0.512651 | 1466 | 2189 | 6 | 8 | 5 | 8 |
3 rows × 45 columns
Normalization, log-transformation, HVG and dimensionality reduction have been already performed.
We follow the workflow described in the SEACells tutorial
Parameters to be defined:
We then employ the SEACells.core.SEACells function to initialize the model.
## Core parameters
n_SEACells = round(adata.n_obs/75)
print(n_SEACells)
build_kernel_on = 'X_pca_harmony' # key in ad.obsm to use for computing metacells
# This would be replaced by 'X_svd' for ATAC data
## Additional parameters
n_waypoint_eigs = 10 # Number of eigenvalues to consider when initializing metacells
860
#help(SEACells.core.SEACells)
model = SEACells.core.SEACells(adata,
build_kernel_on=build_kernel_on,
n_SEACells=n_SEACells,
n_waypoint_eigs=n_waypoint_eigs,
convergence_epsilon = 1e-5,
use_gpu=True)
Welcome to SEACells GPU!
construct_kernel_matrix function constructs the kernel matrix from data matrix using PCA/SVD and nearest neighbors. Key parameters are:
model.construct_kernel_matrix(n_neighbors=20)
M = model.kernel_matrix
Computing kNN graph using scanpy NN ...
computing neighbors
finished: added to `.uns['neighbors']`
`.obsp['distances']`, distances for each pair of neighbors
`.obsp['connectivities']`, weighted adjacency matrix (0:00:34)
Computing radius for adaptive bandwidth kernel...
0%| | 0/64500 [00:00<?, ?it/s]
Making graph symmetric... Parameter graph_construction = union being used to build KNN graph... Computing RBF kernel...
0%| | 0/64500 [00:00<?, ?it/s]
Building similarity LIL matrix...
0%| | 0/64500 [00:00<?, ?it/s]
Constructing CSR matrix...
# Initialize archetypes
model.initialize_archetypes()
Building kernel on X_pca_harmony
Computing diffusion components from X_pca_harmony for waypoint initialization ...
computing neighbors
finished: added to `.uns['neighbors']`
`.obsp['distances']`, distances for each pair of neighbors
`.obsp['connectivities']`, weighted adjacency matrix (0:00:13)
Done.
Sampling waypoints ...
Done.
Selecting 846 cells from waypoint initialization.
Initializing residual matrix using greedy column selection
Initializing f and g...
100%|██████████| 24/24 [00:03<00:00, 6.54it/s]
Selecting 14 cells from greedy initialization.
adata
AnnData object with n_obs × n_vars = 64500 × 20266
obs: 'Auth_Sample_ID', 'Auth_Estimated_postconceptional_age_in_days', 'Auth_Group', 'Auth_Region', 'Auth_nCount_RNA', 'Auth_nFeature_RNA', 'Auth_ATAC_fragments_in_peaks', 'Auth_Scrublet_doublet_score', 'Auth_S.Score', 'Auth_G2M.Score', 'Auth_Class', 'Auth_Subclass', 'Auth_Type_updated', 'Auth_Cluster', 'Auth_cell_type_ontology_term_id', 'Auth_development_stage_ontology_term_id', 'Auth_donor_id', 'Auth_cell_type', 'Auth_sex', 'Auth_tissue', 'Auth_self_reported_ethnicity', 'Auth_development_stage', 'dataset_id', 'sample_id', 'age', 'stage', 'cell_label', 'brain_region', 'n_genes_by_counts', 'log1p_n_genes_by_counts', 'total_counts', 'log1p_total_counts', 'total_counts_mito', 'log1p_total_counts_mito', 'pct_counts_mito', 'total_counts_ribo', 'log1p_total_counts_ribo', 'pct_counts_ribo', 'log1p_gene_UMI_ratio', 'n_genes', 'n_counts', 'Leiden_02', 'Leiden_04', 'Leiden_06', 'Leiden_Sel'
var: 'gene_name', 'feature_is_filtered', 'feature_name', 'feature_length', 'feature_type', 'EnsembleCode', 'mito', 'ribo', 'n_cells_by_counts', 'mean_counts', 'log1p_mean_counts', 'pct_dropout_by_counts', 'total_counts', 'log1p_total_counts', 'n_cells', 'highly_variable', 'means', 'dispersions', 'dispersions_norm', 'highly_variable_nbatches', 'highly_variable_intersection'
uns: 'Auth_Group_colors', 'Leiden_02', 'Leiden_02_colors', 'Leiden_04', 'Leiden_04_colors', 'Leiden_06', 'Leiden_06_colors', 'Leiden_Sel_colors', 'age_colors', 'brain_region_colors', 'cell_label_colors', 'diffmap_evals', 'draw_graph', 'harmony', 'hvg', 'log1p', 'pca', 'sample_id_colors', 'umap', 'neighbors'
obsm: 'X_draw_graph_fa_harmony', 'X_pca', 'X_pca_harmony', 'X_umap_harmony', 'X_umap_nocorr'
varm: 'PCs'
layers: 'counts', 'lognorm'
obsp: 'harmony_connectivities', 'harmony_distances', 'pca_connectivities', 'pca_distances', 'distances', 'connectivities'
adata.obsm['X_umap'] = adata.obsm['X_umap_harmony'].copy()
# Plot the initilization to ensure they are spread across phenotypic space
SEACells.plot.plot_initialization(adata, model)
We apply the model.fit function.
model.fit(min_iter=10, max_iter=50)
model
Randomly initialized A matrix. Setting convergence threshold at 0.00533 Starting iteration 1. Completed iteration 1. Starting iteration 10. Completed iteration 10. Starting iteration 20. Completed iteration 20. Converged after 25 iterations.
<SEACells.gpu.SEACellsGPU at 0x155432286260>
# Plot model convergence
model.plot_convergence()
#model.A_
plt.figure(figsize=(4,3))
sns.distplot((model.A_.T > 0.1).sum(axis=1), kde=False)
plt.title(f'Non-trivial (> 0.1) assignments per cell')
plt.xlabel('# Non-trivial SEACell Assignments')
plt.ylabel('# Cells')
plt.show()
plt.figure(figsize=(4,3))
b = np.partition(model.A_.T, -5)
sns.heatmap(np.sort(b[:,-5:])[:, ::-1], cmap='viridis', vmin=0)
plt.title('Strength of top 5 strongest assignments')
plt.xlabel('$n^{th}$ strongest assignment')
plt.show()
/tmp/ipykernel_137042/2880491417.py:4: UserWarning: `distplot` is a deprecated function and will be removed in seaborn v0.14.0. Please adapt your code to use either `displot` (a figure-level function with similar flexibility) or `histplot` (an axes-level function for histograms). For a guide to updating your code to use the new functions, please see https://gist.github.com/mwaskom/de44147ed2974457ad6372750bbe5751 sns.distplot((model.A_.T > 0.1).sum(axis=1), kde=False)
labels,weights = model.get_soft_assignments()
#labels.head()
We will use hard assignment of each cell to a single metacell to define our metacells for downstream steps. Hard assingment can be retreived in two ways:
adata.obs[['SEACell']].head()
# Alternatively:
# model.get_hard_assignments().head()
| SEACell | |
|---|---|
| index | |
| ARKFrozen-18-PFC_AAACAGCCAAGGTGCA-1 | SEACell-710 |
| ARKFrozen-18-PFC_AAACAGCCACTAAATC-1 | SEACell-206 |
| ARKFrozen-18-PFC_AAACAGCCAGGTTCAC-1 | SEACell-763 |
| ARKFrozen-18-PFC_AAACAGCCATCCATCT-1 | SEACell-237 |
| ARKFrozen-18-PFC_AAACAGCCATGAATAG-1 | SEACell-392 |
# By default, ad.raw is used for summarization. Other layers present in the anndata can be specified using the parameter summarize_layer parameter
SEA_adata = SEACells.core.summarize_by_SEACell(adata, SEACells_label='SEACell', summarize_layer='counts', celltype_label='cell_label')
SEA_adata
100%|██████████| 860/860 [00:14<00:00, 60.06it/s] /env/lib/python3.10/site-packages/anndata/_core/anndata.py:430: FutureWarning: The dtype argument is deprecated and will be removed in late 2024. warnings.warn(
AnnData object with n_obs × n_vars = 860 × 20266
obs: 'cell_label', 'cell_label_purity'
layers: 'raw'
SEA_adata.obs.head()
| cell_label | cell_label_purity | |
|---|---|---|
| SEACell-710 | ExN | 1.000000 |
| SEACell-206 | ExN | 1.000000 |
| SEACell-763 | RadialGlia | 1.000000 |
| SEACell-237 | InN | 0.972973 |
| SEACell-392 | ExN | 1.000000 |
print(SEA_adata.X[40:43, 40:43])
<Compressed Sparse Row sparse matrix of dtype 'float64' with 5 stored elements and shape (3, 3)> Coords Values (0, 1) 1.0 (1, 1) 1.0 (1, 2) 4.0 (2, 1) 3.0 (2, 2) 4.0
adata.obs['brain_region']
index
ARKFrozen-18-PFC_AAACAGCCAAGGTGCA-1 PreFrontalCortex
ARKFrozen-18-PFC_AAACAGCCACTAAATC-1 PreFrontalCortex
ARKFrozen-18-PFC_AAACAGCCAGGTTCAC-1 PreFrontalCortex
ARKFrozen-18-PFC_AAACAGCCATCCATCT-1 PreFrontalCortex
ARKFrozen-18-PFC_AAACAGCCATGAATAG-1 PreFrontalCortex
...
ARKFrozen-8-V1_TTTGTGGCACATTAAC-1 VisualCortex
ARKFrozen-8-V1_TTTGTGGCACTCAACA-1 VisualCortex
ARKFrozen-8-V1_TTTGTGGCAGAAACGT-1 VisualCortex
ARKFrozen-8-V1_TTTGTTGGTCCTCCAA-1 VisualCortex
ARKFrozen-8-V1_TTTGTTGGTTTATGGG-1 VisualCortex
Name: brain_region, Length: 64500, dtype: category
Categories (3, object): ['Neocortex', 'PreFrontalCortex', 'VisualCortex']
top_sampleid = adata.obs['sample_id'].groupby(adata.obs['SEACell']).value_counts().groupby(level=0, group_keys=False).head(1)
SEA_adata.obs['agg_sample_id'] = top_sampleid[SEA_adata.obs_names].index.get_level_values(1)
top_brain_region = adata.obs['brain_region'].groupby(adata.obs['SEACell']).value_counts().groupby(level=0, group_keys=False).head(1)
SEA_adata.obs['Aggregated_brain_region'] = top_brain_region[SEA_adata.obs_names].index.get_level_values(1)
SEA_adata.obs["Auth_Group"] = 'Second_trimester'
SEA_adata.obs.head()
| cell_label | cell_label_purity | agg_sample_id | Aggregated_brain_region | Auth_Group | |
|---|---|---|---|---|---|
| SEACell-710 | ExN | 1.000000 | ARKFrozen-43-PFC | PreFrontalCortex | Second_trimester |
| SEACell-206 | ExN | 1.000000 | ARKFrozen-43-PFC | PreFrontalCortex | Second_trimester |
| SEACell-763 | RadialGlia | 1.000000 | ARKFrozen-45-CTX | Neocortex | Second_trimester |
| SEACell-237 | InN | 0.972973 | ARKFrozen-41-PFC-2 | PreFrontalCortex | Second_trimester |
| SEACell-392 | ExN | 1.000000 | ARKFrozen-18-PFC | PreFrontalCortex | Second_trimester |
plot_2D(): visualize metacell assignments on UMAP or any 2-dimensional embedding froma adata.obsm. Plots can also be coloured by metacell assignment. The visualization allows to assess the representativeness of the calculated metacells: ability to represent the global structure of the original dataset. Better representation corresponds to a more uniform coverage of the dataset.
plot_SEACell_sizes(): distribution of number of cells assigned to each metacell. Given to the non-uniform distribution of cell type density, metacells are expected to vary in size: larger metacells are retrieved from denser regions, and smaller metacells from sparser ones. However outlier values may require further inspection.
SEACells.plot.plot_2D(adata, key='X_umap', colour_metacells=False)
/env/lib/python3.10/site-packages/SEACells/plot.py:63: FutureWarning: The default of observed=False is deprecated and will be changed to True in a future version of pandas. Pass observed=False to retain current behavior or observed=True to adopt the future default and silence this warning.
mcs = umap.groupby("SEACell").mean().reset_index()
/env/lib/python3.10/site-packages/seaborn/relational.py:438: UserWarning: No data for colormapping provided via 'c'. Parameters 'cmap' will be ignored
points = ax.scatter(x=x, y=y, **kws)
/env/lib/python3.10/site-packages/seaborn/relational.py:438: UserWarning: No data for colormapping provided via 'c'. Parameters 'cmap' will be ignored
points = ax.scatter(x=x, y=y, **kws)
SEACells.plot.plot_2D(adata, key='X_umap', colour_metacells=True)
/env/lib/python3.10/site-packages/SEACells/plot.py:63: FutureWarning: The default of observed=False is deprecated and will be changed to True in a future version of pandas. Pass observed=False to retain current behavior or observed=True to adopt the future default and silence this warning.
mcs = umap.groupby("SEACell").mean().reset_index()
/env/lib/python3.10/site-packages/seaborn/relational.py:438: UserWarning: No data for colormapping provided via 'c'. Parameters 'cmap' will be ignored
points = ax.scatter(x=x, y=y, **kws)
/env/lib/python3.10/site-packages/seaborn/relational.py:438: UserWarning: No data for colormapping provided via 'c'. Parameters 'cmap' will be ignored
points = ax.scatter(x=x, y=y, **kws)
SEACells.plot.plot_SEACell_sizes(adata, bins=10, figsize=(10, 5))
/env/lib/python3.10/site-packages/SEACells/plot.py:130: UserWarning:
`distplot` is a deprecated function and will be removed in seaborn v0.14.0.
Please adapt your code to use either `displot` (a figure-level function with
similar flexibility) or `histplot` (an axes-level function for histograms).
For a guide to updating your code to use the new functions, please see
https://gist.github.com/mwaskom/de44147ed2974457ad6372750bbe5751
sns.distplot(label_df.groupby("SEACell").count().iloc[:, 0], bins=bins)
| size | |
|---|---|
| SEACell | |
| SEACell-0 | 174 |
| SEACell-1 | 81 |
| SEACell-10 | 286 |
| SEACell-100 | 104 |
| SEACell-101 | 68 |
| ... | ... |
| SEACell-95 | 56 |
| SEACell-96 | 41 |
| SEACell-97 | 51 |
| SEACell-98 | 36 |
| SEACell-99 | 104 |
860 rows × 1 columns
Purity: compute_celltype_purity(ad, col_name) computes the purity of different celltype labels within a SEACell metacell.
Compactness: per-SEAcell variance in diffusion components (typically 'X_pca' for RNA). Lower values of compactness suggest more compact/lower variance metacells.
Separation: distance between a SEACell and its nth_nbr. If cluster is provided as a string, e.g. 'celltype', nearest neighbors are restricted to have the same celltype value. Higher values of separation suggest better distinction between metacells.
SEACell_purity = SEACells.evaluate.compute_celltype_purity(adata, 'cell_label')
plt.figure(figsize=(6,4))
sns.boxplot(data=SEACell_purity, y='cell_label_purity')
plt.title('cell_label Purity')
sns.despine()
plt.show()
plt.close()
SEACell_purity.head()
| cell_label | cell_label_purity | |
|---|---|---|
| SEACell | ||
| SEACell-0 | RadialGlia | 0.827586 |
| SEACell-1 | IPC_ExN | 0.703704 |
| SEACell-10 | ExN | 1.000000 |
| SEACell-100 | ExN | 1.000000 |
| SEACell-101 | InN | 1.000000 |
compactness = SEACells.evaluate.compactness(adata, 'X_pca_harmony')
plt.figure(figsize=(6,4))
sns.boxplot(data=compactness, y='compactness')
plt.title('Compactness')
sns.despine()
plt.show()
plt.close()
compactness.head()
computing neighbors
finished: added to `.uns['neighbors']`
`.obsp['distances']`, distances for each pair of neighbors
`.obsp['connectivities']`, weighted adjacency matrix (0:00:12)
| compactness | |
|---|---|
| SEACell | |
| SEACell-0 | 0.000398 |
| SEACell-1 | 0.022915 |
| SEACell-10 | 0.000796 |
| SEACell-100 | 0.000737 |
| SEACell-101 | 0.004004 |
separation = SEACells.evaluate.separation(adata, 'X_pca_harmony')
plt.figure(figsize=(6,4))
sns.boxplot(data=separation, y='separation')
plt.title('Separation')
sns.despine()
plt.show()
plt.close()
separation.head()
computing neighbors
finished: added to `.uns['neighbors']`
`.obsp['distances']`, distances for each pair of neighbors
`.obsp['connectivities']`, weighted adjacency matrix (0:00:12)
| separation | |
|---|---|
| SEACell | |
| SEACell-0 | 0.016510 |
| SEACell-1 | 0.107914 |
| SEACell-10 | 0.020469 |
| SEACell-100 | 0.027564 |
| SEACell-101 | 0.112693 |
SEA_adata.layers['counts'] = SEA_adata.X.copy()
sc.pp.normalize_total(SEA_adata)
sc.pp.log1p(SEA_adata)
SEA_adata.layers['lognorm'] = SEA_adata.X.copy()
sc.pp.highly_variable_genes(SEA_adata, inplace=True, batch_key="agg_sample_id")
sc.tl.pca(SEA_adata, use_highly_variable=True)
sc.pp.neighbors(SEA_adata, use_rep='X_pca')
sc.tl.umap(SEA_adata)
normalizing counts per cell
finished (0:00:00)
extracting highly variable genes
finished (0:00:00)
--> added
'highly_variable', boolean vector (adata.var)
'means', float vector (adata.var)
'dispersions', float vector (adata.var)
'dispersions_norm', float vector (adata.var)
computing PCA
with n_comps=50
/env/lib/python3.10/site-packages/scanpy/preprocessing/_pca.py:385: FutureWarning: Argument `use_highly_variable` is deprecated, consider using the mask argument. Use_highly_variable=True can be called through mask_var="highly_variable". Use_highly_variable=False can be called through mask_var=None warn(msg, FutureWarning)
finished (0:00:00)
computing neighbors
finished: added to `.uns['neighbors']`
`.obsp['distances']`, distances for each pair of neighbors
`.obsp['connectivities']`, weighted adjacency matrix (0:00:00)
computing UMAP
finished: added
'X_umap', UMAP coordinates (adata.obsm) (0:00:01)
sc.pl.umap(SEA_adata, color=['cell_label'], s=75)
SEA_adata
AnnData object with n_obs × n_vars = 860 × 20266
obs: 'cell_label', 'cell_label_purity', 'agg_sample_id', 'Aggregated_brain_region', 'Auth_Group'
var: 'highly_variable', 'means', 'dispersions', 'dispersions_norm', 'highly_variable_nbatches', 'highly_variable_intersection'
uns: 'log1p', 'hvg', 'pca', 'neighbors', 'umap', 'cell_label_colors'
obsm: 'X_pca', 'X_umap'
varm: 'PCs'
layers: 'raw', 'counts', 'lognorm'
obsp: 'distances', 'connectivities'
sc.pl.umap(SEA_adata, color=['agg_sample_id'], s=75)
sc.pl.umap(SEA_adata, color=['Aggregated_brain_region'], s=75)
sc.pl.umap(SEA_adata, color=['cell_label_purity'], s=75)
SEA_adata.obs.columns
Index(['cell_label', 'cell_label_purity', 'agg_sample_id',
'Aggregated_brain_region', 'Auth_Group'],
dtype='object')
SEA_adata
AnnData object with n_obs × n_vars = 860 × 20266
obs: 'cell_label', 'cell_label_purity', 'agg_sample_id', 'Aggregated_brain_region', 'Auth_Group'
var: 'highly_variable', 'means', 'dispersions', 'dispersions_norm', 'highly_variable_nbatches', 'highly_variable_intersection'
uns: 'log1p', 'hvg', 'pca', 'neighbors', 'umap', 'cell_label_colors', 'agg_sample_id_colors', 'Aggregated_brain_region_colors'
obsm: 'X_pca', 'X_umap'
varm: 'PCs'
layers: 'raw', 'counts', 'lognorm'
obsp: 'distances', 'connectivities'
SEA_adata.X
<Compressed Sparse Row sparse matrix of dtype 'float64' with 12511062 stored elements and shape (860, 20266)>
SEA_adata.write(output_file)
%%bash
# save also html and python versions for git
jupyter nbconvert SEACellsWang_SecondTrimester.ipynb --to="python" --output="SEACellsWang_SecondTrimester"
jupyter nbconvert SEACellsWang_SecondTrimester.ipynb --to="html" --output="SEACellsWang_SecondTrimester"
[NbConvertApp] Converting notebook SEACellsWang_SecondTrimester.ipynb to python [NbConvertApp] Writing 13154 bytes to SEACellsWang_SecondTrimester.py [NbConvertApp] Converting notebook SEACellsWang_SecondTrimester.ipynb to html [NbConvertApp] WARNING | Alternative text is missing on 17 image(s). [NbConvertApp] Writing 7359277 bytes to SEACellsWang_SecondTrimester.html
print(datetime.now())
2026-03-11 16:04:08.299139