Site icon Ampersand Tutorials

Bedtools Tutorial: Genomic Interval Arithmetic You Will Use Every Week

Quick answer: Bedtools is the Swiss-army knife for genomic intervals. You hand it two or more files of genomic coordinates — BED, GFF, VCF, even BAM — and it answers set-style questions: which reads fall inside these peaks, what is the nearest gene to this variant, how much of the genome do these exons cover. The whole toolchain rests on one idea: intervals are rows in a text file, and once you can sort, intersect, merge, and subtract them, most daily bioinformatics data-wrangling problems collapse into a one-line command.

Companion to the file formats guide and the genome annotation article on this blog — bedtools is where those formats start talking to each other.

The one rule that prevents 90% of mistakes: coordinates

Every interval format answers “where?” slightly differently, and mixing them silently shifts your results:

Bedtools assumes the coordinates you feed it are already in the format the file claims. It does not check. The classic symptom is every intersect coming back off by one base — or off by one direction (one-base-short, one-base-long), which looks like a rounding problem but is a base-system problem. Convert deliberately:

# GFF3 (1-based) -> BED (0-based): subtract 1 from the start column
awk 'BEGIN{OFS="\t"} !/^#/ {print $1, $4-1, $5, $9, 0, $7}' genes.gff3 > genes.bed

Two more prerequisites before any command runs:

The core verbs

Install (conda install -c bioconda bedtools) and the daily drivers, in order of how often you will type them:

# 1. intersect: which intervals from A overlap B?
bedtools intersect -a reads.bed -b peaks.bed                 # only overlapping A rows
bedtools intersect -a reads.bed -b peaks.bed -wa -wb         # report both sides
bedtools intersect -a reads.bed -b peaks.bed -wo             # ...plus overlap length
bedtools intersect -a reads.bed -b exons.bed -v              # A rows with NO overlap

# 2. subtract / closest
bedtools subtract -a genes.bed -b repeats.bed               # genes minus repeat regions
bedtools closest -a variants.bed -b genes.bed -d            # nearest gene + distance

# 3. merge / cluster
bedtools merge -i sorted.bed                                # fuse overlapping/abutting intervals
bedtools merge -i sorted.bed -c 4 -o count                  # ...counting original intervals

# 4. coverage and depth
bedtools genomecov -i reads.bed -g genome.fa.fai -bg        # per-base depth, BEDGRAPH
bedtools coverage -a regions.bed -b reads.bed               # count + fraction covered

# 5. convenience
bedtools flank -i genes.bed -g genome.fa.fai -b 1000        # 1 kb windows either side
bedtools slop -i peaks.bed -g genome.fa.fai -b 200          # extend peaks by 200 bp
bedtools getfasta -fi genome.fa -bed orfs.bed               # extract the actual sequence
bedtools jaccard -a a.bed -b b.bed                           # overlap statistic between sets

A worked question most analysts meet early — how many of my ChIP-seq peaks overlap annotated exons? — is exactly two commands: bedtools sort both files, then bedtools intersect -a peaks.bed -b exons.bed -u | wc -l.

Where it quietly goes wrong

What a defensible interval analysis hands over

The deliverable is not just the resulting BED: it is the BED plus the genome build it was computed against, the exact bedtools version, and the sorting/filtering steps that produced the inputs. Interval arithmetic is cheap and fast, which makes it dangerously easy to re-run in five years against a different assembly and get confident, incompatible answers.

Key takeaways

Challenge

Take a BED file of promoters (flank the TSS of every gene with bedtools flank -b 500) and a BED of variants from a public VCF (grep -v '^#' in.vcf | awk 'BEGIN{OFS="\t"}{print $1, $2-1, $2}'). Compute: how many variants fall in promoters, how many of those are in repeats (subtract), and what the nearest gene is for the rest (closest -d). Every one of those answers is a single command — if you needed more than one, the interval probably was not in the form you assumed.

Want guided practice turning coordinate files into defensible results? Ampersand Academy offers one-to-one mentoring in bioinformatics — part of Mahadhi, a development and digital marketing company.

FAQ

What is the difference between BED and GFF coordinates?

BED counts from 0 and excludes the end position (0-based half-open); GFF counts from 1 and includes it (1-based closed). Converting means subtracting 1 from the GFF start only, never the end.

Why does bedtools intersect return nothing even though the regions clearly overlap?

Usually one of three causes: files are on different chromosome builds, chromosome names differ (chr1 vs 1), or one file is unsorted while the -sorted flag is set. Check all three before suspecting the biology.

Should I use -wa, -u, or -c when counting overlaps?

-wa writes one line per overlap, so an A interval hitting three B intervals appears three times. -u writes each A interval at most once; -c adds a column counting overlaps. Use u or c for per-interval statistics.

How do I know if a feature is 0-based or 1-based?

Check the format spec: BED, bigBed and PSL are 0-based; GFF/GTF, VCF, SAM and GenBank are 1-based. When a file’s origin is unclear, compare a known feature’s length against its coordinates — off-by-one lengths reveal the system.

bedtools is slow on my 10 GB BAM-derived BED. What do I do?

Sort both files in the same chromosome order and pass -sorted so it streams instead of loading into memory. For repeated queries, bgzip and tabix-index the larger file, and consider converting BAM work to bedtools bamtobed output once rather than re-converting per run.

Can bedtools work directly on BAM and VCF files?

Yes for many subcommands: intersect, coverage, genomecov and bamtobed accept BAM, and intersect accepts VCF. Results are still interval math, so the same coordinate and sorting rules apply.

When should I move from bedtools one-liners to a workflow manager?

When a command chain has to be re-run with new parameters, shared with a collaborator, or audited a year later. At that point the shell one-liner becomes a maintenance liability and belongs in Snakemake or Nextflow — the subject of the workflow guide on this blog.

Exit mobile version