sub new
{ my($class,@args) = @_;
my $self = $class->SUPER::new(@args);
($t1, $t2, $font, $size, my $top, my $bottom, my $left, my $right,
$tip, my $column, $compact, $ratio, $colors,$bootstrap) =
$self->_rearrange([qw(TREE SECOND FONT SIZE TOP BOTTOM LEFT RIGHT
TIP COLUMN COMPACT RATIO COLORS BOOTSTRAP)],
@args);
$font ||= "Helvetica-Narrow";
$size ||= 12;
$top ||= 10;
$bottom ||= 10;
$left ||= 10;
$right ||= 10;
$tip ||= 5;
$column ||= 60;
$compact ||= 0;
$ratio ||= 1 / 1.6180339887; $colors ||= 0;
$bootstrap ||= 0;
my @taxa1 = $t1->get_leaf_nodes;
my $root1 = $t1->get_root_node;
$tipwidth1 = 0;
foreach my $taxon (@taxa1) {
my $w = PostScript::Metrics::stringwidth($taxon->id,$font,$size);
if ($w > $tipwidth1) { $tipwidth1 = $w; }
}
my @taxa2;
my $root2;
my $ystep = 20;
if ($t2) {
@taxa2 = $t2->get_leaf_nodes;
$root2 = $t2->get_root_node;
$tipwidth2 = 0;
foreach my $taxon (@taxa2) {
my $w = PostScript::Metrics::stringwidth($taxon->id,$font,$size);
if ($w > $tipwidth2) { $tipwidth2 = $w; }
}
}
my $stems = $root1->height + 1;
if ($t2) { $stems += $root2->height + 1; }
my $labels = $tipwidth1;
if ($t2) { $labels += $tipwidth2; }
$xstep = 20;
$width = $left + $stems * $xstep + $tip + $labels + $right;
if ($t2) { $width += $tip + $column + $tip + $tip; }
$height = $bottom + $ystep * (@taxa1 - 1) + $top;
if ($t2) {
if ( scalar(@taxa2) > scalar(@taxa1) ) {
$height = $bottom + $ystep * (@taxa2 - 1) + $top;
}
}
my $ystep1 = $height / scalar(@taxa1); my $ystep2;
if ($t2) {
$ystep2 = $height / scalar(@taxa2); }
my $x = $left + $xstep * ($root1->height + 1) + $tip;
my $y = $bottom;
for my $taxon (reverse @taxa1) {
$xx{$taxon} = $x - $tip;
$yy{$taxon} = $y;
$y += $ystep1;
}
$x -= $xstep;
my @stack;
my @queue; push @stack, $t1->get_root_node;
while (@stack) {
my $node = pop @stack;
push @queue, $node;
foreach my $child ($node->each_Descendent(-sortby => 'internal_id')) {
push @stack, $child;
}
}
@queue = reverse @queue;
for my $node (@queue) {
if (!$node->is_Leaf) {
my @children = $node->each_Descendent;
my $child = shift @children;
my $xmin = $xx{$child};
my $ymin = my $ymax = $yy{$child};
foreach $child (@children) {
$xmin = $xx{$child} if $xx{$child} < $xmin;
$ymax = $yy{$child} if $yy{$child} > $ymax;
$ymin = $yy{$child} if $yy{$child} < $ymin;
}
$xx{$node} = $xmin - $xstep;
$yy{$node} = ($ymin + $ymax)/2; }
}
$xx{$t1->get_root_node} = $left + $xstep;
my @preorder = $t1->get_nodes(-order => 'depth');
for my $node (@preorder) {
if ($colors) {
if ($node->has_tag('Rcolor')) {
$Rcolor{$node} = $node->get_tag_values('Rcolor')
} else {
$Rcolor{$node} = 0
}
if ($node->has_tag('Gcolor')) {
$Gcolor{$node} = $node->get_tag_values('Gcolor')
} else {
$Gcolor{$node} = 0
}
if ($node->has_tag('Bcolor')) {
$Bcolor{$node} = $node->get_tag_values('Bcolor')
} else {
$Bcolor{$node} = 0
}
}
}
if ($compact) {
$width = 0;
shift @preorder; for my $node (@preorder) {
$xx{$node} = $xx{$node->ancestor} + $xstep;
$width = $xx{$node} if $xx{$node} > $width;
}
$width += $tip + $tipwidth1 + $right;
} else {
my $total_height = (scalar($t1->get_leaf_nodes) - 1) * $ystep;
my $scale_factor = $total_height * $ratio / $t1->get_root_node->height;
$width = $t1->get_root_node->height * $scale_factor;
$width += $left + $xstep;
$width += $tip + $tipwidth1 + $right;
shift @preorder; for my $node (@preorder) {
my $bl = $node->branch_length;
$bl = 1 unless (defined $bl && $bl =~ /^\-?\d+(\.\d+)?$/);
$xx{$node} = $xx{$node->ancestor} + $bl * $scale_factor;
}
}
if ($t2) {
$x = $left + $xstep * ($root1->height + 1) + $tip;
$x += $tipwidth1 + $tip + $column + $tip;
my $y = $bottom;
for my $taxon (reverse @taxa2) {
$xx{$taxon} = $x + $tipwidth2 + $tip;
$yy{$taxon} = $y;
$y += $ystep2;
}
$x += $xstep;
my @stack;
my @queue; push @stack, $t2->get_root_node;
while (@stack) {
my $node = pop @stack;
push @queue, $node;
foreach my $child ($node->each_Descendent(-sortby => 'internal_id')) {
push @stack, $child;
}
}
@queue = reverse @queue;
for my $node (@queue) {
if (!$node->is_Leaf) {
my @children = $node->each_Descendent;
my $child = shift @children;
my $xmax = $xx{$child};
my $ymin = my $ymax = $yy{$child};
foreach $child (@children) {
$xmax = $xx{$child} if $xx{$child} > $xmax;
$ymax = $yy{$child} if $yy{$child} > $ymax;
$ymin = $yy{$child} if $yy{$child} < $ymin;
}
$xx{$node} = $xmax + $xstep;
$yy{$node} = ($ymin + $ymax)/2; }
}
}
return $self;} |
sub print
{ my($self,@args) = @_;
my ($file) = $self->_rearrange([qw(FILE)], @args);
$file ||= "output.eps";
open(my $INFO,">", $file);
print $INFO "%!PS-Adobe-\n";
print $INFO "%%BoundingBox: 0 0 ", $width, " ", $height, "\n";
print $INFO "1 setlinewidth\n";
print $INFO "/$font findfont\n";
print $INFO "$size scalefont\n";
print $INFO "setfont\n";
for my $taxon (reverse $t1->get_leaf_nodes) {
if ($colors) {
print $INFO $Rcolor{$taxon}, " ", $Gcolor{$taxon}, " ", $Bcolor{$taxon}, " setrgbcolor\n";
}
print $INFO $xx{$taxon} + $tip, " ", $yy{$taxon} - $size / 3, " moveto\n"; print $INFO "(", $taxon->id, ") show\n";
}
my $root1 = $t1->get_root_node;
for my $node ($t1->get_nodes) {
if ($node->ancestor) {
if ($colors) {
print $INFO "stroke\n";
print $INFO $Rcolor{$node}, " ", $Gcolor{$node}, " ",
$Bcolor{$node}, " setrgbcolor\n";
}
print $INFO $xx{$node}, " ", $yy{$node}, " moveto\n";
print $INFO $xx{$node->ancestor}, " ", $yy{$node}, " lineto\n";
if( $bootstrap ) {
print $INFO $xx{$node->ancestor}+ $size/10, " ", $yy{$node->ancestor} - ($size / 3), " moveto\n";
print $INFO "(", $node->ancestor->id, ") show\n";
print $INFO $xx{$node->ancestor}, " ", $yy{$node}, " moveto\n";
}
print $INFO $xx{$node->ancestor}, " ", $yy{$node->ancestor}, " lineto\n";
}
}
my $ymin = $yy{$root1};
my $ymax = $yy{$root1};
foreach my $child ($root1->each_Descendent) {
$ymax = $yy{$child} if $yy{$child} > $ymax;
$ymin = $yy{$child} if $yy{$child} < $ymin;
}
my $zz = ($ymin + $ymax)/2; if ($colors) {
print $INFO "stroke\n";
print $INFO $Rcolor{$root1}, " ", $Gcolor{$root1}, " ", $Bcolor{$root1}, " setrgbcolor\n";
}
print $INFO $xx{$root1}, " ", $zz, " moveto\n";
print $INFO $xx{$root1} - $xstep, " ", $zz, " lineto\n";
if ($t2) {
for my $taxon (reverse $t2->get_leaf_nodes) {
my $tiplen2 = PostScript::Metrics::stringwidth($taxon->id,$font,$size);
print $INFO $xx{$taxon} - $tiplen2 - $tip, " ",
$yy{$taxon} - $size / 3, " moveto\n"; printf $INFO "(%s) show\n", $taxon->id;
}
for my $node ($t2->get_nodes) {
if ($node->ancestor) {
print $INFO $xx{$node}, " ", $yy{$node}, " moveto\n";
print $INFO $xx{$node->ancestor}, " ", $yy{$node}, " lineto\n";
print $INFO $xx{$node->ancestor}, " ",
$yy{$node->ancestor}, " lineto\n";
}
}
my $root2 = $t2->get_root_node;
my $ymin = $yy{$root2};
my $ymax = $yy{$root2};
foreach my $child2 ($root2->each_Descendent) {
$ymax = $yy{$child2} if $yy{$child2} > $ymax;
$ymin = $yy{$child2} if $yy{$child2} < $ymin;
}
my $zz = ($ymin + $ymax)/2; print $INFO $xx{$root2}, " ", $zz, " moveto\n";
print $INFO $xx{$root2} + $xstep, " ", $zz, " lineto\n";
my @taxa1 = $t1->get_leaf_nodes;
my @taxa2 = $t2->get_leaf_nodes;
foreach my $taxon1 (@taxa1) {
foreach my $taxon2 (@taxa2) {
if ($taxon1->id eq $taxon2->id) {
$taxon1->add_tag_value('connection',$taxon2);
last;
}
}
}
print $INFO "stroke\n";
print $INFO "0.5 setgray\n";
foreach my $taxon1 (@taxa1) {
my @match = $taxon1->get_tag_values('connection');
foreach my $taxon2 (@match) {
my $x0 = $xx{$taxon1} + $tip
+ PostScript::Metrics::stringwidth($taxon1->id,$font,$size) + $tip;
my $x1 = $xx{$taxon1} + $tip + $tipwidth1 + $tip;
my $y1 = $yy{$taxon1};
my $x2 = $xx{$taxon2} - $tip - $tipwidth2 - $tip;
my $x3 = $xx{$taxon2} - $tip
- PostScript::Metrics::stringwidth($taxon2->id,$font,$size) - $tip;
my $y2 = $yy{$taxon2};
print $INFO $x0, " ", $y1, " moveto\n";
print $INFO $x1, " ", $y1, " lineto\n";
print $INFO $x2, " ", $y2, " lineto\n";
print $INFO $x3, " ", $y2, " lineto\n";
}
}
}
print $INFO "stroke\n";
print $INFO "showpage\n";
}
1; } |
The rest of the documentation details each of the object methods.
Internal methods are usually preceded with a _