File Coverage

blib/lib/GenOO/Gene.pm
Criterion Covered Total %
statement 124 178 69.6
branch 23 46 50.0
condition 16 18 88.8
subroutine 16 22 72.7
pod 0 10 0.0
total 179 274 65.3


line stmt bran cond sub pod time code
1             # POD documentation - main docs before the code
2              
3             =head1 NAME
4              
5             GenOO::Gene - Gene object
6              
7             =head1 SYNOPSIS
8              
9             # This object represents a gene (collection of transcripts)
10             # It extends the L<GenOO::GenomicRegion> object
11            
12             # To initialize
13             my $gene = GenOO::Gene->new(
14             name => undef, #required
15             species => undef,
16             strand => undef, #can be inferred from transcripts
17             chromosome => undef, #can be inferred from transcripts
18             start => undef, #can be inferred from transcripts
19             stop => undef, #can be inferred from transcripts
20             copy_number => undef, #defaults to 1
21             sequence => undef,
22             description => undef,
23             transcripts => reference to an array of L<GenOO::Transcript> objects
24             );
25              
26             =head1 DESCRIPTION
27              
28             GenOO::Gene describes a gene. A gene is defined as a genomic region (it has the strand, chromosome, start and stop
29             attributes required by L<GenOO::GenomicRegion>) as well as collection of L<GenOO::Transcript> objects. The genomic
30             location attributes can be inferred by the locations of the contained transcripts. The start position of the gene
31             will be the smallest coordinate of all the contained transcripts etc.
32             Whenever a transcript is added to a gene object the genomic coordinates of the gene are automatically updated.
33             It is a good idea NOT to set the genomic location of the gene directly but to let it be inferred by the transcripts.
34              
35             =head1 EXAMPLES
36             # Create a new gene object
37             my $gene = GenOO::Gene->new(
38             name => '2310016C08Rik',
39             description => 'hypoxia-inducible gene 2 protein isoform 2',
40             transcripts => [
41             GenOO::Transcript->new(
42             id => 'uc012eiw.1',
43             strand => 1,
44             chromosome => 'chr6',
45             start => 29222487,
46             stop => 29225448,
47             coding_start => 29222571,
48             coding_stop => 29224899,
49             biotype => 'coding',
50             splice_starts => [29222487,29224649],
51             splice_stops => [29222607,29225448]
52             ),
53             GenOO::Transcript->new(
54             id => 'uc009bdd.2',
55             strand => 1,
56             chromosome => 'chr6',
57             start => 29222625,
58             stop => 29225448,
59             coding_start => 29224705,
60             coding_stop => 29224899,
61             biotype => 'coding',
62             splice_starts => [29222625,29224649],
63             splice_stops => [29222809,29225448]
64             )
65             ],
66             );
67            
68             # Get gene information
69             $gene->strand; # 1
70             $gene->chromosome; # chr6
71             $gene->start; # 29222487
72             $gene->stop; # 29225448
73              
74             =cut
75              
76             # Let the code begin...
77              
78             package GenOO::Gene;
79             $GenOO::Gene::VERSION = '1.4.6';
80 1     1   4 use Moose;
  1         1  
  1         12  
81 1     1   3467 use namespace::autoclean;
  1         3  
  1         8  
