File Coverage

blib/lib/Bio/Phylo/Treedrawer/Abstract.pm
Criterion Covered Total %
statement 104 274 37.9
branch 33 98 33.6
condition 6 21 28.5
subroutine 12 27 44.4
pod n/a
total 155 420 36.9


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