tag fourth (and hopefully last) alpha
[bioperl-live.git] / branch-1-6 / Bio / AlignIO / clustalw.pm
blobbb7817432bf913cddc9bc09f992cca18a44507f4
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 I<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('\.','-');
217 # no sequences added, so just return
218 return $aln if $aln->num_sequences;
219 return;
222 =head2 write_aln
224 Title : write_aln
225 Usage : $stream->write_aln(@aln)
226 Function: writes the clustalw-format object (.aln) into the stream
227 Returns : 1 for success and 0 for error
228 Args : Bio::Align::AlignI object
230 =cut
232 sub write_aln {
233 my ( $self, @aln ) = @_;
234 my ( $count, $length, $seq, @seq, $tempcount, $line_len );
235 $line_len = $self->line_length || $LINELENGTH;
236 foreach my $aln (@aln) {
237 if ( !$aln || !$aln->isa('Bio::Align::AlignI') ) {
238 $self->warn(
239 "Must provide a Bio::Align::AlignI object when calling write_aln"
241 next;
243 my $matchline = $aln->match_line;
244 if ( $self->force_displayname_flat ) {
245 $aln->set_displayname_flat(1);
247 $self->_print(
248 sprintf( "CLUSTAL W(%s) multiple sequence alignment\n\n\n",
249 $CLUSTALPRINTVERSION )
250 ) or return;
251 $length = $aln->length();
252 $count = $tempcount = 0;
253 @seq = $aln->each_seq();
254 my $max = 22;
255 foreach $seq (@seq) {
256 $max = length( $aln->displayname( $seq->get_nse() ) )
257 if ( length( $aln->displayname( $seq->get_nse() ) ) > $max );
260 while ( $count < $length ) {
261 my ( $linesubstr, $first ) = ( '', 1 );
262 foreach $seq (@seq) {
265 # Following lines are to suppress warnings
266 # if some sequences in the alignment are much longer than others.
268 my ($substring);
269 my $seqchars = $seq->seq();
270 SWITCH: {
271 if ( length($seqchars) >= ( $count + $line_len ) ) {
272 $substring = substr( $seqchars, $count, $line_len );
273 if ($first) {
274 $linesubstr =
275 substr( $matchline, $count, $line_len );
276 $first = 0;
278 last SWITCH;
280 elsif ( length($seqchars) >= $count ) {
281 $substring = substr( $seqchars, $count );
282 if ($first) {
283 $linesubstr = substr( $matchline, $count );
284 $first = 0;
286 last SWITCH;
288 $substring = "";
290 $self->_print(
291 sprintf(
292 "%-" . $max . "s %s\n",
293 $aln->displayname( $seq->get_nse() ), $substring
295 ) or return;
298 my $percentages = '';
299 if ( $self->percentages ) {
300 my ($strcpy) = ($linesubstr);
301 my $count = ( $strcpy =~ tr/\*// );
302 $percentages =
303 sprintf( "\t%d%%", 100 * ( $count / length($linesubstr) ) );
305 $self->_print(
306 sprintf(
307 "%-" . $max . "s %s%s\n",
308 '', $linesubstr, $percentages
311 $self->_print( sprintf("\n\n") ) or return;
312 $count += $line_len;
315 $self->flush if $self->_flush_on_write && defined $self->_fh;
316 return 1;
319 =head2 percentages
321 Title : percentages
322 Usage : $obj->percentages($newval)
323 Function: Set the percentages flag - whether or not to show percentages in
324 each output line
325 Returns : value of percentages
326 Args : newvalue (optional)
329 =cut
331 sub percentages {
332 my ( $self, $value ) = @_;
333 if ( defined $value ) {
334 $self->{'_percentages'} = $value;
336 return $self->{'_percentages'};
339 =head2 line_length
341 Title : line_length
342 Usage : $obj->line_length($newval)
343 Function: Set the alignment output line length
344 Returns : value of line_length
345 Args : newvalue (optional)
348 =cut
350 sub line_length {
351 my ( $self, $value ) = @_;
352 if ( defined $value ) {
353 $self->{'_line_length'} = $value;
355 return $self->{'_line_length'};