Skills › Knowledge Work Plugins › scvi-tools › data_preparation.md
data_preparation.md
286 lines · bio-research/skills/scvi-tools/references/data_preparation.md at 2574e29
Most marks come from matching words in the file, so treat them as pointers.
1# Data Preparation for scvi-tools
3This reference covers how to properly prepare AnnData objects for use with scvi-tools models.
Data Preparation for scvi-tools
This reference covers how to properly prepare AnnData objects for use with scvi-tools models.
Raw lines 1 to 45## Overview
7Proper data preparation is critical for scvi-tools. Key requirements:
81. **Raw counts** (not normalized)
92. **Highly variable gene selection**
103. **Proper setup_anndata() call**
Overview
Proper data preparation is critical for scvi-tools. Key requirements:
- Raw counts (not normalized)
- Highly variable gene selection
- Proper setup_anndata() call
12## Step 1: Load and Inspect Data
14```python
15import scanpy as sc
16import scvi
17import numpy as np
19# Load data
20adata = sc.read_h5ad("data.h5ad")
22# Check what's in adata.X
23print(f"Shape: {adata.shape}")
24print(f"X dtype: {adata.X.dtype}")
25print(f"X contains integers: {np.allclose(adata.X.data, adata.X.data.astype(int))}")
26print(f"X min: {adata.X.min()}, max: {adata.X.max()}")
27```
Step 1: Load and Inspect Data
import scanpy as sc
import scvi
import numpy as np
# Load data
adata = sc.read_h5ad("data.h5ad")
# Check what's in adata.X
print(f"Shape: {adata.shape}")
print(f"X dtype: {adata.X.dtype}")
print(f"X contains integers: {np.allclose(adata.X.data, adata.X.data.astype(int))}")
print(f"X min: {adata.X.min()}, max: {adata.X.max()}")Raw lines 12 to 2829### Verify Raw Counts
31```python
32# scvi-tools needs INTEGER counts
33# If X appears normalized, check for raw counts
35if hasattr(adata, 'raw') and adata.raw is not None:
36 print("Found adata.raw")
37 # Use raw counts
38 adata = adata.raw.to_adata()
40# Or check layers
41if 'counts' in adata.layers:
42 print("Found counts layer")
43 # Will specify layer in setup_anndata
44```
Verify Raw Counts
# scvi-tools needs INTEGER counts
# If X appears normalized, check for raw counts
if hasattr(adata, 'raw') and adata.raw is not None:
print("Found adata.raw")
# Use raw counts
adata = adata.raw.to_adata()
# Or check layers
if 'counts' in adata.layers:
print("Found counts layer")
# Will specify layer in setup_anndataRaw lines 29 to 4546## Step 2: Basic Filtering
48```python
49# Filter cells (standard QC)
50sc.pp.filter_cells(adata, min_genes=200)
51sc.pp.filter_cells(adata, max_genes=5000)
53# Calculate mito percent if not present
54# Handle both human (MT-) and mouse (mt-, Mt-) mitochondrial genes
55adata.var['mt'] = (
56 adata.var_names.str.startswith('MT-') |
57 adata.var_names.str.startswith('mt-') |
58 adata.var_names.str.startswith('Mt-')
59)
60sc.pp.calculate_qc_metrics(adata, qc_vars=['mt'], inplace=True)
61adata = adata[adata.obs['pct_counts_mt'] < 20].copy()
63# Filter genes
64sc.pp.filter_genes(adata, min_cells=3)
66print(f"After filtering: {adata.shape}")
67```
Step 2: Basic Filtering
# Filter cells (standard QC)
sc.pp.filter_cells(adata, min_genes=200)
sc.pp.filter_cells(adata, max_genes=5000)
# Calculate mito percent if not present
# Handle both human (MT-) and mouse (mt-, Mt-) mitochondrial genes
adata.var['mt'] = (
adata.var_names.str.startswith('MT-') |
adata.var_names.str.startswith('mt-') |
adata.var_names.str.startswith('Mt-')
)
sc.pp.calculate_qc_metrics(adata, qc_vars=['mt'], inplace=True)
adata = adata[adata.obs['pct_counts_mt'] < 20].copy()
# Filter genes
sc.pp.filter_genes(adata, min_cells=3)
print(f"After filtering: {adata.shape}")Raw lines 46 to 6869## Step 3: Store Raw Counts
71**Critical**: Always preserve raw counts before any normalization.
73```python
74# Store raw counts in a layer
75adata.layers["counts"] = adata.X.copy()
77# Now you can normalize for other purposes (HVG selection)
78# But scvi will use the counts layer
79```
Step 3: Store Raw Counts
Critical: Always preserve raw counts before any normalization.
# Store raw counts in a layer
adata.layers["counts"] = adata.X.copy()
# Now you can normalize for other purposes (HVG selection)
# But scvi will use the counts layerRaw lines 69 to 80Step 4: Highly Variable Gene Selection
scvi-tools works best with 1,500-5,000 HVGs.
Raw lines 81 to 8485### For Single-Batch Data
87```python
88# Normalize for HVG selection only
89adata_hvg = adata.copy()
90sc.pp.normalize_total(adata_hvg, target_sum=1e4)
91sc.pp.log1p(adata_hvg)
93# Select HVGs
94sc.pp.highly_variable_genes(
95 adata_hvg,
96 n_top_genes=2000,
97 flavor="seurat" # or "cell_ranger"
98)
100# Transfer HVG annotation
101adata.var['highly_variable'] = adata_hvg.var['highly_variable']
102```
For Single-Batch Data
# Normalize for HVG selection only
adata_hvg = adata.copy()
sc.pp.normalize_total(adata_hvg, target_sum=1e4)
sc.pp.log1p(adata_hvg)
# Select HVGs
sc.pp.highly_variable_genes(
adata_hvg,
n_top_genes=2000,
flavor="seurat" # or "cell_ranger"
)
# Transfer HVG annotation
adata.var['highly_variable'] = adata_hvg.var['highly_variable']Raw lines 85 to 103104### For Multi-Batch Data (Recommended)
106```python
107# Use seurat_v3 flavor with batch_key
108# This selects genes variable across batches
109sc.pp.highly_variable_genes(
110 adata,
111 n_top_genes=2000,
112 flavor="seurat_v3",
113 batch_key="batch", # Your batch column
114 layer="counts" # Use raw counts
115)
116```
For Multi-Batch Data (Recommended)
# Use seurat_v3 flavor with batch_key
# This selects genes variable across batches
sc.pp.highly_variable_genes(
adata,
n_top_genes=2000,
flavor="seurat_v3",
batch_key="batch", # Your batch column
layer="counts" # Use raw counts
)Raw lines 104 to 117118### Subset to HVGs
120```python
121# Subset to highly variable genes
122adata = adata[:, adata.var['highly_variable']].copy()
123print(f"After HVG selection: {adata.shape}")
124```
Subset to HVGs
# Subset to highly variable genes
adata = adata[:, adata.var['highly_variable']].copy()
print(f"After HVG selection: {adata.shape}")Raw lines 118 to 125130### Basic Setup
132```python
133scvi.model.SCVI.setup_anndata(
134 adata,
135 layer="counts" # Specify layer with raw counts
136)
137```
Basic Setup
scvi.model.SCVI.setup_anndata(
adata,
layer="counts" # Specify layer with raw counts
)Raw lines 130 to 138139### With Batch Information
141```python
142scvi.model.SCVI.setup_anndata(
143 adata,
144 layer="counts",
145 batch_key="batch" # Column in adata.obs
146)
147```
With Batch Information
scvi.model.SCVI.setup_anndata(
adata,
layer="counts",
batch_key="batch" # Column in adata.obs
)Raw lines 139 to 148149### With Cell Type Labels (for scANVI)
151```python
152scvi.model.SCANVI.setup_anndata(
153 adata,
154 layer="counts",
155 batch_key="batch",
156 labels_key="cell_type" # Column with cell type labels
157)
158```
With Cell Type Labels (for scANVI)
scvi.model.SCANVI.setup_anndata(
adata,
layer="counts",
batch_key="batch",
labels_key="cell_type" # Column with cell type labels
)Raw lines 149 to 159160### With Continuous Covariates
162```python
163scvi.model.SCVI.setup_anndata(
164 adata,
165 layer="counts",
166 batch_key="batch",
167 continuous_covariate_keys=["percent_mito", "n_genes"]
168)
169```
With Continuous Covariates
scvi.model.SCVI.setup_anndata(
adata,
layer="counts",
batch_key="batch",
continuous_covariate_keys=["percent_mito", "n_genes"]
)Raw lines 160 to 170171### With Categorical Covariates
173```python
174scvi.model.SCVI.setup_anndata(
175 adata,
176 layer="counts",
177 batch_key="batch",
178 categorical_covariate_keys=["donor", "technology"]
179)
180```
With Categorical Covariates
scvi.model.SCVI.setup_anndata(
adata,
layer="counts",
batch_key="batch",
categorical_covariate_keys=["donor", "technology"]
)Raw lines 171 to 181Multi-Modal Data Setup
Raw lines 182 to 183184### CITE-seq (for totalVI)
186```python
187# Protein data in adata.obsm
188# RNA in adata.X, protein in separate matrix
190# Add protein data
191adata.obsm["protein_expression"] = protein_counts # numpy array
193# Setup for totalVI
194scvi.model.TOTALVI.setup_anndata(
195 adata,
196 layer="counts",
197 batch_key="batch",
198 protein_expression_obsm_key="protein_expression"
199)
200```
CITE-seq (for totalVI)
# Protein data in adata.obsm
# RNA in adata.X, protein in separate matrix
# Add protein data
adata.obsm["protein_expression"] = protein_counts # numpy array
# Setup for totalVI
scvi.model.TOTALVI.setup_anndata(
adata,
layer="counts",
batch_key="batch",
protein_expression_obsm_key="protein_expression"
)Raw lines 184 to 201202### Multiome RNA+ATAC (for MultiVI)
204```python
205# RNA and ATAC in separate AnnData objects or MuData
207import mudata as md
209# If using MuData
210mdata = md.read("multiome.h5mu")
212scvi.model.MULTIVI.setup_mudata(
213 mdata,
214 rna_layer="counts",
215 protein_layer=None,
216 batch_key="batch",
217 modalities={"rna": "rna", "accessibility": "atac"}
218)
219```
Multiome RNA+ATAC (for MultiVI)
# RNA and ATAC in separate AnnData objects or MuData
import mudata as md
# If using MuData
mdata = md.read("multiome.h5mu")
scvi.model.MULTIVI.setup_mudata(
mdata,
rna_layer="counts",
protein_layer=None,
batch_key="batch",
modalities={"rna": "rna", "accessibility": "atac"}
)Raw lines 202 to 220221## Complete Preparation Pipeline
223For a complete preparation function, use `prepare_adata()` from `scripts/model_utils.py`:
225```python
226from model_utils import prepare_adata
228# Prepare data with QC, HVG selection, and layer setup
229adata = prepare_adata(
230 adata,
231 batch_key="batch",
232 n_top_genes=2000,
233 min_genes=200,
234 max_mito_pct=20
235)
237# Then setup for your model
238import scvi
239scvi.model.SCVI.setup_anndata(adata, layer="counts", batch_key="batch")
240```
242This function handles:
243- Mitochondrial QC filtering
244- Cell and gene filtering
245- Storing counts in layer
246- HVG selection (batch-aware if batch_key provided)
247- Subsetting to HVGs
Complete Preparation Pipeline
For a complete preparation function, use prepare_adata() from scripts/model_utils.py:
from model_utils import prepare_adata
# Prepare data with QC, HVG selection, and layer setup
adata = prepare_adata(
adata,
batch_key="batch",
n_top_genes=2000,
min_genes=200,
max_mito_pct=20
)
# Then setup for your model
import scvi
scvi.model.SCVI.setup_anndata(adata, layer="counts", batch_key="batch")This function handles:
- Mitochondrial QC filtering
- Cell and gene filtering
- Storing counts in layer
- HVG selection (batch-aware if batch_key provided)
- Subsetting to HVGs
Runs code scripts/model_utils.py :223
249## Checking Setup
251```python
252# View registered data
253print(adata.uns['_scvi_manager_uuid'])
254print(adata.uns['_scvi_adata_minify_type'])
256# For scVI
257scvi.model.SCVI.view_anndata_setup(adata)
258```
Checking Setup
# View registered data
print(adata.uns['_scvi_manager_uuid'])
print(adata.uns['_scvi_adata_minify_type'])
# For scVI
scvi.model.SCVI.view_anndata_setup(adata)Raw lines 249 to 259260## Common Issues and Solutions
262| Issue | Cause | Solution |
263|-------|-------|----------|
264| "X should contain integers" | Normalized data in X | Use layer="counts" |
265| "batch_key not found" | Wrong column name | Check adata.obs.columns |
266| Sparse matrix errors | Incompatible format | Convert: adata.X = adata.X.toarray() |
267| Memory error | Too many genes | Subset to HVGs first |
268| NaN in data | Missing values | Filter or impute |
Common Issues and Solutions
| Issue | Cause | Solution |
|---|---|---|
| "X should contain integers" | Normalized data in X | Use layer="counts" |
| "batch_key not found" | Wrong column name | Check adata.obs.columns |
| Sparse matrix errors | Incompatible format | Convert: adata.X = adata.X.toarray() |
| Memory error | Too many genes | Subset to HVGs first |
| NaN in data | Missing values | Filter or impute |
Data Format Reference
Raw lines 270 to 271272### Required
274- `adata.X` or `adata.layers["counts"]`: Raw integer counts (sparse OK)
275- `adata.obs`: Cell metadata DataFrame
276- `adata.var`: Gene metadata DataFrame
Required
adata.Xoradata.layers["counts"]: Raw integer counts (sparse OK)adata.obs: Cell metadata DataFrameadata.var: Gene metadata DataFrame
278### Recommended
280- `adata.obs["batch"]`: Batch/sample identifiers
281- `adata.var["highly_variable"]`: HVG boolean mask
Recommended
adata.obs["batch"]: Batch/sample identifiersadata.var["highly_variable"]: HVG boolean mask
283### For scANVI
285- `adata.obs["labels"]`: Cell type annotations
286- Can include "Unknown" for unlabeled cells
For scANVI
adata.obs["labels"]: Cell type annotations- Can include "Unknown" for unlabeled cells