Pysam操作BAM文件
Pysam包是一个处理基因组数据的python模块,它打包了htslib-1.3、samtools-1.3 和 bcftools-1.3的核心功能,能在编程时非常灵活的处理bam和bcf文件,实现python处理基因组数据的无缝衔接,而不用在python程序内部调用samtools、bcftools等软件。
>>> import pysam
>>> samfile = pysam.AlignmentFile("ex1.bam", "rb")
导入pysam包,samfile是一个pysam.AlignmentFile对象,该对象有很多内置方法提供后续的分析,对BAM文件的操作也基本上基于这个对象。
AlignmentFile对象内置方法
- check_index(self)
如果index文件存在则返回True
>>> samfile.check_index()
True
- close(self)
关闭pysam.AlignmentFile - count(self,contig=None, start=None, stop=None, region=None, until_eof=False, read_callback='nofilter', reference=None,end=None)
计算目标区域内比对上的reads数目
>>> samfile.count(contig='chr1', start=1000000, stop=1000100)
107
- count_coverage(self, contig=None, start=None, stop=None, region=None, quality_threshold=15, read_callback='all', reference=None, end=None)
计算目标区域内的覆盖度。返回1个4维的array,代表ACGT的覆盖度,而每个维度的array长度为100,里面的数字代表该碱基在各个位置上的覆盖度。
>>> samfile.count_coverage(contig='chr1', start=1000000, stop=1000100)
(array('L', [0, 1, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 58, 0, 0, 0, 52, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 1, 1, 0, 0, 20, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),\
array('L', [0, 0, 0, 0, 0, 0, 77, 0, 70, 0, 68, 67, 0, 58, 58, 0, 59, 0, 0, 1, 51, 49, 0, 48, 0, 0, 0, 41, 0, 0, 0, 40, 0, 0, 0, 38, 0, 0, 0, 36, 0, 0, 0, 36, 0, 0, 34, 0, 0, 0, 28, 0, 31, 0, 28, 0, 0, 25, 0, 0, 0, 21, 24, 0, 0, 0, 22, 22, 22, 22, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 17, 20, 20, 0, 0, 17, 0, 17, 17, 0, 0, 0, 14, 15, 15, 0, 12, 0, 13, 0]), \
array('L', [94, 0, 88, 87, 0, 83, 0, 72, 0, 67, 0, 0, 61, 0, 0, 0, 0, 59, 56, 0, 0, 0, 0, 0, 46, 46, 40, 0, 41, 41, 41, 0, 0, 38, 38, 0, 36, 36, 36, 0, 36, 0, 36, 0, 34, 34, 0, 31, 0, 31, 0, 31, 0, 29, 0, 26, 25, 0, 24, 0, 1, 0, 0, 23, 0, 21, 0, 0, 0, 0, 0, 0, 20, 22, 21, 0, 19, 19, 9, 0, 0, 0, 0, 17, 19, 0, 0, 0, 0, 0, 15, 15, 0, 0, 0, 14, 0, 13, 0, 13]), \
array('L', [0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]))
- fetch(self, contig=None, start=None, stop=None, region=None, tid=None, until_eof=False, multiple_iterators=False, reference=None, end=None)
提取出比对到目标区域内的全部reads。返回的是一个迭代器,可以通过for循环或者next函数从中取出reads,我们使用next()函数取出第一条reads,reads是用AlignedSegment对象表示,可以通过该对象的内置方法再对这条reads进行一些查询操作。
>>> allreads=samfile.fetch(contig='chr1', start=1000000, stop=1000010)
>>> allreads
>>> reads1=next(allreads)
>>> reads1
- find_introns(self, read_iterator)
返回一个字典{(start, stop): count},列出了reads中的intronic sites(cigar字符串中的'N') - get_index_statistics(self)
通过index统计该BAM文件中在各个染色体上mapped/unmapped的reads个数。
>>> samfile.get_index_statistics()
[IndexStats(contig='chr1', mapped=310538, unmapped=940, total=311478), IndexStats(contig='chr2', mapped=0, unmapped=0, total=0), IndexStats(contig='chr3', mapped=0, unmapped=0, total=0), IndexStats(contig='chr4', mapped=0, unmapped=0, total=0), IndexStats(contig='chr5', mapped=0, unmapped=0, total=0), IndexStats(contig='chr6', mapped=0, unmapped=0, total=0), IndexStats(contig='chr7', mapped=0, unmapped=0, total=0), IndexStats(contig='chr8', mapped=0,unmapped=0,
total=0), IndexStats(contig='chr9', mapped=0, unmapped=0, total=0), IndexStats(contig='chr10', mapped=0, unmapped=0, total=0), IndexStats(contig='chr11', mapped=0, unmapped=0, total=0), IndexStats(contig='chr12', mapped=0, unmapped=0, total=0), IndexStats(contig='chr13', mapped=0, unmapped=0, total=0), IndexStats(contig='chr14', mapped=0, unmapped=0, total=0), IndexStats(contig='chr15', mapped=0, unmapped=0, total=0), IndexStats(contig='chr16', mapped=0, unmapped=0, total=0), IndexStats(contig='chr17', mapped=0, unmapped=0, total=0), IndexStats(contig='chr18', mapped=0, unmapped=0, total=0), IndexStats(contig='chr19', mapped=0, unmapped=0, total=0), IndexStats(contig='chr20', mapped=0, unmapped=0, total=0), IndexStats(contig='chr21', mapped=0, unmapped=0, total=0), IndexStats(contig='chr22', mapped=0, unmapped=0, total=0), IndexStats(contig='chrX', mapped=0, unmapped=0, total=0), IndexStats(contig='chrY', mapped=0, unmapped=0, total=0), IndexStats(contig='chrM', mapped=0, unmapped=0, total=0)]
- get_reference_name(self, tid)
得到tid(数字)相对应的reference name(字符串),例如在这个BAM中tid为0代表chr1,tid为1代表chr2,tid为24代表chrM。
>>> samfile.get_reference_name(0)
'chr1'
>>> samfile.get_reference_name(1)
'chr2'
>>> samfile.get_reference_name(24)
'chrM'
- get_tid(self, reference)
相似的,将reference转换成tid
>>> samfile.get_tid('chr2')
1
- has_index(self)
如果hts文件存在打开的index文件则返回True。 - head(self, n, multiple_iterators=True)
返回含有前n个比对reads的迭代器,常用于检查bam文件。 - header
得到BAM文件的头文件,用字典表示。 - is_valid_tid(self, tid)
判断这个tid是否存在(合法),若存在则返回True。 - lengths
返回各个reference的长度的一个元组。 - mapped
返回比对的上(mapped)的reads个数。 - unmapped
返回未比对的上(unmapped)的reads个数。 - mate(self, AlignedSegment read)
返回传入的AlignedSegment read的另一配对reads(mate reads)。
>>> reads1
>>> samfile.mate(reads1)
- nocoordinate
通过index文件统计没有比对坐标的reads数目 - nreferences
返回reference的个数 - pileup(self, contig=None, start=None, stop=None, region=None, reference=None, end=None, **kwargs)
类似于samtools的pileup操作,返回一个迭代器,每次迭代返回一个位点的PileupColumn对象,该对象的操作在后面进行详细介绍。
>>> pileupcolumn = samfile.pileup("chr1", 999863, 999865,truncate=True)
>>> pileupcolumn
>>> pc=next(pileupcolumn)
>>> pc
- references
得到所有的reference name。
>>> samfile.references
('chr1', 'chr2', 'chr3', 'chr4', 'chr5', 'chr6', 'chr7', 'chr8', 'chr9', 'chr10', 'chr11', 'chr12', 'chr13', 'chr14', 'chr15', 'chr16', 'chr17', 'chr18', 'chr19', 'chr20', 'chr21', 'chr22', 'chrX', 'chrY', 'chrM')
- text
得到字符串类型的BAM header信息 - write(self, AlignedSegment read) → int
向samfile中写入信息(AlignedSegment格式reads)
AlignedSegmennt对象内置方法
该对象代表了某个比对上的segment。使用以下的内置方法属性来查询操作这个segment。
- bin
不知道什么意思 - cigarstring
该segment的cigar,同bam文件中一个segment记录的cigar字段,字符串格式。
>>> reads1.cigarstring
'151M'
- cigartuples
cigar记录的元组格式,下面的例子就代表了151M(0 代表 M)。
>>> reads1.cigartuples
[(0, 151)]
alignment | meaning | operation |
---|---|---|
M | BAM_CMATCH | 0 |
I | BAM_CINS | 1 |
D | BAM_CDEL | 2 |
N | BAM_CREF_SKIP | 3 |
S | BAM_CSOFT_CLIP | 4 |
H | BAM_CHARD_CLIP | 5 |
P | BAM_CPAD | 6 |
= | BAM_CEQUAL | 7 |
X | BAM_CDIFF | 8 |
B | BAM_CBACK | 9 |
- compare(self, AlignedSegment other)
和其他AlignedSegment比较,值为两个segment在reference上坐标差值
>>> reads1.compare(reads2)
-17
- flag
返回该segment的flag信息 - get_aligned_pairs(self, matches_only=False, with_seq=False)
展示了query和reference之间的比对情况,如果遇到indel或者skipping的情况,相应的query或者reference会变为None
>>> reads1.get_aligned_pairs(matches_only=False, with_seq=True)
[(0, 999850, 'C'), (1, 999851, 'G'), (2, 999852, 'G'), (3, 999853, 'C'), (4, 999854, 'C'), (5, 999855, 'G'), (6, 999856, 'G'), (7, 999857, 'G'), (8, 999858, 'A'), (9, 999859, 'C'), (10, 999860, 'C'), (11, 999861, 'C'), (12, 999862, 'C'), (13, 999863, 'A'), (14, 999864, 'C'), (15, 999865, 'C'), (16, 999866, 'T'), (17, 999867, 'T'), (18, 999868, 'G'), (19, 999869, 'C'), (20, 999870, 'G'), (21, 999871, 'G'), (22, 999872, 'T'), (23, 999873, 'G'), (24, 999874, 'C'), (25, 999875, 'T'), (26, 999876, 'C'), (27, 999877, 'G'), (28, 999878, 'G'), (29, 999879, 'C'), (30, 999880, 'C'), (31, 999881, 'G'), (32, 999882, 'C'), (33, 999883, 'G'), (34, 999884, 'C'), (35, 999885, 'T'), (36, 999886, 'C'), (37, 999887, 'C'), (38, 999888, 'G'), (39, 999889, 'G'), (40, 999890, 'G'), (41, 999891, 'G'), (42, 999892, 'C'), (43, 999893, 'T'), (44, 999894, 'T'), (45, 999895, 'G'), (46, 999896, 'T'), (47, 999897, 'C'), (48, 999898, 'T'), (49, 999899, 'G'), (50, 999900, 'G'), (51, 999901, 'G'), (52, 999902, 'G'), (53, 999903, 'T'), (54, 999904, 'C'), (55, 999905, 'C'), (56, 999906, 'G'), (57, 999907, 'G'), (58, 999908, 'C'), (59, 999909, 'T'), (60, 999910, 'G'), (61, 999911, 'G'), (62, 999912, 'C'), (63, 999913, 'G'), (64, 999914, 'C'), (65, 999915, 'T'), (66, 999916, 'G'), (67, 999917, 'G'), (68, 999918, 'C'), (69, 999919, 'C'), (70, 999920, 'G'), (71, 999921, 'G'), (72, 999922, 'C'), (73, 999923, 'G'), (74, 999924, 'C'), (75, 999925, 'T'), (76, 999926, 'C'), (77, 999927, 'C'), (78, 999928, 'T'), (79, 999929, 'G'), (80, 999930, 'C'), (81, 999931, 'C'), (82, 999932, 'A'), (83, 999933, 'T'), (84, 999934, 'C'), (85, 999935, 'G'), (86, 999936, 'G'), (87, 999937, 'C'), (88, 999938, 'G'), (89, 999939, 'A'), (90, 999940, 'G'), (91, 999941, 'G'), (92, 999942, 'C'), (93, 999943, 'G'), (94, 999944, 'C'), (95, 999945, 'T'), (96, 999946, 'C'), (97, 999947, 'G'), (98, 999948, 'G'), (99, 999949, 'T'), (100, 999950, 'T'), (101, 999951, 'T'), (102, 999952, 'C'), (103, 999953, 'C'), (104, 999954, 'C'), (105, 999955, 'C'), (106, 999956, 'G'), (107, 999957, 'G'), (108, 999958, 'C'), (109, 999959, 'G'), (110, 999960, 'T'), (111, 999961, 'G'), (112, 999962, 'T'), (113, 999963, 'C'), (114, 999964, 'T'), (115, 999965, 'G'), (116, 999966, 'C'), (117, 999967, 'G'), (118, 999968, 'G'), (119, 999969, 'C'), (120, 999970, 'C'), (121, 999971, 'A'), (122, 999972, 'T'), (123, 999973, 'G'), (124, 999974, 'G'), (125, 999975, 'T'), (126, 999976, 'G'), (127, 999977, 'C'), (128, 999978, 'G'), (129, 999979, 'C'), (130, 999980, 'C'), (131, 999981, 'C'), (132, 999982, 'C'), (133, 999983, 'G'), (134, 999984, 'C'), (135, 999985, 'G'), (136, 999986, 'C'), (137, 999987, 'C'), (138, 999988, 'T'), (139, 999989, 'C'), (140, 999990, 'C'), (141, 999991, 'C'), (142, 999992, 'C'), (143, 999993, 'G'), (144, 999994, 'T'), (145, 999995, 'G'), (146, 999996, 'C'), (147, 999997, 'C'), (148, 999998, 'G'), (149, 999999, 'G'), (150, 1000000, 'G')]
- get_blocks(self)
返回该segment比对到reference的start和end坐标。 - get_cigar_stats(self)
同样返回cigar信息,不过是两个arrays的形式。
>>> reads1.get_cigar_stats()
(array('I', [151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), array('I', [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]))
>>> reads2.get_cigar_stats()
(array('I', [151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), array('I', [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]))
>>> reads3.get_cigar_stats()
(array('I', [134, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0]), array('I', [1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]))
- get_overlap(self, uint32_t start, uint32_t end)
返回和reference传入参数区域内比对上的碱基数
>>> reads1.get_blocks()
[(999850, 1000001)]
>>> reads1.get_overlap(999950, 1000010)
51
- get_reference_positions(self, full_length=False)
返回和reference比对上的位置列表,数值为ref上的位置 - get_reference_sequence(self)
返回该reads比对到的ref区域的reference碱基。
>>> reads1.get_reference_sequence()
'CGGCCGGGACCCCACCTTGCGGTGCTCGGCCGCGCTCCGGGGCTTGTCTGGGGTCCGGCTGGCGCTGGCCGGCGCTCCTGCCATCGGCGAGGCGCTCGGTTTCCCCGGCGTGTCTGCGGCCATGGTGCGCCCCGCGCCTCCCCGTGCCGGG'
- get_tags(self, with_value_type=False)
得到该segment的tag信息
>>> reads1.get_tags()
[('MC', '151M'), ('BD', 'MMMOQNNKOPNJJNKMNLMOKLNKOOMMLNNKNKNOMNKLIINPMNLPNPOJJOPOLMOPPOOLOPPOOOLMOLOPNONPPOOPQNMOLPOPOLOPNNMONDNOKKLMOLPLLPNPPLMOOOPPOOLPLOOKKLOLOPPOPLLNRNROLMJ'), ('MD', '151'), ('PG', 'MarkDuplicates.H'), ('RG', 'group1'), ('BI', 'OOPQQOQLRRPKKQNOQOPQNOPNQQNOPPONQOQROPNPLLQRPQOSQSQLLQSPNPQRSQQOQRSQQPNPQOQRPPRSRPRQRPPQOSRQQPRSOPPQPHRPLLNQRPRPPTRTSPQRQSRSRRPSPRQMMORPRQSPQMMOQQTPNPL'), ('NM', 0), ('MQ', 60), ('AS', 151), ('XS', 0)]
- get_tag(self, tag, with_value_type=False)
查询某个tag的值
>>> reads1.get_tag( 'MC')
'151M'
- has_tag(self, tag)
查询是否有某个tag值,若有则返回True。 - infer_query_length(self, always=False)
通过CIGAR推断query的长度,不包括hard-clipped区域碱基 - infer_reads_length(self)
通过CIGAR推断reads的长度,包括hard-clipped区域碱基 - is_duplicate
判断是否是PCR duplicate - is_paired
判断reads是不是成对的 - is_proper_pair
判断reads对是否都比对上了 - is_qcfail
判断是否QC失败了 - is_read1
判断是否是read1 - is_read2
判断是否是read2 - is_reverse
判断是否比对到了ref的负义链上 - is_secondary
若不是primary比对则返回true - is_supplementary
判断是否是supplementary比对 - is_unmapped
判断是否没比对上 - mapping_quality
比对质量 - mate_is_reverse
配对reads是否比对到负义链 - mate_is_unmapped
配对reads是否没比对上 - next_reference_id
配对reads比对上的reference id - next_refernece_name
配对reads比对上的reference name - next_reference_start
配对reads比对在reference的起始位置 - query_alignment_end
query比对上ref的结束位置,数值为query上的相对位置
>>> reads1.query_alignment_end
151
- query_alignment_start
query比对上ref的起始位置,数值为query上的相对位置 - query_alignment_length
相当于query_alignment_end-query_alignment_start - query_alignment_qualities
query比对上ref的碱基的质量值
>>> reads1.query_alignment_qualities
array('B', [28, 26, 29, 34, 33, 28, 32, 32, 29, 35, 34, 34, 34, 30, 35, 34, 35, 30, 37, 37, 29, 32, 28, 37, 37, 35, 36, 29, 32, 37, 34, 29, 37, 29, 37, 35, 36, 34, 29, 32, 32, 32, 37, 35, 30, 37, 28, 36, 35, 37, 32, 32, 32, 28, 36, 34, 29, 32, 37, 35, 37, 32, 37, 29, 37, 35, 37, 32, 37, 34, 29, 32, 37, 29, 37, 35, 36, 34, 35, 37, 37, 34, 30, 28, 36, 29, 32, 37, 29, 14, 37, 32, 37, 29, 37, 35, 36, 29, 32, 28, 30, 30, 36, 34, 34, 34, 29, 32, 37, 29, 28, 37, 28, 36, 35, 37, 37, 29, 32, 37, 34, 30, 28, 37, 32, 28, 37, 37, 29, 37, 34, 34, 34, 29, 37, 29, 37, 34, 35, 36, 34, 34, 34, 29, 28, 36, 35, 30, 23, 26, 26])
- query_alignment_sequence
query比对上ref的碱基 - query_length
query的长度 - query_name
query的名字 - query_qualities
query的碱基质量值,这个和query_alignment_qualities不一样,query_alignment_qualities为query比对上那部分序列的碱基质量值,若存在soft-clip,query_alignment_qualities的碱基质量值个数会少相应的部分。 - query_sequence
query碱基序列 - reference_id
比对上的reference ID - reference_name
比对上的reference name - reference_length
和reference能比对上的序列的长度 - reference_start
和reference能比对上部分的起始坐标(reference坐标) - set_tag(self, tag, value, value_type=None, replace=True)
设定tag值 - set_tags(self, tags)
重新设定tag
PileupColumn对象内置方法
之前说到AlignmentFile对象使用pileup方法产生一个存储了PileupColumn对象的迭代器,这个PileupColumn对象就代表了某个位点上的pileup结果。通过PileupColumn对象的内置方法我们可以得到更多的信息。
- nsegments
在这个pileupcolumn上比对上的segment个数 - pileups
返回一个列表,列表中的元素为PuleupRead对象
>>> pr=pc.pileups
>>> pr1 = pr[0]
>>> pr1
- reference_id
- reference_name
- reference_pos
这个pileupcolumn在ref上的位置
PileupRead对象内置方法
代表了比对到ref某个位置的reads。
- alignment
返回一个AlignedSegment对象
>>> pr1.alignment
- indel
后面的碱基是否处在indel上,若在insertion上则返回正数,数值为insertion长度,若在deltion上则为负数,数值为deltion长度。 - is_del
此位点的碱基是否处在deltion上,若是则返回1,不是则返回0。 - id_head
此位点的碱基是否是比对上的第一个碱基,若是则返回1,不是则返回0。 - is_refskip
此位点的碱基是否是CIGAR N碱基,若是则返回1,不是则返回0。 - is_tail
此位点的碱基是否是比对上的最后一个碱基,若是则返回1,不是则返回0。 - level
the level of the read in the “viewer” mode. Note that this value is currently not computed. - query_position
该碱基位点在query上的位置,0代表第一个。若处在deltion上或者是refskip则返回None。 - query_position_or_next
同上,但是如果此位点是deltion则返回下一个碱基的位置。