sync w/ main trunk
[bioperl-live.git] / Bio / AlignIO / clustalw.pm
blob60d691e3700a330f552d7548c73d04a526dd3a67
1 # $Id$
3 # BioPerl module for Bio::AlignIO::clustalw
5 # based on the Bio::SeqIO modules
6 # by Ewan Birney <birney@ebi.ac.uk>
7 # and Lincoln Stein <lstein@cshl.org>
8 # and the Bio::SimpleAlign module of Ewan Birney
10 # Copyright Peter Schattner
12 # You may distribute this module under the same terms as perl itself
13 # History
14 # September 5, 2000
15 # POD documentation - main docs before the code
17 =head1 NAME
19 Bio::AlignIO::clustalw - clustalw sequence input/output stream
21 =head1 SYNOPSIS
23 Do not use this module directly. Use it via the Bio::AlignIO class.
25 =head1 DESCRIPTION
27 This object can transform Bio::Align::AlignI objects to and from clustalw
28 files.
30 =head1 FEEDBACK
32 =head2 Mailing Lists
34 User feedback is an integral part of the evolution of this and other
35 Bioperl modules. Send your comments and suggestions preferably to one
36 of the Bioperl mailing lists. Your participation is much appreciated.
38 bioperl-l@bioperl.org - General discussion
39 http://bioperl.org/wiki/Mailing_lists - About the mailing lists
41 =head2 Support
43 Please direct usage questions or support issues to the mailing list:
45 L<bioperl-l@bioperl.org>
47 rather than to the module maintainer directly. Many experienced and
48 reponsive experts will be able look at the problem and quickly
49 address it. Please include a thorough description of the problem
50 with code and data examples if at all possible.
52 =head2 Reporting Bugs
54 Report bugs to the Bioperl bug tracking system to help us keep track
55 the bugs and their resolution. Bug reports can be submitted via the
56 web:
58 http://bugzilla.open-bio.org/
60 =head1 AUTHORS - Peter Schattner
62 Email: schattner@alum.mit.edu
65 =head1 APPENDIX
67 The rest of the documentation details each of the object
68 methods. Internal methods are usually preceded with a _
70 =cut
72 # Let the code begin...
74 package Bio::AlignIO::clustalw;
75 use vars qw($LINELENGTH $CLUSTALPRINTVERSION);
76 use strict;
79 $LINELENGTH = 60;
80 $CLUSTALPRINTVERSION = '1.81';
81 use base qw(Bio::AlignIO);
83 =head2 new
85 Title : new
86 Usage : $alignio = Bio::AlignIO->new(-format => 'clustalw',
87 -file => 'filename');
88 Function: returns a new Bio::AlignIO object to handle clustalw files
89 Returns : Bio::AlignIO::clustalw object
90 Args : -verbose => verbosity setting (-1, 0, 1, 2)
91 -file => name of file to read in or to write, with ">"
92 -fh => alternative to -file param - provide a filehandle
93 to read from or write to
94 -format => alignment format to process or produce
95 -percentages => display a percentage of identity
96 in each line of the alignment (clustalw only)
97 -linelength=> alignment output line length (default 60)
99 =cut
101 sub _initialize {
102 my ( $self, @args ) = @_;
103 $self->SUPER::_initialize(@args);
104 my ( $percentages, $ll ) =
105 $self->_rearrange( [qw(PERCENTAGES LINELENGTH)], @args );
106 defined $percentages && $self->percentages($percentages);
107 $self->line_length( $ll || $LINELENGTH );
110 =head2 next_aln
112 Title : next_aln
113 Usage : $aln = $stream->next_aln()
114 Function: returns the next alignment in the stream
115 Returns : Bio::Align::AlignI object
116 Args : NONE
118 See L<Bio::Align::AlignI> for details
120 =cut
122 sub next_aln {
123 my ($self) = @_;
124 my $first_line;
126 while ( $first_line = $self->_readline ) {
127 last if $first_line !~ /^$/;
129 $self->_pushback($first_line);
130 if ( defined( $first_line = $self->_readline )
131 && $first_line !~ /CLUSTAL/ )
133 $self->throw(
134 "trying to parse a file which does not start with a CLUSTAL header"
137 my %alignments;
138 my $aln = Bio::SimpleAlign->new(
139 -source => 'clustalw',
140 -verbose => $self->verbose
142 my $order = 0;
143 my %order;
144 $self->{_lastline} = '';
145 my ($first_block, $seen_block) = (0,0);
146 while ( defined( $_ = $self->_readline ) ) {
147 next if (/^\s+$/ && !$first_block);
148 if (/^\s$/) { # line contains no description
149 $seen_block = 1;
150 next;
152 $first_block = 1;
153 # break the loop if we come to the end of the current alignment
154 # and push back the CLUSTAL header
155 if (/CLUSTAL/) {
156 $self->_pushback($_);
157 last;
160 my ( $seqname, $aln_line ) = ( '', '' );
161 if (/^\s*(\S+)\s*\/\s*(\d+)-(\d+)\s+(\S+)\s*$/ox) {
163 # clustal 1.4 format
164 ( $seqname, $aln_line ) = ( "$1:$2-$3", $4 );
166 # } elsif( /^\s*(\S+)\s+(\S+)\s*$/ox ) { without trailing numbers
168 elsif (/^\s*(\S+)\s+(\S+)\s*\d*\s*$/ox) { # with numbers
169 ( $seqname, $aln_line ) = ( $1, $2 );
170 if ( $seqname =~ /^[\*\.\+\:]+$/ ) {
171 $self->{_lastline} = $_;
172 next;
175 else {
176 $self->{_lastline} = $_;
177 next;
180 if ( !$seen_block ) {
181 if (exists $order{$seqname}) {
182 $self->warn("Duplicate sequence : $seqname\n".
183 "Can't guarantee alignment quality");
185 else {
186 $order{$seqname} = $order++;
190 $alignments{$seqname} .= $aln_line;
193 my ( $sname, $start, $end );
194 foreach my $name ( sort { $order{$a} <=> $order{$b} } keys %alignments ) {
195 if ( $name =~ /(\S+):(\d+)-(\d+)/ ) {
196 ( $sname, $start, $end ) = ( $1, $2, $3 );
198 else {
199 ( $sname, $start ) = ( $name, 1 );
200 my $str = $alignments{$name};
201 $str =~ s/[^A-Za-z]//g;
202 $end = length($str);
204 my $seq = Bio::LocatableSeq->new(
205 -seq => $alignments{$name},
206 -id => $sname,
207 -start => $start,
208 -end => $end
210 $aln->add_seq($seq);
213 # not sure if this should be a default option - or we can pass in
214 # an option to do this in the future? --jason stajich
215 # $aln->map_chars('\.','-');
216 undef $aln if ( !defined $end || $end <= 0 );
217 return $aln;
220 =head2 write_aln
222 Title : write_aln
223 Usage : $stream->write_aln(@aln)
224 Function: writes the clustalw-format object (.aln) into the stream
225 Returns : 1 for success and 0 for error
226 Args : Bio::Align::AlignI object
228 =cut
230 sub write_aln {
231 my ( $self, @aln ) = @_;
232 my ( $count, $length, $seq, @seq, $tempcount, $line_len );
233 $line_len = $self->line_length || $LINELENGTH;
234 foreach my $aln (@aln) {
235 if ( !$aln || !$aln->isa('Bio::Align::AlignI') ) {
236 $self->warn(
237 "Must provide a Bio::Align::AlignI object when calling write_aln"
239 next;
241 my $matchline = $aln->match_line;
242 if ( $self->force_displayname_flat ) {
243 $aln->set_displayname_flat(1);
245 $self->_print(
246 sprintf( "CLUSTAL W(%s) multiple sequence alignment\n\n\n",
247 $CLUSTALPRINTVERSION )
248 ) or return;
249 $length = $aln->length();
250 $count = $tempcount = 0;
251 @seq = $aln->each_seq();
252 my $max = 22;
253 foreach $seq (@seq) {
254 $max = length( $aln->displayname( $seq->get_nse() ) )
255 if ( length( $aln->displayname( $seq->get_nse() ) ) > $max );
258 while ( $count < $length ) {
259 my ( $linesubstr, $first ) = ( '', 1 );
260 foreach $seq (@seq) {
263 # Following lines are to suppress warnings
264 # if some sequences in the alignment are much longer than others.
266 my ($substring);
267 my $seqchars = $seq->seq();
268 SWITCH: {
269 if ( length($seqchars) >= ( $count + $line_len ) ) {
270 $substring = substr( $seqchars, $count, $line_len );
271 if ($first) {
272 $linesubstr =
273 substr( $matchline, $count, $line_len );
274 $first = 0;
276 last SWITCH;
278 elsif ( length($seqchars) >= $count ) {
279 $substring = substr( $seqchars, $count );
280 if ($first) {
281 $linesubstr = substr( $matchline, $count );
282 $first = 0;
284 last SWITCH;
286 $substring = "";
288 $self->_print(
289 sprintf(
290 "%-" . $max . "s %s\n",
291 $aln->displayname( $seq->get_nse() ), $substring
293 ) or return;
296 my $percentages = '';
297 if ( $self->percentages ) {
298 my ($strcpy) = ($linesubstr);
299 my $count = ( $strcpy =~ tr/\*// );
300 $percentages =
301 sprintf( "\t%d%%", 100 * ( $count / length($linesubstr) ) );
303 $self->_print(
304 sprintf(
305 "%-" . $max . "s %s%s\n",
306 '', $linesubstr, $percentages
309 $self->_print( sprintf("\n\n") ) or return;
310 $count += $line_len;
313 $self->flush if $self->_flush_on_write && defined $self->_fh;
314 return 1;
317 =head2 percentages
319 Title : percentages
320 Usage : $obj->percentages($newval)
321 Function: Set the percentages flag - whether or not to show percentages in
322 each output line
323 Returns : value of percentages
324 Args : newvalue (optional)
327 =cut
329 sub percentages {
330 my ( $self, $value ) = @_;
331 if ( defined $value ) {
332 $self->{'_percentages'} = $value;
334 return $self->{'_percentages'};
337 =head2 line_length
339 Title : line_length
340 Usage : $obj->line_length($newval)
341 Function: Set the alignment output line length
342 Returns : value of line_length
343 Args : newvalue (optional)
346 =cut
348 sub line_length {
349 my ( $self, $value ) = @_;
350 if ( defined $value ) {
351 $self->{'_line_length'} = $value;
353 return $self->{'_line_length'};