File Coverage

blib/lib/Bio/Phylo/Models/Substitution/Binary.pm
Criterion Covered Total %
statement 18 76 23.6
branch 0 12 0.0
condition 0 5 0.0
subroutine 6 13 46.1
pod 6 6 100.0
total 30 112 26.7


line stmt bran cond sub pod time code
1             package Bio::Phylo::Models::Substitution::Binary;
2 13     13   78 use strict;
  13         25  
  13         326  
3 13     13   62 use warnings;
  13         24  
  13         285  
4 13     13   66 use Data::Dumper;
  13         24  
  13         557  
5 13     13   72 use Bio::Phylo::Util::Logger;
  13         34  
  13         460  
6 13     13   59 use Bio::Phylo::Util::CONSTANT qw'/looks_like/ :objecttypes';
  13         26  
  13         3470  
7 13     13   83 use Bio::Phylo::Util::Exceptions qw'throw';
  13         27  
  13         8315  
8              
9             my $logger = Bio::Phylo::Util::Logger->new;
10              
11             =head1 NAME
12              
13             Bio::Phylo::Models::Substitution::Binary - Binary character substitution model
14              
15             =head1 SYNOPSIS
16              
17             use Bio::Phylo::Models::Substitution::Binary;
18              
19             # create a binary substitution model
20             # by doing a modeltest
21             my $model = Bio::Phylo::Models::Substitution::Binary->modeltest(
22             -tree => $tree, # phylogeny
23             -matrix => $matrix, # character state matrix, standard categorical data
24             -model => 'ARD', # ace model
25             -char => 'c1', # column ID in $matrix
26             );
27              
28             # after model test, forward and reverse instantaneous transition
29             # rates are available, e.g. for simulation
30             print $model->forward, "\n";
31             print $model->reverse, "\n";
32              
33             =head1 DESCRIPTION
34              
35             This is a class that encapsulates an instantaneous transition model
36             for a binary character. The model is asymmetrical in that the forward
37             and reverse rates (can) differ. The rates can be inferred from a
38             character in a character state matrix by modeltesting. This is done
39             by delegation to the R package C<ape>. For this to work, you therefore
40             need to have R and C<ape> installed, as well as the bridge that allows
41             Perl to communicate with R, which is done by the optional package
42             L<Statistics::R>.
43              
44             =head1 METHODS
45              
46             =head2 CONSTRUCTOR
47              
48             =over
49              
50             =item new
51              
52             Binary character model constructor.
53              
54             Type : Constructor
55             Title : new
56             Usage : my $model = Bio::Phylo::Models::Substitution::Binary->new(%args);
57             Function: Instantiates a Bio::Phylo::Models::Substitution::Binary object.
58             Returns : A Bio::Phylo::Models::Substitution::Binary object.
59             Args : Optional:
60             -forward => sets forward rate
61             -reverse => sets reverse rate
62              
63             =cut
64              
65             sub new {
66 0     0 1   my $class = shift;
67 0           my %args = looks_like_hash @_;
68 0           my $self = { '_fw' => undef, '_rev' => undef };
69 0           bless $self, $class;
70 0           while ( my ( $key, $value ) = each %args ) {
71 0           $key =~ s/^-/set_/;
72 0           $self->$key($value);
73             }
74 0           return $self;
75             }
76              
77             =item set_forward
78              
79             Setter for forward transition rate
80              
81             Type : method
82             Title : set_forward
83             Usage : $model->set_forward($rate);
84             Function: Setter for forward transition rate
85             Returns : $self
86             Args : A rate (floating point number)
87              
88             =cut
89              
90             sub set_forward {
91 0     0 1   my ( $self, $fw ) = @_;
92 0           $self->{'_fw'} = $fw;
93 0           return $self;
94             }
95              
96             =item set_reverse
97              
98             Setter for reverse transition rate
99              
100             Type : method
101             Title : set_reverse
102             Usage : $model->set_reverse($rate);
103             Function: Setter for reverse transition rate
104             Returns : $self
105             Args : A rate (floating point number)
106              
107             =cut
108              
109             sub set_reverse {
110 0     0 1   my ( $self, $rev ) = @_;
111 0           $self->{'_rev'} = $rev;
112 0           return $self;
113             }
114              
115             =item get_forward
116              
117             Setter for forward transition rate
118              
119             Type : method
120             Title : get_forward
121             Usage : my $rate = $model->get_forward;
122             Function: Getter for forward transition rate
123             Returns : A rate (floating point number)
124             Args : NONE
125              
126             =cut
127              
128 0     0 1   sub get_forward { shift->{'_fw'} }
129              
130             =item get_reverse
131              
132             Setter for reverse transition rate
133              
134             Type : method
135             Title : get_reverse
136             Usage : my $rate = $model->get_reverse;
137             Function: Getter for reverse transition rate
138             Returns : A rate (floating point number)
139             Args : NONE
140              
141             =cut
142              
143 0     0 1   sub get_reverse { shift->{'_rev'} }
144              
145             =item modeltest
146              
147             Performs a model test to infer transition rates
148              
149             Type : method
150             Title : modeltest
151             Usage : my $model = $package->modeltest;
152             Function: Performs a model test to infer transition rates
153             Returns : A populated $model object
154             Args : All required:
155             -tree => $tree, # phylogeny
156             -matrix => $matrix, # character state matrix, standard categorical data
157             -model => 'ARD', # ace model
158             -char => 'c1', # column ID in $matrix
159              
160             =cut
161              
162             sub modeltest {
163              
164             # process arguments
165 0     0 1   my ( $class, %args ) = @_;
166 0 0         my $tree = $args{'-tree'} or throw 'BadArgs' => "Need -tree argument";
167 0 0         my $char = $args{'-char'} or throw 'BadArgs' => "Need -char argument";
168 0 0         my $matrix = $args{'-matrix'} or throw 'BadArgs' => "Need -matrix argument";
169 0   0       my $model = $args{'-model'} || 'ARD';
170            
171             # we don't actually check if the character is binary here. perhaps we should,
172             # and verify that the tips in the tree match the rows in the matrix, and
173             # prune tips with missing data, and, and, and...
174 0 0         if ( $matrix->get_type !~ /standard/i ) {
175 0           throw 'BadArgs' => "Need standard categorical data";
176             }
177 0 0         if ( looks_like_class 'Statistics::R' ) {
178            
179             # start R, load library
180 0           $logger->info("going to run 'ace'");
181 0           my $R = Statistics::R->new;
182 0           $R->run(q[library("ape")]);
183            
184             # insert data
185 0           my $newick = $tree->to_newick;
186 0           my %hash = $class->_data_hash($char,$matrix);
187 0           $R->run(qq[phylo <- read.tree(text="$newick")]);
188 0           $R->set('chars', [values %hash]);
189 0           $R->set('labels', [keys %hash]);
190 0           $R->run(q[names(chars) <- labels]);
191            
192             # do calculation
193 0           $R->run(qq[ans <- ace(chars,phylo,type="d",model="$model")]);
194 0           $R->run(q[rates <- ans$rates]);
195 0           my $rates = $R->get(q[rates]);
196 0           $logger->info("Rates: ".Dumper($rates));
197            
198             # return instance
199 0           return $class->new(
200             '-forward' => $rates->[1],
201             '-reverse' => $rates->[0],
202             );
203             }
204             }
205              
206             sub _data_hash {
207 0     0     my ( $self, $char, $matrix ) = @_;
208 0           my $cid = $char->get_id;
209 0           my $chars = $matrix->get_characters;
210 0           my $nchar = $matrix->get_nchar;
211 0   0       my $name = $char->get_name || $cid;
212            
213             # find index of character
214 0           my $index;
215 0           CHAR: for my $i ( 0 .. $nchar - 1 ) {
216 0           my $c = $chars->get_by_index($i);
217 0 0         if ( $c->get_id == $cid ) {
218 0           $index = $i;
219 0           $logger->info("index of character ${name}: ${index}");
220 0           last CHAR;
221             }
222             }
223            
224             # get character states
225 0           my %result;
226 0           for my $row ( @{ $matrix->get_entities } ) {
  0            
227 0           my @char = $row->get_char;
228 0           my $name = $row->get_name;
229 0           $result{$name} = $char[$index];
230             }
231 0           $logger->debug(Dumper(\%result));
232 0           return %result;
233             }
234              
235             =back
236              
237             =head1 SEE ALSO
238              
239             There is a mailing list at L<https://groups.google.com/forum/#!forum/bio-phylo>
240             for any user or developer questions and discussions.
241              
242             =over
243              
244             =item L<Bio::Phylo::Manual>
245              
246             Also see the manual: L<Bio::Phylo::Manual> and L<http://rutgervos.blogspot.com>.
247              
248             =back
249              
250             =head1 CITATION
251              
252             If you use Bio::Phylo in published research, please cite it:
253              
254             B<Rutger A Vos>, B<Jason Caravas>, B<Klaas Hartmann>, B<Mark A Jensen>
255             and B<Chase Miller>, 2011. Bio::Phylo - phyloinformatic analysis using Perl.
256             I<BMC Bioinformatics> B<12>:63.
257             L<http://dx.doi.org/10.1186/1471-2105-12-63>
258              
259             =cut
260              
261             1;