omics.co.in logo omics.co.in

Chapter 5: Computational Quality Control & Spatial Outlier Filtering in R

Tested Stacks: GATK 4.6.1 Samtools 1.21 Nextflow 24.10 Seurat v5.1 Python 3.12
Prerequisites: Basic Linux CLI & Sequencing Formats
Day 2 • Computational QC Track 21 • 10 Modular Chapters Visium HD • Seurat v5 • Space Ranger

Chapter 5: Computational Quality Control & Spatial Outlier Filtering in R

Ingesting spatial data into R; evaluating library size (nCount_Spatial), gene diversity (nFeature_Spatial), and mitochondrial percentage; spatial QC feature plots, identifying tissue tears and bubbles, and establishing defensible QC cutoffs.

⏱️ Estimated Time: 55 min 💻 Environment: R 4.4+ • Seurat v5 • Space Ranger 3.0+ 📁 Dataset: 10x Genomics Visium HD Colorectal Cancer (FFPE)

Key Learning Deliverables & Competencies

  • Load Space Ranger outputs into R utilizing Seurat v5 and hdf5r.
  • Compute key spatial bin quality control metrics: nCount_Spatial, nFeature_Spatial, and percent.mt.
  • Identify technical spatial artifacts: tissue folds, tears, bubbles, edge drying, and detachment zones.
  • Establish defensible, data-driven filtering thresholds accompanied by written mathematical justifications.

1. Loading Data & Calculating QC Metrics in R

In spatial analysis, quality control must be evaluated in both statistical distribution space (violin/scatter plots) and 2D spatial tissue space (spatial feature plots):

library(Seurat)
library(ggplot2)
library(patchwork)
library(viridis)

# 1. Load 8 µm Binned Visium HD Data
data_dir <- "/data/Visium_HD_Colorectal_Cancer_TME/outs"
seurat_obj <- Load10X_Spatial(
    data.dir = data_dir,
    filename = "binned_outputs/square_008um/filtered_feature_bc_matrix.h5",
    assay = "Spatial.008um",
    slice = "colorectal_section1"
)

# 2. Calculate Mitochondrial & Ribosomal Percentages
seurat_obj[["percent.mt"]] <- PercentageFeatureSet(seurat_obj, pattern = "^MT-")
seurat_obj[["percent.ribo"]] <- PercentageFeatureSet(seurat_obj, pattern = "^RP[SL]")

# 3. Inspect Distribution Summaries
summary(seurat_obj$nCount_Spatial.008um)
summary(seurat_obj$nFeature_Spatial.008um)
summary(seurat_obj$percent.mt)

2. Visualizing Spatial Outliers in Tissue Space

Standard scRNA-seq thresholds cannot be blindly applied to spatial bins. For instance, acellular necrotic regions or dense collagenous stroma naturally have lower transcript counts without being technical failures:

# Spatial Feature Plots for Quality Control
p1 <- SpatialFeaturePlot(seurat_obj, features = "nCount_Spatial.008um") + 
    scale_fill_viridis(option = "magma") + 
    ggtitle("Total UMIs per 8 µm Bin")

p2 <- SpatialFeaturePlot(seurat_obj, features = "nFeature_Spatial.008um") + 
    scale_fill_viridis(option = "viridis") + 
    ggtitle("Detected Genes per 8 µm Bin")

p3 <- SpatialFeaturePlot(seurat_obj, features = "percent.mt") + 
    scale_fill_gradient2(low = "blue", mid = "yellow", high = "red", midpoint = 15) + 
    ggtitle("Mitochondrial % (Cell Lysis / Artifacts)")

(p1 | p2) / p3

✍️ Checkpoint: Defensible Threshold Selection

Participants must justify QC cutoff parameters before proceeding to normalization:
• Minimum UMI Count: Filter bins with $nCount < 50$ (eliminates empty background bins and low-permeabilized tissue fragments).
• Minimum Detected Genes: Filter bins with $nFeature < 30$ to ensure sufficient gene diversity for multivariate clustering.
• Maximum Mitochondrial Ratio: Filter bins with $percent.mt > 25\%$ (signals mitochondrial membrane disruption and severe cytoplasmic transcript loss).

⚠️ Common Pitfalls & Troubleshooting in Spatial Genomics

  • Out-Of-Memory (OOM) Crashes on 2 µm/8 µm Grids: Never run default FindVariableFeatures() or dense Euclidean distance matrices across raw unsketched 2 µm arrays. Always leverage Seurat v5's SketchData() with on-disk BPCells streaming.
  • Tissue Detachment & Optical Misalignment: Inspect fiducial edge coordinates in Loupe Browser before downstream R processing. If tissue folds or lifts during CytAssist transfer, manually flag and filter affected spatial barcodes.
  • Over-Filtering Low-Cellularity Stromal Bins: Dense desmoplastic collagen or mucinous lakes naturally possess low transcript abundance. Setting an overly aggressive $nFeature$ threshold risks completely discarding critical acellular microenvironments.
⚠️

Common Pitfalls & Troubleshooting Checklist

  • Java Heap Exhaustion (GATK / Picard): If processes terminate with java.lang.OutOfMemoryError, set your environment variable explicitly: export _JAVA_OPTIONS="-Xmx16g -Djava.io.tmpdir=/tmp".
  • Index Timestamp Mismatch: If tools complain that a BAM index is missing or out of date, regenerate with samtools index -@ 4 sample.bam.
  • Conda Channel Conflicts: Avoid ABI incompatibilities between bioconda and conda-forge by setting strict priority: conda config --set channel_priority strict.
  • Chromosome Naming Contamination: Always verify whether reference FASTA headers use chr1 or 1; divergent naming causes silent alignment drops.
Was this guide helpful to your research?
Help us maintain 100% accurate, peer-reviewed bioinformatics standards.
📝 Propose Edit on GitHub ↗