annotate tools/indels/indel_sam2interval.py @ 0:9071e359b9a3

Uploaded
author xuebing
date Fri, 09 Mar 2012 19:37:19 -0500
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
1 #!/usr/bin/env python
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
2
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
3 """
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
4 Allows user to filter out non-indels from SAM.
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
5
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
6 usage: %prog [options]
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
7 -i, --input=i: The input SAM file
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
8 -u, --include_base=u: Whether or not to include the base for insertions
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
9 -c, --collapse=c: Wheter to collapse multiple occurrences of a location with counts shown
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
10 -o, --int_out=o: The interval output file for the converted SAM file
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
11 -b, --bed_ins_out=b: The bed output file with insertions only for the converted SAM file
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
12 -d, --bed_del_out=d: The bed output file with deletions only for the converted SAM file
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
13 """
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
14
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
15 import re, sys
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
16 from galaxy import eggs
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
17 import pkg_resources; pkg_resources.require( "bx-python" )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
18 from bx.cookbook import doc_optparse
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
19
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
20
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
21 def stop_err( msg ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
22 sys.stderr.write( '%s\n' % msg )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
23 sys.exit()
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
24
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
25 def numeric_sort( text1, text2 ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
26 """
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
27 For two items containing space-separated text, compares equivalent pieces
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
28 numerically if both numeric or as text otherwise
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
29 """
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
30 pieces1 = text1.split()
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
31 pieces2 = text2.split()
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
32 if len( pieces1 ) == 0:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
33 return 1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
34 if len( pieces2 ) == 0:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
35 return -1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
36 for i, pc1 in enumerate( pieces1 ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
37 if i == len( pieces2 ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
38 return 1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
39 if not pieces2[i].isdigit():
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
40 if pc1.isdigit():
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
41 return -1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
42 else:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
43 if pc1 > pieces2[i]:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
44 return 1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
45 elif pc1 < pieces2[i]:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
46 return -1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
47 else:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
48 if not pc1.isdigit():
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
49 return 1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
50 else:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
51 if int( pc1 ) > int( pieces2[i] ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
52 return 1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
53 elif int( pc1 ) < int( pieces2[i] ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
54 return -1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
55 if i < len( pieces2 ) - 1:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
56 return -1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
57 return 0
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
58
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
59 def __main__():
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
60 #Parse Command Line
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
61 options, args = doc_optparse.parse( __doc__ )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
62
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
63 # open up output files
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
64 output = open( options.int_out, 'wb' )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
65 if options.bed_ins_out != 'None':
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
66 output_bed_ins = open( options.bed_ins_out, 'wb' )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
67 else:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
68 output_bed_ins = None
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
69 if options.bed_del_out != 'None':
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
70 output_bed_del = open( options.bed_del_out, 'wb' )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
71 else:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
72 output_bed_del = None
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
73
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
74 # the pattern to match, assuming just one indel per cigar string
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
75 pat_indel = re.compile( '^(?P<lmatch>\d+)M(?P<ins_del_width>\d+)(?P<ins_del>[ID])(?P<rmatch>\d+)M$' )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
76 pat_multi = re.compile( '(\d+[MIDNSHP])(\d+[MIDNSHP])(\d+[MIDNSHP])+' )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
77
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
78 # go through all lines in input file
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
79 out_data = {}
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
80 multi_indel_lines = 0
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
81 for line in open( options.input, 'rb' ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
82 if line and not line.startswith( '#' ) and not line.startswith( '@' ) :
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
83 split_line = line.split( '\t' )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
84 if split_line < 12:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
85 continue
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
86 # grab relevant pieces
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
87 cigar = split_line[5].strip()
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
88 pos = int( split_line[3] )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
89 chr = split_line[2]
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
90 base_string = split_line[9]
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
91 # parse cigar string
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
92 m = pat_indel.match( cigar )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
93 if not m:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
94 m = pat_multi.match( cigar )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
95 # skip this line if no match
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
96 if not m:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
97 continue
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
98 # account for multiple indels or operations we don't process
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
99 else:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
100 multi_indel_lines += 1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
101 continue
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
102 else:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
103 match = m.groupdict()
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
104 left = int( match[ 'lmatch' ] )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
105 middle = int( match[ 'ins_del_width' ] )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
106 middle_type = match[ 'ins_del' ]
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
107 bases = base_string[ left : left + middle ]
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
108 # calculate start and end positions, and output to insertion or deletion file
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
109 start = left + pos
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
110 if middle_type == 'D':
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
111 end = start + middle
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
112 data = [ chr, start, end, 'D' ]
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
113 if options.include_base == "true":
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
114 data.append( '-' )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
115 else:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
116 end = start + 1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
117 data = [ chr, start, end, 'I' ]
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
118 if options.include_base == "true":
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
119 data.append( bases )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
120 location = '\t'.join( [ '%s' % d for d in data ] )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
121 try:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
122 out_data[ location ] += 1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
123 except KeyError:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
124 out_data[ location ] = 1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
125 # output to interval file
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
126 # get all locations and sort
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
127 locations = out_data.keys()
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
128 locations.sort( numeric_sort )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
129 last_line = ''
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
130 # output each location, either with counts or each occurrence
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
131 for loc in locations:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
132 sp_loc = loc.split( '\t' )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
133 cur_line = '\t'.join( sp_loc[:3] )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
134 if options.collapse == 'true':
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
135 output.write( '%s\t%s\n' % ( loc, out_data[ loc ] ) )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
136 if output_bed_del and sp_loc[3] == 'D':
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
137 output_bed_del.write( '%s\n' % cur_line )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
138 if output_bed_ins and sp_loc[3] == 'I' and last_line != cur_line:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
139 output_bed_ins.write( '%s\n' % cur_line )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
140 last_line = cur_line
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
141 else:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
142 for i in range( out_data[ loc ] ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
143 output.write( '%s\n' % loc )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
144 if output_bed_del or output_bed_ins:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
145 if output_bed_del and sp_loc[3] == 'D':
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
146 output_bed_del.write( '%s\n' % cur_line )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
147 if output_bed_ins and sp_loc[3] == 'I':
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
148 output_bed_ins.write( '%s\n' % cur_line )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
149
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
150 # cleanup, close files
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
151 if output_bed_ins:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
152 output_bed_ins.close()
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
153 if output_bed_del:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
154 output_bed_del.close()
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
155 output.close()
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
156
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
157 # if skipped lines because of more than one indel, output message
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
158 if multi_indel_lines > 0:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
159 sys.stdout.write( '%s alignments were skipped because they contained more than one indel.' % multi_indel_lines )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
160
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
161 if __name__=="__main__": __main__()