@@ -7,6 +7,43 @@ from cpython cimport bool
77from pysam .libcalignmentfile cimport AlignmentFile , AlignedSegment
88import sys
99
10+
11+ cdef class read_fragment :
12+ cdef :
13+ long start , end
14+
15+ def __init__ (self , frag_start , frag_end ):
16+ self .end = frag_end
17+ self .start = frag_start
18+
19+ def fragment_ends (self ):
20+ return self .start , self .end
21+
22+ def start_site (self ):
23+ return self .start
24+
25+ def end_site (self ):
26+ return self .end
27+
28+
29+ def read_to_fragment (read ):
30+ cdef :
31+ long init_pos , start , end , pos
32+ int i
33+
34+ positions = read .get_reference_positions ()
35+ init_pos = positions [0 ]
36+ start = positions [0 ]
37+
38+ for i , pos in enumerate (positions ):
39+ if pos - init_pos > 1 :
40+ end = init_pos
41+ yield read_fragment (start , end )
42+ start = pos
43+ init_pos = pos
44+ yield read_fragment (start , init_pos )
45+
46+
1047cdef bool qualify_pairs (AlignedSegment read1 , AlignedSegment read2 ):
1148 '''
1249 Only extract concordant proper pairs
@@ -16,6 +53,25 @@ cdef bool qualify_pairs(AlignedSegment read1, AlignedSegment read2):
1653 bool forward_fragment = read1 .flag == 99 and read2 .flag == 147
1754 return reverse_fragment or forward_fragment
1855
56+
57+ def split_fragment_ends (AlignedSegment read1 , AlignedSegment read2 ):
58+ '''
59+ get outer ends of the fragments
60+ '''
61+ cdef :
62+ long start1 , end1 , start2 , end2
63+ long start , end
64+ read_fragment frag_1 , frag_2
65+ bool intersect
66+
67+ for num_frag_1 , frag_1 in enumerate (read_to_fragment (read1 )):
68+ for num_frag_2 , frag_2 in enumerate (read_to_fragment (read2 )):
69+ intersect = frag_1 .end_site () > frag_2 .start_site () and frag_2 .end_site () > frag_1 .start_site ()
70+ if intersect :
71+ start = min (frag_1 .start_site (), frag_2 .start_site ())
72+ end = max (frag_1 .end_site (), frag_2 .end_site ()) + 1
73+ yield start , end
74+
1975def read_ends (AlignedSegment read ):
2076 '''
2177 get read end positions
@@ -59,18 +115,28 @@ def bam_to_bed(bam_file, out_file, int min_size, int max_size):
59115 try :
60116 read_1 = in_bam .next ()
61117 read_2 = in_bam .next ()
62- assert read_1 .query_name == read_2 .query_name , 'Paired not stored together'
118+ assert read_1 .query_name == read_2 .query_name , 'Paired not stored together: %s, %s' % ( read_1 . query_name , read_2 . query_name )
63119 if qualify_pairs (read_1 , read_2 ):
64120 chrom = read_1 .reference_name
65121 strand = '-' if read_1 .is_reverse else '+'
66- start , end = fragment_ends (read_1 , read_2 )
67- fragment_size = end - start
68- if min_size < fragment_size < max_size :
69- line = '%s\t %i\t %i\t %s\t %i\t %s' % (chrom , start , end ,
122+ if 'N' in read_1 .cigarstring or 'N' in read_2 .cigarstring :
123+ for start , end in split_fragment_ends (read_1 , read_2 ):
124+ fragment_size = end - start
125+ if min_size < fragment_size < max_size :
126+ line = '%s\t %i\t %i\t %s\t %i\t %s' % (chrom , start , end ,
127+ read_1 .query_name ,
128+ fragment_size ,strand )
129+ pair_count += 1
130+ print (line , file = out_file )
131+ else :
132+ start , end = fragment_ends (read_1 , read_2 )
133+ fragment_size = end - start
134+ if min_size < fragment_size < max_size :
135+ line = '%s\t %i\t %i\t %s\t %i\t %s' % (chrom , start , end ,
70136 read_1 .query_name ,
71137 fragment_size ,strand )
72- pair_count += 1
73- print (line , file = out_file )
138+ pair_count += 1
139+ print (line , file = out_file )
74140 except StopIteration :
75141 break
76142 sys .stderr .write ('Witten %i fragments\n ' % (pair_count ))
0 commit comments