Skip to content
GMODPublic

About

Parse BAM and BAM index files in javascript for node and the browser

Resources

Contributing

Stars

27 stars

Watchers

12 watching

Forks

Repository files navigation

@gmod/bam

NPM version Build Status

Read BAM files and their BAI or CSI indexes in node or the browser.

npm install @gmod/bam

Quick start

import { BamFile } from '@gmod/bam'

const bam = new BamFile({
  bamUrl: 'https://example.com/file.bam',
  baiUrl: 'https://example.com/file.bam.bai',
})

const records = await bam.getRecordsForRange('chr1', 10000, 20000)

for (const record of records) {
  console.log(record.name, record.start, record.CIGAR)
}

URLs work in node and the browser, and local files take bamPath and baiPath instead.

Range caching

With bamUrl, bam-js sends a separate HTTP request for each byte range a query reads (this visualizer draws them). @gmod/range-cache-filehandle fetches only the bytes it does not hold yet, merging nearby reads into one request, and later queries reuse the bytes it already has:

import { RemoteFileWithRangeCache } from '@gmod/range-cache-filehandle'

const bam = new BamFile({
  bamFilehandle: new RemoteFileWithRangeCache(url),
  baiFilehandle: new RemoteFileWithRangeCache(`${url}.bai`),
})

Coordinates

Coordinates are 0-based half-open, where samtools view takes 1-based closed, so samtools view file.bam ctgA:1-50000 returns the same records as getRecordsForRange('ctgA', 0, 50000). A query for a reference the file lacks returns [].

Records

record.name // read name
record.start // 0-based start
record.CIGAR // '50M2I48M'
record.seq // read sequence
record.getTag('NM') // one auxiliary tag
record.isReverseComplemented() // the usual SAM flags

Queries return records unfiltered, and overlapping queries share them, so treat them as read-only. getTag decodes one tag instead of all of them, which makes it the cheap way to filter:

const records = (await bam.getRecordsForRange('chr1', 0, 100000)).filter(
  r => r.isProperlyPaired() && !r.isSecondary() && r.getTag('RG') === 'rg1',
)

docs/api.md lists every field and method.

Mismatches

record.getMismatches() lists each difference between a read and the reference: substitutions, insertions, deletions, reference skips and clips.

// a read at 100 with CIGAR 5M1I4M2D3M, SEQ ACGGTCAACGTTA and MD 3A5^GG3
for (const { code, refPos, length, bases } of record.getMismatches()) {
  console.log(String.fromCharCode(code), refPos, length, bases)
}
// X 103 1 G   substitution to G
// I 105 0 C   one base inserted before 105
// D 109 2     two reference bases deleted from 109

A substitution needs the read's MD tag or the reference bases. Most aligners leave MD off, so pass fetchReferenceSequence: (refName, start, end) => ... to BamFile. bam-js calls it only for a query with a read that lacks MD. docs/api.md has the fields and options.

Worker pool

A worker pool spreads BGZF decompression across threads, which measured 2.7-4.1x faster on the pool's own fixtures:

import { getSharedWorkerPool } from '@gmod/bgzf-filehandle'

const bam = new BamFile({
  bamUrl,
  baiUrl,
  bgzfWorkerPool: getSharedWorkerPool(),
})

The pool is undefined under node and wherever the host forbids workers, and bam-js then decompresses in-process, so the option is safe to pass everywhere. bgzf-filehandle's docs cover pool size and lifecycle.

Unsorted BAM

For an unsorted or name-sorted BAM, streamBamRecords reads the file from start to end, an array of records at a time:

import { streamBamRecords } from '@gmod/bam'

for await (const records of streamBamRecords({ bamUrl: 'unsorted.bam' })) {
  for (const record of records) {
    // ...
  }
}

docs/api.md has the options.

htsget

import { HtsgetFile } from '@gmod/bam'

const bam = new HtsgetFile({
  baseUrl: 'http://htsnexus.rnd.dnanex.us/v1/reads',
  trackId: 'BroadHiSeqX_b37/NA12878',
})
const records = await bam.getRecordsForRange('1', 2000000, 2000001)

docs/api.md shows how to add authentication.

Docs

Academic use

Written with NHGRI funding as part of JBrowse. If you use this in a publication, please cite the most recent JBrowse paper at jbrowse.org.

License

MIT © Colin Diesh

About

Parse BAM and BAM index files in javascript for node and the browser

Resources

Contributing

Stars

27 stars

Watchers

12 watching

Forks

Releases

Packages

Used by

Contributors

Languages