omics.co.in logo omics.co.in

8: Sequence Motifs, Position Weight Matrices & Information Content

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 13 0% Course Completed

Chapter 8: Sequence Motifs, Position Weight Matrices & Information Content

Gene regulation relies on sequence-specific DNA-binding proteins, such as transcription factors, recognizing short (6–20 bp) degenerate regulatory elements in promoters and enhancers. Because DNA-binding proteins tolerate nucleotide substitutions at non-critical positions, representing these motifs with simple consensus strings loses vital biological affinity data. Position Weight Matrices (PWMs) provide the rigorous mathematical standard for modeling sequence motifs.

Information Content & Sequence Logo Bits

The total information content \(R(l)\) at position \(l\) of a DNA motif is measured in bits (maximum 2 bits for 4 nucleotides), defined by Claude Shannon's information entropy:

R(l) = 2 - [ - ∑b p(b, l) × log2 p(b, l) ] - e(n)

Where \(p(b, l)\) is the probability of base \(b\) at position \(l\), and \(e(n)\) is a small-sample correction factor. In a graphical Sequence Logo, the total height of a column represents its information content (conservation), and the height of individual letters reflects their relative frequency.

1. Constructing a Position Weight Matrix (PWM)

# Given a set of aligned TATA-box binding sites:
# Step 1: Position Frequency Matrix (PFM) - Count observed bases per position
# Step 2: Position Probability Matrix (PPM) - Add pseudocounts and normalize:
#         p(b, l) = (Count(b, l) + s(b)) / (Total + sum(s))
# Step 3: Position Weight Matrix (PWM) - Log-odds ratio against background:
#         W(b, l) = log2( p(b, l) / q(b) ) where q(b) = 0.25

2. Programmatic Motif Scanning with BioPython

from Bio import motifs
from Bio.Seq import Seq

# Define a collection of binding site instances
instances = [
    Seq("TATAAA"),
    Seq("TATATA"),
    Seq("TATAAA"),
    Seq("TATAAT"),
    Seq("CATAAA"),
]

# Create motif object and build PWM
m = motifs.create(instances)
print("Position Frequency Matrix (PFM):\n", m.counts)

# Convert to Position Specific Scoring Matrix (PSSM / PWM)
pwm = m.counts.normalize(pseudocounts=0.5)
pssm = pwm.log_odds()
print("\nPSSM (Log-odds scores):\n", pssm)

# Scan a promoter sequence for candidate binding sites
promoter = Seq("CGGATATAAACCGGCTATATAATGCC")
for position, score in pssm.search(promoter, threshold=3.0):
    print(f"Discovered hit at position {position:2d} | Score = {score:.2f} | Sequence = {promoter[position:position+6]}")
⚠️

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 ↗