82              
83             extends 'GenOO::GenomicRegion';
84              
85             has 'name' => (
86             isa => 'Str',
87             is => 'rw',
88             required => 1
89             );
90              
91             has 'description' => (
92             isa => 'Str',
93             is => 'rw'
94             );
95              
96             has 'transcripts' => (
97             isa => 'ArrayRef[GenOO::Transcript]',
98             is => 'rw',
99             default => sub {[]}
100             );
101              
102             has 'strand' => (
103             is => 'rw',
104             builder => '_find_strand',
105             clearer => '_clear_strand',
106             lazy => 1,
107             );
108              
109             has 'chromosome' => (
110             is => 'rw',
111             builder => '_find_chromosome',
112             clearer => '_clear_chromosome',
113             lazy => 1,
114             );
115              
116             has 'start' => (
117             is => 'rw',
118             builder => '_find_start',
119             clearer => '_clear_start',
120             lazy => 1,
121             );
122              
123             has 'stop' => (
124             is => 'rw',
125             builder => '_find_stop',
126             clearer => '_clear_stop',
127             lazy => 1,
128             );
129              
130             has 'exonic_regions' => (
131             traits => ['Array'],
132             is => 'ro',
133             builder => '_build_exonic_regions',
134             clearer => '_clear_exonic_regions',
135             handles => {
136             all_exonic_regions => 'elements',
137             exonic_regions_count => 'count',
138             },
139             lazy => 1
140             );
141              
142             has 'utr5_exonic_regions' => (
143             traits => ['Array'],
144             is => 'ro',
145             builder => '_build_utr5_exonic_regions',
146             clearer => '_clear_utr5_exonic_regions',
147             handles => {
148             all_utr5_exonic_regions => 'elements',
149             utr5_exonic_regions_count => 'count',
150             },
151             lazy => 1
152             );
153              
154             has 'cds_exonic_regions' => (
155             traits => ['Array'],
156             is => 'ro',
157             builder => '_build_cds_exonic_regions',
158             clearer => '_clear_cds_exonic_regions',
159             handles => {
160             all_cds_exonic_regions => 'elements',
161             cds_exonic_regions_count => 'count',
162             },
163             lazy => 1
164             );
165              
166             has 'utr3_exonic_regions' => (
167             traits => ['Array'],
168             is => 'ro',
169             builder => '_build_utr3_exonic_regions',
170             clearer => '_clear_utr3_exonic_regions',
171             handles => {
172             all_utr3_exonic_regions => 'elements',
173             utr3_exonic_regions_count => 'count',
174             },
175             lazy => 1
176             );
177              
178             #######################################################################
179             ######################## Interface Methods ########################
180             #######################################################################
181             sub coding_transcripts {
182 2     2 0 743 my ($self) = @_;
183            
184 2 50       59 if (defined $self->transcripts) {
185 2         2 return [grep {$_->is_coding} @{$self->transcripts}];
  4         17  
  2         46  
186             }
187             else {
188 0         0 warn "No transcripts found for ".$self->name."\n";
189 0         0 return undef;
190             }
191             }
192              
193             sub non_coding_transcripts {
194 1     1 0 637 my ($self) = @_;
195            
196 1 50       32 if (defined $self->transcripts) {
197 1         1 return [grep {not $_->is_coding} @{$self->transcripts}];
  2         7  
  1         29  
198             }
199             else {
200 0         0 warn "No transcripts found for ".$self->name."\n";
201 0         0 return undef;
202             }
203             }
204              
205             sub add_transcript {
206 350     350 0 681 my ($self, $transcript) = @_;
207            
208 350 50 33     2798 if (defined $transcript and ($transcript->isa('GenOO::Transcript'))) {
209 350         471 push @{$self->transcripts}, $transcript;
  350         8546  
210 350         1376 $self->_reset;
211             }
212             else {
213 0         0 warn 'Object "'.ref($transcript).'" is not a GenOO::Transcript ... skipped';
214             }
215             }
216              
217             sub constitutive_exonic_regions {
218 1     1 0 752 my ($self) = @_;
219            
220 1         3 my %counts;
221 1         1 foreach my $transcript (@{$self->transcripts}) {
  1         32  
222 2         6 foreach my $exon (@{$transcript->exons}) {
  2         49  
223 4         13 $counts{$exon->location}++;
224             }
225             }
226            
227 1         2 my @constitutive_exons;
228 1         7 my $transcript_count = @{$self->transcripts};
  1         27  
229 1         4 foreach my $transcript (@{$self->transcripts}) {
  1         56  
230 2         5 foreach my $exon (@{$transcript->exons}) {
  2         50  
231 4 100 100     10 if (exists $counts{$exon->location} and ($counts{$exon->location} == $transcript_count)) {
232 1         25 push @constitutive_exons, GenOO::GenomicRegion->new(
233             strand => $exon->strand,
234             chromosome => $exon->chromosome,
235             start => $exon->start,
236             stop => $exon->stop
237             );
238            
239 1         8 delete $counts{$exon->location};
240             }
241             }
242             }
243 1         5 return \@constitutive_exons;
244             }
245              
246             sub constitutive_coding_exonic_regions {
247 1     1 0 676 my ($self) = @_;
248            
249 1         2 my %counts;
250 1         5 foreach my $transcript (@{$self->transcripts}) {
  1         34  
251 2         6 foreach my $exon (@{$transcript->exons}) {
  2         48  
252 4         31 $counts{$exon->location}++;
253             }
254             }
255            
256 1         5 my @constitutive_exons;
257 1         4 my $transcript_count = @{$self->coding_transcripts};
  1         4  
258 1         6 foreach my $transcript (@{$self->transcripts}) {
  1         25  
259 2         5 foreach my $exon (@{$transcript->exons}) {
  2         59  
260 4 100 100     10 if (exists $counts{$exon->location} and ($counts{$exon->location} == $transcript_count)) {
261 1         27 push @constitutive_exons, GenOO::GenomicRegion->new(
262             strand => $exon->strand,
263             chromosome => $exon->chromosome,
264             start => $exon->start,
265             stop => $exon->stop
266             );
267            
268 1         7 delete $counts{$exon->location};
269             }
270             }
271             }
272 1         5 return \@constitutive_exons;
273             }
274              
275             sub has_coding_transcript {
276 1     1 0 732 my ($self) = @_;
277            
278 1         2 foreach my $transcript (@{$self->transcripts}) {
  1         34  
279 1 50       5 if ($transcript->is_coding) {
280 1         7 return 1;
281             }
282             }
283            
284 0         0 return 0;
285             }
286              
287             sub exonic_length {
288 1     1 0 749 my ($self) = @_;
289            
290 1         3 my $exonic_length = 0;
291 1         48 foreach my $region ($self->all_exonic_regions) {
292 3         79 $exonic_length += $region->length
293             }
294            
295 1         7 return $exonic_length;
296             }
297              
298             sub utr5_exonic_length {
299 0     0 0 0 my ($self) = @_;
300            
301 0         0 my $exonic_length = 0;
302 0         0 foreach my $region ($self->all_utr5_exonic_regions) {
303 0         0 $exonic_length += $region->length
304             }
305            
306 0         0 return $exonic_length;
307             }
308              
309             sub cds_exonic_length {
310 0     0 0 0 my ($self) = @_;
311            
312 0         0 my $exonic_length = 0;
313 0         0 foreach my $region ($self->all_cds_exonic_regions) {
314 0         0 $exonic_length += $region->length
315             }
316            
317 0         0 return $exonic_length;
318             }
319              
320             sub utr3_exonic_length {
321 0     0 0 0 my ($self) = @_;
322            
323 0         0 my $exonic_length = 0;
324 0         0 foreach my $region ($self->all_utr3_exonic_regions) {
325 0         0 $exonic_length += $region->length
326             }
327            
328 0         0 return $exonic_length;
329             }
330              
331             #######################################################################
332             ######################### Private methods ##########################
333             #######################################################################
334             sub _find_strand {
335 163     163   189 my ($self) = @_;
336            
337 163         143 my $strand;
338 163 50       3578 if (defined $self->transcripts) {
339 163         3239 $strand = $self->transcripts->[0]->strand;
340             }
341            
342 163 50       325 if (not defined $strand) {
343 0         0 die "No strand found for ".$self->name."\n";
344             }
345             else {
346 163         3165 return $strand;
347             }
348             }
349              
350             sub _find_chromosome {
351 163     163   171 my ($self) = @_;
352            
353 163         156 my $chromosome;
354 163 50       3323 if (defined $self->transcripts) {
355 163         3141 $chromosome = $self->transcripts->[0]->chromosome;
356             }
357            
358 163 50       383 if (not defined $chromosome) {
359 0         0 die "No chromosome found for ".$self->name."\n";
360             }
361             else {
362 163         3242 return $chromosome;
363             }
364             }
365              
366             sub _find_start {
367 193     193   261 my ($self) = @_;
368            
369 193         298 my $start;
370 193 50       4710 if (defined $self->transcripts) {
371 193         269 foreach my $transcript (@{$self->transcripts}) {
  193         4101  
372 374 100 100     4957 if ((not defined $start) or ($start > $transcript->start)) {
373 194         4650 $start = $transcript->start;
374             }
375             }
376             }
377            
378 193 50       510 if (not defined $start) {
379 0         0 die "No start found for ".$self->name."\n";
380             }
381             else {
382 193         4101 return $start;
383             }
384             }
385              
386             sub _find_stop {
387 193     193   366 my ($self) = @_;
388            
389 193         309 my $stop;
390 193 50       4148 if (defined $self->transcripts) {
391 193         255 foreach my $transcript (@{$self->transcripts}) {
  193         4089  
392 374 100 100     4977 if ((not defined $stop) or ($stop < $transcript->stop)) {
393 235         5459 $stop = $transcript->stop;
394             }
395             }
396             }
397            
398 193 50       581 if (not defined $stop) {
399 0         0 die "No stop found for ".$self->name."\n";
400             }
401             else {
402 193         4068 return $stop;
403             }
404             }
405              
406             sub _build_exonic_regions {
407 2     2   6 my ($self) = @_;
408            
409 2         3 my @all_exons;
410 2         3 foreach my $transcript (@{$self->transcripts}) {
  2         54  
411 4         4 foreach my $exon (@{$transcript->exons}) {
  4         101  
412 8         15 push @all_exons, $exon;
413             }
414             }
415            
416 2         8 return $self->_merge_exons(\@all_exons);
417             }
418              
419             sub _build_utr5_exonic_regions {
420 0     0   0 my ($self) = @_;
421            
422 0         0 my @all_exons;
423 0         0 foreach my $transcript (@{$self->transcripts}) {
  0         0  
424 0 0       0 next if !$transcript->is_coding;
425 0 0       0 next if !defined $transcript->utr5;
426 0         0 foreach my $exon (@{$transcript->utr5->exons}) {
  0         0  
427 0         0 push @all_exons, $exon;
428             }
429             }
430            
431 0         0 return $self->_merge_exons(\@all_exons);
432             }
433              
434             sub _build_cds_exonic_regions {
435 0     0   0 my ($self) = @_;
436            
437 0         0 my @all_exons;
438 0         0 foreach my $transcript (@{$self->transcripts}) {
  0         0  
439 0 0       0 next if !$transcript->is_coding;
440 0         0 foreach my $exon (@{$transcript->cds->exons}) {
  0         0  
441 0         0 push @all_exons, $exon;
442             }
443             }
444            
445 0         0 return $self->_merge_exons(\@all_exons);
446             }
447              
448             sub _build_utr3_exonic_regions {
449 0     0   0 my ($self) = @_;
450            
451 0         0 my @all_exons;
452 0         0 foreach my $transcript (@{$self->transcripts}) {
  0         0  
453 0 0       0 next if !$transcript->is_coding;
454 0 0       0 next if !defined $transcript->utr3;
455 0         0 foreach my $exon (@{$transcript->utr3->exons}) {
  0         0  
456 0         0 push @all_exons, $exon;
457             }
458             }
459            
460 0         0 return $self->_merge_exons(\@all_exons);
461             }
462              
463             sub _merge_exons {
464 2     2   4 my ($self, $exons) = @_;
465            
466 2         15 my @sorted_exons = sort{$a->start <=> $b->start} @$exons;
  10         234  
467            
468 2         3 my @exonic_regions;
469 2         6 foreach my $exon (@sorted_exons) {
470 8         9 my $merge_region = $exonic_regions[-1];
471 8 100 100     44 if (defined $merge_region and $merge_region->overlaps($exon)) {
472 2 50       77 $merge_region->stop($exon->stop) if $exon->stop > $merge_region->stop;
473             }
474             else {
475 6         164 push @exonic_regions, GenOO::GenomicRegion->new(
476             strand => $exon->strand,
477             chromosome => $exon->chromosome,
478             start => $exon->start,
479             stop => $exon->stop,
480             );
481             }
482             }
483            
484 2         71 return \@exonic_regions;
485             }
486              
487             sub _reset {
488 350     350   481 my ($self) = @_;
489            
490 350         9135 $self->_clear_strand;
491 350         9895 $self->_clear_chromosome;
492 350         8891 $self->_clear_start;
493 350         8716 $self->_clear_stop;
494 350         10031 $self->_clear_exonic_regions;
495 350         10404 $self->_clear_utr5_exonic_regions;
496 350         10002 $self->_clear_cds_exonic_regions;
497 350         9984 $self->_clear_utr3_exonic_regions;
498             }
499              
500             __PACKAGE__->meta->make_immutable;
501              
502             1;