annotate tools/maf/vcf_to_maf_customtrack.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 #Dan Blankenberg
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
2 from optparse import OptionParser
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
3 import sys
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
4 import galaxy_utils.sequence.vcf
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
5
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
6 from galaxy import eggs
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
7 import pkg_resources; pkg_resources.require( "bx-python" )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
8 import bx.align.maf
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
9
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
10 UNKNOWN_NUCLEOTIDE = '*'
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
11
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
12 class PopulationVCFParser( object ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
13 def __init__( self, reader, name ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
14 self.reader = reader
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
15 self.name = name
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
16 self.counter = 0
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
17 def next( self ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
18 rval = []
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
19 vc = self.reader.next()
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
20 for i, allele in enumerate( vc.alt ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
21 rval.append( ( '%s_%i.%i' % ( self.name, i + 1, self.counter + 1 ), allele ) )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
22 self.counter += 1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
23 return ( vc, rval )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
24 def __iter__( self ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
25 while True:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
26 yield self.next()
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
27
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
28 class SampleVCFParser( object ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
29 def __init__( self, reader ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
30 self.reader = reader
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
31 self.counter = 0
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
32 def next( self ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
33 rval = []
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
34 vc = self.reader.next()
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
35 alleles = [ vc.ref ] + vc.alt
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
36
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
37 if 'GT' in vc.format:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
38 gt_index = vc.format.index( 'GT' )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
39 for sample_name, sample_value in zip( vc.sample_names, vc.sample_values ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
40 gt_indexes = []
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
41 for i in sample_value[ gt_index ].replace( '|', '/' ).replace( '\\', '/' ).split( '/' ): #Do we need to consider phase here?
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
42 try:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
43 gt_indexes.append( int( i ) )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
44 except:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
45 gt_indexes.append( None )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
46 for i, allele_i in enumerate( gt_indexes ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
47 if allele_i is not None:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
48 rval.append( ( '%s_%i.%i' % ( sample_name, i + 1, self.counter + 1 ), alleles[ allele_i ] ) )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
49 self.counter += 1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
50 return ( vc, rval )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
51 def __iter__( self ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
52 while True:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
53 yield self.next()
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
54
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
55 def main():
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
56 usage = "usage: %prog [options] output_file dbkey inputfile pop_name"
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
57 parser = OptionParser( usage=usage )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
58 parser.add_option( "-p", "--population", action="store_true", dest="population", default=False, help="Create MAF on a per population basis")
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
59 parser.add_option( "-s", "--sample", action="store_true", dest="sample", default=False, help="Create MAF on a per sample basis")
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
60 parser.add_option( "-n", "--name", dest="name", default='Unknown Custom Track', help="Name for Custom Track")
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
61 parser.add_option( "-g", "--galaxy", action="store_true", dest="galaxy", default=False, help="Tool is being executed by Galaxy (adds extra error messaging).")
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
62
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
63
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
64 ( options, args ) = parser.parse_args()
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
65
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
66 if len ( args ) < 3:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
67 if options.galaxy:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
68 print >>sys.stderr, "It appears that you forgot to specify an input VCF file, click 'Add new VCF...' to add at least input.\n"
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
69 parser.error( "Need to specify an output file, a dbkey and at least one input file" )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
70
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
71 if not ( options.population ^ options.sample ):
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
72 parser.error( 'You must specify either a per population conversion or a per sample conversion, but not both' )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
73
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
74 out = open( args.pop(0), 'wb' )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
75 out.write( 'track name="%s" visibility=pack\n' % options.name.replace( "\"", "'" ) )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
76
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
77 maf_writer = bx.align.maf.Writer( out )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
78
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
79 dbkey = args.pop(0)
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
80
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
81 vcf_files = []
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
82 if options.population:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
83 i = 0
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
84 while args:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
85 filename = args.pop( 0 )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
86 pop_name = args.pop( 0 ).replace( ' ', '_' )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
87 if not pop_name:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
88 pop_name = 'population_%i' % ( i + 1 )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
89 vcf_files.append( PopulationVCFParser( galaxy_utils.sequence.vcf.Reader( open( filename ) ), pop_name ) )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
90 i += 1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
91 else:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
92 while args:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
93 filename = args.pop( 0 )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
94 vcf_files.append( SampleVCFParser( galaxy_utils.sequence.vcf.Reader( open( filename ) ) ) )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
95
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
96 non_spec_skipped = 0
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
97 for vcf_file in vcf_files:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
98 for vc, variants in vcf_file:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
99 num_ins = 0
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
100 num_dels = 0
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
101 for variant_name, variant_text in variants:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
102 if 'D' in variant_text:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
103 num_dels = max( num_dels, int( variant_text[1:] ) )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
104 elif 'I' in variant_text:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
105 num_ins = max( num_ins, len( variant_text ) - 1 )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
106
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
107 alignment = bx.align.maf.Alignment()
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
108 ref_text = vc.ref + '-' * num_ins + UNKNOWN_NUCLEOTIDE * ( num_dels - len( vc.ref ) )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
109 start_pos = vc.pos - 1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
110 if num_dels and start_pos:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
111 ref_text = UNKNOWN_NUCLEOTIDE + ref_text
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
112 start_pos -= 1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
113 alignment.add_component( bx.align.maf.Component( src='%s.%s%s' % (
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
114 dbkey, ("chr" if not vc.chrom.startswith("chr") else ""), vc.chrom ),
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
115 start = start_pos, size = len( ref_text.replace( '-', '' ) ),
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
116 strand = '+', src_size = start_pos + len( ref_text ),
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
117 text = ref_text ) )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
118 for variant_name, variant_text in variants:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
119 #FIXME:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
120 ## skip non-spec. compliant data, see: http://1000genomes.org/wiki/doku.php?id=1000_genomes:analysis:vcf3.3 for format spec
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
121 ## this check is due to data having indels not represented in the published format spec,
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
122 ## e.g. 1000 genomes pilot 1 indel data: ftp://ftp-trace.ncbi.nih.gov/1000genomes/ftp/pilot_data/release/2010_03/pilot1/indels/CEU.SRP000031.2010_03.indels.sites.vcf.gz
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
123 if variant_text and variant_text[0] in [ '-', '+' ]:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
124 non_spec_skipped += 1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
125 continue
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
126
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
127 #do we need a left padding unknown nucleotide (do we have deletions)?
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
128 if num_dels and start_pos:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
129 var_text = UNKNOWN_NUCLEOTIDE
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
130 else:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
131 var_text = ''
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
132 if 'D' in variant_text:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
133 cur_num_del = int( variant_text[1:] )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
134 pre_del = min( len( vc.ref ), cur_num_del )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
135 post_del = cur_num_del - pre_del
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
136 var_text = var_text + '-' * pre_del + '-' * num_ins + '-' * post_del
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
137 var_text = var_text + UNKNOWN_NUCLEOTIDE * ( len( ref_text ) - len( var_text ) )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
138 elif 'I' in variant_text:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
139 cur_num_ins = len( variant_text ) - 1
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
140 var_text = var_text + vc.ref + variant_text[1:] + '-' * ( num_ins - cur_num_ins ) + UNKNOWN_NUCLEOTIDE * max( 0, ( num_dels - 1 ) )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
141 else:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
142 var_text = var_text + variant_text + '-' * num_ins + UNKNOWN_NUCLEOTIDE * ( num_dels - len( vc.ref ) )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
143 alignment.add_component( bx.align.maf.Component( src=variant_name, start = 0, size = len( var_text.replace( '-', '' ) ), strand = '+', src_size = len( var_text.replace( '-', '' ) ), text = var_text ) )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
144 maf_writer.write( alignment )
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
145
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
146 maf_writer.close()
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
147
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
148 if non_spec_skipped:
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
149 print 'Skipped %i non-specification compliant indels.' % non_spec_skipped
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
150
9071e359b9a3 Uploaded
xuebing
parents:
diff changeset
151 if __name__ == "__main__": main()