BAM/SAM文件格式的一些小知识

BAM/SAM文件的一些小知识

前言

如果不是在陈老师这读博,然后开始折腾BAM/SAM文件,我估计这辈子都不会了解到这么多东西吧

SAM/BAM简介

See Wiki

Sequence Alignment Map (SAM) is a text-based format for storing biological sequences aligned to a reference sequence developed by Heng Li and Bob Handsaker et al.

  • SAM是李恒大佬在冷泉港鼓捣出来的一种文件格式,存储了测序获得的信息,map到基因组后的各种信息。SAM格式为纯文本格式,字里行间压缩了极大的信息。
  • BAM则是SAM的二进制版,在SAM的基础上运用二进制编码,又极大的压缩了SAM文件的体积。

在这个文件基础上,大家常用的各种alignment软件基本都支持SAM/BAM格式,围绕着这个文件格式,李恒等还开发了多个软件和不同语言版本的依赖库,以供大家使用该文本格式储存信息,并且在该文件基础上进行开发。

  • samtools: 对SAM/BAM等格式进行各种相关操作的软件,功能最丰富。
  • htslib: samtools的C接口,可以通过该库,在C语言中完成samtools的同等功能。
  • htsjdk: Java接口
  • pysam: Python接口

具体用法,推荐看各自的文档,比如javadoc或者python doc

格式

格式说明

以下为SAM格式示例(BAM格式参照SAM即可)

@HD VN:1.6 SO:coordinate
@SQ SN:ref LN:45
r001 99 ref 7 30 8M2I4M1D3M = 37 39 TTAGATAAAGGATACTG *
r002 0 ref 9 30 3S6M1P1I4M * 0 0 AAAAGATAAGGATA *
r003 0 ref 9 30 5S6M * 0 0 GCCTAAGCTAA * SA:Z:ref,29,-,6H5M,17,0;
r004 0 ref 16 30 6M14N5M * 0 0 ATAGCTTCAGC *
r003 2064 ref 29 17 6H5M * 0 0 TAGGC * SA:Z:ref,9,+,5S6M,30,1;
r001 147 ref 37 30 9M = 7 -39 CAGCGGCAT * NM:i:1

SAM文件主要由两个部分构成

  • header:标记了该SAM文件的一些基本信息,比如版本、按照什么方式排序的、Reference信息等等。
  • 本体:每行为一个reads,不同列记录了不同的信息,列与列之间通过tab分隔。

每列的含义:

column
  1. QNAME:测序的reads的名字。
  2. FLAG:二进制数字之和,不同数字代表了不同的意义;比如正负链,R1/R2(双端测序的哪一端)等。
  3. RNAME:map到参考基因组后的染色体名称。
  4. POS:1-based 基因组起始位点。
  5. MAPQ:map的质量。
  6. CIGAR:一个数字与字母交替构成的字符串,标记了这段reads不同位置的match情况。不同字母的含义后边介绍。
  7. RNEXT:如果是pair-end测序,这个为mate(另一端中对应的)的read的染色体名称;否则为下一条read的染色体名称。
  8. PNEXT:同上,read对应的起始位点。
  9. TLEN:模板的长度。
  10. SEQ:序列。
  11. QUAL:序列的质量打分(fasta文件中的那个)。

flag的含义:

flag tests 查询flag中具体数字含义,以及测试flag内容的网页

flag

flag比较特殊的是一点在于flag最后的数字中包含了这个数即为true(包含该特性),不包含这个数字即为false(不包含该特性)。

检测方法也比较巧妙,通过二进制与进行计算。比如:16 and 16 -> 16。结果与测试的数字一致,则表明flag中包含该数字。否则,不包含。

当然,不同语言版本的接口也直接提供了api来直接获取这些特性,不必在进行人工的计算。

cigar的含义

cigar中会包含数字,代表了特定match持续了多少nt;以及不同的字符,代表了不同的match情况。

cigar string examples:

30S512M216N12S (30nt soft clip -> 512nt exact match -> 216nt skipped region -> 12nt soft clip)
30S (30nt soft clip)
40M (40nt exact match)

