Skip to content

Commit 91d73be

Browse files
committed
Use mapping position of read1 in addition to query name as a mate pair's key in get_readpairs
This should make get_readpairs work also for multi-mapped data, as long as mates aren't re-used in multiple (multi-mapped) pairs.
1 parent f81bb13 commit 91d73be

1 file changed

Lines changed: 21 additions & 10 deletions

File tree

umi_tools/umi_methods.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,6 +1108,10 @@ class get_readpairs:
11081108
# Used in place of a real read in incomplete pairs before they are completed
11091109
PendingMate = object()
11101110

1111+
# Read key. To allow for multi-mapping, we also use the mapping position
1112+
def get_pair_key(self, read):
1113+
return (read.qname, read.reference_start if not read.is_read2 == 0 else read.next_reference_start)
1114+
11111115
def drain_queue_forcibly(self):
11121116
# Forcibly convert incomplete queued pairs into singletons.
11131117
# These necessarily contains only a read1, but not read2, since we
@@ -1117,15 +1121,15 @@ def drain_queue_forcibly(self):
11171121
if pair[1] is get_readpairs.PendingMate:
11181122
pair[1] = None
11191123
U.warn("inconsistent BAM file: only read1 of proper pair %s found on chromosome %s, treating as unpaired" %
1120-
(pair[0].qname, pair[0].reference_name))
1124+
(str(self.get_pair_key(pair[0])), pair[0].reference_name))
11211125
yield pair
11221126
# Forcibly convert also incomplete unqueued pairs into singletons.
11231127
# These are the ones that contain only a read2 but no read1
11241128
for pair in self.incomplete_pairs.values():
11251129
if pair[0] is get_readpairs.PendingMate:
11261130
pair[0] = None
11271131
U.warn("inconsistent BAM file: only read2 of proper pair %s found on chromosome %s, treating as unpaired" %
1128-
(pair[1].qname, pair[1].reference_name))
1132+
(str(self.get_pair_key(pair[1])), pair[1].reference_name))
11291133
yield pair
11301134
self.incomplete_pairs.clear()
11311135

@@ -1135,35 +1139,42 @@ def __call__(self, inreads):
11351139
self.current_chr = None
11361140

11371141
for read in inreads:
1138-
read_i = int(read.is_read2)
11391142
read_chr = read.reference_name
1143+
# Read index. 0 for read1 and 1 for read2
1144+
read_i = int(read.is_read2)
1145+
pair_key = self.get_pair_key(read)
11401146

11411147
# Output leftover incomplete read pairs if the chrosomome changes
11421148
if self.current_chr is not None and self.current_chr != read_chr:
11431149
for queue_entry in self.drain_queue_forcibly():
11441150
yield queue_entry
11451151
self.current_chr = read_chr
11461152

1147-
# Queue read, either as a singleton, or as part of a read pair
1148-
if read.is_unmapped or read.mate_is_unmapped or not read.is_proper_pair:
1153+
# Queue read, either as a singleton, or as part of a read pair.
1154+
# Proper pairs should always have both mates mapped to the same chromosome,
1155+
# but to avoid weird behaviour for broken BAM file, we re-check.
1156+
if ((not read.is_proper_pair) or
1157+
read.is_unmapped or
1158+
read.mate_is_unmapped or
1159+
(read.reference_id != read.next_reference_id)):
11491160
# Read is not part of a proper pair. Enqueue as singleton
11501161
pair = [None, None]
11511162
pair[read_i] = read
11521163
self.queue.append(pair)
11531164
else:
1154-
if read.qname in self.incomplete_pairs:
1165+
if pair_key in self.incomplete_pairs:
11551166
# Read is part of an already queued (incomplete) read pair. Complete it.
1156-
pair = self.incomplete_pairs.pop(read.qname)
1167+
pair = self.incomplete_pairs.pop(pair_key)
11571168
if pair[read_i] is not get_readpairs.PendingMate:
1158-
U.warn("inconsistent BAM file: both mates %s flagged to be read%d" %
1159-
(read.qname, read_i+1))
1169+
U.warn("inconsistent BAM file: both mates of %s flagged to be read%d" %
1170+
(str(pair_key), read_i+1))
11601171
read_i = 1 - read_i
11611172
pair[read_i] = read
11621173
else:
11631174
# Read is part of a new read pair. Create incomplete pair
11641175
pair = [get_readpairs.PendingMate, get_readpairs.PendingMate]
11651176
pair[read_i] = read
1166-
self.incomplete_pairs[read.qname] = pair
1177+
self.incomplete_pairs[pair_key] = pair
11671178
# Enqueue pair in the correct place for its 1st read
11681179
if read_i == 0:
11691180
self.queue.append(pair)

0 commit comments

Comments
 (0)