4

给你一些背景信息:我正在尝试将 sam 文件转换为 bam

samtools view -bT reference.fasta sequences.sam > sequences.bam

退出并出现以下错误

[E::sam_parse1] CIGAR and query sequence are of different length
[W::sam_read1] parse error at line 102
[main_samview] truncated file

违规行如下所示:

SRR808297.2571281       99      gi|309056|gb|L20934.1|MSQMTCG   747     80      101M    =       790     142     TTGGTATAAAATTTAATAATCCCTTATTAATTAATAAACTTCGGCTTCCTATTCGTTCATAAGAAATATTAGCTAAACAAAATAAACCAGAAGAACAT      @@CFDDFD?HFDHIGEGGIEEJIIJJIIJIGIDGIGDCHJJCHIGIJIJIIJJGIGHIGICHIICGAHDGEGGGGACGHHGEEEFDC@=?CACC>CCC      NM:i:2  MD:Z:98A1A

我的序列长 98 个字符,但在创建 sam 文件时可能存在错误,在 CIGAR 中报告了 101。我可以让自己奢侈地丢失几次读取,并且我目前无法访问生成 sam 文件的源代码,因此没有机会寻找错误并重新运行对齐。换句话说,我需要一个务实的解决方案来继续前进(目前)。因此,我设计了一个 python 脚本来计算我的核苷酸字符串的长度,将其与 CIGAR 中注册的内容进行比较,并将“正常”行保存在一个新文件中。

#!/usr/bin/python
import itertools
import cigar

with open('myfile.sam', 'r') as f:
    for line in itertools.islice(f,3,None): #Loop through the file and skip the first three lines
            cigar=line.split("\t")[5]
            cigarlength = len(Cigar(cigar)) #Use module Cigar to obtain the length reported in the CIGAR string
            seqlength = len(line.split("\t")[9])

            if (cigarlength == seqlength):
                    ...Preserve the line in a new file...

如您所见,要将 CIGAR 转换为显示长度的整数,我正在使用模块CIGAR。老实说,我对它的行为有点警惕。在非常明显的情况下,这个模块似乎错误地计算了长度。是否有另一个模块或更明确的策略将 CIGAR 转换为序列的长度?

旁注:有趣的是,至少可以说,这个问题已被广泛报道,但在互联网上找不到实用的解决方案。请参阅以下链接:

https://github.com/COMBINE-lab/RapMap/issues/9
http://seqanswers.com/forums/showthread.php?t=67253
http://seqanswers.com/forums/showthread.php?t=21120
https://groups.google.com/forum/#!msg/snap-user/FoDsGeNBDE0/nRFq-GhlAQAJ
4

2 回答 2

2

我怀疑没有解决此问题的工具的原因是因为没有通用解决方案,除了使用没有出现此问题的软件再次执行对齐之外。在您的示例中,查询序列与参考完全对齐,因此在这种情况下,CIGAR 字符串不是很有趣(只是一个M以总查询长度为前缀的 atch 操作)。在这种情况下,修复只需要更改101M98M.

但是,对于更复杂的 CIGAR 字符串(例如,那些包含I插入、D删除或任何其他操作的字符串),您将无法知道 CIGAR 字符串的哪一部分太长。如果您从 CIGAR 字符串的错误部分中减去,您将得到一个未对齐的读数,这对于您的下游分析可能比只留下整个读数更糟糕。

也就是说,如果它恰好是微不足道的(也许你损坏的对齐过程总是在第一个或最后一个 CIGAR 操作中添加额外的碱基),那么你需要知道的是根据CIGAR 字符串,以便您知道要从中减去什么。

samtoolshtslib使用函数bam_cigar2qlen计算此值。

调用的其他函数bam_cigar2qlensam.h中定义,包括一个有用的注释,显示操作消耗查询序列与参考序列的真值表。

简而言之,要以 samtools(实际上是 htslib)的方式计算 CIGAR 字符串的查询长度,您应该为 CIGAR 操作添加给定的长度,或者M忽略任何其他操作的 CIGAR 操作的长度.IS=X

当前版本的 python cigar 模块似乎使用相同的一组操作,并且计算查询长度(len(Cigar(cigar))将返回的内容)的算法对我来说看起来很合适。是什么让您认为它没有给出正确的结果?

看起来您应该能够使用 cigar python 模块使用mask_leftormask_right方法从左端或右端硬剪辑mask="H"

于 2016-10-02T01:18:55.617 回答
1

SAM规范为我们提供了这张 CIGAR 操作表,它指示哪些“消耗”查询或引用,并附有关于如何从 CIGAR 字符串计算序列长度的明确说明:

                                                             Consumes  Consumes
Op  BAM Description                                             query  reference
M   0   alignment match (can be a sequence match or mismatch)   yes   yes
I   1   insertion to the reference                              yes   no
D   2   deletion from the reference                             no    yes
N   3   skipped region from the reference                       no    yes
S   4   soft clipping (clipped sequences present in SEQ)        yes   no
H   5   hard clipping (clipped sequences NOT present in SEQ)    no    no
P   6   padding (silent deletion from padded reference)         no    no
=   7   sequence match                                          yes   yes
X   8   sequence mismatch                                       yes   yes
  • “使用查询”和“使用参考”表示 CIGAR 操作是否导致对齐分别沿着查询序列和参考序列进行。

...

  • M/I/S/=/X 操作的长度之和应等于 SEQ 的长度。

这让我们可以通过将 CIGAR 中所有“消费查询”操作的长度相加,轻松地从其 CIGAR 计算序列的长度。这正是雪茄模块中发生的事情(参见https://github.com/brentp/cigar/blob/754cfed348364d390ec1aa40c951362ca1041f7a/cigar.py#L88-L93),所以我不知道为什么这里的 OP 认为该模块的实现错了。

如果我们从(已经很短的)雪茄模块中提取相关代码,我们将得到类似这样的东西,作为上面引用中描述的求和操作的简短 Python 实现:

from itertools import groupby

def query_len(cigar_string):
    """
    Given a CIGAR string, return the number of bases consumed from the
    query sequence.
    """
    read_consuming_ops = ("M", "I", "S", "=", "X")
    result = 0
    cig_iter = groupby(cigar_string, lambda chr: chr.isdigit())
    for _, length_digits in cig_iter:
        length = int(''.join(length_digits))
        op = next(next(cig_iter)[1])
        if op in read_consuming_ops:
            result += length
    return result
于 2019-07-07T16:38:07.430 回答