Single-cell Best Practices

repository·main·Indexed 22 days ago

https://github.com/theislab/single-cell-best-practices

A collection of tutorials and expert recommendations for single-cell analysis across various modalities. It provides reproducible workflows, including scATAC-seq quality control, doublet detection using scDblFinder and AMULET, and guidance on interoperability between the scverse (Python), Bioconductor, and Seurat (R) ecosystems using tools like zellkonverter, SeuratDisk, rpy2, and reticulate.

Tokens
19.2K
Snippets
46
Records
64
Agent score
79%

What's inside single-cell-best-practices

  1. Adapt notebooks to other datasets

    main
    To use the tutorial notebooks with your own datasets, you can find all notebooks for the various analysis steps in the jupyter-book folder. Each notebook is provided with a minimal Conda environment to ensure reproducibility. Alternatively, notebooks can be downloaded directly from the rendered version of the book.
  2. Choose between single-cell and single-nuclei sequencing

    main

    The decision to sequence whole cells versus nuclei is largely driven by the type of tissue being studied and the preservation of cell types.

    Single-cell sequencing

    • Mechanism: Captures whole cells.
    • Risks: Tissue dissociation can be biased. Certain cell types (e.g., specific neurons in the brain) are more vulnerable to mechanical/enzymatic dissociation and may be underrepresented in the final suspension. Requires fresh tissue.

    Single-nuclei sequencing

    • Mechanism: Captures only the nuclei.
    • Strengths: Nuclei are more resistant to mechanical force and can be isolated from frozen tissue (useful for biobanks) without enzymatic dissociation.
    • Accuracy: Nuclei have been shown to accurately reflect the transcriptional patterns of the original cells.

    Key Consideration: Always discuss experimental design between wet lab and dry lab scientists, as dissociation ability significantly impacts which cell types are observable in the data.

  3. Configure RMM memory management strategies

    main

    The RAPIDS Memory Manager (RMM) controls how VRAM is allocated. You must pick exactly one strategy and configure it at the very top of your notebook before any CuPy arrays are created.

    1. Pool Allocator: Fastest option. Grabs a large slab of VRAM upfront. Use this if your dataset fits entirely in VRAM. Set initial_pool_size close to your expected peak to avoid fragmentation.
    2. Managed (Unified) Memory: Use this if your dataset is larger than your VRAM. It uses CUDA managed memory to page data between host RAM and GPU. It is slower but allows analyzing datasets larger than physical VRAM.

    Warning: Do not enable both pool_allocator=True and managed_memory=True simultaneously; they conflict and degrade performance.

    import cupy as cp
    import rmm
    from rmm.allocators.cupy import rmm_cupy_allocator
    
    # Strategy 1: Pool Allocator (for datasets that fit in VRAM)
    rmm.reinitialize(
        pool_allocator=True,
        managed_memory=False,
        initial_pool_size="4GB",
        maximum_pool_size="32GB",
    )
    cp.cuda.set_allocator(rmm_cupy_allocator)
    
    # Strategy 2: Managed Memory (for datasets larger than VRAM)
    rmm.reinitialize(
        pool_allocator=False,
        managed_memory=True,
    )
    cp.cuda.set_allocator(rmm_cupy_allocator)
  4. Understand the NGS process steps

    main

    Next-Generation Sequencing (NGS) generally follows three main stages:

    1. Sample and library preparation: DNA/RNA samples are fragmented and ligated with adapter molecules. These adapters facilitate hybridization to the sequencing matrix and provide priming sites.
    2. Amplification and sequencing: The library is converted into single-strand molecules. During amplification (e.g., PCR), clusters of DNA molecules are created, and each cluster undergoes individual reactions during the run.
    3. Data output and analysis: Sequencing technologies generate either fluorescence or electrical signals, which are stored in specific file formats. The resulting raw data is typically massive and requires heavy computational processing.
  5. Compare droplet-based and plate-based scRNA-seq protocols

    main

    Single-cell sequencing protocols are categorized by how they isolate cells:

    Separation in Droplets

    These methods encapsulate cells into tiny droplets (emulsions) using microfluidics, enabling massive parallelization and high throughput.

    • Common Protocols: inDrop, Drop-seq, and 10x Genomics Chromium.
    • Mechanism: Cells and beads (containing cell barcodes, UMIs, and primers) are trapped in droplets. Upon lysis, mRNA is captured by the beads. The droplets are then broken to release transcriptomes attached to microparticles (STAMPs).
    • Pros/Cons: High throughput and cost-efficient for large cell numbers, but typically have lower transcript recovery rates (~10%) and capture only the 3' or 5' ends of transcripts.

    Separation in Physical Compartments (Plate-based)

    These methods isolate cells into individual wells in a microwell plate.

    • Mechanism: Cells are typically sorted into wells using techniques like FACS (fluorescence-activated cell sorting) or micro-pipetting. Lysis and reverse transcription then occur within each individual well.
    • Pros/Cons: Can achieve higher sensitivity (5,000 to 10,000 captured genes per cell) compared to droplet methods, but is generally lower throughput as it is limited to several hundred cells per experiment.
  6. Distinguish between Bulk and Single-cell RNA sequencing

    main

    RNA-Seq can be performed at two different resolutions:

    • Bulk RNA sequencing: Measures the average expression profile of all cells in a sample. It is cheaper and easier to analyze but masks cellular heterogeneity (e.g., rare cell types or specific cell-to-cell interactions).
    • Single-cell RNA sequencing (scRNA-Seq): Measures the transcriptome of individual cells. This provides high resolution to identify rare cell types (like drug-resistant tumor cells) but is more expensive, technically difficult, and requires more complex downstream analysis due to increased data resolution.
  7. Understand single-cell ecosystem interoperability

    main

    Single-cell analysis is dominated by three main ecosystems: Bioconductor (R), Seurat (R), and scverse (Python). To be a competent analyst, you should be able to move between them to use the best-performing tools.

    Interoperability is achieved through two main methods:

    1. Disk-based interoperability: Writing files to disk in one language and reading them in another. This is often more reliable and scalable for large datasets and pipeline integration (e.g., with Nextflow or Snakemake), but it is less interactive.
    2. In-memory interoperability: Running active sessions of two languages simultaneously (e.g., using rpy2 in Python or reticulate in R) to access the same object or convert it in real-time. This is highly interactive but increases memory overhead and can be complex to set up.
  8. Use UMIs to resolve amplification bias

    main

    In RNA-seq, transcript amplification (via PCR) is necessary but can introduce amplification bias, where certain sequences are preferentially amplified, leading to artificially high counts.

    Unique Molecular Identifiers (UMIs) are short, random nucleotide sequences (molecular barcodes) added to every molecule during library generation before the amplification step. Because each original molecule receives a unique UMI, researchers can distinguish between original molecules and their PCR duplicates. This allows for accurate quantification of the original number of molecules and helps normalize gene counts without losing accuracy.

  9. Set up the environment for Quality Control analysis

    main

    To perform single-cell quality control (QC) using Scanpy and Lamindb, you need to import several libraries including scanpy, lamindb, seaborn, and rpy2 for R integration. It is recommended to suppress Scanpy's verbose logging and set figure parameters for clean plots.

    To load the specific dataset used in this tutorial, use lamindb to connect to the theislab/sc-best-practices instance and retrieve the quality_control_adata.h5ad artifact. Always ensure variable names are unique using adata.var_names_make_unique() to prevent downstream errors.

    import lamindb as ln
    import numpy as np
    import scanpy as sc
    import seaborn as sns
    from rpy2.robjects import numpy2ri
    from rpy2.robjects.conversion import localconverter
    from scipy.sparse import csc_matrix
    from scipy.stats import median_abs_deviation
    
    # Suppress verbose logging from Scanpy
    sc.settings.verbosity = 0
    
    # Set figure parameters for clean, minimal plots
    sc.settings.set_figure_params(dpi=80, facecolor="white", frameon=False)
    
    assert ln.setup.settings.instance.slug == "theislab/sc-best-practices"
    
    ln.track()
    
    # Load the dataset
    af = ln.Artifact.connect("theislab/sc-best-practices").get(
        key="preprocessing_visualization/quality_control_adata.h5ad", is_latest=True
    )
    adata = af.load()
    
    # Ensure unique variable names
    adata.var_names_make_unique()
  10. Normalize counts using scran

    main

    For differentiated normalization, the notebook uses the scran R package to compute size factors based on clusters.

    Workflow:

    1. Preliminary Clustering: Perform standard Scanpy preprocessing (normalize, log1p, PCA, neighbors, Leiden) to create temporary clusters (groups).
    2. Transfer to R: Convert the normalized data matrix and the cluster labels to R.
    3. Compute Size Factors: In R, use scran::computeSumFactors on a SingleCellExperiment object using the provided clusters.
    4. Apply in Python: Retrieve the size_factors from R, add them to adata.obs, and perform the normalization: adata.X / adata.obs["size_factors"].
    # 1. Preliminary clustering
    adata_pp = adata.copy()
    sc.pp.normalize_total(adata_pp)
    sc.pp.log1p(adata_pp)
    sc.pp.pca(adata_pp, n_comps=15)
    sc.pp.neighbors(adata_pp)
    sc.tl.leiden(adata_pp, key_added="groups", flavor="igraph", n_iterations=2, directed=False)
    
    # 2. Transfer to R and 3. Compute size factors
    %%R -o size_factors
    library(scran)
    library(BiocParallel)
    size_factors = sizeFactors(
        computeSumFactors(
            SingleCellExperiment(list(counts=data_mat)), 
            clusters = input_groups,
            min.mean = 0.1,
            BPPARAM = MulticoreParam()
        )
    )
    
    # 4. Apply in Python
    adata.obs["size_factors"] = size_factors
    scran = adata.X / adata.obs["size_factors"].values[:, None]
    scran_logged = np.log1p(scran)
    adata.layers["scran_normalization"] = csr_matrix(scran_logged)
  11. Use the single-cell best practices chapter template

    main

    The template.ipynb file is a guide for creating new chapters for the single-cell best practices book.

    Workflow:

    1. Review CONTRIBUTING.md for project-specific rules.
    2. Copy this template to your new chapter file.
    3. Replace the string template with your specific chapter name throughout the file.
    4. Use the provided Markdown and code snippets to maintain consistent styling for key takeaways, figures, admonitions, and quizzes.

    Important Note: Always replace the placeholder name template with your actual chapter name to ensure file paths and labels work correctly.