De novo and known TF motif enrichment in ChIP-seq/ATAC-seq peaks via HOMER. findMotifsGenome.pl finds over-represented patterns vs background; annotatePeaks.pl assigns context (TSS distance, gene, repeat). Use after MACS3 to identify enriched TFs, annotate peaks with nearest genes, and validate ChIP-seq via the target motif.
De novo and known TF motif enrichment in ChIP-seq/ATAC-seq peaks via HOMER. findMotifsGenome.pl finds over-represented patterns vs background; annotatePeaks.pl assigns context (TSS distance, gene, repeat). Use after MACS3 to identify enriched TFs, annotate peaks with nearest genes, and validate ChIP-seq via the target motif.
license
GPL-3.0
HOMER — Motif Analysis and Peak Annotation
Overview
HOMER (Hypergeometric Optimization of Motif EnRichment) is a suite of Perl/C++ tools for analyzing genomic regulatory elements. Its two primary commands are findMotifsGenome.pl, which performs de novo motif discovery and known motif enrichment against JASPAR/HOMER databases, and annotatePeaks.pl, which maps each peak to the nearest gene, distance to TSS, and genomic feature class (promoter, intron, intergenic, repeat). HOMER takes BED-format peak files from MACS3 or similar peak callers and a reference genome assembly as input, and outputs HTML/text reports ranking enriched motifs by p-value and fold enrichment over a matched background.
When to Use
Identifying which transcription factors are bound in a ChIP-seq peak set by enriching their known motifs from JASPAR or the HOMER motif library
Discovering novel sequence motifs de novo in open chromatin regions from ATAC-seq without prior knowledge of the binding TF
Comparing motif landscapes between two conditions (e.g., treated vs. untreated peak sets) by running HOMER with one set as target and the other as background
Annotating genomic peaks with nearest genes and distance to TSS for downstream functional analysis or integration with DESeq2 results
Validating ChIP-seq experiment quality: a successful pull-down should show the target TF's canonical motif as the top hit
Use macs3-peak-calling first to generate the peak BED files that serve as input to HOMER
Use jaspar-database to cross-reference HOMER-discovered motifs with JASPAR IDs and additional TF metadata
Use MEME-CHIP (web or local) when you need a more probabilistic ZOOPS/TCM model or the MEME Suite ecosystem
Use AME (part of MEME Suite) as a faster alternative for known motif scanning without de novo discovery
Prerequisites
Software: HOMER (Perl + compiled binaries), conda or manual install
Genomes: must download genome sequence via installGenome.pl after HOMER install
Input: BED file of peaks (at minimum: chr, start, end columns); ideally summit-centered peaks from MACS3
Check before installing: The tool may already be available in the current environment (e.g., inside a pixi / conda env). Run command -v findMotifsGenome.pl first and skip the install commands below if it returns a path. When running inside a pixi project, invoke the tool via pixi run findMotifsGenome.pl rather than bare findMotifsGenome.pl.
# Run de novo + known motif enrichment on TF ChIP-seq peaks (hg38, 200 bp window)
findMotifsGenome.pl peaks/tf_chip_summits.bed hg38 motif_output/ \
-size 200 -mask -p 4
# Annotate peaks with nearest genes and genomic features
annotatePeaks.pl peaks/tf_chip_peaks.narrowPeak hg38 > annotated_peaks.txt
echo"Top known motif:"head -2 motif_output/knownResults.txt | tail -1 | cut -f1-4
echo"Annotated peaks: $(wc -l < annotated_peaks.txt) lines"
Workflow
Step 1: Installation and Genome Setup
Install HOMER and download the reference genome sequence required for motif analysis.
# Activate conda environment (or use existing env)
conda create -n homer_env -c bioconda homer python=3.10 -y
conda activate homer_env
# List available genomes
installGenome.pl list
# Install human (hg38) and mouse (mm10) genomes# Downloads masked genome sequence and annotation files
installGenome.pl hg38
# Output: Installing hg38... Done. (3-5 min, ~3 GB)
installGenome.pl mm10
# Output: Installing mm10... Done. (3-5 min, ~2.5 GB)# Verify genome is installedls ~/.homer/data/genomes/hg38/
# genome.fa chrom.sizes ...# Check HOMER motif databasels ~/.homer/data/knownTFs/
# vertebrates.motifs jaspar.motifs ...
Step 2: Prepare Input Peak File
Prepare a summit-centered BED file from MACS3 output for optimal motif resolution.
# Option A: Use MACS3 summit file directly (already 1 bp summit positions)# Expand summits to ±100 bp (200 bp total) centered on summit
awk 'BEGIN{OFS="\t"} {
start = ($2 - 100 < 0) ? 0 : $2 - 100;
print $1, start, $2 + 100, $4, $5
}' peaks/tf_chip_summits.bed > peaks/tf_chip_200bp.bed
echo"Summit-centered peaks: $(wc -l < peaks/tf_chip_200bp.bed)"# Summit-centered peaks: 12453# Option B: Use narrowPeak file directly (HOMER accepts multi-column BED)# HOMER uses columns 1-3 (chr, start, end) and centers internally with -sizecp peaks/tf_chip_peaks.narrowPeak peaks/input_peaks.bed
# Option C: Prepare a custom background region file (matched GC content)# HOMER auto-generates background if not provided, but explicit background# is recommended when comparing two peak sets# Use the control peak set or random genomic regions as background:
bedtools shuffle -i peaks/tf_chip_peaks.narrowPeak \
-g ~/.homer/data/genomes/hg38/chrom.sizes \
-excl peaks/tf_chip_peaks.narrowPeak > peaks/background_regions.bed
echo"Background regions: $(wc -l < peaks/background_regions.bed)"# Background regions: 12453
Step 3: De Novo Motif Discovery
Run findMotifsGenome.pl for de novo motif discovery and known motif enrichment simultaneously.
mkdir -p motif_output/
# Full run: de novo + known motif enrichment# -size 200: use 200 bp window centered on peak midpoint# -mask: mask repetitive elements (recommended for clean motifs)# -p 4: use 4 CPU threads# -S 25: find top 25 de novo motifs (default)
findMotifsGenome.pl peaks/tf_chip_200bp.bed hg38 motif_output/ \
-size 200 \
-mask \
-p 4 \
-S 25
# Check progress output:# Reading genome sizes for hg38 ...# Scanning for motifs...# Optimizing 25 motifs...# Done! Output in motif_output/echo"Known results: $(wc -l < motif_output/knownResults.txt) motifs"echo"De novo motifs: $(ls motif_output/homerResults/*.motif 2>/dev/null | wc -l) motifs"# Known results: 392 motifs# De novo motifs: 25 motifs# For mouse peaks (mm10)# findMotifsGenome.pl peaks/atac_peaks.bed mm10 motif_output_mm10/ \# -size 200 -mask -p 4
Step 4: Known Motif Enrichment Only
Scan peaks for occurrences of a specific known motif or skip de novo discovery for speed.
# Skip de novo discovery (faster when you only need known motifs)
findMotifsGenome.pl peaks/tf_chip_200bp.bed hg38 motif_output_known/ \
-size 200 \
-mask \
-p 4 \
-nomotif
echo"Known motif results: $(wc -l < motif_output_known/knownResults.txt)"# Known motif results: 392# Find occurrences of a specific motif across peaks (outputs peak-level annotation)# Extract the motif matrix file for the TF of interest from homerResults/
findMotifsGenome.pl peaks/tf_chip_200bp.bed hg38 motif_scan_out/ \
-size 200 \
-mask \
-find motif_output/homerResults/motif1.motif \
> peaks_with_motif1.txt
echo"Peaks containing motif1: $(wc -l < peaks_with_motif1.txt)"# Peaks containing motif1: 8941# Custom background: compare treated vs. control peak sets
findMotifsGenome.pl peaks/treated_peaks.bed hg38 motif_treated_vs_ctrl/ \
-size 200 \
-mask \
-p 4 \
-bg peaks/control_peaks.bed
Step 5: Peak Annotation
Use annotatePeaks.pl to assign each peak to a genomic feature and nearest gene.
# Annotate peaks with nearest gene and TSS distance# Outputs a tab-delimited file with genomic context for each peak
annotatePeaks.pl peaks/tf_chip_peaks.narrowPeak hg38 \
> annotated_peaks.txt
echo"Annotated peaks: $(($(wc -l < annotated_peaks.txt) - 1)) peaks"# Annotated peaks: 12453 peaks# Preview column headers and first peakhead -2 annotated_peaks.txt | cut -f1-10
# Annotate ATAC-seq peaks (same command, different input)
annotatePeaks.pl peaks/atac_sample_peaks.narrowPeak hg38 \
> annotated_atac.txt
# Generate TSS-distance histogram (for tag density plots)# annotatePeaks.pl can compute read density around peaks with -d flag# annotatePeaks.pl tss hg38 -size 4000 -hist 10 \# -d chip_tagdir/ > tss_histogram.txt
Step 6: Parse HOMER Results with Python
Read knownResults.txt and de novo motif files into pandas for downstream analysis.
Recipe 3: Parse De Novo Motif Matrices from homerResults/
Load de novo motif PWM matrices for downstream comparison or plotting.
import os
import re
import pandas as pd
defparse_homer_motif(motif_file: str) -> dict:
"""Parse a HOMER .motif file into name, log_odds_threshold, and PWM."""withopen(motif_file) as f:
header = f.readline().strip() # >motif_name\tlog_odds\tlog_p-value\t0\tnucs
rows = []
for line in f:
line = line.strip()
if line:
rows.append([float(x) for x in line.split("\t")])
parts = header.lstrip(">").split("\t")
name = parts[0]
log_odds = float(parts[1]) iflen(parts) > 1else0.0
log_p = float(parts[2]) iflen(parts) > 2else0.0
pwm = pd.DataFrame(rows, columns=["A", "C", "G", "T"])
return {"name": name, "log_odds": log_odds, "log_p": log_p, "pwm": pwm}
# Load all de novo motifs
motif_dir = "motif_output/homerResults/"
motifs = []
for fn insorted(os.listdir(motif_dir)):
if fn.endswith(".motif"):
motif = parse_homer_motif(os.path.join(motif_dir, fn))
motifs.append(motif)
print(f"{fn}: {motif['name']} ({len(motif['pwm'])} positions, log_p={motif['log_p']:.1f})")
print(f"\nLoaded {len(motifs)} de novo motifs")
# motif1.motif: CTCF-motif (19 positions, log_p=-8234.1)# motif2.motif: CTCFL-motif (17 positions, log_p=-3421.7)# ...# Loaded 25 de novo motifs
Recipe 4: Annotate Peaks and Join with Differential Expression Results
Combine peak annotations with RNA-seq DE results to find regulated genes near peaks.
import pandas as pd
# Load annotated peaks
annot = pd.read_csv("annotated_peaks.txt", sep="\t", header=0, low_memory=False)
annot.columns = annot.columns.str.strip()
# Key columns from HOMER annotation
peak_genes = annot[["PeakID (cmd=annotatePeaks.pl peaks.bed hg38)",
"Chr", "Start", "End",
"Annotation", "Distance to TSS",
"Nearest RefSeq", "Gene Name"]].copy()
peak_genes.columns = ["peak_id", "chr", "start", "end",
"annotation", "tss_dist", "refseq", "gene_name"]
# Filter promoter-proximal peaks (within 2 kb of TSS)
promoter_peaks = peak_genes[peak_genes["tss_dist"].abs() < 2000].copy()
print(f"Promoter-proximal peaks (|TSS| < 2kb): {len(promoter_peaks)}")
# Promoter-proximal peaks (|TSS| < 2kb): 2218# Load DESeq2 results (gene_name, log2FC, padj)
de_results = pd.read_csv("deseq2_results.csv")
de_sig = de_results[de_results["padj"] < 0.05].copy()
# Merge: find DE genes with a nearby peak
merged = promoter_peaks.merge(de_sig, on="gene_name", how="inner")
print(f"DE genes with promoter-proximal peak: {len(merged)}")
print(merged[["gene_name", "tss_dist", "annotation", "log2FC", "padj"]].head())
# DE genes with promoter-proximal peak: 347
Expected Outputs
Output
Format
Description
motif_output/knownResults.txt
TSV
All known motifs tested: name, p-value, q-value, % target, % background; primary result file
motif_output/knownResults.html
HTML
Interactive HTML report with motif logos, statistics, and links
motif_output/homerResults/
Directory
De novo motifs: motifN.motif (PWM matrix), motifN.logo.png, similar.motifs.txt
motif_output/homerResults.html
HTML
Interactive HTML report for de novo motifs
annotated_peaks.txt
TSV
One row per peak: chr, start, end, annotation, TSS distance, nearest gene, RefSeq ID
Heinz S et al. (2010) "Simple Combinations of Lineage-Determining Transcription Factors Prime cis-Regulatory Elements Required for Macrophage and B Cell Identities." Molecular Cell 38(4):576–589. DOI:10.1016/j.molcel.2010.05.004