| name | bio-genome-intervals-bed-file-basics |
| description | BED file format fundamentals, creation, validation, and basic operations. Covers BED3 through BED12 formats, coordinate systems, sorting, and format conversion using bedtools and pybedtools. Use when working with genomic coordinates or preparing interval files for downstream tools. |
| tool_type | mixed |
| primary_tool | bedtools |
BED File Basics
BED (Browser Extensible Data) format stores genomic intervals. Uses 0-based, half-open coordinates.
BED Format Columns
BED3: chr start end
BED4: chr start end name
BED5: chr start end name score
BED6: chr start end name score strand
BED12: chr start end name score strand thickStart thickEnd rgb blockCount blockSizes blockStarts
Coordinate System
BED uses 0-based, half-open coordinates:
- Start: 0-based (first base is 0)
- End: exclusive (not included)
- Position 100-200 means bases at positions 100-199
Create BED Files
From Text (CLI)
echo -e "chr1\t100\t200\nchr1\t300\t400" > regions.bed
echo -e "chr1\t100\t200\tpeak1\t100\t+" > peaks.bed
From Python
import pybedtools
bed_string = '''chr1\t100\t200\tpeak1\t100\t+
chr1\t300\t400\tpeak2\t200\t-'''
bed = pybedtools.BedTool(bed_string, from_string=True)
intervals = [
('chr1', 100, 200, 'peak1', 100, '+'),
('chr1', 300, 400, 'peak2', 200, '-'),
]
bed = pybedtools.BedTool(intervals)
import pandas as pd
df = pd.DataFrame({
'chrom': ['chr1', 'chr1'],
'start': [100, 300],
'end': [200, 400],
'name': ['peak1', 'peak2'],
'score': [100, 200],
'strand': ['+', '-']
})
bed = pybedtools.BedTool.from_dataframe(df)
bed.saveas('output.bed')
Sort BED Files
CLI
sort -k1,1 -k2,2n input.bed > sorted.bed
bedtools sort -i input.bed > sorted.bed
sort -k1,1 -k2,2n -k3,3n input.bed > sorted.bed
Python
import pybedtools
bed = pybedtools.BedTool('input.bed')
sorted_bed = bed.sort()
sorted_bed.saveas('sorted.bed')
Validate BED Files
Check Format
awk -F'\t' '{print NF}' input.bed | sort -u
awk '$2 >= $3' input.bed
awk '$2 < 0 || $3 < 0' input.bed
bedtools sort -i input.bed > /dev/null 2>&1 && echo "Valid" || echo "Invalid"
Python Validation
import pybedtools
def validate_bed(filepath):
try:
bed = pybedtools.BedTool(filepath)
for interval in bed:
if interval.start < 0 or interval.end < 0:
return False, 'Negative coordinates'
if interval.start >= interval.end:
return False, f'Invalid interval: {interval.start} >= {interval.end}'
return True, 'Valid'
except Exception as e:
return False, str(e)
valid, msg = validate_bed('input.bed')
print(f'{msg}')
Read BED Files
Python
import pybedtools
bed = pybedtools.BedTool('input.bed')
for interval in bed:
print(f'{interval.chrom}:{interval.start}-{interval.end}')
print(f'Name: {interval.name}, Score: {interval.score}, Strand: {interval.strand}')
n_intervals = bed.count()
df = bed.to_dataframe()
df = bed.to_dataframe(names=['chrom', 'start', 'end', 'name', 'score', 'strand'])
Filter BED Files
By Chromosome
grep "^chr1\t" input.bed > chr1.bed
grep -E "^(chr1|chr2)\t" input.bed > chr1_2.bed
grep -v "^chrM\t" input.bed > no_chrM.bed
By Size
awk '($3 - $2) >= 100' input.bed > large.bed
awk '($3 - $2) >= 100 && ($3 - $2) <= 500' input.bed > medium.bed
Python Filtering
import pybedtools
bed = pybedtools.BedTool('input.bed')
chr1 = bed.filter(lambda x: x.chrom == 'chr1')
large = bed.filter(lambda x: len(x) >= 100)
plus_strand = bed.filter(lambda x: x.strand == '+')
high_score = bed.filter(lambda x: float(x.score) >= 500)
result = bed.filter(lambda x: x.chrom == 'chr1' and len(x) >= 100)
result.saveas('filtered.bed')
Convert Formats
BED to Other Formats
bedtools bed12togff -i input.bed > output.gff
bedtools getfasta -fi reference.fa -bed input.bed -fo output.fa
bedtools getfasta -fi reference.fa -bed input.bed -name -fo output.fa
From VCF to BED
bcftools query -f '%CHROM\t%POS0\t%END\n' input.vcf > variants.bed
grep -v "^#" input.vcf | awk '{print $1"\t"$2-1"\t"$2}' > snps.bed
From BAM to BED
bedtools bamtobed -i input.bam > alignments.bed
bedtools bamtobed -i input.bam -split > spliced.bed
Interval Arithmetic Basics
import pybedtools
interval = pybedtools.create_interval_from_list(['chr1', '100', '200', 'peak1', '0', '+'])
print(interval.chrom)
print(interval.start)
print(interval.end)
print(interval.name)
print(interval.score)
print(interval.strand)
print(len(interval))
print(interval.fields)
Make Windows - Create Genomic Intervals
CLI
bedtools makewindows -g genome.txt -w 10000 > windows_10kb.bed
bedtools makewindows -g genome.txt -w 10000 -s 5000 > sliding_10kb.bed
bedtools makewindows -g genome.txt -n 100 > 100_windows_per_chr.bed
bedtools makewindows -b regions.bed -w 1000 > windows_in_regions.bed
bedtools makewindows -g genome.txt -w 10000 -i winnum > numbered_windows.bed
bedtools makewindows -g genome.txt -w 10000 -i srcwinnum > windows_with_source.bed
Python
import pybedtools
windows = pybedtools.BedTool().window_maker(g='genome.txt', w=10000)
windows = pybedtools.BedTool().window_maker(g='genome.txt', w=10000, s=5000)
bed = pybedtools.BedTool('regions.bed')
windows = pybedtools.BedTool().window_maker(b=bed.fn, w=1000)
windows.saveas('windows.bed')
Common BED Extensions
| Format | Description | Columns |
|---|
| narrowPeak | ENCODE narrow peaks | BED6 + signalValue, pValue, qValue, peak |
| broadPeak | ENCODE broad peaks | BED6 + signalValue, pValue, qValue |
| bedGraph | Signal track | chr, start, end, value |
| bedpe | Paired intervals | chr1, s1, e1, chr2, s2, e2, name, score, strand1, strand2 |
Cleanup Temp Files
import pybedtools
pybedtools.cleanup()
pybedtools.set_tempdir('/tmp/pybedtools')
Related Skills
- interval-arithmetic - intersect, subtract, merge operations
- gtf-gff-handling - annotation file parsing
- coverage-analysis - depth calculations
- alignment-files/sam-bam-basics - BAM to BED conversion