File Coverage

blib/lib/Bio/Phylo/Treedrawer/Abstract.pm
Criterion Covered Total %
statement 108 278 38.8
branch 33 98 33.6
condition 6 21 28.5
subroutine 13 28 46.4
pod n/a
total 160 425 37.6


line stmt bran cond sub pod time code
1             package Bio::Phylo::Treedrawer::Abstract;
2 3     3   19 use strict;
  3         6  
  3         71  
3 3     3   12 use warnings;
  3         6  
  3         139  
4 3     3   17 use Bio::Phylo::Util::Exceptions 'throw';
  3         6  
  3         176  
5 3     3   15 use Bio::Phylo::Util::Logger ':levels';
  3         6  
  3         8941  
6              
7             my $logger = Bio::Phylo::Util::Logger->new;
8             our $DEFAULT_FONT = 'Arial';
9             our @FONT_DIR;
10              
11             =head1 NAME
12              
13             Bio::Phylo::Treedrawer::Abstract - Abstract graphics writer used by treedrawer, no
14             serviceable parts inside
15              
16             =head1 DESCRIPTION
17              
18             This module is an abstract super class for the various graphics formats that
19             Bio::Phylo supports. There is no direct usage of this class. Consult
20             L<Bio::Phylo::Treedrawer> for documentation on how to draw trees.
21              
22             =cut
23              
24             sub _new {
25 3     3   637 my $class = shift;
26 3         11 my %args = @_;
27             my $self = {
28             'TREE' => $args{'-tree'},
29             'DRAWER' => $args{'-drawer'},
30 3         14 'API' => $args{'-api'},
31             };
32 3         13 return bless $self, $class;
33             }
34 191     191   1073 sub _api { shift->{'API'} }
35 56     56   202 sub _drawer { shift->{'DRAWER'} }
36 9     9   92 sub _tree { shift->{'TREE'} }
37              
38             =begin comment
39              
40             Type : Internal method.
41             Title : _draw
42             Usage : $svg->_draw;
43             Function: Main drawing method.
44             Returns :
45             Args : None.
46              
47             =end comment
48              
49             =cut
50              
51             sub _draw {
52 3     3   7 my $self = shift;
53 3         15 my $td = $self->_drawer;
54 3         19 $self->_draw_scale;
55             $self->_tree->visit_depth_first(
56             '-post' => sub {
57 17     17   30 my $node = shift;
58 17         82 my $x = $node->get_x;
59 17         81 my $y = $node->get_y;
60 17         83 my $is_terminal = $node->is_terminal;
61 17 100       88 my $r = $is_terminal ? $td->get_tip_radius : $td->get_node_radius;
62 17         61 $logger->debug("going to draw branch");
63 17         80 $self->_draw_branch($node);
64 17 50       670 if ( $node->get_collapsed ) {
65 0         0 $logger->debug("going to draw collapsed clade");
66 0         0 $self->_draw_collapsed($node);
67             }
68             else {
69 17 100       54 if ( my $name = $node->get_name ) {
70 14         67 $logger->debug("going to draw node label '$name'");
71 14         42 $name =~ s/_/ /g;
72 14         29 $name =~ s/^'(.*)'$/$1/;
73 14         26 $name =~ s/^"(.*)"$/$1/;
74 14 100       55 $self->_draw_text(
75             '-x' => int( $x + $td->get_text_horiz_offset ),
76             '-y' => int( $y + $td->get_text_vert_offset ),
77             '-text' => $name,
78             '-rotation' => [ $node->get_rotation, $x, $y ],
79             '-font_face' => $node->get_font_face,
80             '-font_size' => $node->get_font_size,
81             '-font_style' => $node->get_font_style,
82             '-font_colour' => $node->get_font_colour,
83             '-font_weight' => $node->get_font_weight,
84             '-url' => $node->get_link,
85             'class' => $is_terminal ? 'taxon_text' : 'node_text',
86             );
87             }
88             }
89 17 100       1032 if ( $r ) {
90 3         14 $self->_draw_circle(
91             '-radius' => $r,
92             '-x' => $x,
93             '-y' => $y,
94             '-width' => $node->get_branch_width,
95             '-stroke' => $node->get_node_outline_colour,
96             '-fill' => $node->get_node_colour,
97             '-url' => $node->get_link,
98             );
99             }
100 17 50       103 if ( $node->get_clade_label ) {
101 0 0       0 if ( not $self->_tree->get_meta_object('map:tree_size') ) {
102 0         0 my $tips = $self->_tree->get_root->get_terminals;
103 0         0 $self->_tree->set_meta_object( 'map:tree_size' => scalar(@$tips) );
104             }
105 0         0 $logger->debug("going to draw clade label");
106 0         0 $self->_draw_clade_label($node);
107             }
108             }
109 3         14 );
110 3         48 $logger->debug("going to draw node pie charts");
111 3         17 $self->_draw_pies;
112 3         63 $logger->debug("going to draw legend");
113 3         15 $self->_draw_legend;
114 3         14 return $self->_finish;
115             }
116              
117             sub _draw_pies {
118 0     0   0 my $self = shift;
119 0         0 $logger->warn( ref($self) . " can't draw pies" );
120             }
121              
122             sub _draw_legend {
123 0     0   0 my $self = shift;
124 0         0 $logger->warn( ref($self) . " can't draw a legend" );
125             }
126              
127             sub _finish {
128 0     0   0 my $self = shift;
129 0         0 throw 'NotImplemented' => ref($self) . " won't complete its drawing";
130             }
131              
132             sub _draw_text {
133 0     0   0 my $self = shift;
134 0         0 throw 'NotImplemented' => ref($self) . " can't draw text";
135             }
136              
137             sub _draw_line {
138 0     0   0 my $self = shift;
139 0         0 throw 'NotImplemented' => ref($self) . " can't draw line";
140             }
141              
142             sub _draw_arc {
143 0     0   0 my $self = shift;
144 0         0 throw 'NotImplemented' => ref($self) . " can't draw arc";
145             }
146              
147             sub _draw_curve {
148 0     0   0 my $self = shift;
149 0         0 throw 'NotImplemented' => ref($self) . " can't draw curve";
150             }
151              
152             sub _draw_multi {
153 0     0   0 my $self = shift;
154 0         0 throw 'NotImplemented' => ref($self) . " can't draw multi line";
155             }
156              
157             sub _draw_triangle {
158 0     0   0 my $self = shift;
159 0         0 throw 'NotImplemented' => ref($self) . " can't draw triangle";
160             }
161              
162             sub _draw_rectangle {
163 0     0   0 my $self = shift;
164 0         0 throw 'NotImplemented' => ref($self) . " can't draw rectangle";
165             }
166              
167             # XXX incomplete, still needs work for the radial part
168             sub _draw_clade_label {
169 0     0   0 my ( $self, $node ) = @_;
170 0         0 $logger->info("Drawing clade label ".$node->get_clade_label);
171 0         0 my $td = $self->_drawer;
172 0         0 my $tho = $td->get_text_horiz_offset;
173 0         0 my $tw = $td->get_text_width;
174            
175 0         0 my $desc = $node->get_descendants;
176 0         0 my $ntips = [ grep { $_->is_terminal } @$desc ];
  0         0  
177 0         0 my $lmtl = $node->get_leftmost_terminal;
178 0         0 my $rmtl = $node->get_rightmost_terminal;
179 0         0 my $root = $node->get_tree->get_root;
180 0         0 my $ncl = scalar( grep { $_->get_clade_label } @{ $node->get_ancestors } );
  0         0  
  0         0  
181            
182             # copy font preferences, if any
183 0         0 my %font = ( '-text' => $node->get_clade_label );
184 0   0     0 my $f = $node->get_clade_label_font || {};
185 0         0 my @properties = qw(face size style weight colour);
186 0         0 for my $p ( @properties ) {
187 0 0       0 if ( my $value = $f->{"-$p"} ) {
188 0         0 $font{"-font_$p"} = $value;
189             }
190             else {
191 0         0 my $method = "get_font_$p";
192 0 0       0 if ( $value = $node->$method ) {
193 0         0 $font{"-font_$p"} = $value;
194             }
195             }
196             }
197            
198             # get cartesian coordinates for root and leftmost and rightmost tip
199 0         0 my ( $cx, $cy ) = ( $root->get_x, $root->get_y );
200 0         0 my ( $rx, $ry ) = ( $rmtl->get_x, $rmtl->get_y );
201 0         0 my ( $lx, $ly ) = ( $lmtl->get_x, $lmtl->get_y );
202            
203             # handle radial projection, either phylogram or cladogram
204 0 0       0 if ( $td->get_shape =~ /radial/i ) {
205            
206             # compute tallest node in the clade and radius from the root
207 0         0 my $radius;
208 0 0       0 if ( @$desc ) {
209 0         0 for my $d ( @$desc ) {
210            
211             # pythagoras
212 0         0 my ( $x1, $y1 ) = ( $d->get_x, $d->get_y );
213 0         0 my $h1 = sqrt( abs($cx-$x1)*abs($cx-$x1) + abs($cy-$y1)*abs($cy-$y1) );
214 0 0       0 $radius = $h1 if not defined $radius; # initialize
215 0 0       0 $radius = $h1 if $h1 >= $radius; # bump up if higher value
216             }
217             }
218             else {
219             # pythagoras
220 0         0 my ( $x1, $y1 ) = ( $node->get_x, $node->get_y );
221 0         0 $radius = sqrt( abs($cx-$x1)*abs($cx-$x1) + abs($cy-$y1)*abs($cy-$y1) );
222             }
223            
224             # compute angles and coordinates of start and end of arc
225 0         0 my $offset = $td->get_clade_label_width * $ncl;
226 0         0 $radius += ( $tho * 2 + $tw + $offset );
227 0         0 my ( $rr, $ra ) = $td->cartesian_to_polar( ($rx-$cx), ($ry-$cy) ); # rightmost
228 0         0 my ( $lr, $la ) = $td->cartesian_to_polar( ($lx-$cx), ($ly-$cy) ); # leftmost
229 0         0 my ( $x1, $y1 ) = $td->polar_to_cartesian( $radius, $ra ); # + add origin!
230 0         0 my ( $x2, $y2 ) = $td->polar_to_cartesian( $radius, $la ); # + add origin!
231            
232             # draw line and label
233             #my $ntips = $node->get_terminals;
234             #my $rtips = $root->get_terminals;
235 0         0 my $size = $node->get_tree->get_meta_object('map:tree_size');
236 0 0       0 my $large = (scalar(@$ntips)/$size) > 1/2 ? 1 : 0; # spans majority of tips
237 0         0 $self->_draw_arc(
238             '-x1' => $x1 + $cx,
239             '-y1' => $y1 + $cy,
240             '-x2' => $x2 + $cx,
241             '-y2' => $y2 + $cy,
242             '-radius' => $radius,
243             '-large' => $large,
244             '-sweep' => 0,
245             );
246            
247             # include $tho
248 0         0 my ( $tx1, $ty1 ) = $td->polar_to_cartesian(($radius+$tho),$ra); # + add origin!
249 0         0 $self->_draw_text( %font,
250             '-x' => $tx1 + $cx,
251             '-y' => $ty1 + $cy,
252             '-rotation' => [ $ra, $tx1 + $cx, $ty1 + $cy ],
253             );
254             }
255            
256             # can do the same thing for clado and phylo
257             else {
258            
259             # fetch the tallest node in t
260 0         0 my $x1;
261 0         0 for my $d ( @$desc ) {
262 0         0 my $x = $d->get_x;
263 0 0       0 $x1 = $x if not defined $x1; # initialize
264 0 0       0 $x1 = $x if $x >= $x1; # bump if $higher
265             }
266            
267             # draw line and label
268 0         0 my $offset = $td->get_clade_label_width * $ncl;
269 0         0 $x1 += ( $tho * 2 + $tw + $offset );
270 0         0 my ( $y1, $y2 ) = ( $lmtl->get_y, $rmtl->get_y );
271 0         0 $self->_draw_line(
272             '-x1' => $x1,
273             '-x2' => $x1,
274             '-y1' => $y1,
275             '-y2' => $y2,
276             );
277 0         0 $self->_draw_text( %font,
278             '-x' => ($x1+$tho),
279             '-y' => $y1,
280             '-rotation' => [ 90, ($x1+$tho), $y1 ],
281             );
282             }
283            
284            
285             }
286              
287             sub _draw_collapsed {
288 0     0   0 $logger->info("drawing collapsed node");
289 0         0 my ( $self, $node ) = @_;
290 0         0 my $td = $self->_drawer;
291 0         0 $node->set_collapsed(0);
292              
293             # Get the height of the tallest node above the collapsed clade; for cladograms this
294             # is 1, for phylograms it's the sum of the branch lengths. Then, compute x1 and x2,
295             # i.e. the tip and the base of the triangle, which consequently are different between
296             # cladograms and phylograms.
297 0         0 my $tallest = 0;
298 0         0 my ( $x1, $x2 );
299 0         0 my $clado = $td->get_mode =~ m/clado/i;
300 0 0       0 if ( $clado ) {
301 0         0 $tallest = 1;
302 0         0 $x1 = $node->get_x - $tallest * $td->_get_scalex;
303 0         0 $x2 = $node->get_x;
304             }
305             else {
306             $node->visit_depth_first(
307             '-pre' => sub {
308 0     0   0 my $n = shift;
309 0         0 my $height = $n->get_parent->get_generic('height') + $n->get_branch_length;
310 0         0 $n->set_generic( 'height' => $height );
311 0 0       0 $tallest = $height if $height > $tallest;
312             }
313 0         0 );
314 0         0 $tallest -= $node->get_branch_length;
315 0         0 $x1 = $node->get_x;
316 0         0 $x2 = ( $tallest * $td->_get_scalex + $node->get_x );
317             }
318            
319             # draw the collapsed triangle
320 0         0 my $padding = $td->get_padding;
321 0         0 my $cladew = $td->get_collapsed_clade_width($node);
322 0         0 my $y1 = $node->get_y;
323 0         0 $self->_draw_triangle(
324             '-fill' => $node->get_node_colour,
325             '-stroke' => $node->get_node_outline_colour,
326             '-width' => $td->get_branch_width($node),
327             '-url' => $node->get_link,
328             'id' => 'collapsed' . $node->get_id,
329             'class' => 'collapsed',
330             '-x1' => $x1,
331             '-y1' => $y1,
332             '-x2' => $x2,
333             '-y2' => $y1 + $cladew / 2 * $td->_get_scaley,
334             '-x3' => $x2,
335             '-y3' => $y1 - $cladew / 2 * $td->_get_scaley,
336             );
337            
338             # draw the collapsed clade label
339 0 0       0 if ( my $name = $node->get_name ) {
340 0         0 $name =~ s/_/ /g;
341 0         0 $name =~ s/^'(.*)'$/$1/;
342 0         0 $name =~ s/^"(.*)"$/$1/;
343 0         0 $self->_draw_text(
344             'id' => 'collapsed_text' . $node->get_id,
345             'class' => 'collapsed_text',
346             '-font_face' => $node->get_font_face,
347             '-font_size' => $node->get_font_size,
348             '-font_style' => $node->get_font_style,
349             '-font_colour' => $node->get_font_colour,
350             '-font_weight' => $node->get_font_weight,
351             '-x' => int( $x2 + $td->get_text_horiz_offset ),
352             '-y' => int( $y1 + $td->get_text_vert_offset ),
353             '-text' => $name,
354             );
355             }
356 0         0 $node->set_collapsed(1);
357             }
358              
359             =begin comment
360              
361             Type : Internal method.
362             Title : _draw_scale
363             Usage : $svg->_draw_scale();
364             Function: Draws scale for phylograms
365             Returns :
366             Args : None
367              
368             =end comment
369              
370             =cut
371              
372             sub _draw_scale {
373 3     3   7 my $self = shift;
374 3         9 my $drawer = $self->_drawer;
375            
376             # if not options provided, won't attempt to draw a scale
377 3 100       12 if ( my $options = $drawer->get_scale_options ) {
378 2         8 my $tree = $self->_tree;
379 2         10 my $root = $tree->get_root;
380 2         11 my $rootx = $root->get_x;
381 2         8 my $height = $drawer->get_height;
382            
383             # read and convert the font preferences for the _draw_text method
384 2         4 my %font;
385 2 50 33     33 if ( $options->{'-font'} and ref $options->{'-font'} eq 'HASH' ) {
386 0         0 for my $key ( keys %{ $options->{'-font'} } ) {
  0         0  
387 0         0 my $nk = $key;
388 0         0 $nk =~ s/-/-font_/;
389 0         0 $font{$nk} = $options->{'-font'}->{$key};
390             }
391             }
392              
393             # convert width and major/minor ticks to absolute pixel values
394 2         8 my ( $major, $minor ) = ( $options->{'-major'}, $options->{'-minor'} );
395 2         6 my $width = $options->{'-width'};
396 2         4 my $blocks = $options->{'-blocks'};
397            
398             # find the tallest tip, irrespective of it being collapsed
399 2         14 my ($tt) = sort { $b->get_x <=> $a->get_x } @{ $tree->get_entities };
  14         57  
  2         7  
400 2         10 my $ttx = $tt->get_x;
401 2         24 my $ptr = $tt->calc_path_to_root;
402 2 50       18 if ( $width =~ m/^(\d+)%$/ ) {
403 2         14 $width = ( $1 / 100 ) * ( $ttx - $rootx );
404             }
405 2 50       10 if ( my $units = $options->{'-units'} ) {
406            
407             # now we need to calculate how much each branch length unit (e.g.
408             # substitutions) is in pixels. The $width then becomes the length
409             # of one branch length unit in pixels times $units
410 0         0 my $unit_in_pixels = ( $ttx - $rootx ) / $ptr;
411 0         0 $width = $units * $unit_in_pixels;
412             }
413 2 50       12 if ( $major =~ m/^(\d+)%$/ ) {
414 2         9 $major = ( $1 / 100 ) * $width;
415             }
416 2 50       8 if ( $minor =~ m/^(\d+)%$/ ) {
417 2         7 $minor = ( $1 / 100 ) * $width;
418             }
419 2 50 33     18 if ( $blocks and $blocks =~ m/^(\d+)%$/ ) {
420 0         0 $blocks = ( $1 / 100 ) * $width;
421             }
422            
423             # draw scale line and apply label
424 2 50       7 my $x1 = $options->{'-reverse'} ? $ttx : $rootx;
425 2 50       7 my $ws = $options->{'-reverse'} ? -1 : 1;
426 2 50       7 my $ts = $options->{'-reverse'} ? 0 : 1;
427 2         20 $self->_draw_line(
428             '-x1' => $x1,
429             '-y1' => ( $height - 40 ),
430             '-x2' => $x1 + ($width*$ws),
431             '-y2' => ( $height - 40 ),
432             'class' => 'scale_bar',
433             );
434             $self->_draw_text( %font,
435             '-x' => ( $x1 + ($width*$ts) + $drawer->get_text_horiz_offset ),
436             '-y' => ( $height - 30 ),
437 2   100     184 '-text' => $options->{'-label'} || ' ',
438             'class' => 'scale_label',
439             );
440            
441             # pre-compute indexes so we can reverse
442 2         128 my ( @maji, @mini, @blocksi ); # major/minor/blocks indexes
443 2         4 my $j = 0;
444 2 50       5 if ( $options->{'-reverse'} ) {
445 0         0 for ( my $i = $ttx ; $i >= ( $ttx - $width ) ; $i -= $minor ) {
446 0 0       0 if ( not $j % sprintf('%.0f', $major/$minor) ) {
447 0         0 push @maji, $i;
448 0 0 0     0 if ( $blocks and not scalar(@maji) % 2 ) {
449 0         0 push @blocksi, $i;
450             }
451             }
452 0         0 push @mini, $i;
453 0         0 $j++;
454             }
455             }
456             else {
457 2         9 for ( my $i = $rootx ; $i <= ( $rootx + $width ) ; $i += $minor ) {
458 102 100       190 if ( not $j % sprintf('%.0f', $major/$minor) ) {
459 22         28 push @maji, $i;
460 22 50 33     42 if ( $blocks and not scalar(@maji) % 2 ) {
461 0         0 push @blocksi, $i;
462             }
463             }
464 102         125 push @mini, $i;
465 102         127 $j++;
466             }
467             }
468            
469             # draw ticks and labels
470 2         5 my $major_text = 0;
471 2         8 my $major_scale = ( $major / $width ) * $ptr;
472 2   50     10 my $tmpl = $options->{'-tmpl'} || '%s';
473 2 50   22   14 my $code = ref $tmpl ? $tmpl : sub { sprintf $tmpl, shift };
  22         117  
474 2         6 for my $i ( @maji ) {
475 22         64 $self->_draw_line(
476             '-x1' => $i,
477             '-y1' => ( $height - 40 ),
478             '-x2' => $i,
479             '-y2' => ( $height - 25 ),
480             'class' => 'scale_major',
481             );
482 22         1252 $self->_draw_text( %font,
483             '-x' => $i,
484             '-y' => ( $height - 5 ),
485             '-text' => $code->( $major_text ),
486             'class' => 'major_label',
487             );
488 22         1245 $major_text += $major_scale;
489             }
490 2         6 for my $i ( @mini ) {
491 102 50       5495 next if not $i % $major;
492 102         230 $self->_draw_line(
493             '-x1' => $i,
494             '-y1' => ( $height - 40 ),
495             '-x2' => $i,
496             '-y2' => ( $height - 35 ),
497             'class' => 'scale_minor',
498             );
499             }
500            
501             # draw blocks
502 2 50       120 if ( @blocksi ) {
503 0         0 my @y = map { $_->get_y } sort { $a->get_y <=> $b->get_y } @{ $tree->get_entities };
  0         0  
  0         0  
  0         0  
504 0         0 my $y = $y[0] - 20;
505 0         0 my $height = ( $y[-1] - $y[0] ) + 40;
506 0         0 my $width = ( $blocksi[0] - $blocksi[1] ) / 2;
507 0         0 for my $i ( @blocksi ) {
508 0         0 $self->_draw_rectangle(
509             '-x' => $i,
510             '-y' => $y,
511             '-height' => $height,
512             '-width' => $width,
513             '-fill' => 'whitesmoke',
514             '-stroke_width' => 0,
515             '-stroke' => 'whitesmoke',
516             );
517             }
518             }
519             }
520             }
521              
522             =begin comment
523              
524             Type : Internal method.
525             Title : _draw_branch
526             Usage : $svg->_draw_branch($node);
527             Function: Draws internode between $node and $node->get_parent, if any
528             Returns :
529             Args :
530              
531             =end comment
532              
533             =cut
534              
535             sub _draw_branch {
536 17     17   40 my ( $self, $node ) = @_;
537 17         101 $logger->info( "Drawing branch for " . $node->get_internal_name );
538 17 100       56 if ( my $parent = $node->get_parent ) {
539 14         67 my ( $x1, $x2 ) = ( int $parent->get_x, int $node->get_x );
540 14         71 my ( $y1, $y2 ) = ( int $parent->get_y, int $node->get_y );
541 14         58 my $shape = $self->_drawer->get_shape;
542 14         30 my $drawer = '_draw_curve';
543 14 100       66 if ( $shape =~ m/CURVY/i ) {
    50          
    0          
    0          
    0          
544 8         18 $drawer = '_draw_curve';
545             }
546             elsif ( $shape =~ m/RECT/i ) {
547 6         11 $drawer = '_draw_multi';
548             }
549             elsif ( $shape =~ m/DIAG/i ) {
550 0         0 $drawer = '_draw_line';
551             }
552             elsif ( $shape =~ m/UNROOTED/i ) {
553 0         0 $drawer = '_draw_line';
554             }
555             elsif ( $shape =~ m/RADIAL/i ) {
556 0         0 return $self->_draw_radial_branch($node);
557             }
558 14         39 return $self->$drawer(
559             '-x1' => $x1,
560             '-y1' => $y1,
561             '-x2' => $x2,
562             '-y2' => $y2,
563             '-width' => $self->_drawer->get_branch_width($node),
564             '-color' => $node->get_branch_color
565             );
566             }
567             }
568              
569             =begin comment
570              
571             Type : Internal method.
572             Title : _draw_radial_branch
573             Usage : $svg->_draw_radial_branch($node);
574             Function: Draws radial internode between $node and $node->get_parent, if any
575             Returns :
576             Args :
577              
578             =end comment
579              
580             =cut
581              
582             sub _draw_radial_branch {
583 0     0     my ( $self, $node ) = @_;
584            
585 0 0         if ( my $parent = $node->get_parent ) {
586 0           my $td = $self->_drawer;
587 0           my $center_x = $td->get_width / 2;
588 0           my $center_y = $td->get_height / 2;
589 0           my $width = $td->get_branch_width($node);
590            
591             # first the straight piece up to the arc
592 0           my ( $x1, $y1 ) = ( $node->get_x, $node->get_y );
593 0           my $rotation = $node->get_rotation;
594 0           my $parent_radius = $parent->get_generic('radius');
595 0           my ( $x2, $y2 ) = $td->polar_to_cartesian( $parent_radius, $rotation );
596 0           $x2 += $center_x;
597 0           $y2 += $center_y;
598 0           $self->_draw_line(
599             '-x1' => $x1,
600             '-y1' => $y1,
601             '-x2' => $x2,
602             '-y2' => $y2,
603             '-width' => $width,
604             '-color' => $node->get_branch_color,
605             '-linecap' => 'square'
606             );
607            
608             # then the arc
609 0           my ( $x3, $y3 ) = ( $parent->get_x, $parent->get_y );
610 0 0         if ( $parent->get_rotation < $rotation ) {
611 0           ( $x2, $x3 ) = ( $x3, $x2 );
612 0           ( $y2, $y3 ) = ( $y3, $y2 );
613             }
614             $self->_draw_arc(
615 0           '-x1' => $x2,
616             '-y1' => $y2,
617             '-x2' => $x3,
618             '-y2' => $y3,
619             '-radius' => $parent_radius,
620             '-width' => $width,
621             '-color' => $node->get_branch_color,
622             '-linecap' => 'square'
623             )
624             }
625             }
626              
627             sub _font_path {
628 0     0     my $self = shift;
629 0   0       my $font = shift || $DEFAULT_FONT;
630 0 0         if ( $^O =~ /darwin/ ) {
    0          
    0          
631 0           push @FONT_DIR, '/System/Library/Fonts', '/Library/Fonts';
632             }
633             elsif ( $^O =~ /linux/ ) {
634 0           push @FONT_DIR, '/usr/share/fonts';
635             }
636             elsif ( $^O =~ /MSWin/ ) {
637 0           push @FONT_DIR, $ENV{'WINDIR'} . '\Fonts';
638             }
639             else {
640 0           $logger->warn("Don't know where fonts are on $^O");
641             }
642 0           for my $dir ( @FONT_DIR ) {
643 0 0         if ( -e "${dir}/${font}.ttf" ) {
644 0           return "${dir}/${font}.ttf";
645             }
646             }
647 0           $logger->warn("Couldn't find font $font");
648             }
649              
650             =head1 SEE ALSO
651              
652             There is a mailing list at L<https://groups.google.com/forum/#!forum/bio-phylo>
653             for any user or developer questions and discussions.
654              
655             =over
656              
657             =item L<Bio::Phylo::Treedrawer>
658              
659             Treedrawer subclasses are called by the L<Bio::Phylo::Treedrawer> object. Look
660             there to learn how to create tree drawings.
661              
662             =item L<Bio::Phylo::Manual>
663              
664             Also see the manual: L<Bio::Phylo::Manual> and L<http://rutgervos.blogspot.com>.
665              
666             =back
667              
668             =head1 CITATION
669              
670             If you use Bio::Phylo in published research, please cite it:
671              
672             B<Rutger A Vos>, B<Jason Caravas>, B<Klaas Hartmann>, B<Mark A Jensen>
673             and B<Chase Miller>, 2011. Bio::Phylo - phyloinformatic analysis using Perl.
674             I<BMC Bioinformatics> B<12>:63.
675             L<http://dx.doi.org/10.1186/1471-2105-12-63>
676              
677             =cut
678              
679             1;