root/bin/add_utr_start_stop_gff

Revision 221, 9.6 kB (checked in by cholt, 5 months ago)

mpi_iprscan added

  • Property svn:executable set to *
Line 
1 #! /usr/bin/perl -w
2 use strict;
3
4 my $usage = "
5 Usage:
6        add_utr_start_stop_gff <maker_gff3_file>
7
8        Use this script to add UTR and start and stop codon entries
9        to a maker produced gff3 file.
10
11
12 ";
13
14 my $COUNT = 1;
15 my $NUM = 1;
16 my %INDEX;
17
18 my $file = shift;
19 my $header;
20 my $footer;
21
22 if(! $file){
23     print $usage;
24     exit(1);
25 }
26
27 if(! -e $file){
28     warn "ERROR: File does not exist\n";
29     print $usage;
30     exit(1);
31 }
32
33 my @regions = ({chr => 'I',  b => '1000001',  e => '2000000'},
34                {chr => 'I',  b => '14000001', e => '15000000'},
35                {chr => 'II', b => '1',        e => '1000000'},
36                {chr => 'IV', b => '1',        e => '1000000'},
37                {chr => 'IV', b => '14000001', e => '15000000'},
38                {chr => 'IV', b => '7000001',  e => '8000000'},
39                {chr => 'V',  b => '12000001', e => '13000000'},
40                {chr => 'V',  b => '16000001', e => '17000000'},
41                {chr => 'X',  b => '4000001',  e => '5000000'},
42                {chr => 'X',  b => '8000001',  e => '9000000'}
43                );
44
45 #parse file
46 open (IN, "< $file");
47 my @genes;
48 my @mRNAs;
49 my @stuff;
50 my @exons;
51 while (defined(my $line = <IN>)){
52     #skip comments and fasta (add to header and footer)
53     if($line =~ /^\#/){
54         next if($line =~/\#\#\#/);
55         if($line =~ /\#\#FASTA/){
56             $footer .= $line,
57             $footer .= join('', <IN>);
58             last;
59         }
60         $header .= $line;
61         next;
62     }
63
64     #add contig lines to header
65     my $f = parse($line);
66     if($f->{type} eq 'contig'){
67         $header .= $line;
68         next;
69     }
70
71     push(@genes, $f) if($f->{type} eq 'gene');
72     push(@mRNAs, $f) if($f->{type} eq 'mRNA');
73     push(@exons, $f) if($f->{type} eq 'exon');
74     push(@stuff, $f) if($f->{type} eq 'CDS');
75     push(@stuff, $f) if($f->{type} eq 'five_prime_UTR');
76     push(@stuff, $f) if($f->{type} eq 'three_prime_UTR');
77 }
78 close(IN);
79
80 #print header
81 print $header;
82
83 #get fasta index
84 my @data = grep {!/\#\#FASTA/} split("\n", $footer);
85 my %fastas;
86 my $current;
87 while (defined(my $line = shift @data)){
88     if($line =~ /^>([^\s\t\n]+)/){
89         $current = $1;
90     }
91     else{
92         chomp($line);
93         $fastas{$current} .= $line;
94     }
95 }
96
97 #organize UTRs and CDSs
98 my %stuffinx;
99 foreach my $f (@stuff){
100     my $parent = $f->{Parent};
101     if($parent =~ /\,/){
102         my @Ps = split("\,", $parent);
103         foreach my $p (@Ps){
104             my %new_f = %$f; #make a copy
105             $new_f{Parent} = $p;
106             push (@{$stuffinx{$p}}, \%new_f);
107         }
108         next;
109     }
110     push (@{$stuffinx{$parent}}, $f);
111 }
112
113 #organize mRNAs
114 my %mRNAinx;
115 foreach my $f (@mRNAs){
116     my $parent = $f->{Parent};
117     if($parent =~ /\,/){
118         my @Ps = split("\,", $parent);
119         foreach my $p (@Ps){
120             my %new_f = %$f; #make a copy
121             $new_f{Parent} = $p;
122             push (@{$mRNAinx{$p}}, \%new_f);
123         }
124         next;
125     }
126     push (@{$mRNAinx{$parent}}, $f);
127 }
128
129 #organize exons
130 my %exoninx;
131 foreach my $f (@exons){
132     my $parent = $f->{Parent};
133     if($parent =~ /\,/){
134         my @Ps = split("\,", $parent);
135         foreach my $p (@Ps){
136             my %new_f = %$f; #make a copy
137             $new_f{Parent} = $p;
138             push (@{$exoninx{$p}}, \%new_f);
139         }
140         next;
141     }
142     push (@{$exoninx{$parent}}, $f);
143 }
144
145 foreach my $g (@genes){
146     print_it($g);
147     my $g_exons = $exoninx{$g->{ID}};
148     my $g_mRNAs = $mRNAinx{$g->{ID}};
149
150     foreach my $t (@$g_mRNAs){
151         print_it($t);
152         my $t_stuff = $stuffinx{$t->{ID}};
153         my $t_exons = $exoninx{$t->{ID}};
154         if(! $t_exons || ! @$t_exons){
155             $t_exons = [];
156             @$t_exons = get_exons($g_exons, $t_stuff);
157         }
158         @$t_stuff = add_UTRs($t_exons, $t_stuff);
159         my $t_CDS = [grep {$_->{type} eq 'CDS'} @$t_stuff];
160
161         if(!@$t_CDS){
162             sleep 0;
163         }
164
165         my $seq_ref = \$fastas{$t->{seqid}};
166
167         my $start_stop = [];
168         @$start_stop = add_start_stop($t_CDS, $seq_ref);
169
170         print_it(@$t_exons, @$t_stuff, @$start_stop);
171     }
172 }
173
174 #print footer
175 print $footer;
176
177 #------------------------SUBS------------------------
178
179 sub print_it {
180     while(my $f = shift @_){
181         $INDEX{$f->{ID}} = $COUNT;
182
183         print $f->{seqid} . "\t";
184         print $f->{source} . "\t";
185         print $f->{type} . "\t";
186         print $f->{start} . "\t";
187         print $f->{end} . "\t";
188         print $f->{score} . "\t";
189         print $f->{strand} . "\t";
190         print $f->{phase} . "\t";
191         print 'ID='.$COUNT;
192         print ';Name='.$f->{Name};
193         print ';Parent='.$INDEX{$f->{Parent}} if($f->{Parent});
194         print "\n";
195
196         $COUNT++;
197     }
198 }
199
200 sub get_exons{
201     my $exons = shift;
202     my $stuff =shift;
203
204     my $t = $stuff->[0];
205     my $parent = $t->{Parent};
206
207     my @seq;
208     foreach my $stuff (@$stuff){
209         @seq[$stuff->{start}..$stuff->{end}] = map {1} @seq[$stuff->{start}..$stuff->{end}];
210     }
211
212     my @coors;
213     my $start;
214     my $end;
215     for(my $i = 0; $i < @seq; $i++){
216         if($seq[$i]){
217             $start = $i unless($start);
218             $end = $i;
219         }
220         else{
221             if($end){
222                 push(@coors, [$start, $end]);
223                 $start = undef;
224                 $end = undef;
225             }
226         }
227     }
228     push(@coors, [$start, $end]) if(defined $start && defined $end);
229
230     my @keepers;
231     my $i = 1;
232     foreach my $set (@coors){
233         my $b = $set->[0];
234         my $e = $set->[1];
235         my $ok = 0;
236         foreach my $exon (@$exons){
237             if(is_same($exon->{start}, $b, $exon->{end}, $e)){
238                 $exon->{Parent} = $parent;
239                 push(@keepers, $exon);
240                 $ok = 1;
241                 last;
242             }
243         }
244
245         if(! $ok){
246             my $exon = {seqid => $t->{seqid},
247                         source => $t->{source},
248                         type => 'exon',
249                         start => $b,
250                         end => $e,
251                         score => $t->{score},
252                         strand => $t->{strand},
253                         phase => '.',
254                         ID => $parent .":".$i,
255                         Name => $parent .":".$i++,
256                         Parent => $parent};
257
258             push(@keepers, $exon);
259         }
260     }
261
262     return @keepers;
263 }
264
265 sub val{
266     my $val = shift;
267    
268     $val = 0 if(! $val);
269
270     return $val;
271 }
272
273 sub add_start_stop{
274     my $CDSs = shift;
275     my $seq = shift;
276
277     my $f = $CDSs->[0];
278     my $parent = $f->{Parent};
279
280     my $five;
281     my $three;
282     my $start;
283     my $stop;
284
285     if($f->{strand} eq '+'){
286         @$CDSs = sort {$a->{start} <=> $b->{start}} @$CDSs;
287
288         $five = $CDSs->[0]->{start} - 1;
289         $three = $CDSs->[-1]->{end} - 3;
290
291         $start = substr($$seq, $five, 3);
292         $stop = substr($$seq, $three, 3);
293     }
294     else{
295         @$CDSs = sort {$a->{start} <=> $b->{start}} @$CDSs;
296
297         $three = $CDSs->[0]->{start} - 1;
298         $five = $CDSs->[-1]->{end} - 3;
299
300         $start = reverse substr($$seq, $five, 3);
301         $stop = reverse substr($$seq, $three, 3);
302
303         $start =~ tr/ATCG/TAGC/;
304         $stop =~ tr/ATCG/TAGC/;
305     }
306
307     my $i = 1;
308     my @keep;
309     if($start eq 'ATG'){
310         my $codon = {seqid => $f->{seqid},
311                      source => $f->{source},
312                      type => 'start_codon',
313                      start => $five + 1,
314                      end => $five + 3,
315                      score => $f->{score},
316                      strand => $f->{strand},
317                      phase => '.',
318                      ID => $parent .":start".$i,
319                      Name => $parent .":start".$i++,
320                      Parent => $parent};
321
322         push(@keep, $codon);
323     }
324     if($stop =~/^TGA$|^TAA$|^TAG$/){
325         my $codon = {seqid => $f->{seqid},
326                      source => $f->{source},
327                      type => 'stop_codon',
328                      start => $three + 1,
329                      end => $three + 3,
330                      score => $f->{score},
331                      strand => $f->{strand},
332                      phase => '.',
333                      ID => $parent .":stop".$i,
334                      Name => $parent .":stop".$i++,
335                      Parent => $parent};
336         push(@keep, $codon);
337     }
338
339     return @keep;
340 }
341
342 sub add_UTRs{
343     my $exons = shift;
344     my $stuff = shift;
345
346     my $t = $stuff->[0];
347     my $parent = $t->{Parent};
348
349     my @seq;
350     foreach my $exon (@$exons){
351         @seq[$exon->{start}..$exon->{end}] = map {1} @seq[$exon->{start}..$exon->{end}];
352     }
353     foreach my $stuff (@$stuff){
354         @seq[$stuff->{start}..$stuff->{end}] = map {val($_) + 2} @seq[$stuff->{start}..$stuff->{end}];
355     }
356
357     my @coors;
358     my $start;
359     my $end;
360     for(my $i = 0; $i < @seq; $i++){
361         if(defined $seq[$i] && $seq[$i] == 1){
362             $start = $i unless($start);
363             $end = $i;
364         }
365         else{
366             if($end){
367                 push(@coors, [$start, $end]);
368                 $start = undef;
369                 $end = undef;
370             }
371         }
372     }
373     push(@coors, [$start, $end]) if(defined $start && defined $end);
374
375     my @keepers;
376     my $i = 1;
377     foreach my $set (@coors){
378         my $b = $set->[0];
379         my $e = $set->[1];
380
381         my $UTR = {seqid => $t->{seqid},
382                    source => $t->{source},
383                    type => 'UTR',
384                    start => $b,
385                    end => $e,
386                    score => $t->{score},
387                    strand => $t->{strand},
388                    phase => '.',
389                    ID => $parent .":UTR".$i,
390                    Name => $parent .":UTR".$i++,
391                    Parent => $parent};
392        
393         push(@$stuff, $UTR);
394     }
395
396     if($t->{strand} eq '+'){
397         @$stuff = sort {$a->{start} <=> $b->{start}} @$stuff;
398
399         my $utr_type = 'five_prime_UTR';
400         foreach my $f (@$stuff){
401             if($f->{type} eq 'UTR'){
402                 $f->{type} =  $utr_type;
403             }
404             else{
405                 $utr_type = 'three_prime_UTR';
406             }
407         }
408     }
409     else{
410         @$stuff = sort {$b->{start} <=> $a->{start}} @$stuff;
411
412         my $utr_type = 'three_prime_UTR';
413         foreach my $f (@$stuff){
414             if($f->{type} eq 'UTR'){
415                 $f->{type} =  $utr_type;
416             }
417             else{
418                 $utr_type = 'five_prime_UTR';
419             }
420         }
421     }
422
423     return @$stuff;
424 }
425
426 sub parse {
427     my $l = shift;
428    
429     chomp $l;
430     my @F = split("\t", $l);
431     my @att = attrib($F[8]);
432
433     if(my ($r) = grep { $_->{chr} eq $F[0] && $_->{b} <= $F[3] && $F[3] <= $_->{e} } @regions){
434         $F[0] = $r->{chr}.':'.$r->{b}.'..'.$r->{e};
435
436         $F[3] -= ($r->{b} - 1);
437         $F[4] -= ($r->{b} - 1);
438     }
439    
440     my $f = {seqid => $F[0],
441             source => $F[1],
442             type => $F[2],
443             start => $F[3],
444             end => $F[4],
445             score => $F[5],
446             strand => $F[6],
447             phase => $F[7],
448             ID => $att[0],
449             Name => $att[1],
450             Parent => $att[2]};
451
452     return $f;
453 }
454
455 sub attrib {
456     my $att = shift;
457
458     my ($ID) = $att =~ /ID\=([^\;\n]+)/;
459     my ($name) = $att =~ /Name\=([^\;\n]+)/;
460     my ($parent) = $att =~ /Parent\=([^\;\n]+)/;   
461    
462     $ID = $name if(! defined $ID);
463     $name = $ID if(! defined $name);
464     $ID = $NUM++ if(! defined $ID);
465     $name = $ID if(! defined $name);
466
467     return ($ID, $name, $parent);
468 }
469
470 sub is_same {
471     my $aB = shift;
472     my $aE = shift;
473     my $bB = shift;
474     my $bE = shift;
475
476     return 1 if($aB == $bB && $aE == $bE);
477 }
Note: See TracBrowser for help on using the browser.