其中不同的字符及其含义如下:


cigar from official

另一个版本的说明来源

cigar from blog

注意

双端测序,正负链的问题

双端测序很麻烦,mate和read两条序列的flag信息基本都是完全相反的,包括strand等信息。那么如何判断这一对reads测到的到底是哪条链就成了问题。

  • 最稳妥的方法是,通过GT/AG规则来确定。缺点就是你很难提取到GT/AG这个序列,最起码在我的测试中如此。
    • 在我的理解中,cigar中的I、D、N三个字符代表的区域不计入位点序列中。那么N区域的第一个位点周边的序列即为内含子周边的序列,然而在这个位点周边,很难获取到标准的GT/AG序列及其互补序列。可能由junctions的突变造成的,即N区域并不一定是标注的内含子区域
    • STAR应该是通过这个途径识别链方向的
      alignSJstitchMismatchNmax   0 -1 0 0
          4*int>=0: maximum number of mismatches for stitching of the splice junctions (-1: no limit).
                                  (1) non-canonical motifs, (2) GT/AG and CT/AC motif, (3) GC/AG and CT/GC motif, (4) AT/AC and GT/AT motif.
      
  • 另外就是根据readNegativeStrand和mateNegativeStrand,配合以First in pair以及second in pair进行判断。
    • 这个办法,依赖于是否确定R1和R2的建库方式和建库方向,如果我们确定R1是某个特定方向,那么我们就能够通过这四个参数的组合获取到正确的方向。
    • 目前我已知的regtools就是通过这种途径进行链的识别的。
      //Get the strand from the bitwise flag
      void JunctionsExtractor::set_junction_strand_flag(bam1_t *aln, Junction& j1) {
          uint32_t flag = (aln->core).flag;
          
          // 从flag中提取出readNegativeReversed,mateNegativeReversed, first in pair和second in pair的信息
          int reversed = (flag >> 4) % 2;
          int mate_reversed = (flag >> 5) % 2;
          int first_in_pair = (flag >> 6) % 2;
          int second_in_pair = (flag >> 7) % 2;
          
          // 下面就是判断正负链的过程
          // strandness_ is 0 for unstranded, 1 for RF, and 2 for FR
          int bool_strandness = strandness_ - 1;
          int first_strand = !bool_strandness ^ first_in_pair ^ reversed;
          int second_strand = !bool_strandness ^ second_in_pair ^ mate_reversed;
          
          char strand;
          if (first_strand){
              strand = '+';
          } else {
              strand = '-';
          }
          
          //cerr << "flag is " << flag << endl;
          // if strand inferences from first and second in pair don't agree, we've got a problem
          if (first_strand == second_strand){
              j1.strand = string(1, strand);
          } else {
              j1.strand = string(1, '?');
          }
          //cerr <<"flag strand is " << j1.strand << endl;
          return;
      }
      
    • 根据参数推测,hisat2可能也是这个方式。
      --fr/--rf/--ff     -1, -2 mates align fw/rev, rev/fw, fw/fw (--fr)
      
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • wes定义: 全外显子组测序,是利用目标序列捕获技术, 将全基因组编码基因外显子区域的DNA捕获并富集后,进行高通...
    凤凰_0949阅读 9,937评论 0 7
  • Introduction What is Bowtie 2? Bowtie 2 is an ultrafast a...
    wzz阅读 11,164评论 0 5
  • fastafasta格式是最基本的表示序列信息(核苷酸或者蛋白质)的格式。这里简单介绍下,fasta格式的文件通常...
    tianzhanlan阅读 10,559评论 0 10
  • 夜半你的倩影总是入梦 都不可再假装糊涂 简直是甜蜜的捉弄 叫人难以轻言放弃 明知道隔着阻碍万千 注定了是坎坷折磨 ...
    花少颜阅读 2,256评论 1 0
  • 今天道路依旧难行,我慢吞吞行驶车辆来到孩子托付班,接她回家路上,说有一个好消息一个坏消息,问我想听哪一...
    兆木兆木阅读 1,287评论 0 0