omics.co.in logo omics.co.in

Chapter 8: Functional Enrichment with clusterProfiler & Statistical Background Definition

Tested Stacks: GATK 4.6.1 Samtools 1.21 Nextflow 24.10 Seurat v5.1 Python 3.12
Prerequisites: Basic Linux CLI & Sequencing Formats
📚 Chapter 8 of 10 0% Course Completed
Module 08 • Functional Enrichment Track 23 • 10 Modular Chapters WGCNA • DESeq2 • clusterProfiler • Cytoscape

Chapter 8: Functional Enrichment with clusterProfiler & Statistical Background Definition

Performing Gene Ontology (GO) Biological Process and KEGG over-representation analysis; avoiding false positive inflation by properly defining the gene universe as non-grey, mapped network genes; semantic reduction with simplify; generating publication dotplots.

⏱️ Estimated Study: 45–60 mins 🧪 Workflows: R / Bioconductor (WGCNA 1.73+, DESeq2, clusterProfiler, Cytoscape 3.10+) 📋 Level: Intermediate to Advanced Systems Transcriptomics

1. The Fatal Fallacy of Whole-Genome Universes in Co-expression

One of the most pervasive methodological errors in computational transcriptomics literature is performing Gene Ontology (GO) or KEGG over-representation analysis on WGCNA modules using the entire organismal genome (e.g., all 30,000 Arabidopsis genes) as the statistical background.

Why Whole-Genome Backgrounds Invalidate Hypergeometric Tests

Hypergeometric and Fisher's exact tests evaluate whether the proportion of module genes annotated with term $T$ exceeds the proportion in the eligible reference pool. If you test leaf drought tissue, thousands of root-specific, flower-specific, and embryonic genes are unexpressed and were filtered out during preprocessing.

Including those inactive genes in the background artificially suppresses the baseline frequency of leaf-expressed terms, causing widespread false-positive inflation of generic metabolic terms.

The Rigorous Rule: The statistical universe must consist strictly of expressed, non-grey network genes that are actively annotated with valid Gene Ontology terms in the organism's database.

2. Background Formulation & clusterProfiler enrichGO() Execution

Formulate the valid background and execute Biological Process (BP) enrichment with Benjamini-Hochberg adjustment using Bioconductor's clusterProfiler:

library(clusterProfiler)
library(enrichplot)

# Step 1: Define eligible network genes (All non-grey module genes)
eligible_genes <- names(module_labels)[module_colors[names(module_labels)] != "grey"]

# Step 2: Query OrgDb and retain only genes with valid Biological Process (BP) GO terms
mapped_ids <- AnnotationDbi::select(
    org.At.tair.db,
    keys = unique(eligible_genes),
    keytype = "TAIR",
    columns = c("GO", "ONTOLOGY")
)
mapped_ids <- mapped_ids[!is.na(mapped_ids$GO) & mapped_ids$ONTOLOGY == "BP", ]

# The True Statistical Background
background <- unique(mapped_ids$TAIR)
cat("Verified Non-Grey GO BP Background size:", length(background), "genes\n")

# Step 3: Intersect module genes with background
module_genes <- intersect(target_genes, background)
if (length(module_genes) == 0) {
    stop("No genes from the target module map to the GO BP background.")
}

# Step 4: Perform Over-Representation Analysis (ORA)
ego_module <- enrichGO(
    gene          = module_genes,
    universe      = background,       # Strictly controlled network universe
    OrgDb         = org.At.tair.db,
    keyType       = "TAIR",
    ont           = "BP",
    pAdjustMethod = "BH",
    pvalueCutoff  = 0.05,
    qvalueCutoff  = 0.05,
    minGSSize     = 10,
    maxGSSize     = 500,
    readable      = TRUE
)

ego_df <- as.data.frame(ego_module)
cat("\nEnriched Biological Process Terms (Top 10):\n")
print(head(ego_df[, c("ID", "Description", "GeneRatio", "BgRatio", "p.adjust")], 10))

3. Semantic Redundancy Reduction & Publication Dotplots

Gene Ontology hierarchies contain extensive parent-child overlap. Use simplify() to collapse redundant terms based on semantic similarity, then render publication dotplots:

if (nrow(ego_df) > 0) {
    # Collapse redundant terms with Wang semantic similarity cutoff
    ego_simple <- simplify(ego_module, cutoff = 0.7, by = "p.adjust", select_fun = min)
    
    # Generate Publication Dotplot
    p_dot <- dotplot(ego_simple, showCategory = 15) +
        ggtitle(paste("GO Biological Process Enrichment:", target_ME, "(Drought Response)")) +
        theme_minimal(base_size = 12) +
        theme(
            plot.title = element_text(face = "bold", size = 14),
            axis.text.y = element_text(color = "black")
        )
    print(p_dot)
} else {
    message("No GO BP terms achieved statistical significance at BH q < 0.05.")
}
⚠️

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 ↗