Normalize ChIP-seq data using exogenous spike-in chromatin: Drosophila chromatin (ChIP-Rx; Orlando 2014 / Egan 2016) for human/mouse ChIP, or E. coli carryover from bacterial pA-MNase/pA-Tn5 for CUT&RUN/CUT&Tag. Required when global signal shifts are expected (HDACi, BETi, EZH2i, target knockdown, dosage). Covers RRPM vs Rx-Input scaling formulas, integration with DiffBind/DESeq2/edgeR/csaw, ChIPseqSpikeInFree for post-hoc detection without spike-in, and the Patel et al 2024 review's failure-mode framework. Emphasizes the internal-control sanity check (blacklist regions should NOT shift post-scaling).
conda install -c bioconda samtools bowtie2 bedtools deeptools
BiocManager::install(c('DiffBind', 'DESeq2', 'edgeR', 'csaw', 'ChIPseqSpikeInFree'))
# SpikeFlow (Snakemake wrapper, optional)
# https://github.com/DavideBrex/SpikeFlow
Tell the agent what to do:
- "I have H3K27ac ChIP-seq from DMSO vs JQ1 (BET inhibitor). Compute Drosophila spike-in scaling factors and apply via DiffBind."
- "Align reads to combined hg38 + dm6 genome and count Drosophila reads per sample"
- "Apply spike-in scaling at the read level via DESeq2 sizeFactors (inverse convention)"
- "Generate spike-in-scaled bigWigs with --scaleFactor alone (not combined with --normalizeUsing)"
- "Verify internal-control sanity: blacklist regions should show no signal change post-scaling"
- "I didn't add spike-in. Run ChIPseqSpikeInFree for post-hoc detection of global shifts (diagnostic only)."
- "Compute Rx-Input scaling factor incorporating spike-in fractions in BOTH ChIP and input"
"I have 4 samples (2 DMSO, 2 JQ1) for H3K27ac. Build a combined hg38+dm6 bowtie2 index, align reads, filter with -F 1804 -q 30, count Drosophila reads per sample, compute scale factors as min/each, and apply to DESeq2 as
sizeFactors(dds) <- 1/scale_factors."
"Use DiffBind 3.20+ with
dba.normalize(obj, spikein = TRUE). Sample sheet hasSpikeincolumn with Drosophila read counts."
"Generate spike-in-scaled bigWigs with
bamCoverage --scaleFactor X. Do NOT also pass--normalizeUsing."
"After applying spike-in scaling, verify ENCODE blacklist regions show no signal change between conditions. Also check signal at U6 snRNA promoter (constitutively bound by Pol III; should be stable across H3K27ac conditions)."
"I didn't run spike-in but suspect a global shift in my BET-inhibitor experiment. Run ChIPseqSpikeInFree to estimate scaling factors from signal-distribution shape."
"Apply Rx-Input scaling (Fursova 2019) which scales by both ChIP and input spike-in fractions to correct for IP efficiency variation."
"My results have wrong signs after scaling. Check inverse convention; check whether scaling was applied to peak counts instead of read counts; verify internal-control regions."
-F 1804 -q 30 applied to both target and spike alignmentsmin(spike) / per_sample_spike; Rx-Input: ratio of ChIP/input spike fractionsbamCoverage --scaleFactor X (NOT with --normalizeUsing)dba.normalize(obj, spikein = TRUE)sizeFactors(dds) <- 1 / scale_factors (inverse convention)normFactors via DGEListnormFactors/normOffsets), not inside windowCounts itselfsizeFactors use inverse convention. sizeFactors(dds) <- 1 / scale_factors, not direct.--scaleFactor alone in bamCoverage for spike-in. deepTools multiplies --scaleFactor by any --normalizeUsing factor, so combining them reintroduces depth normalization.Spike-in not added at fixed amount, OR samples not properly randomized. Re-check Egan 2016 protocol (fixed Drosophila chromatin mass, ~27:1 human:Drosophila genome-copy ratio).
Spike-in lost during library prep, OR too few cells used. Scaling unreliable; re-do experiment.
Spike-in too concentrated; saturating. Titration not in linear range; scaling factors unreliable.
Library prep batch effects on spike-in fraction. Re-extract spike reads after deduplication and mapq filter; if still variable, library prep needs improvement.
Inverse convention bug. sizeFactors(dds) <- 1 / scale_factors, not sizeFactors(dds) <- scale_factors.
Scaling broken. Common causes:
1. Scaling applied to peak counts -> fix application layer
2. Spike-in reads not dedup'd -> re-extract from filtered BAM
3. mapq filter too loose -> use -q 30
4. Spike-in saturated -> verify titration linearity
If spike-in is properly applied and internal controls are stable, the biology may not have the global shift. Consider: 1. Mark biology; H3K27ac may shift less than H3K27me3 with EZH2i 2. Time-course; acute (1 hr) vs chronic (24 hr) differs 3. Inhibitor concentration; sub-saturating doesn't produce global shift
Trust spike-in measurement. ChIPseqSpikeInFree is a distribution-shape heuristic; it may misinterpret biology as a global shift.