File Coverage

blib/lib/Bio/NEXUS/CharactersBlock.pm
Criterion Covered Total %
statement 226 285 79.3
branch 66 94 70.2
condition 34 50 68.0
subroutine 30 33 90.9
pod 16 16 100.0
total 372 478 77.8


line stmt bran cond sub pod time code
1             #######################################################################
2             # CharactersBlock.pm
3             #######################################################################
4             #
5             # $Id: CharactersBlock.pm,v 1.82 2008/04/24 19:07:25 astoltzfus Exp $
6             #
7             #################### START POD DOCUMENTATION ##########################
8              
9             =head1 NAME
10              
11             Bio::NEXUS::CharactersBlock - Represents a CHARACTERS Block (Data or Characters) of a NEXUS file
12              
13             =head1 SYNOPSIS
14              
15             $block_object = new Bio::NEXUS::CharactersBlock($type, $block, $verbose, $taxlabels_ref);
16              
17             =head1 DESCRIPTION
18              
19             This is a class representing a Characters Block in a NEXUS file. Characters Blocks generally contain state data for a set of characters for each taxon in the Taxa Block. One common use of a Characters Block is to house multiple sequence alignments.
20              
21             =head1 FEEDBACK
22              
23             All feedbacks (bugs, feature enhancements, etc.) are greatly appreciated.
24              
25             =head1 AUTHORS
26              
27             Chengzhi Liang (liangc@umbi.umd.edu)
28             Weigang Qiu (weigang@genectr.hunter.cuny.edu)
29             Eugene Melamud (melamud@carb.nist.gov)
30             Peter Yang (pyang@rice.edu)
31             Thomas Hladish (tjhladish at yahoo)
32              
33             =head1 VERSION
34              
35             $Revision: 1.82 $
36              
37             =head1 METHODS
38              
39             =cut
40              
41             package Bio::NEXUS::CharactersBlock;
42 34     34   206 use strict;
  34         80  
  34         1815  
43             # use Data::Dumper; # used for debugging only
44             # use Carp; # for debugging only
45 34     34   197 use Bio::NEXUS::Functions;
  34         73  
  34         19294  
46 34     34   22741 use Bio::NEXUS::TaxUnitSet;
  34         112  
  34         1149  
47 34     34   23281 use Bio::NEXUS::Matrix;
  34         101  
  34         5955  
48 34     34   246 use Bio::NEXUS::Util::Logger;
  34         63  
  34         764  
49 34     34   1359 use Bio::NEXUS::Util::Exceptions 'throw';
  34         79  
  34         2067  
50 34     34   185 use vars qw(@ISA $VERSION $AUTOLOAD);
  34         62  
  34         1954  
51              
52 34     34   167 use Bio::NEXUS; $VERSION = $Bio::NEXUS::VERSION;
  34         66  
  34         138541  
