2 # BioPerl module for Bio::Matrix::Generic
4 # Please direct questions and support issues to <bioperl-l@bioperl.org>
6 # Cared for by Jason Stajich <jason-at-bioperl-dot-org>
8 # Copyright Jason Stajich
10 # You may distribute this module under the same terms as perl itself
12 # POD documentation - main docs before the code
16 Bio::Matrix::Generic - A generic matrix implementation
20 # A matrix has columns and rows
21 my $matrix = Bio::Matrix::Generic->new;
22 $matrix->add_column(1,$column1);
23 $matrix->add_column(2,$column2);
25 my $element = $matrix->entry_by_num(1,2);
26 $matrix->entry_by_num(1,2,$newval);
28 my $entry = $matrix->entry('human', 'mouse');
30 $matrix->entry('human','mouse', $newval);
35 This is a general purpose matrix object for dealing with row+column
36 data which is typical when enumerating all the pairwise combinations
37 and desiring to get slices of the data.
39 Data can be accessed by column and row names or indexes. Matrix
46 User feedback is an integral part of the evolution of this and other
47 Bioperl modules. Send your comments and suggestions preferably to
48 the Bioperl mailing list. Your participation is much appreciated.
50 bioperl-l@bioperl.org - General discussion
51 http://bioperl.org/wiki/Mailing_lists - About the mailing lists
55 Please direct usage questions or support issues to the mailing list:
57 I<bioperl-l@bioperl.org>
59 rather than to the module maintainer directly. Many experienced and
60 reponsive experts will be able look at the problem and quickly
61 address it. Please include a thorough description of the problem
62 with code and data examples if at all possible.
66 Report bugs to the Bioperl bug tracking system to help us keep track
67 of the bugs and their resolution. Bug reports can be submitted via the
70 https://github.com/bioperl/bioperl-live/issues
72 =head1 AUTHOR - Jason Stajich
74 Email jason-at-bioperl-dot-org
78 The rest of the documentation details each of the object methods.
79 Internal methods are usually preceded with a _
83 package Bio
::Matrix
::Generic
;
88 use base
qw(Bio::Root::Root Bio::Matrix::MatrixI);
93 Usage : my $obj = Bio::Matrix::Generic->new();
94 Function: Builds a new Bio::Matrix::Generic object
95 Returns : an instance of Bio::Matrix::Generic
96 Args : -values => arrayref of arrayrefs of data initialization
97 -rownames => arrayref of row names
98 -colnames => arrayref of col names
99 -matrix_id => id of the matrix
100 -matrix_name=> name of the matrix
101 -matrix_init_value => default value to initialize empty cells
106 my($class,@args) = @_;
108 my $self = $class->SUPER::new
(@args);
109 my ($values, $rownames, $colnames,
110 $id,$name,$init_val) =
111 $self->_rearrange([qw(VALUES ROWNAMES COLNAMES
112 MATRIX_ID MATRIX_NAME
113 MATRIX_INIT_VALUE)],@args);
114 $self->matrix_id($id) if defined $id;
115 $self->matrix_name($name) if defined $name;
116 if( defined $rownames && defined $colnames ) {
117 if( ref($rownames) !~ /ARRAY/i ) {
118 $self->throw("need an arrayref for the -rownames option");
120 # insure we copy the values
121 $self->{'_rownames'} = [ @
$rownames ];
123 %{$self->{'_rownamesmap'}} = map { $_ => $count++ } @
$rownames;
125 if( ref($colnames) !~ /ARRAY/i ) {
126 $self->throw("need an arrayref for the -colnames option");
128 # insure we copy the values
129 $self->{'_colnames'} = [ @
$colnames ];
131 %{$self->{'_colnamesmap'}} = map { $_ => $count++ } @
$colnames;
133 $self->{'_values'} = [];
134 if( defined $values ) {
135 if( ref($values) !~ /ARRAY/i ) {
136 $self->throw("Need an arrayref of arrayrefs (matrix) for -values option");
138 for my $v ( @
$values ) {
139 if( ref($v) !~ /ARRAY/i ) {
140 $self->throw("Need and array of arrayrefs (matrix) for -values option");
142 push @
{$self->{'_values'}}, [@
$v];
145 my @fill = ($init_val) x
scalar @
$colnames; # undef init_val will be default
147 push @
{$self->{'_values'}}, [@fill];
150 } elsif( ! defined $rownames && ! defined $colnames && ! defined $values ) {
151 $self->{'_values'} = [];
152 $self->{'_rownames'} = [];
153 $self->{'_colnames'} = [];
155 $self->throw("Must have either provided no values/colnames/rownames or provided all three");
165 Usage : my $id = $matrix->matrix_id
166 Function: Get/Set the matrix ID
167 Returns : scalar value
168 Args : [optional] new id value to store
175 return $self->{'_matid'} = shift if @_;
176 return $self->{'_matid'};
184 Usage : my $name = $matrix->matrix_name();
185 Function: Get/Set the matrix name
186 Returns : scalar value
187 Args : [optional] new matrix name value
194 return $self->{'_matname'} = shift if @_;
195 return $self->{'_matname'};
202 Usage : my $entry = $matrix->entry($row,$col,$value)
203 Function: Get the value for a specific cell as specified
204 by the row and column names
205 Returns : scalar value or undef if row or col does not
207 Args : $rowname - name of the row
208 $colname - column name
209 $value - [optional] New value for the entry
214 my ($self,$row,$column,$newvalue) = @_;
215 if( ! defined $row || ! defined $column ) {
216 $self->throw("Need at least 2 ids");
219 my ($rownum) = $self->row_num_for_name($row);
220 my ($colnum) = $self->column_num_for_name($column);
221 return $self->entry_by_num($rownum,$colnum,$newvalue);
227 Usage : my $entry = $matrix->get_entry($rowname,$columname,$value)
228 Function: Get the entry for a given row,column pair
237 sub get_entry
{ $_[0]->entry($_[1],$_[2]) }
242 Usage : my $entry = $matrix->entry_by_num($rownum,$colnum)
243 Function: Get an entry by row and column numbers instead of by name
244 (rows and columns start at 0)
245 Returns : scalar value or undef if row or column name does not
247 Args : $row - row number
249 [optional] $newvalue to store at this cell
254 my ($self,$row,$col,$newvalue) = @_;
255 if( ! defined $row || ! defined $col ||
258 $self->warn("expected to get 2 number for entry_by_num");
262 if( defined $newvalue ) {
263 return $self->_values->[$row][$col] = $newvalue;
265 return $self->_values->[$row][$col];
278 Usage : my @col = $matrix->column('ALPHA');
280 $matrix->column('ALPHA', \@col);
281 Function: Get/Set a particular column
282 Returns : Array (in array context) or arrayref (in scalar context)
284 For setting will warn if the new column is of a different
285 length from the rest of the columns.
286 Args : name of the column
287 [optional] new column to store here
292 my ($self,$column,$newcol) = @_;
294 if( ! defined $column ) {
295 $self->warn("Need at least a column id");
298 my $colnum = $self->column_num_for_name($column);
299 if( ! defined $colnum ) {
300 $self->warn("could not find column number for $column");
303 return $self->column_by_num($colnum,$newcol);
310 Usage : my @row = $matrix->get_column('ALPHA');
311 Function: Get a particular column
312 Returns : Array (in array context) or arrayref (in scalar context)
314 Args : name of the column
319 sub get_column
{ $_[0]->column($_[1]) }
324 Title : column_by_num
325 Usage : my @col = $matrix->column_by_num(1);
327 $matrix->column_by_num(1,\@newcol);
328 Function: Get/Set a column by its number instead of name
329 (cols/rows start at 0)
330 Returns : Array (in array context) or arrayref (in scalar context)
332 Args : name of the column
333 [optional] new value to store for a particular column
338 my ($self,$colnum,$newcol) = @_;
339 if( ! defined $colnum ) {
340 $self->warn("need at least a column number");
343 my $rowcount = $self->num_rows;
344 my $colcount = $self->num_columns;
347 if( defined $newcol ) {
348 if( ref($newcol) !~ /ARRAY/i) {
349 $self->warn("expected a valid arrayref for resetting a column");
352 if( scalar @
$newcol != $rowcount ) {
353 $self->warn("new column is not the correct length ($rowcount) - call add or remove row to shrink or grow the number of rows first");
356 for(my $i=0; $i < $rowcount; $i++) {
357 $self->entry_by_num($i,$colnum,$newcol->[$i]);
362 for(my $i=0; $i < $rowcount; $i++) {
363 push @
$ret,$self->entry_by_num($i,$colnum);
366 if( wantarray ) { return @
$ret }
374 Usage : my @row = $matrix->row($rowname);
376 $matrix->row($rowname,\@rowvalues);
377 Function: Get/Set the row of the matrix
378 Returns : Array (in array context) or arrayref (in scalar context)
380 [optional] new value of row to store
386 my ($self,$row,$newrow) = @_;
387 if( ! defined $row) {
388 $self->warn("Need at least a row id");
391 my $rownum = $self->row_num_for_name($row);
392 return $self->row_by_num($rownum,$newrow);
399 Usage : my @row = $matrix->get_row('ALPHA');
400 Function: Get a particular row
401 Returns : Array (in array context) or arrayref (in scalar context)
403 Args : name of the row
407 sub get_row
{ $_[0]->row($_[1]) }
412 Usage : my @row = $matrix->row_by_num($rownum);
414 $matrix->row($rownum,\@rowvalues);
415 Function: Get/Set the row of the matrix
416 Returns : Array (in array context) or arrayref (in scalar context)
418 [optional] new value of row to store
423 my ($self,$rownum,$newrow) = @_;
424 if( ! defined $rownum ) {
425 $self->warn("need at least a row number");
428 my $colcount = $self->num_columns;
430 if( defined $newrow ) {
431 if( ref($newrow) !~ /ARRAY/i) {
432 $self->warn("expected a valid arrayref for resetting a row");
435 if( scalar @
$newrow != $colcount ) {
436 $self->warn("new row is not the correct length ($colcount) - call add or remove column to shrink or grow the number of columns first");
439 for(my $i=0; $i < $colcount; $i++) {
440 $self->entry_by_num($rownum,$i, $newrow->[$i]);
445 for(my $i=0; $i < $colcount; $i++) {
446 # we're doing this to explicitly
447 # copy the entire row
448 push @
$ret, $self->entry_by_num($rownum,$i);
451 if( wantarray ) { return @
$ret }
461 Usage : my @diagonal = $matrix->get_diagonal()
462 Function: Get the diagonal of a matrix
463 Returns : Array (in array context) or arrayref (in scalar context)
464 of values which lie along the diagonal
473 my $rowcount = $self->num_rows;
474 my $colcount = $self->num_columns;
475 for(my $i = 0; $i < $rowcount; $i++ ) {
476 push @diag, $self->entry_by_num($i,$i);
485 Usage : $matrix->add_row($index,\@newrow);
486 Function: Adds a row at particular location in the matrix.
487 If $index < the rowcount will shift all the rows down
488 by the number of new rows.
489 To add a single empty row, simply call
490 $matrix->add_row($index,undef);
491 Returns : the updated number of total rows in the matrix
492 Args : index to store
493 name of the row (header)
494 newrow to add, if this is undef will add a single
495 row with all values set to undef
500 my ($self,$index,$name,$newrow) = @_;
501 if( !defined $index ||
502 $index !~ /^\d+$/ ) {
503 $self->warn("expected a valid row index in add_row");
505 } elsif( ! defined $name) {
506 $self->warn("Need a row name or heading");
508 } elsif( defined $self->row_num_for_name($name) ) {
509 $self->warn("Need a unqiue name for the column heading, $name is already used");
512 my $colcount = $self->num_columns;
513 my $rowcount = $self->num_rows;
515 if( $index > $rowcount ) {
516 $self->warn("cannot add a row beyond 1+last row at the end ($rowcount) not $index - adding at $rowcount instead");
520 if( ! defined $newrow ) {
522 $newrow->[$colcount] = undef;
523 } elsif( ref($newrow) !~ /ARRAY/i ) {
524 $self->throw("Expected either undef or a valid arrayref for add_row");
526 # add this row to the matrix by carving out space for it with
528 splice(@
{$self->{'_values'}}, $index,0,[]);
529 for( my $i = 0; $i < $colcount; $i++ ) {
530 $self->entry_by_num($index,$i,$newrow->[$i]);
532 splice(@
{$self->{'_rownames'}}, $index,0,$name);
533 # Sadly we have to remap these each time (except for the case
534 # when we're adding a new column to the end, but I don't think
535 # the speedup for that case warrants the extra code at this time.
537 %{$self->{'_rownamesmap'}} = map { $_ => $ct++} @
{$self->{'_rownames'}};
538 return $self->num_rows;
544 Usage : $matrix->remove_row($colnum)
545 Function: remove a row from the matrix shifting all the rows
547 Returns : Updated number of rows in the matrix
554 my ($self,$rowindex) = @_;
555 my $rowcount = $self->num_rows;
557 if( $rowindex > $rowcount ) {
558 $self->warn("rowindex $rowindex is greater than number of rows $rowcount, cannot process");
561 splice(@
{$self->_values},$rowindex,1);
562 delete $self->{'_rownamesmap'}->{$self->{'_rownames'}->[$rowindex]};
563 splice(@
{$self->{'_rownames'}},$rowindex,1);
566 %{$self->{'_rownamesmap'}} = map { $_ => $ct++} @
{$self->{'_rownames'}};
567 return $self->num_rows;
573 Usage : $matrix->add_column($index,$colname,\@newcol);
574 Function: Adds a column at particular location in the matrix.
575 If $index < the colcount will shift all the columns right
576 by the number of new columns.
577 To add a single empty column, simply call
578 $matrix->add_column($index,undef);
579 Returns : the updated number of total columns in the matrix
580 Args : index to store
581 name of the column (header)
582 newcolumn to add, if this is undef will add a single
583 column with all values set to undef
590 my ($self,$index,$name,$newcol) = @_;
591 if( !defined $index ||
592 $index !~ /^\d+$/ ) {
593 $self->warn("expected a valid col index in add_column");
595 } elsif( ! defined $name) {
596 $self->warn("Need a column name or heading");
598 } elsif( defined $self->column_num_for_name($name) ) {
599 $self->warn("Need a unqiue name for the column heading, $name is already used");
602 my $colcount = $self->num_columns;
603 my $rowcount = $self->num_rows;
604 if( $index > $colcount ) {
605 $self->warn("cannot add a column beyond 1+last column at the end ($colcount) not $index - adding at $colcount instead");
609 if( ! defined $newcol ) {
611 $newcol->[$rowcount] = undef; # make the array '$rowcount' long
612 } elsif( ref($newcol) !~ /ARRAY/i ) {
613 $self->throw("Expected either undef or a valid arrayref for add_row");
615 for( my $i = 0; $i < $rowcount; $i++ ) {
616 # add this column to each row
617 splice(@
{$self->_values->[$i]},$index,0,[]);
618 $self->entry_by_num($i,$index,$newcol->[$i]);
620 splice(@
{$self->{'_colnames'}}, $index,0,$name);
621 # Sadly we have to remap these each time (except for the case
622 # when we're adding a new column to the end, but I don't think
623 # the speedup for that case warrants the extra code at this time.
625 %{$self->{'_colnamesmap'}} = map {$_ => $ct++} @
{$self->{'_colnames'}};
626 return $self->num_columns;
631 Title : remove_column
632 Usage : $matrix->remove_column($colnum)
633 Function: remove a column from the matrix shifting all the columns
635 Returns : Updated number of columns in the matrix
641 my ($self,$colindex) = @_;
643 my $colcount = $self->num_columns;
644 my $rowcount = $self->num_rows;
645 if( $colindex > $colcount ) {
646 $self->warn("colindex $colindex is greater than number of columns ($colcount), cannot process");
649 for(my $i = 0; $i < $rowcount; $i++ ) {
650 splice(@
{$self->_values->[$i]},$colindex,1);
652 delete $self->{'_colnamesmap'}->{$self->{'_colnames'}->[$colindex]};
653 splice(@
{$self->{'_colnames'}},$colindex,1);
656 %{$self->{'_colnamesmap'}} = map {$_ => $ct++} @
{$self->{'_colnames'}};
657 return $self->num_columns;
660 =head2 column_num_for_name
662 Title : column_num_for_name
663 Usage : my $num = $matrix->column_num_for_name($name)
664 Function: Gets the column number for a particular column name
671 sub column_num_for_name
{
672 my ($self,$name) = @_;
674 return $self->{'_colnamesmap'}->{$name};
677 =head2 row_num_for_name
679 Title : row_num_for_name
680 Usage : my $num = $matrix->row_num_for_name
681 Function: Gets the row number for a particular row name
688 sub row_num_for_name
{
689 my ($self,$name) = @_;
690 return $self->{'_rownamesmap'}->{$name}
696 Title : column_header
697 Usage : my $name = $matrix->column_header(0)
698 Function: Gets the column header for a particular column number
706 my ($self,$num) = @_;
707 return $self->{'_colnames'}->[$num];
714 Usage : my $name = $matrix->row_header(0)
715 Function: Gets the row header for a particular row number
723 my ($self,$num) = @_;
724 return $self->{'_rownames'}->[$num];
730 Usage : my $rowcount = $matrix->num_rows;
731 Function: Get the number of rows
740 return scalar @
{$self->_values};
747 Usage : my $colcount = $matrix->num_columns
748 Function: Get the number of columns
757 return scalar @
{$self->_values->[0] || []};
764 Usage : my @rows = $matrix->row_names
765 Function: The names of all the rows
766 Returns : array in array context, arrayref in scalar context
774 return @
{shift->{'_rownames'}};
776 return shift->{'_rownames'};
784 Usage : my @columns = $matrix->column_names
785 Function: The names of all the columns
786 Returns : array in array context, arrayref in scalar context
794 return @
{shift->{'_colnames'}};
796 return shift->{'_colnames'};
800 =head2 private methods
802 Private methods for a Generic Matrix
807 Usage : $matrix->_values();
808 Function: get/set for array ref of the matrix containing
810 Returns : an array reference
811 Args : an array reference
817 my ($self,$val) = @_;
819 $self->{'_values'} = $val;
821 return $self->{'_values'};