53              
54             @ISA = qw(Bio::NEXUS::Matrix);
55             my $logger = Bio::NEXUS::Util::Logger->new();
56              
57             =head2 new
58              
59             Title : new
60             Usage : block_object = new Bio::NEXUS::CharactersBlock($block_type, $commands, $verbose, $taxa);
61             Function: Creates a new Bio::NEXUS::CharactersBlock object
62             Returns : Bio::NEXUS::CharactersBlock object
63             Args : type (string), the commands/comments to parse (array ref), and a verbose flag (0 or 1)
64              
65             =cut
66              
67             sub new {
68 73     73 1 213 my ( $class, $type, $commands, $verbose, $taxa ) = @_;
69 73 50       259 if ( not $type) {
70 0         0 ( $type = lc $class ) =~ s/Bio::NEXUS::(.+)Block/$1/i;
71             }
72 73         339 my $self = {
73             'type' => $type
74             };
75 73         250 bless $self, $class;
76 73         569 $self->set_taxlabels($taxa);
77 73         693 $self->{'otuset'} = Bio::NEXUS::TaxUnitSet->new();
78 73 50 33     601 if ( ( defined $commands ) and @$commands ) {
79 73         555 $self->_parse_block( $commands, $verbose )
80             }
81              
82 70         342 return $self;
83             }
84              
85             sub _post_processing {
86 72     72   187 my ($self) = @_;
87              
88             # We prefer using the more versatile/expressive character-state labels,
89             # rather than state labels
90 72 50       327 if ( $self->get_statelabels() ) {
91 72         294 $self->add_states_to_charstates( $self->get_statelabels() );
92 72         259 delete $self->get_otuset->{'statelabels'};
93             }
94              
95             # The 'ntax' subcommand is not required unless the 'newtaxa' subcommand has
96             # been used
97 72         301 my $dimensions = $self->get_dimensions();
98 72 50       306 if ( !$dimensions->{'newtaxa'} ) {
99 72         179 delete $dimensions->{'ntax'};
100 72         345 $self->set_dimensions($dimensions);
101             }
102              
103 72         186 return;
104             }
105              
106             =begin comment
107              
108             Title : _parse_charstatelabels
109             Usage : $self->_parse_charstatelabels($buffer);
110             Function: Parses the buffer containing character labels, stores it
111             Returns : none
112             Args : buffer (string)
113             Method : parse a charstatelabels command in Characters Block and store in hash
114              
115             =end comment
116              
117             =cut
118              
119             # NOTE: format of charstatelabel is comma-separated list of elements, where each element
120             # has the form /
121              
122             # NOTE: the parse method below is not elegant, but its rational and so far its robust to tests
123              
124             sub _parse_charstatelabels {
125 3     3   8 my ( $self, $buffer ) = @_;
126 3         21 my $command_tokens = _parse_nexus_words($buffer);
127 3         7 my @out;
128             # print "command_tokens: ", Dumper @$command_tokens;
129              
130 3         9 my ($this_token, $this_element_token );
131 0         0 my ( @this_element_tokens, @this_half_tokens );
132 0         0 my ( $char_id, $char_label );
133 3         14 while ( $this_token = shift( @$command_tokens ) ) {
134 138 100 100     507 if ( $this_token eq ',' || $#$command_tokens == -1 ) {
135 18 100       45 if ( $#$command_tokens == -1 ) {
136 3         6 push ( @this_element_tokens, $this_token );
137             }
138             # print "processing this element . . . ", Dumper @this_element_tokens;
139             # process this_element_tokens to yield id, label, and state labels
140 18         42 while ( $this_element_token = shift( @this_element_tokens ) ) {
141 123 100       247 if ( $this_element_token eq '/' ) {
142             # print "processing char half. . . ", Dumper @this_half_tokens;
143 19         24 $char_id = shift(@this_half_tokens);
144             # label may be empty, but thats ok
145 19         45 $char_label = shift(@this_half_tokens);
146             # print "char_id = $char_id, char_label = $char_label\n";
147             }
148             else {
149 104         237 push( @this_half_tokens, $this_element_token );
150             }
151             }
152 18         55 push @out, $self->create_charstates( $char_id, $char_label, \@this_half_tokens );
153 18         38 @this_half_tokens = ();
154             # print "latest character: ", Dumper \$out[$#out];
155 18         22 $char_id = undef;
156 18         50 $char_label = undef;
157             }
158             else {
159 120         331 push( @this_element_tokens, $this_token );
160             }
161             }
162 3         26 $self->get_otuset->set_charstatelabels( \@out );
163             # print "\nout: ", Dumper @out;
164              
165 3         18 return;
166             }
167              
168             =begin comment
169              
170             Title : _parse_charlabels
171             Usage : $self->_parse_charlabels($buffer);
172             Function: Parses the buffer containing character labels, stores it
173             Returns : array of charstates
174             Args : buffer (string)
175             Method : Gets rid of leading blanks in the buffer and removes the
176             semicolon. Splits the buffer by whitespace into a list of
177             character labels and assigns that to charlabels.
178              
179             =end comment
180              
181             =cut
182              
183             sub _parse_charlabels {
184 35     35   91 my ( $self, $labels ) = @_;
185 35         71 my $id = 0;
186 35         66 my @charstates;
187 35         69 my @charlabels = @{ _parse_nexus_words($labels) };
  35         142  
188 35         132 for my $charlabel (@charlabels) {
189 220         593 push @charstates, $self->create_charstates( ++$id, $charlabel );
190             }
191 35         194 $self->set_charlabels( \@charlabels );
192 35         168 $self->set_charstatelabels( \@charstates );
193 35         195 return \@charstates;
194             }
195              
196             =begin comment
197              
198             Title : _parse_statelabels
199             Usage : $self->_parse_statelabels($buffer);
200             Function: Parses the buffer containing state labels, stores it
201             Returns : array of states
202             Args : buffer (string)
203             Method : parse a statelabels command in Characters Block and store in hash
204              
205             =end comment
206              
207             =cut
208              
209             sub _parse_statelabels {
210 0     0   0 my ( $self, $buffer ) = @_;
211 0         0 my @states;
212 0         0 my ( $charnum, @statenames );
213 0         0 my @statetokens = @{ _parse_nexus_words($buffer) };
  0         0  
214 0         0 for my $token (@statetokens) {
215 0 0 0     0 if ( $token =~ /^\d+$/ && !$charnum > 0 ) { $charnum = $token; next; }
  0 0       0  
  0         0  
216             elsif ( $token =~ /^,$/ ) {
217 0         0 push @states,
218             $self->create_charstates( $charnum, "", \@statenames );
219 0         0 $charnum = "";
220 0         0 @statenames = ();
221             }
222             else {
223 0         0 push @statenames, $token;
224             }
225             }
226 0         0 $self->set_statelabels( \@states );
227 0         0 return \@states;
228             }
229              
230             =head2 add_states_to_charstates
231              
232             Title : add_states_to_charstates
233             Usage : $self->add_states_to_charstates($states);
234             Function: Adds states to the character states
235             Returns : None
236             Args : states
237              
238             =cut
239              
240             sub add_states_to_charstates {
241 72     72 1 156 my ( $self, $states ) = @_;
242 72         119 my $newstates;
243 72         342 my $charstates = $self->get_charstatelabels();
244 72 100       318 if ( !@$charstates ) {
245 34         178 $self->set_charstatelabels($states);
246 34         75 return;
247             }
248 38         129 STATE: for my $state (@$states) {
249 0         0 for my $charstate (@$charstates) {
250 0 0       0 if ( $state->{'id'} == $charstate->{'id'} ) {
251 0         0 $charstate->{'states'} = $state->{'states'};
252 0         0 next STATE;
253             }
254             }
255 0         0 splice @$charstates, $state->{'id'} - 1, 1, $state;
256             }
257             }
258              
259             =head2 create_charstates
260              
261             Title : create_charstates
262             Usage : my $char_state_hash = $self->create_charstates($id,$label,$states);
263             Function: Converts the input id, label, states to an hash ref for processing.
264             Returns : Hash reference with (id, charlabel,states as keys)
265             Args : id, label, states
266              
267             =cut
268              
269             sub create_charstates {
270 238     238 1 423 my ( $self, $id, $label, $states ) = @_;
271 238         265 my %states;
272 238 100       318 for ( my $i = 0; $i < @{ $states || [] }; $i++ ) {
  304         1386  
273 66         168 $states{$i} = $states->[$i];
274             }
275             return {
276 238         1392 'id' => $id,
277             'charlabel' => $label,
278             'states' => \%states
279            
280             };
281             }
282              
283             =head2 find_taxon
284              
285             Title : find_taxon
286             Usage : my $is_taxon_present = $self->find_taxon($taxon_name);
287             Function: Finds whether the input taxon name is present in the taxon label.
288             Returns : 0 (not present) or 1 (if present).
289             Args : taxon label (as string)
290              
291             =cut
292              
293             sub find_taxon {
294 532     532 1 20251 my ( $self, $name ) = @_;
295 532 50       542 if ( @{ $self->get_taxlabels || [] } == 0 ) { return 1; }
  532 100       1394  
  147         360  
296 385         583 for my $taxon ( @{ $self->get_taxlabels() } ) {
  385         976  
297 1619 100       3594 if ( lc $taxon eq lc $name ) { return 1; }
  375         1120  
298             }
299 10         36 return 0;
300             }
301              
302             =head2 set_otuset
303              
304             Title : set_otuset
305             Usage : $block->set_otuset($otuset);
306             Function: Set the otus
307             Returns : none
308             Args : TaxUnitSet object
309              
310             =cut
311              
312             sub set_otuset {
313 0     0 1 0 my ( $self, $otuset ) = @_;
314 0         0 $self->{'otuset'} = $otuset;
315 0         0 $self->set_taxlabels( $otuset->get_otu_names() );
316 0         0 return;
317             }
318              
319             =head2 add_otu_clone
320              
321             Title : add_otu_clone
322             Usage : ...
323             Function: ...
324             Returns : ...
325             Args : ...
326              
327             =cut
328              
329             sub add_otu_clone {
330 8     8 1 21 my ( $self, $original_otu_name, $copy_otu_name ) = @_;
331             # print "Warning: Bio::NEXUS::CharactersBlock::add_otu_clone() method not fully implemented\n";
332            
333 8 50       28 if ( $self->find_taxon($copy_otu_name) ) {
334 0         0 throw 'ObjectMismatch' => "OTU with that name [$copy_otu_name] already exists";
335             }
336             else {
337 8         32 $self->add_taxlabel($copy_otu_name);
338 8         16 my @otu_set = @{ $self->{'otuset'}->{'otus'} };
  8         45  
339 8         21 for my $otu (@otu_set) {
340 60 50       113 if (defined $otu) {
341 60 100       142 if ( $otu->get_name() eq $original_otu_name ) {
342 8         37 my $otu_clone = $otu->clone();
343 8         33 $otu_clone->set_name($copy_otu_name);
344 8         40 $self->{'otuset'}->add_otu($otu_clone);
345             }
346             }
347             }
348             }
349             }
350              
351             =head2 set_charstatelabels
352              
353             Title : set_charstatelabels
354             Usage : $block->set_charstatelabels($labels);
355             Function: Set the character names and states
356             Returns : none
357             Args : array of character states
358              
359             =cut
360              
361             sub set_charstatelabels {
362 69     69 1 154 my ( $self, $charstatelabels ) = @_;
363 69         256 $self->get_otuset->set_charstatelabels($charstatelabels);
364 69         133 return;
365             }
366              
367             =head2 get_charstatelabels
368              
369             Title : get_charstatelabels
370             Usage : $set->get_charstatelabels();
371             Function: Returns an array of character states
372             Returns : character states
373             Args : none
374              
375             =cut
376              
377 76     76 1 1672 sub get_charstatelabels { shift->get_otuset->get_charstatelabels() }
378              
379             =head2 set_charlabels
380              
381             Title : set_charlabels
382             Usage : $set->set_charlabels($labels);
383             Function: Set the character names
384             Returns : none
385             Args : array of character names
386              
387             =cut
388              
389             sub set_charlabels {
390 35     35 1 65 my ( $self, $labels ) = @_;
391 35         251 $self->get_otuset()->set_charlabels($labels);
392             }
393              
394             =head2 get_charlabels
395              
396             Title : get_charlabels
397             Usage : $set->get_charlabels();
398             Function: Returns an array of character labels
399             Returns : character names
400             Args : none
401              
402             =cut
403              
404 5     5 1 25 sub get_charlabels { shift->get_otuset()->get_charlabels() }
405              
406             =head2 set_statelabels
407              
408             Title : set_statelabels
409             Usage : $set->set_statelabels($labels);
410             Function: Set the state names
411             Returns : none
412             Args : array of state names
413              
414             =cut
415              
416             sub set_statelabels {
417 0     0 1 0 my ( $self, $labels ) = @_;
418 0         0 $self->get_otuset()->set_statelabels($labels);
419             }
420              
421             =head2 get_statelabels
422              
423             Title : get_statelabels
424             Usage : $set->get_statelabels();
425             Function: Returns an array of stateacter labels
426             Returns : stateacter names
427             Args : none
428              
429             =cut
430              
431 144     144 1 442 sub get_statelabels { shift->get_otuset()->get_statelabels() }
432              
433             =head2 get_nchar
434              
435             Title : get_nchar
436             Usage : $block->get_nchar();
437             Function: Returns the number of characters of the block
438             Returns : # charaters
439             Args : none
440              
441             =cut
442              
443             sub get_nchar {
444 85     85 1 1920 my $self = shift;
445 85         525 my $nchar = $self->get_dimensions('nchar');
446 85 50       300 if ( not defined $nchar ) {
447 0         0 my $otuset = $self->get_otuset();
448 0 0       0 $nchar = $otuset ? $otuset->get_nchar() : undef;
449 0         0 $self->set_nchar($nchar);
450             }
451 85         300 return $nchar;
452             }
453              
454             =begin comment
455              
456             Title : _parse_matrix
457             Usage : $self->_parse_matrix($buffer); (private)
458             Function: Processes buffer containing matrix data
459             Returns : arrayref
460             Args : buffer (string)
461             Method : parse according to if name is quoted string or single word,
462             if each state is single character or multi-character (use token keyword)
463              
464             =end comment
465              
466             =cut
467              
468             sub _parse_matrix {
469 73     73   320 my ( $self, $matrix, $verbose ) = @_;
470 73         310 my $nchar = $self->get_nchar();
471 73         153 my @taxlabels = @{ $self->get_taxlabels() };
  73         404  
472              
473 73         167 my %format = %{ $self->get_format() };
  73         428  
474              
475 73         257 my $expect_labels = !$format{'nolabels'};
476 73         167 my $expect_interleave = $format{'interleave'};
477 73   66     480 my $expect_tokens = $format{'tokens'}
478             || ( lc $format{'datatype'} eq 'continuous' );
479              
480 73   100     307 my $missing_symbol = $format{'missing'} || q{};
481 73   100     299 my $gap_symbol = $format{'gap'} || q{};
482              
483             # statesformat is the stored value (if one exists), otherwise it's
484             # the default value ('individuals' for continuous data, 'statespresent'
485             # for others).
486 73 50       374 my $statesformat =
    100          
487             $format{'statesformat'} ? $format{'statesformat'}
488             : $format{'datatype'} eq 'continuous' ? 'individuals'
489             : 'statespresent';
490 73 100 66     586 my $expect_freq =
491             ( $statesformat eq 'count' || $statesformat eq 'frequency' ) ? 1 : 0;
492              
493             # '+' and '-' are not included as punctuation because they are allowed as
494             # state symbols in a matrix; colons are used to separate states from their
495             # frequencies in polymorphisms (e.g. "(A:0.9 E:0.04 N:0.06)" )
496 73         388 my $punctuation_regex = qr/[\/\\,;=*"`<>]/;
497              
498 73         138 my ( @lines, %taxa );
499              
500 73 100       210 if ($expect_interleave) {
501 6         205 @lines = split /\n+/, $matrix;
502             }
503             else {
504              
505             # This is a funny hoop we have to jump through to avoid major code
506             # duplication
507 67         200 @lines = ($matrix);
508             }
509              
510 73         272 for my $line (@lines) {
511 235         326 my @words = @{ _parse_nexus_words($line) };
  235         891  
512 235         917 my $name = q{};
513 235         357 my $in_grouping = 0;
514              
515             # my $group_position = 0;
516 235         355 my $saw_colon = 0;
517 235         315 my $last_state = q{};
518 235         286 my $i = 0;
519              
520             WORD:
521 235         451 for my $word (@words) {
522              
523             # If it's not an interleaved matrix and we've already parsed all
524             # the states for this taxon (nchar = number parsed), then move onto
525             # the next taxon
526 5728 100 100     29034 if ( !$expect_interleave
  3216   100     11050  
      100        
527             && !$in_grouping
528             && $taxa{$name}
529             && scalar @{ $taxa{$name} } == $nchar )
530             {
531 406         606 $name = q{};
532             }
533              
534             # If $name is empty, we're looking at the beginning of a new row
535 5728 100       11715 if ( $name eq q{} ) {
536 639 50       1280 if ($expect_labels) {
537 639         779 $name = $word;
538 639 100       3399 $taxa{$name} = [] unless exists $taxa{$name};
539 639         1245 next WORD;
540             }
541             else {
542 0         0 $name = $taxlabels[ $i++ ]; # (if 'NoLabels')
543 0         0 $taxa{$name} = [];
544              
545             # In case we're dealing with an interleaved, unlabeled matrix,
546             # reset $i if we've passed the end of the @taxlabels array
547 0 0       0 $i = $i > $#taxlabels ? 0 : $i;
548             }
549             }
550              
551 5089 50 100     57165 if ( $word ne $missing_symbol
    100 66        
    100 100        
    100          
    100          
552             && $word ne $gap_symbol
553             && $word =~ $punctuation_regex )
554             {
555 0         0 next WORD;
556             }
557             elsif ( $word eq '(' ) {
558 97         110 push @{ $taxa{$name} },
  97         377  
559             { 'type' => 'polymorphism', 'states' => undef };
560 97         172 $in_grouping = 1;
561             }
562             elsif ( $word eq '{' ) {
563 4         7 push @{ $taxa{$name} },
  4         140  
564             { 'type' => 'uncertainty', 'states' => undef };
565 4         7 $in_grouping = 1;
566             }
567             elsif ( $word eq ')' || $word eq '}' ) {
568 101         215 $in_grouping = 0;
569              
570             # $group_position = 0;
571             }
572             elsif ( $word eq ':' ) {
573 139 50 33     577 $saw_colon = 1 if ( $in_grouping && $expect_freq );
574             }
575             else {
576 4748 100       7473 if ($in_grouping) {
577 294 100       446 if ( !$saw_colon ) {
578 155 100       252 if ($expect_freq) {
579 139         390 $taxa{$name}->[-1]{'states'}{$word} = undef;
580 139         258 $last_state = $word;
581             }
582             else {
583              
584             # $taxa{$name}->[-1]{'states'}{$group_position++} = $word;
585 16         14 push @{ $taxa{$name}->[-1]{'states'} }, $word;
  16         49  
586             }
587             }
588             else {
589 139 50       441 $taxa{$name}->[-1]{'states'}{$last_state} = $word
590             if $expect_freq;
591 139         151 $saw_colon = 0;
592 139         213 $last_state = q{};
593             }
594             }
595             else {
596 4454 100       18143 my @seq = $expect_tokens ? ($word) : split //, $word;
597 4454         6063 push @{ $taxa{$name} }, @seq;
  4454         23622  
598             }
599             }
600             }
601             }
602              
603 73         813 my $title = $self->get_title();
604 73 100       278 $title = ": $title " if $title;
605 73         135 my (@otus);
606              
607 73         456 while ( my ( $name, $seq ) = each %taxa ) {
608 520 100       1225 unless ( $self->find_taxon($name) ) {
609 1   50     6 $title ||= '';
610 1         30 Bio::NEXUS::Util::Exceptions::BadArgs->throw(
611             'error' => "Characters$title block error...\n"
612             . "Unknown taxon '$name\' encountered in matrix. "
613             . "Common causes include: Misspelled names, "
614             . "sequence lengths that don't match the specified number of characters (nchar), "
615             . "including a taxon that is not listed in the Taxa Block, "
616             . "and not quoting names with whitespace or punctuation"
617             );
618             }
619 519         2344 push @otus, Bio::NEXUS::TaxUnit->new( $name, $seq );
620              
621             }
622              
623 72         446 my $otuset = $self->get_otuset();
624 72         504 $otuset->set_otus( \@otus );
625 72         382 $self->set_taxlabels( $otuset->get_otu_names() );
626 72         768 return \@otus;
627             }
628              
629             =head2 select_columns
630              
631             Title : select_columns
632             Usage : $block->select_columns($columns);
633             Function: select a subset of characters
634             Returns : new $self with subset of columns of characters
635             Args : column numbers
636              
637             =cut
638              
639             sub select_columns {
640 1     1 1 24 my ( $self, $columns ) = @_;
641 1         4 my $otuset = $self->get_otuset();
642 1         7 $otuset->select_columns($columns);
643 1         5 $self->set_nchar( $otuset->get_nchar );
644 1         2 return $self;
645             }
646              
647             =head2 rename_otus
648              
649             Title : rename_otus
650             Usage : $block->rename_otus(\%translation);
651             Function: Renames all the OTUs to something else
652             Returns : none
653             Args : hash containing translation
654              
655             =cut
656              
657             sub rename_otus {
658 4     4 1 916 my ( $self, $translation ) = @_;
659 4         20 $self->get_otuset()->rename_otus($translation);
660             }
661              
662             =head2 equals
663              
664             Name : equals
665             Usage : $block->equals($another);
666             Function: compare if two Bio::NEXUS::CharactersBlock objects are equal
667             Returns : boolean
668             Args : a Bio::NEXUS::CharactersBlock object
669              
670             =cut
671              
672             sub equals {
673 9     9 1 30 my ( $self, $block ) = @_;
674 9 50       62 if ( ! $self->SUPER::equals($block) ) { return 0; }
  0         0  
675 9         31 return $self->get_otuset()->equals( $block->get_otuset() );
676             }
677              
678             =begin comment
679              
680             Name : _write
681             Usage : $block->_write();
682             Function: Writes NEXUS block containing character data
683             Returns : none
684             Args : file handle
685              
686             =end comment
687              
688             =cut
689              
690             sub _write {
691 2     2   4 my ( $self, $fh, $verbose ) = @_;
692 2   50     5 $fh ||= \*STDOUT;
693              
694 2         6 Bio::NEXUS::Block::_write( $self, $fh );
695 2         15 $self->_write_dimensions( $fh, $verbose );
696 2         9 $self->_write_format( $fh, $verbose );
697 2         7 $self->_write_labels( $fh, $verbose );
698 2         9 $self->_write_matrix( $fh, $verbose );
699 2         6 print $fh "END;\n";
700             }
701              
702             =begin comment
703              
704             Name : _write_labels
705             Usage : $self->_write_labels($file_handle,$verbose);
706             Function: Writes Character labels and Character-State labels to the filehandle
707             Returns : none
708             Args : $file_handle and $verbose
709              
710             =end comment
711              
712             =cut
713              
714             sub _write_labels {
715 2     2   4 my ( $self, $fh, $verbose ) = @_;
716 2   50     6 $fh ||= \*STDOUT;
717              
718 2         3 my @charstates = @{ $self->get_charstatelabels() };
  2         6  
719 2 50       3 if ( keys %{ $charstates[0]->{'states'} } ) {
  2 50       10  
  2         8  
720 0         0 print $fh "\tCHARSTATELABELS\n";
721 0         0 for my $label (@charstates) {
722 0   0     0 my ( $id, $charlabel ) =
723             ( $label->{'id'}, $label->{'charlabel'} || '' );
724 0         0 $charlabel = _nexus_formatted($charlabel);
725 0         0 print $fh "\t$id $charlabel / ";
726 0         0 for my $key ( sort keys %{ $label->{'states'} } ) {
  0         0  
727 0         0 my $state = $label->{'states'}{$key};
728 0         0 $state = _nexus_formatted($state);
729 0         0 print $fh "$state ";
730             }
731 0         0 print $fh ",\n";
732             }
733 0         0 print $fh "\t;\n";
734             }
735             elsif ( @{ $self->get_charlabels } > 0 ) {
736 0         0 print $fh "\tCHARLABELS\n\t";
737 0         0 for my $charlabel ( @{ $self->get_charlabels } ) {
  0         0  
738 0         0 $charlabel = _nexus_formatted($charlabel);
739 0         0 print $fh " $charlabel";
740             }
741 0         0 print $fh ";\n";
742             }
743             }
744              
745             =begin comment
746              
747             Name : _write_matrix
748             Usage : $self->_write_matrix($file_handle,$verbose);
749             Function: Writes CharactersBlock matrix( The data stored in the matrix command) into the filehandle
750             Returns : none
751             Args : $file_handle and $verbose
752              
753             =end comment
754              
755             =cut
756              
757             sub _write_matrix {
758 2     2   3 my ( $self, $fh, $verbose ) = @_;
759 2   50     5 $fh ||= \*STDOUT;
760              
761 2         3 my @otus = @{ $self->get_otuset()->get_otus() };
  2         7  
762 2         4 print $fh "\tMATRIX\n";
763 2         3 for my $otu (@otus) {
764 12         32 my $otu_name = _nexus_formatted( $otu->get_name() );
765 12         47 my $seq = $otu->get_seq_string( $self->{'format'}->{'tokens'} );
766 12         40 print $fh "\t", $otu_name, "\t", $seq, "\n";
767             }
768 2         7 print $fh "\t;\n";
769              
770             }
771              
772             sub AUTOLOAD {
773 2 50   2   8 return if $AUTOLOAD =~ /DESTROY$/;
774 2         3 my $package_name = __PACKAGE__ . '::';
775              
776             # The following methods are deprecated and are temporarily supported
777             # via a warning and a redirection
778 2         12 my %synonym_for = (
779             "${package_name}set_charstates" => "${package_name}set_charstatelabels",
780             "${package_name}get_charstates" => "${package_name}get_charstatelabels",
781             );
782              
783 2 50       11 if ( defined $synonym_for{$AUTOLOAD} ) {
784 0         0 $logger->warn("$AUTOLOAD() is deprecated; use $synonym_for{$AUTOLOAD}() instead");
785 0         0 goto &{ $synonym_for{$AUTOLOAD} };
  0         0  
786             }
787             else {
788 2         17 Bio::NEXUS::Util::Exceptions::UnknownMethod->throw(
789             'error' => "ERROR: Unknown method $AUTOLOAD called"
790             );
791             }
792             }
793              
794             1;