Mercurial > repos > mahtabm > ensemb_rep_gvl
comparison variant_effect_predictor/Bio/Graphics/Panel.pm @ 0:2bc9b66ada89 draft default tip
Uploaded
author | mahtabm |
---|---|
date | Thu, 11 Apr 2013 06:29:17 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:2bc9b66ada89 |
---|---|
1 package Bio::Graphics::Panel; | |
2 | |
3 use strict; | |
4 use Bio::Graphics::Glyph::Factory; | |
5 use Bio::Graphics::Feature; | |
6 use GD;; | |
7 | |
8 | |
9 use constant KEYLABELFONT => gdMediumBoldFont; | |
10 use constant KEYSPACING => 5; # extra space between key columns | |
11 use constant KEYPADTOP => 5; # extra padding before the key starts | |
12 use constant KEYCOLOR => 'wheat'; | |
13 use constant KEYSTYLE => 'bottom'; | |
14 use constant KEYALIGN => 'left'; | |
15 use constant GRIDCOLOR => 'lightcyan'; | |
16 use constant MISSING_TRACK_COLOR =>'gray'; | |
17 | |
18 my %COLORS; # translation table for symbolic color names to RGB triple | |
19 | |
20 # Create a new panel of a given width and height, and add lists of features | |
21 # one by one | |
22 sub new { | |
23 my $class = shift; | |
24 my %options = @_; | |
25 | |
26 $class->read_colors() unless %COLORS; | |
27 | |
28 my $length = $options{-length} || 0; | |
29 my $offset = $options{-offset} || 0; | |
30 my $spacing = $options{-spacing} || 5; | |
31 my $bgcolor = $options{-bgcolor} || 0; | |
32 my $keyfont = $options{-key_font} || KEYLABELFONT; | |
33 my $keycolor = $options{-key_color} || KEYCOLOR; | |
34 my $keyspacing = $options{-key_spacing} || KEYSPACING; | |
35 my $keystyle = $options{-key_style} || KEYSTYLE; | |
36 my $keyalign = $options{-key_align} || KEYALIGN; | |
37 my $allcallbacks = $options{-all_callbacks} || 0; | |
38 my $gridcolor = $options{-gridcolor} || GRIDCOLOR; | |
39 my $grid = $options{-grid} || 0; | |
40 my $flip = $options{-flip} || 0; | |
41 my $empty_track_style = $options{-empty_tracks} || 'key'; | |
42 my $truecolor = $options{-truecolor} || 0; | |
43 | |
44 if (my $seg = $options{-segment}) { | |
45 $offset = eval {$seg->start-1} || 0; | |
46 $length = $seg->length; | |
47 } | |
48 | |
49 $offset ||= $options{-start}-1 if defined $options{-start}; | |
50 $length ||= $options{-stop}-$options{-start}+1 | |
51 if defined $options{-start} && defined $options{-stop}; | |
52 | |
53 return bless { | |
54 tracks => [], | |
55 width => $options{-width} || 600, | |
56 pad_top => $options{-pad_top}||0, | |
57 pad_bottom => $options{-pad_bottom}||0, | |
58 pad_left => $options{-pad_left}||0, | |
59 pad_right => $options{-pad_right}||0, | |
60 length => $length, | |
61 offset => $offset, | |
62 gridcolor => $gridcolor, | |
63 grid => $grid, | |
64 bgcolor => $bgcolor, | |
65 height => 0, # AUTO | |
66 spacing => $spacing, | |
67 key_font => $keyfont, | |
68 key_color => $keycolor, | |
69 key_spacing => $keyspacing, | |
70 key_style => $keystyle, | |
71 key_align => $keyalign, | |
72 all_callbacks => $allcallbacks, | |
73 truecolor => $truecolor, | |
74 flip => $flip, | |
75 empty_track_style => $empty_track_style, | |
76 },$class; | |
77 } | |
78 | |
79 sub pad_left { | |
80 my $self = shift; | |
81 my $g = $self->{pad_left}; | |
82 $self->{pad_left} = shift if @_; | |
83 $g; | |
84 } | |
85 sub pad_right { | |
86 my $self = shift; | |
87 my $g = $self->{pad_right}; | |
88 $self->{pad_right} = shift if @_; | |
89 $g; | |
90 } | |
91 sub pad_top { | |
92 my $self = shift; | |
93 my $g = $self->{pad_top}; | |
94 $self->{pad_top} = shift if @_; | |
95 $g; | |
96 } | |
97 sub pad_bottom { | |
98 my $self = shift; | |
99 my $g = $self->{pad_bottom}; | |
100 $self->{pad_bottom} = shift if @_; | |
101 $g; | |
102 } | |
103 | |
104 sub flip { | |
105 my $self = shift; | |
106 my $g = $self->{flip}; | |
107 $self->{flip} = shift if @_; | |
108 $g; | |
109 } | |
110 | |
111 # values of empty_track_style are: | |
112 # "suppress" -- suppress empty tracks entirely (default) | |
113 # "key" -- show just the key in "between" mode | |
114 # "line" -- draw a thin grey line | |
115 # "dashed" -- draw a dashed line | |
116 sub empty_track_style { | |
117 my $self = shift; | |
118 my $g = $self->{empty_track_style}; | |
119 $self->{empty_track_style} = shift if @_; | |
120 $g; | |
121 } | |
122 | |
123 sub key_style { | |
124 my $self = shift; | |
125 my $g = $self->{key_style}; | |
126 $self->{key_style} = shift if @_; | |
127 $g; | |
128 } | |
129 | |
130 # public routine for mapping from a base pair | |
131 # location to pixel coordinates | |
132 sub location2pixel { | |
133 my $self = shift; | |
134 my $end = $self->end + 1; | |
135 my @coords = $self->{flip} ? map { $end-$_ } @_ : @_; | |
136 $self->map_pt(@coords); | |
137 } | |
138 | |
139 # numerous direct calls into array used here for performance considerations | |
140 sub map_pt { | |
141 my $self = shift; | |
142 my $offset = $self->{offset}; | |
143 my $scale = $self->{scale} || $self->scale; | |
144 my $pl = $self->{pad_left}; | |
145 my $pr = $self->{width} - $self->{pad_right}; | |
146 my $flip = $self->{flip}; | |
147 my $length = $self->{length}; | |
148 my @result; | |
149 foreach (@_) { | |
150 my $val = $flip ? int (0.5 + $pr - ($length - ($_- 1)) * $scale) : int (0.5 + $pl + ($_-$offset-1) * $scale); | |
151 $val = $pl-1 if $val < $pl; | |
152 $val = $pr+1 if $val > $pr; | |
153 push @result,$val; | |
154 } | |
155 @result; | |
156 } | |
157 | |
158 sub map_no_trunc { | |
159 my $self = shift; | |
160 my $offset = $self->{offset}; | |
161 my $scale = $self->scale; | |
162 my $pl = $self->{pad_left}; | |
163 my $pr = $self->{width} - $self->{pad_right}; | |
164 my $flip = $self->{flip}; | |
165 my $length = $self->{length}; | |
166 my $end = $offset+$length; | |
167 my @result; | |
168 foreach (@_) { | |
169 my $val = $flip ? int (0.5 + $pl + ($end - ($_- 1)) * $scale) : int (0.5 + $pl + ($_-$offset-1) * $scale); | |
170 push @result,$val; | |
171 } | |
172 @result; | |
173 } | |
174 | |
175 sub scale { | |
176 my $self = shift; | |
177 $self->{scale} ||= ($self->{width}-$self->pad_left-$self->pad_right)/($self->length); | |
178 } | |
179 | |
180 sub start { shift->{offset}+1} | |
181 sub end { $_[0]->start + $_[0]->{length}-1} | |
182 | |
183 sub offset { shift->{offset} } | |
184 sub width { | |
185 my $self = shift; | |
186 my $d = $self->{width}; | |
187 $self->{width} = shift if @_; | |
188 $d; | |
189 # $d + $self->pad_left + $self->pad_right; | |
190 } | |
191 | |
192 sub left { | |
193 my $self = shift; | |
194 $self->pad_left; | |
195 } | |
196 sub right { | |
197 my $self = shift; | |
198 $self->width - $self->pad_right; | |
199 } | |
200 | |
201 sub spacing { | |
202 my $self = shift; | |
203 my $d = $self->{spacing}; | |
204 $self->{spacing} = shift if @_; | |
205 $d; | |
206 } | |
207 | |
208 sub key_spacing { | |
209 my $self = shift; | |
210 my $d = $self->{key_spacing}; | |
211 $self->{key_spacing} = shift if @_; | |
212 $d; | |
213 } | |
214 | |
215 sub length { | |
216 my $self = shift; | |
217 my $d = $self->{length}; | |
218 if (@_) { | |
219 my $l = shift; | |
220 $l = $l->length if ref($l) && $l->can('length'); | |
221 $self->{length} = $l; | |
222 } | |
223 $d; | |
224 } | |
225 | |
226 sub gridcolor {shift->{gridcolor}} | |
227 | |
228 sub all_callbacks { shift->{all_callbacks} } | |
229 | |
230 sub add_track { | |
231 my $self = shift; | |
232 $self->_do_add_track(scalar(@{$self->{tracks}}),@_); | |
233 } | |
234 | |
235 sub unshift_track { | |
236 my $self = shift; | |
237 $self->_do_add_track(0,@_); | |
238 } | |
239 | |
240 sub insert_track { | |
241 my $self = shift; | |
242 my $position = shift; | |
243 $self->_do_add_track($position,@_); | |
244 } | |
245 | |
246 | |
247 # create a feature and factory pair | |
248 # see Factory.pm for the format of the options | |
249 # The thing returned is actually a generic Glyph | |
250 sub _do_add_track { | |
251 my $self = shift; | |
252 my $position = shift; | |
253 | |
254 # due to indecision, we accept features | |
255 # and/or glyph types in the first two arguments | |
256 my ($features,$glyph_name) = ([],undef); | |
257 while ( @_ && $_[0] !~ /^-/) { | |
258 my $arg = shift; | |
259 $features = $arg and next if ref($arg); | |
260 $glyph_name = $arg and next unless ref($arg); | |
261 } | |
262 | |
263 my %args = @_; | |
264 my ($map,$ss,%options); | |
265 | |
266 foreach (keys %args) { | |
267 (my $canonical = lc $_) =~ s/^-//; | |
268 if ($canonical eq 'glyph') { | |
269 $map = $args{$_}; | |
270 delete $args{$_}; | |
271 } elsif ($canonical eq 'stylesheet') { | |
272 $ss = $args{$_}; | |
273 delete $args{$_}; | |
274 } else { | |
275 $options{$canonical} = $args{$_}; | |
276 } | |
277 } | |
278 | |
279 $glyph_name = $map if defined $map; | |
280 $glyph_name ||= 'generic'; | |
281 | |
282 local $^W = 0; # uninitialized variable warnings under 5.00503 | |
283 | |
284 my $panel_map = | |
285 ref($map) eq 'CODE' ? sub { | |
286 my $feature = shift; | |
287 return 'track' if eval { defined $feature->primary_tag && $feature->primary_tag eq 'track' }; | |
288 return 'group' if eval { defined $feature->primary_tag && $feature->primary_tag eq 'group' }; | |
289 return $map->($feature); | |
290 } | |
291 : ref($map) eq 'HASH' ? sub { | |
292 my $feature = shift; | |
293 return 'track' if eval { defined $feature->primary_tag && $feature->primary_tag eq 'track' }; | |
294 return 'group' if eval { defined $feature->primary_tag && $feature->primary_tag eq 'group' }; | |
295 return eval {$map->{$feature->primary_tag}} || 'generic'; | |
296 } | |
297 : sub { | |
298 my $feature = shift; | |
299 return 'track' if eval { defined $feature->primary_tag && $feature->primary_tag eq 'track' }; | |
300 return 'group' if eval { defined $feature->primary_tag && $feature->primary_tag eq 'group' }; | |
301 return $glyph_name; | |
302 }; | |
303 | |
304 $self->_add_track($position,$features,-map=>$panel_map,-stylesheet=>$ss,-options=>\%options); | |
305 } | |
306 | |
307 sub _add_track { | |
308 my $self = shift; | |
309 my ($position,$features,@options) = @_; | |
310 | |
311 # build the list of features into a Bio::Graphics::Feature object | |
312 $features = [$features] unless ref $features eq 'ARRAY'; | |
313 | |
314 # optional middle-level glyph is the group | |
315 foreach my $f (grep {ref $_ eq 'ARRAY'} @$features) { | |
316 next unless ref $f eq 'ARRAY'; | |
317 $f = Bio::Graphics::Feature->new( | |
318 -segments=>$f, | |
319 -type => 'group' | |
320 ); | |
321 } | |
322 | |
323 # top-level glyph is the track | |
324 my $feature = Bio::Graphics::Feature->new( | |
325 -segments=>$features, | |
326 -start => $self->offset+1, | |
327 -stop => $self->offset+$self->length, | |
328 -type => 'track' | |
329 ); | |
330 | |
331 my $factory = Bio::Graphics::Glyph::Factory->new($self,@options); | |
332 my $track = $factory->make_glyph(-1,$feature); | |
333 | |
334 splice(@{$self->{tracks}},$position,0,$track); | |
335 return $track; | |
336 } | |
337 | |
338 sub height { | |
339 my $self = shift; | |
340 my $spacing = $self->spacing; | |
341 my $key_height = $self->format_key; | |
342 my $empty_track_style = $self->empty_track_style; | |
343 my $key_style = $self->key_style; | |
344 my $bottom_key = $key_style eq 'bottom'; | |
345 my $between_key = $key_style eq 'between'; | |
346 my $draw_empty = $empty_track_style =~ /^(line|dashed)$/; | |
347 my $keyheight = $self->{key_font}->height; | |
348 my $height = 0; | |
349 for my $track (@{$self->{tracks}}) { | |
350 my $draw_between = $between_key && $track->option('key'); | |
351 my $has_parts = $track->parts; | |
352 next if !$has_parts && ($empty_track_style eq 'suppress' | |
353 or $empty_track_style eq 'key' && $bottom_key); | |
354 $height += $keyheight if $draw_between; | |
355 $height += $self->spacing; | |
356 $height += $track->layout_height; | |
357 } | |
358 | |
359 # get rid of spacing under last track | |
360 $height -= $self->spacing unless $bottom_key; | |
361 return $height + $key_height + $self->pad_top + $self->pad_bottom; | |
362 } | |
363 | |
364 sub gd { | |
365 my $self = shift; | |
366 my $existing_gd = shift; | |
367 | |
368 local $^W = 0; # can't track down the uninitialized variable warning | |
369 | |
370 return $self->{gd} if $self->{gd}; | |
371 | |
372 my $width = $self->width; | |
373 my $height = $self->height; | |
374 | |
375 my $gd = $existing_gd || GD::Image->new($width,$height, | |
376 ($self->{truecolor} && GD::Image->can('isTrueColor') ? 1 : ()) | |
377 ); | |
378 | |
379 my %translation_table; | |
380 for my $name ('white','black',keys %COLORS) { | |
381 my $idx = $gd->colorAllocate(@{$COLORS{$name}}); | |
382 $translation_table{$name} = $idx; | |
383 } | |
384 | |
385 $self->{translations} = \%translation_table; | |
386 $self->{gd} = $gd; | |
387 if ($self->bgcolor) { | |
388 $gd->fill(0,0,$self->bgcolor); | |
389 } elsif (eval {$gd->isTrueColor}) { | |
390 $gd->fill(0,0,$translation_table{'white'}); | |
391 } | |
392 | |
393 my $pl = $self->pad_left; | |
394 my $pt = $self->pad_top; | |
395 my $offset = $pt; | |
396 my $keyheight = $self->{key_font}->height; | |
397 my $bottom_key = $self->{key_style} eq 'bottom'; | |
398 my $between_key = $self->{key_style} eq 'between'; | |
399 my $left_key = $self->{key_style} eq 'left'; | |
400 my $right_key = $self->{key_style} eq 'right'; | |
401 my $empty_track_style = $self->empty_track_style; | |
402 my $spacing = $self->spacing; | |
403 | |
404 # we draw in two steps, once for background of tracks, and once for | |
405 # the contents. This allows the grid to sit on top of the track background. | |
406 for my $track (@{$self->{tracks}}) { | |
407 my $draw_between = $between_key && $track->option('key'); | |
408 next if !$track->parts && ($empty_track_style eq 'suppress' | |
409 or $empty_track_style eq 'key' && $bottom_key); | |
410 $gd->filledRectangle($pl, | |
411 $offset, | |
412 $width-$self->pad_right, | |
413 $offset+$track->layout_height | |
414 + ($between_key ? $self->{key_font}->height : 0), | |
415 $track->tkcolor) | |
416 if defined $track->tkcolor; | |
417 $offset += $keyheight if $draw_between; | |
418 $offset += $track->layout_height + $spacing; | |
419 } | |
420 | |
421 $self->draw_grid($gd) if $self->{grid}; | |
422 | |
423 $offset = $pt; | |
424 for my $track (@{$self->{tracks}}) { | |
425 my $draw_between = $between_key && $track->option('key'); | |
426 my $has_parts = $track->parts; | |
427 next if !$has_parts && ($empty_track_style eq 'suppress' | |
428 or $empty_track_style eq 'key' && $bottom_key); | |
429 | |
430 if ($draw_between) { | |
431 $offset += $self->draw_between_key($gd,$track,$offset); | |
432 } | |
433 | |
434 elsif ($self->{key_style} =~ /^(left|right)$/) { | |
435 $self->draw_side_key($gd,$track,$offset,$self->{key_style}); | |
436 } | |
437 | |
438 $self->draw_empty($gd,$offset,$empty_track_style) | |
439 if !$has_parts && $empty_track_style=~/^(line|dashed)$/; | |
440 | |
441 $track->draw($gd,0,$offset,0,1); | |
442 $self->track_position($track,$offset); | |
443 $offset += $track->layout_height + $spacing; | |
444 } | |
445 | |
446 | |
447 $self->draw_bottom_key($gd,$pl,$offset) if $self->{key_style} eq 'bottom'; | |
448 | |
449 return $self->{gd} = $gd; | |
450 } | |
451 | |
452 sub boxes { | |
453 my $self = shift; | |
454 my @boxes; | |
455 my $offset = 0; | |
456 | |
457 my $pl = $self->pad_left; | |
458 my $pt = $self->pad_top; | |
459 my $between_key = $self->{key_style} eq 'between'; | |
460 my $bottom_key = $self->{key_style} eq 'bottom'; | |
461 my $empty_track_style = $self->empty_track_style; | |
462 my $keyheight = $self->{key_font}->height; | |
463 my $spacing = $self->spacing; | |
464 | |
465 for my $track (@{$self->{tracks}}) { | |
466 my $draw_between = $between_key && $track->option('key'); | |
467 next if !$track->parts && ($empty_track_style eq 'suppress' | |
468 or $empty_track_style eq 'key' && $bottom_key); | |
469 $offset += $keyheight if $draw_between; | |
470 my $boxes = $track->boxes(0,$offset+$pt); | |
471 $self->track_position($track,$offset); | |
472 push @boxes,@$boxes; | |
473 $offset += $track->layout_height + $self->spacing; | |
474 } | |
475 return wantarray ? @boxes : \@boxes; | |
476 } | |
477 | |
478 sub track_position { | |
479 my $self = shift; | |
480 my $track = shift; | |
481 my $d = $self->{_track_position}{$track}; | |
482 $self->{_track_position}{$track} = shift if @_; | |
483 $d; | |
484 } | |
485 | |
486 # draw the keys -- between | |
487 sub draw_between_key { | |
488 my $self = shift; | |
489 my ($gd,$track,$offset) = @_; | |
490 my $key = $track->option('key') or return 0; | |
491 my $x = $self->{key_align} eq 'center' ? $self->width - (CORE::length($key) * $self->{key_font}->width)/2 | |
492 : $self->{key_align} eq 'right' ? $self->width - CORE::length($key) | |
493 : $self->pad_left; | |
494 $gd->string($self->{key_font},$x,$offset,$key,1); | |
495 return $self->{key_font}->height; | |
496 } | |
497 | |
498 # draw the keys -- left or right side | |
499 sub draw_side_key { | |
500 my $self = shift; | |
501 my ($gd,$track,$offset,$side) = @_; | |
502 my $key = $track->option('key') or return; | |
503 my $pos = $side eq 'left' ? $self->pad_left - $self->{key_font}->width * CORE::length($key)-3 | |
504 : $self->width - $self->pad_right+3; | |
505 $gd->string($self->{key_font},$pos,$offset,$key,1); | |
506 } | |
507 | |
508 # draw the keys -- bottom | |
509 sub draw_bottom_key { | |
510 my $self = shift; | |
511 my ($gd,$left,$top) = @_; | |
512 my $key_glyphs = $self->{key_glyphs} or return; | |
513 | |
514 my $color = $self->translate_color($self->{key_color}); | |
515 $gd->filledRectangle($left,$top,$self->width - $self->pad_right,$self->height-$self->pad_bottom,$color); | |
516 $gd->string($self->{key_font},$left,KEYPADTOP+$top,"KEY:",1); | |
517 $top += $self->{key_font}->height + KEYPADTOP; | |
518 | |
519 $_->draw($gd,$left,$top) foreach @$key_glyphs; | |
520 } | |
521 | |
522 # Format the key section, and return its height | |
523 sub format_key { | |
524 my $self = shift; | |
525 return 0 unless $self->key_style eq 'bottom'; | |
526 | |
527 return $self->{key_height} if defined $self->{key_height}; | |
528 | |
529 my $suppress = $self->{empty_track_style} eq 'suppress'; | |
530 my $between = $self->{key_style} eq 'between'; | |
531 | |
532 if ($between) { | |
533 my @key_tracks = $suppress | |
534 ? grep {$_->option('key') && $_->parts} @{$self->{tracks}} | |
535 : grep {$_->option('key')} @{$self->{tracks}}; | |
536 return $self->{key_height} = @key_tracks * $self->{key_font}->height; | |
537 } | |
538 | |
539 elsif ($self->{key_style} eq 'bottom') { | |
540 | |
541 my ($height,$width) = (0,0); | |
542 my %tracks; | |
543 my @glyphs; | |
544 | |
545 # determine how many glyphs become part of the key | |
546 # and their max size | |
547 for my $track (@{$self->{tracks}}) { | |
548 | |
549 next unless $track->option('key'); | |
550 next if $suppress && !$track->parts; | |
551 | |
552 my $glyph; | |
553 if (my @parts = $track->parts) { | |
554 $glyph = $parts[0]->keyglyph; | |
555 } else { | |
556 my $t = Bio::Graphics::Feature->new(-segments=> | |
557 [Bio::Graphics::Feature->new(-start => $self->offset, | |
558 -stop => $self->offset+$self->length)]); | |
559 my $g = $track->factory->make_glyph(0,$t); | |
560 $glyph = $g->keyglyph; | |
561 } | |
562 next unless $glyph; | |
563 | |
564 | |
565 $tracks{$track} = $glyph; | |
566 my ($h,$w) = ($glyph->layout_height, | |
567 $glyph->layout_width); | |
568 $height = $h if $h > $height; | |
569 $width = $w if $w > $width; | |
570 push @glyphs,$glyph; | |
571 | |
572 } | |
573 | |
574 $width += $self->key_spacing; | |
575 | |
576 # no key glyphs, no key | |
577 return $self->{key_height} = 0 unless @glyphs; | |
578 | |
579 # now height and width hold the largest glyph, and $glyph_count | |
580 # contains the number of glyphs. We will format them into a | |
581 # box that is roughly 3 height/4 width (golden mean) | |
582 my $rows = 0; | |
583 my $cols = 0; | |
584 my $maxwidth = $self->width - $self->pad_left - $self->pad_right; | |
585 while (++$rows) { | |
586 $cols = @glyphs / $rows; | |
587 $cols = int ($cols+1) if $cols =~ /\./; # round upward for fractions | |
588 my $total_width = $cols * $width; | |
589 my $total_height = $rows * $width; | |
590 last if $total_width < $maxwidth; | |
591 } | |
592 | |
593 # move glyphs into row-major format | |
594 my $spacing = $self->key_spacing; | |
595 my $i = 0; | |
596 for (my $c = 0; $c < $cols; $c++) { | |
597 for (my $r = 0; $r < $rows; $r++) { | |
598 my $x = $c * ($width + $spacing); | |
599 my $y = $r * ($height + $spacing); | |
600 next unless defined $glyphs[$i]; | |
601 $glyphs[$i]->move($x,$y); | |
602 $i++; | |
603 } | |
604 } | |
605 | |
606 $self->{key_glyphs} = \@glyphs; # remember our key glyphs | |
607 # remember our key height | |
608 return $self->{key_height} = | |
609 ($height+$spacing) * $rows + $self->{key_font}->height +KEYPADTOP; | |
610 } | |
611 | |
612 else { # no known key style, neither "between" nor "bottom" | |
613 return $self->{key_height} = 0; | |
614 } | |
615 } | |
616 | |
617 sub draw_empty { | |
618 my $self = shift; | |
619 my ($gd,$offset,$style) = @_; | |
620 $offset += $self->spacing/2; | |
621 my $left = $self->pad_left; | |
622 my $right = $self->width-$self->pad_right; | |
623 my $color = $self->translate_color(MISSING_TRACK_COLOR); | |
624 if ($style eq 'dashed') { | |
625 $gd->setStyle($color,$color,gdTransparent,gdTransparent); | |
626 $gd->line($left,$offset,$right,$offset,gdStyled); | |
627 } else { | |
628 $gd->line($left,$offset,$right,$offset,$color); | |
629 } | |
630 $offset; | |
631 } | |
632 | |
633 # draw a grid | |
634 sub draw_grid { | |
635 my $self = shift; | |
636 my $gd = shift; | |
637 | |
638 my $gridcolor = $self->translate_color($self->{gridcolor}); | |
639 my @positions; | |
640 if (ref $self->{grid} eq 'ARRAY') { | |
641 @positions = @{$self->{grid}}; | |
642 } else { | |
643 my ($major,$minor) = $self->ticks; | |
644 my $first_tick = $minor * int(0.5 + $self->start/$minor); | |
645 for (my $i = $first_tick; $i < $self->end; $i += $minor) { | |
646 push @positions,$i; | |
647 } | |
648 } | |
649 my $pl = $self->pad_left; | |
650 my $pt = $self->pad_top; | |
651 my $pb = $self->height - $self->pad_bottom; | |
652 local $self->{flip} = 0; | |
653 for my $tick (@positions) { | |
654 my ($pos) = $self->map_pt($tick); | |
655 $gd->line($pos,$pt,$pos,$pb,$gridcolor); | |
656 } | |
657 } | |
658 | |
659 # calculate major and minor ticks, given a start position | |
660 sub ticks { | |
661 my $self = shift; | |
662 my ($length,$minwidth) = @_; | |
663 | |
664 $length = $self->{length} unless defined $length; | |
665 $minwidth = gdSmallFont->width*7 unless defined $minwidth; | |
666 | |
667 my ($major,$minor); | |
668 | |
669 # figure out tick mark scale | |
670 # we want no more than 1 major tick mark every 40 pixels | |
671 # and enough room for the labels | |
672 my $scale = $self->scale; | |
673 | |
674 my $interval = 1; | |
675 | |
676 while (1) { | |
677 my $pixels = $interval * $scale; | |
678 last if $pixels >= $minwidth; | |
679 $interval *= 10; | |
680 } | |
681 | |
682 # to make sure a major tick shows up somewhere in the first half | |
683 # | |
684 $interval *= .5 if ($interval > 0.5*$length); | |
685 | |
686 return ($interval,$interval/10); | |
687 } | |
688 | |
689 # reverse of translate(); given index, return rgb triplet | |
690 sub rgb { | |
691 my $self = shift; | |
692 my $idx = shift; | |
693 my $gd = $self->{gd} or return; | |
694 return $gd->rgb($idx); | |
695 } | |
696 | |
697 sub translate_color { | |
698 my $self = shift; | |
699 my @colors = @_; | |
700 if (@colors == 3) { | |
701 my $gd = $self->gd or return 1; | |
702 return $self->colorClosest($gd,@colors); | |
703 } | |
704 elsif ($colors[0] =~ /^\#([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i) { | |
705 my $gd = $self->gd or return 1; | |
706 my ($r,$g,$b) = (hex($1),hex($2),hex($3)); | |
707 return $self->colorClosest($gd,$r,$g,$b); | |
708 } | |
709 else { | |
710 my $color = $colors[0]; | |
711 my $table = $self->{translations} or return 1; | |
712 return defined $table->{$color} ? $table->{$color} : 1; | |
713 } | |
714 } | |
715 | |
716 # workaround for bad GD | |
717 sub colorClosest { | |
718 my ($self,$gd,@c) = @_; | |
719 return $self->{closestcache}{"@c"} if exists $self->{closestcache}{"@c"}; | |
720 return $self->{closestcache}{"@c"} = $gd->colorClosest(@c) if $GD::VERSION < 2.04; | |
721 my ($value,$index); | |
722 for (keys %COLORS) { | |
723 my ($r,$g,$b) = @{$COLORS{$_}}; | |
724 my $dist = ($r-$c[0])**2 + ($g-$c[1])**2 + ($b-$c[2])**2; | |
725 ($value,$index) = ($dist,$_) if !defined($value) || $dist < $value; | |
726 } | |
727 return $self->{closestcache}{"@c"} = $self->{translations}{$index}; | |
728 } | |
729 | |
730 sub bgcolor { | |
731 my $self = shift; | |
732 return unless $self->{bgcolor}; | |
733 $self->translate_color($self->{bgcolor}); | |
734 } | |
735 | |
736 sub set_pen { | |
737 my $self = shift; | |
738 my ($linewidth,$color) = @_; | |
739 return $self->{pens}{$linewidth,$color} if $self->{pens}{$linewidth,$color}; | |
740 | |
741 my $pen = $self->{pens}{$linewidth} = GD::Image->new($linewidth,$linewidth); | |
742 my @rgb = $self->rgb($color); | |
743 my $bg = $pen->colorAllocate(255,255,255); | |
744 my $fg = $pen->colorAllocate(@rgb); | |
745 $pen->fill(0,0,$fg); | |
746 $self->{gd}->setBrush($pen); | |
747 return gdBrushed; | |
748 } | |
749 | |
750 sub png { | |
751 my $gd = shift->gd; | |
752 $gd->png; | |
753 } | |
754 | |
755 sub read_colors { | |
756 my $class = shift; | |
757 while (<DATA>) { | |
758 chomp; | |
759 last if /^__END__/; | |
760 my ($name,$r,$g,$b) = split /\s+/; | |
761 $COLORS{$name} = [hex $r,hex $g,hex $b]; | |
762 } | |
763 } | |
764 | |
765 sub color_name_to_rgb { | |
766 my $class = shift; | |
767 my $color_name = shift; | |
768 $class->read_colors() unless %COLORS; | |
769 return unless $COLORS{$color_name}; | |
770 return wantarray ? @{$COLORS{$color_name}} | |
771 : $COLORS{$color_name}; | |
772 } | |
773 | |
774 sub color_names { | |
775 my $class = shift; | |
776 $class->read_colors unless %COLORS; | |
777 return wantarray ? keys %COLORS : [keys %COLORS]; | |
778 } | |
779 | |
780 1; | |
781 | |
782 __DATA__ | |
783 white FF FF FF | |
784 black 00 00 00 | |
785 aliceblue F0 F8 FF | |
786 antiquewhite FA EB D7 | |
787 aqua 00 FF FF | |
788 aquamarine 7F FF D4 | |
789 azure F0 FF FF | |
790 beige F5 F5 DC | |
791 bisque FF E4 C4 | |
792 blanchedalmond FF EB CD | |
793 blue 00 00 FF | |
794 blueviolet 8A 2B E2 | |
795 brown A5 2A 2A | |
796 burlywood DE B8 87 | |
797 cadetblue 5F 9E A0 | |
798 chartreuse 7F FF 00 | |
799 chocolate D2 69 1E | |
800 coral FF 7F 50 | |
801 cornflowerblue 64 95 ED | |
802 cornsilk FF F8 DC | |
803 crimson DC 14 3C | |
804 cyan 00 FF FF | |
805 darkblue 00 00 8B | |
806 darkcyan 00 8B 8B | |
807 darkgoldenrod B8 86 0B | |
808 darkgray A9 A9 A9 | |
809 darkgreen 00 64 00 | |
810 darkkhaki BD B7 6B | |
811 darkmagenta 8B 00 8B | |
812 darkolivegreen 55 6B 2F | |
813 darkorange FF 8C 00 | |
814 darkorchid 99 32 CC | |
815 darkred 8B 00 00 | |
816 darksalmon E9 96 7A | |
817 darkseagreen 8F BC 8F | |
818 darkslateblue 48 3D 8B | |
819 darkslategray 2F 4F 4F | |
820 darkturquoise 00 CE D1 | |
821 darkviolet 94 00 D3 | |
822 deeppink FF 14 100 | |
823 deepskyblue 00 BF FF | |
824 dimgray 69 69 69 | |
825 dodgerblue 1E 90 FF | |
826 firebrick B2 22 22 | |
827 floralwhite FF FA F0 | |
828 forestgreen 22 8B 22 | |
829 fuchsia FF 00 FF | |
830 gainsboro DC DC DC | |
831 ghostwhite F8 F8 FF | |
832 gold FF D7 00 | |
833 goldenrod DA A5 20 | |
834 gray 80 80 80 | |
835 green 00 80 00 | |
836 greenyellow AD FF 2F | |
837 honeydew F0 FF F0 | |
838 hotpink FF 69 B4 | |
839 indianred CD 5C 5C | |
840 indigo 4B 00 82 | |
841 ivory FF FF F0 | |
842 khaki F0 E6 8C | |
843 lavender E6 E6 FA | |
844 lavenderblush FF F0 F5 | |
845 lawngreen 7C FC 00 | |
846 lemonchiffon FF FA CD | |
847 lightblue AD D8 E6 | |
848 lightcoral F0 80 80 | |
849 lightcyan E0 FF FF | |
850 lightgoldenrodyellow FA FA D2 | |
851 lightgreen 90 EE 90 | |
852 lightgrey D3 D3 D3 | |
853 lightpink FF B6 C1 | |
854 lightsalmon FF A0 7A | |
855 lightseagreen 20 B2 AA | |
856 lightskyblue 87 CE FA | |
857 lightslategray 77 88 99 | |
858 lightsteelblue B0 C4 DE | |
859 lightyellow FF FF E0 | |
860 lime 00 FF 00 | |
861 limegreen 32 CD 32 | |
862 linen FA F0 E6 | |
863 magenta FF 00 FF | |
864 maroon 80 00 00 | |
865 mediumaquamarine 66 CD AA | |
866 mediumblue 00 00 CD | |
867 mediumorchid BA 55 D3 | |
868 mediumpurple 100 70 DB | |
869 mediumseagreen 3C B3 71 | |
870 mediumslateblue 7B 68 EE | |
871 mediumspringgreen 00 FA 9A | |
872 mediumturquoise 48 D1 CC | |
873 mediumvioletred C7 15 85 | |
874 midnightblue 19 19 70 | |
875 mintcream F5 FF FA | |
876 mistyrose FF E4 E1 | |
877 moccasin FF E4 B5 | |
878 navajowhite FF DE AD | |
879 navy 00 00 80 | |
880 oldlace FD F5 E6 | |
881 olive 80 80 00 | |
882 olivedrab 6B 8E 23 | |
883 orange FF A5 00 | |
884 orangered FF 45 00 | |
885 orchid DA 70 D6 | |
886 palegoldenrod EE E8 AA | |
887 palegreen 98 FB 98 | |
888 paleturquoise AF EE EE | |
889 palevioletred DB 70 100 | |
890 papayawhip FF EF D5 | |
891 peachpuff FF DA B9 | |
892 peru CD 85 3F | |
893 pink FF C0 CB | |
894 plum DD A0 DD | |
895 powderblue B0 E0 E6 | |
896 purple 80 00 80 | |
897 red FF 00 00 | |
898 rosybrown BC 8F 8F | |
899 royalblue 41 69 E1 | |
900 saddlebrown 8B 45 13 | |
901 salmon FA 80 72 | |
902 sandybrown F4 A4 60 | |
903 seagreen 2E 8B 57 | |
904 seashell FF F5 EE | |
905 sienna A0 52 2D | |
906 silver C0 C0 C0 | |
907 skyblue 87 CE EB | |
908 slateblue 6A 5A CD | |
909 slategray 70 80 90 | |
910 snow FF FA FA | |
911 springgreen 00 FF 7F | |
912 steelblue 46 82 B4 | |
913 tan D2 B4 8C | |
914 teal 00 80 80 | |
915 thistle D8 BF D8 | |
916 tomato FF 63 47 | |
917 turquoise 40 E0 D0 | |
918 violet EE 82 EE | |
919 wheat F5 DE B3 | |
920 whitesmoke F5 F5 F5 | |
921 yellow FF FF 00 | |
922 yellowgreen 9A CD 32 | |
923 gradient1 00 ff 00 | |
924 gradient2 0a ff 00 | |
925 gradient3 14 ff 00 | |
926 gradient4 1e ff 00 | |
927 gradient5 28 ff 00 | |
928 gradient6 32 ff 00 | |
929 gradient7 3d ff 00 | |
930 gradient8 47 ff 00 | |
931 gradient9 51 ff 00 | |
932 gradient10 5b ff 00 | |
933 gradient11 65 ff 00 | |
934 gradient12 70 ff 00 | |
935 gradient13 7a ff 00 | |
936 gradient14 84 ff 00 | |
937 gradient15 8e ff 00 | |
938 gradient16 99 ff 00 | |
939 gradient17 a3 ff 00 | |
940 gradient18 ad ff 00 | |
941 gradient19 b7 ff 00 | |
942 gradient20 c1 ff 00 | |
943 gradient21 cc ff 00 | |
944 gradient22 d6 ff 00 | |
945 gradient23 e0 ff 00 | |
946 gradient24 ea ff 00 | |
947 gradient25 f4 ff 00 | |
948 gradient26 ff ff 00 | |
949 gradient27 ff f4 00 | |
950 gradient28 ff ea 00 | |
951 gradient29 ff e0 00 | |
952 gradient30 ff d6 00 | |
953 gradient31 ff cc 00 | |
954 gradient32 ff c1 00 | |
955 gradient33 ff b7 00 | |
956 gradient34 ff ad 00 | |
957 gradient35 ff a3 00 | |
958 gradient36 ff 99 00 | |
959 gradient37 ff 8e 00 | |
960 gradient38 ff 84 00 | |
961 gradient39 ff 7a 00 | |
962 gradient40 ff 70 00 | |
963 gradient41 ff 65 00 | |
964 gradient42 ff 5b 00 | |
965 gradient43 ff 51 00 | |
966 gradient44 ff 47 00 | |
967 gradient45 ff 3d 00 | |
968 gradient46 ff 32 00 | |
969 gradient47 ff 28 00 | |
970 gradient48 ff 1e 00 | |
971 gradient49 ff 14 00 | |
972 gradient50 ff 0a 00 | |
973 __END__ | |
974 | |
975 =head1 NAME | |
976 | |
977 Bio::Graphics::Panel - Generate GD images of Bio::Seq objects | |
978 | |
979 =head1 SYNOPSIS | |
980 | |
981 # This script parses a GenBank or EMBL file named on the command | |
982 # line and produces a PNG rendering of it. Call it like this: | |
983 # render.pl my_file.embl | display - | |
984 | |
985 use strict; | |
986 use Bio::Graphics; | |
987 use Bio::SeqIO; | |
988 | |
989 my $file = shift or die "provide a sequence file as the argument"; | |
990 my $io = Bio::SeqIO->new(-file=>$file) or die "could not create Bio::SeqIO"; | |
991 my $seq = $io->next_seq or die "could not find a sequence in the file"; | |
992 | |
993 my @features = $seq->all_SeqFeatures; | |
994 | |
995 # sort features by their primary tags | |
996 my %sorted_features; | |
997 for my $f (@features) { | |
998 my $tag = $f->primary_tag; | |
999 push @{$sorted_features{$tag}},$f; | |
1000 } | |
1001 | |
1002 my $panel = Bio::Graphics::Panel->new( | |
1003 -length => $seq->length, | |
1004 -key_style => 'between', | |
1005 -width => 800, | |
1006 -pad_left => 10, | |
1007 -pad_right => 10, | |
1008 ); | |
1009 $panel->add_track( arrow => Bio::SeqFeature::Generic->new(-start=>1, | |
1010 -end=>$seq->length), | |
1011 -bump => 0, | |
1012 -double=>1, | |
1013 -tick => 2); | |
1014 $panel->add_track(generic => Bio::SeqFeature::Generic->new(-start=>1, | |
1015 -end=>$seq->length), | |
1016 -glyph => 'generic', | |
1017 -bgcolor => 'blue', | |
1018 -label => 1, | |
1019 ); | |
1020 | |
1021 # general case | |
1022 my @colors = qw(cyan orange blue purple green chartreuse magenta yellow aqua); | |
1023 my $idx = 0; | |
1024 for my $tag (sort keys %sorted_features) { | |
1025 my $features = $sorted_features{$tag}; | |
1026 $panel->add_track($features, | |
1027 -glyph => 'generic', | |
1028 -bgcolor => $colors[$idx++ % @colors], | |
1029 -fgcolor => 'black', | |
1030 -font2color => 'red', | |
1031 -key => "${tag}s", | |
1032 -bump => +1, | |
1033 -height => 8, | |
1034 -label => 1, | |
1035 -description => 1, | |
1036 ); | |
1037 } | |
1038 | |
1039 print $panel->png; | |
1040 exit 0; | |
1041 | |
1042 =head1 DESCRIPTION | |
1043 | |
1044 The Bio::Graphics::Panel class provides drawing and formatting | |
1045 services for any object that implements the Bio::SeqFeatureI | |
1046 interface, including Ace::Sequence::Feature and Das::Segment::Feature | |
1047 objects. It can be used to draw sequence annotations, physical | |
1048 (contig) maps, or any other type of map in which a set of discrete | |
1049 ranges need to be laid out on the number line. | |
1050 | |
1051 The module supports a drawing style in which each type of feature | |
1052 occupies a discrete "track" that spans the width of the display. Each | |
1053 track will have its own distinctive "glyph", a configurable graphical | |
1054 representation of the feature. | |
1055 | |
1056 The module also supports a more flexible style in which several | |
1057 different feature types and their associated glyphs can occupy the | |
1058 same track. The choice of glyph is under run-time control. | |
1059 | |
1060 Semantic zooming (for instance, changing the type of glyph depending | |
1061 on the density of features) is supported by a callback system for | |
1062 configuration variables. The module has built-in support for Bio::Das | |
1063 stylesheets, and stylesheet-driven configuration can be intermixed | |
1064 with semantic zooming, if desired. | |
1065 | |
1066 You can add a key to the generated image using either of two key | |
1067 styles. One style places the key captions at the top of each track. | |
1068 The other style generates a graphical key at the bottom of the image. | |
1069 | |
1070 Note that this modules depends on GD. | |
1071 | |
1072 =head1 METHODS | |
1073 | |
1074 This section describes the class and object methods for | |
1075 Bio::Graphics::Panel. | |
1076 | |
1077 Typically you will begin by creating a new Bio::Graphics::Panel | |
1078 object, passing it the desired width of the image to generate and an | |
1079 origin and length describing the coordinate range to display. The | |
1080 Bio::Graphics::Panel-E<gt>new() method has may configuration variables | |
1081 that allow you to control the appearance of the image. | |
1082 | |
1083 You will then call add_track() one or more times to add sets of | |
1084 related features to the picture. add_track() places a new horizontal | |
1085 track on the image, and is likewise highly configurable. When you | |
1086 have added all the features you desire, you may call png() to convert | |
1087 the image into a PNG-format image, or boxes() to return coordinate | |
1088 information that can be used to create an imagemap. | |
1089 | |
1090 =head2 CONSTRUCTORS | |
1091 | |
1092 new() is the constructor for Bio::Graphics::Panel: | |
1093 | |
1094 =over 4 | |
1095 | |
1096 =item $panel = Bio::Graphics::Panel-E<gt>new(@options) | |
1097 | |
1098 The new() method creates a new panel object. The options are | |
1099 a set of tag/value pairs as follows: | |
1100 | |
1101 Option Value Default | |
1102 ------ ----- ------- | |
1103 | |
1104 -offset Base pair to place at extreme left none | |
1105 of image, in zero-based coordinates | |
1106 | |
1107 -length Length of sequence segment, in bp none | |
1108 | |
1109 -start Start of range, in 1-based none | |
1110 coordinates. | |
1111 | |
1112 -stop Stop of range, in 1-based none | |
1113 coordinates. | |
1114 | |
1115 -segment A Bio::SeqI or Das::Segment none | |
1116 object, used to derive sequence | |
1117 range if not otherwise specified. | |
1118 | |
1119 -width Desired width of image, in pixels 600 | |
1120 | |
1121 -spacing Spacing between tracks, in pixels 5 | |
1122 | |
1123 -pad_top Additional whitespace between top 0 | |
1124 of image and contents, in pixels | |
1125 | |
1126 -pad_bottom Additional whitespace between top 0 | |
1127 of image and bottom, in pixels | |
1128 | |
1129 -pad_left Additional whitespace between left 0 | |
1130 of image and contents, in pixels | |
1131 | |
1132 -pad_right Additional whitespace between right 0 | |
1133 of image and bottom, in pixels | |
1134 | |
1135 -bgcolor Background color for the panel as a white | |
1136 whole | |
1137 | |
1138 -key_color Background color for the key printed wheat | |
1139 at bottom of panel (if any) | |
1140 | |
1141 -key_spacing Spacing between key glyphs in the 10 | |
1142 key printed at bottom of panel | |
1143 (if any) | |
1144 | |
1145 -key_font Font to use in printed key gdMediumBoldFont | |
1146 captions. | |
1147 | |
1148 -key_style Whether to print key at bottom of none | |
1149 panel ("bottom"), between each | |
1150 track ("between"), to the left of | |
1151 each track ("left"), to the right | |
1152 of each track ("right") or | |
1153 not at all ("none"). | |
1154 | |
1155 -empty_tracks What to do when a track is empty. suppress | |
1156 Options are to suppress the track | |
1157 completely ("suppress"), to show just | |
1158 the key in "between" mode ("key"), | |
1159 to draw a thin grey line ("line"), | |
1160 or to draw a dashed line ("dashed"). | |
1161 | |
1162 -flip flip the drawing coordinates left false | |
1163 to right, so that lower coordinates | |
1164 are to the right. This can be | |
1165 useful for drawing (-) strand | |
1166 features. | |
1167 | |
1168 -all_callbacks Whether to invoke callbacks on false | |
1169 the automatic "track" and "group" | |
1170 glyphs. | |
1171 | |
1172 -grid Whether to draw a vertical grid in false | |
1173 the background. Pass a scalar true | |
1174 value to have a grid drawn at | |
1175 regular intervals (corresponding | |
1176 to the minor ticks of the arrow | |
1177 glyph). Pass an array reference | |
1178 to draw the grid at the specified | |
1179 positions. | |
1180 | |
1181 -gridcolor Color of the grid lightcyan | |
1182 | |
1183 | |
1184 Typically you will pass new() an object that implements the | |
1185 Bio::RangeI interface, providing a length() method, from which the | |
1186 panel will derive its scale. | |
1187 | |
1188 $panel = Bio::Graphics::Panel->new(-segment => $sequence, | |
1189 -width => 800); | |
1190 | |
1191 new() will return undef in case of an error. | |
1192 | |
1193 Note that if you use the "left" or "right" key styles, you are | |
1194 responsible for allocating sufficient -pad_left or -pad_right room for | |
1195 the labels to appear. The necessary width is the number of characters | |
1196 in the longest key times the font width (gdMediumBoldFont by default) | |
1197 plus 3 pixels of internal padding. The simplest way to calculate this | |
1198 is to iterate over the possible track labels, find the largest one, | |
1199 and then to compute its width using the formula: | |
1200 | |
1201 $width = gdMediumBoldFont->width * length($longest_key) +3; | |
1202 | |
1203 =back | |
1204 | |
1205 =head2 OBJECT METHODS | |
1206 | |
1207 =over 4 | |
1208 | |
1209 =item $track = $panel-E<gt>add_track($glyph,$features,@options) | |
1210 | |
1211 The add_track() method adds a new track to the image. | |
1212 | |
1213 Tracks are horizontal bands which span the entire width of the panel. | |
1214 Each track contains a number of graphical elements called "glyphs", | |
1215 corresponding to a sequence feature. | |
1216 | |
1217 There are a large number of glyph types. By default, each track will | |
1218 be homogeneous on a single glyph type, but you can mix several glyph | |
1219 types on the same track by providing a code reference to the -glyph | |
1220 argument. Other options passed to add_track() control the color and | |
1221 size of the glyphs, whether they are allowed to overlap, and other | |
1222 formatting attributes. The height of a track is determined from its | |
1223 contents and cannot be directly influenced. | |
1224 | |
1225 The first two arguments are the glyph name and an array reference | |
1226 containing the list of features to display. The order of the | |
1227 arguments is irrelevant, allowing either of these idioms: | |
1228 | |
1229 $panel->add_track(arrow => \@features); | |
1230 $panel->add_track(\@features => 'arrow'); | |
1231 | |
1232 | |
1233 The glyph name indicates how each feature is to be rendered. A | |
1234 variety of glyphs are available, and the number is growing. You may | |
1235 omit the glyph name entirely by providing a B<-glyph> argument among | |
1236 @options, as described below. | |
1237 | |
1238 Currently, the following glyphs are available: | |
1239 | |
1240 Name Description | |
1241 ---- ----------- | |
1242 | |
1243 anchored_arrow | |
1244 a span with vertical bases |---------|. If one or | |
1245 the other end of the feature is off-screen, the base | |
1246 will be replaced by an arrow. | |
1247 | |
1248 arrow An arrow; can be unidirectional or bidirectional. | |
1249 It is also capable of displaying a scale with | |
1250 major and minor tickmarks, and can be oriented | |
1251 horizontally or vertically. | |
1252 | |
1253 cds Draws CDS features, using the phase information to | |
1254 show the reading frame usage. At high magnifications | |
1255 draws the protein translation. | |
1256 | |
1257 crossbox A box with a big "X" inside it. | |
1258 | |
1259 diamond A diamond, useful for point features like SNPs. | |
1260 | |
1261 dna At high magnification draws the DNA sequence. At | |
1262 low magnifications draws the GC content. | |
1263 | |
1264 dot A circle, useful for point features like SNPs, stop | |
1265 codons, or promoter elements. | |
1266 | |
1267 ellipse An oval. | |
1268 | |
1269 extending_arrow | |
1270 Similar to arrow, but a dotted line indicates when the | |
1271 feature extends beyond the end of the canvas. | |
1272 | |
1273 generic A filled rectangle, nondirectional. | |
1274 | |
1275 graded_segments | |
1276 Similar to segments, but the intensity of the color | |
1277 is proportional to the score of the feature. This | |
1278 is used for showing the intensity of blast hits or | |
1279 other alignment features. | |
1280 | |
1281 group A group of related features connected by a dashed line. | |
1282 This is used internally by Panel. | |
1283 | |
1284 heterogeneous_segments | |
1285 Like segments, but you can use the source field of the feature | |
1286 to change the color of each segment. | |
1287 | |
1288 line A simple line. | |
1289 | |
1290 pinsertion A triangle designed to look like an insertion location | |
1291 (e.g. a transposon insertion). | |
1292 | |
1293 processed_transcript multi-purpose representation of a spliced mRNA, including | |
1294 positions of UTRs | |
1295 | |
1296 primers Two inward pointing arrows connected by a line. | |
1297 Used for STSs. | |
1298 | |
1299 redgreen_box A box that changes from green->yellow->red as the score | |
1300 of the feature increases from 0.0 to 1.0. Useful for | |
1301 representing microarray results. | |
1302 | |
1303 rndrect A round-cornered rectangle. | |
1304 | |
1305 segments A set of filled rectangles connected by solid lines. | |
1306 Used for interrupted features, such as gapped | |
1307 alignments. | |
1308 | |
1309 ruler_arrow An arrow with major and minor tick marks and interval | |
1310 labels. | |
1311 | |
1312 toomany Tries to show many features as a cloud. Not very successful. | |
1313 | |
1314 track A group of related features not connected by a line. | |
1315 This is used internally by Panel. | |
1316 | |
1317 transcript Similar to segments, but the connecting line is | |
1318 a "hat" shape, and the direction of transcription | |
1319 is indicated by a small arrow. | |
1320 | |
1321 transcript2 Similar to transcript, but the direction of | |
1322 transcription is indicated by a terminal exon | |
1323 in the shape of an arrow. | |
1324 | |
1325 translation 1, 2 and 3-frame translations. At low magnifications, | |
1326 can be configured to show start and stop codon locations. | |
1327 At high magnifications, shows the multi-frame protein | |
1328 translation. | |
1329 | |
1330 triangle A triangle whose width and orientation can be altered. | |
1331 | |
1332 xyplot Histograms and other graphs plotted against the genome. | |
1333 | |
1334 If the glyph name is omitted from add_track(), the "generic" glyph | |
1335 will be used by default. To get more information about a glyph, run | |
1336 perldoc on "Bio::Graphics::Glyph::glyphname", replacing "glyphname" | |
1337 with the name of the glyph you are interested in. | |
1338 | |
1339 The @options array is a list of name/value pairs that control the | |
1340 attributes of the track. Some options are interpretered directly by | |
1341 the track. Others are passed down to the individual glyphs (see | |
1342 L<"GLYPH OPTIONS">). The following options are track-specific: | |
1343 | |
1344 Option Description Default | |
1345 ------ ----------- ------- | |
1346 | |
1347 -tkcolor Track color white | |
1348 | |
1349 -glyph Glyph class to use. "generic" | |
1350 | |
1351 -stylesheet Bio::Das::Stylesheet to none | |
1352 use to generate glyph | |
1353 classes and options. | |
1354 | |
1355 B<-tkcolor> controls the background color of the track as a whole. | |
1356 | |
1357 B<-glyph> controls the glyph type. If present, it supersedes the | |
1358 glyph name given in the first or second argument to add_track(). The | |
1359 value of B<-glyph> may be a constant string, a hash reference, or a | |
1360 code reference. In the case of a constant string, that string will be | |
1361 used as the class name for all generated glyphs. If a hash reference | |
1362 is passed, then the feature's primary_tag() will be used as the key to | |
1363 the hash, and the value, if any, used to generate the glyph type. If | |
1364 a code reference is passed, then this callback will be passed each | |
1365 feature in turn as its single argument. The callback is expected to | |
1366 examine the feature and return a glyph name as its single result. | |
1367 | |
1368 Example: | |
1369 | |
1370 $panel->add_track(\@exons, | |
1371 -glyph => sub { my $feature = shift; | |
1372 $feature->source_tag eq 'curated' | |
1373 ? 'ellipse' : 'generic'; } | |
1374 ); | |
1375 | |
1376 The B<-stylesheet> argument is used to pass a Bio::Das stylesheet | |
1377 object to the panel. This stylesheet will be called to determine both | |
1378 the glyph and the glyph options. If both a stylesheet and direct | |
1379 options are provided, the latter take precedence. | |
1380 | |
1381 If successful, add_track() returns an Bio::Graphics::Glyph object. | |
1382 You can use this object to add additional features or to control the | |
1383 appearance of the track with greater detail, or just ignore it. | |
1384 Tracks are added in order from the top of the image to the bottom. To | |
1385 add tracks to the top of the image, use unshift_track(). | |
1386 | |
1387 B<Adding groups of features:> It is not uncommon to add a group of | |
1388 features which are logically connected, such as the 5' and 3' ends of | |
1389 EST reads. To group features into sets that remain on the same | |
1390 horizontal position and bump together, pass the sets as an anonymous | |
1391 array. For example: | |
1392 | |
1393 $panel->add_track(segments => [[$abc_5,$abc_3], | |
1394 [$xxx_5,$xxx_3], | |
1395 [$yyy_5,$yyy_3]] | |
1396 ); | |
1397 | |
1398 Typical usage is: | |
1399 | |
1400 $panel->add_track( transcript => \@genes, | |
1401 -fillcolor => 'green', | |
1402 -fgcolor => 'black', | |
1403 -bump => +1, | |
1404 -height => 10, | |
1405 -label => 1); | |
1406 | |
1407 =item $track = unshift_track($glyph,$features,@options) | |
1408 | |
1409 unshift_track() works like add_track(), except that the new track is | |
1410 added to the top of the image rather than the bottom. | |
1411 | |
1412 =item $gd = $panel-E<gt>gd([$gd]) | |
1413 | |
1414 The gd() method lays out the image and returns a GD::Image object | |
1415 containing it. You may then call the GD::Image object's png() or | |
1416 jpeg() methods to get the image data. | |
1417 | |
1418 Optionally, you may pass gd() a preexisting GD::Image object that you | |
1419 wish to draw on top of. If you do so, you should call the width() and | |
1420 height() methods first to ensure that the image has sufficient | |
1421 dimensions. | |
1422 | |
1423 =item $png = $panel-E<gt>png | |
1424 | |
1425 The png() method returns the image as a PNG-format drawing, without | |
1426 the intermediate step of returning a GD::Image object. | |
1427 | |
1428 =item $boxes = $panel-E<gt>boxes | |
1429 | |
1430 =item @boxes = $panel-E<gt>boxes | |
1431 | |
1432 The boxes() method returns the coordinates of each glyph, useful for | |
1433 constructing an image map. In a scalar context, boxes() returns an | |
1434 array ref. In an list context, the method returns the array directly. | |
1435 | |
1436 Each member of the list is an anonymous array of the following format: | |
1437 | |
1438 [ $feature, $x1, $y1, $x2, $y2 ] | |
1439 | |
1440 The first element is the feature object; either an | |
1441 Ace::Sequence::Feature, a Das::Segment::Feature, or another Bioperl | |
1442 Bio::SeqFeatureI object. The coordinates are the topleft and | |
1443 bottomright corners of the glyph, including any space allocated for | |
1444 labels. | |
1445 | |
1446 =item $position = $panel-E<gt>track_position($track) | |
1447 | |
1448 After calling gd() or boxes(), you can learn the resulting Y | |
1449 coordinate of a track by calling track_position() with the value | |
1450 returned by add_track() or unshift_track(). This will return undef if | |
1451 called before gd() or boxes() or with an invalid track. | |
1452 | |
1453 =item @pixel_coords = $panel-E<gt>location2pixel(@feature_coords) | |
1454 | |
1455 Public routine to map feature coordinates (in base pairs) into pixel | |
1456 coordinates relative to the left-hand edge of the picture. | |
1457 | |
1458 =back | |
1459 | |
1460 =head1 GLYPH OPTIONS | |
1461 | |
1462 Each glyph has its own specialized subset of options, but | |
1463 some are shared by all glyphs: | |
1464 | |
1465 Option Description Default | |
1466 ------ ----------- ------- | |
1467 | |
1468 -fgcolor Foreground color black | |
1469 | |
1470 -bgcolor Background color turquoise | |
1471 | |
1472 -linewidth Width of lines drawn by 1 | |
1473 glyph | |
1474 | |
1475 -height Height of glyph 10 | |
1476 | |
1477 -font Glyph font gdSmallFont | |
1478 | |
1479 -fontcolor Primary font color black | |
1480 | |
1481 -font2color Secondary font color turquoise | |
1482 | |
1483 -label Whether to draw a label false | |
1484 | |
1485 -description Whether to draw a false | |
1486 description | |
1487 | |
1488 -bump Bump direction 0 | |
1489 | |
1490 -sort_order Specify layout sort order "default" | |
1491 | |
1492 -bump_limit Maximum number of levels undef (unlimited) | |
1493 to bump | |
1494 | |
1495 -strand_arrow Whether to indicate undef (false) | |
1496 strandedness | |
1497 | |
1498 -stranded Synonym for -strand_arrow undef (false) | |
1499 | |
1500 -connector Type of connector to none | |
1501 use to connect related | |
1502 features. Options are | |
1503 "solid," "hat", "dashed", | |
1504 "quill" and "none". | |
1505 | |
1506 -key Description of track for undef | |
1507 use in key. | |
1508 | |
1509 -all_callbacks Whether to invoke undef | |
1510 callbacks for autogenerated | |
1511 "track" and "group" glyphs | |
1512 | |
1513 -box_subparts Return boxes around feature false | |
1514 subparts rather than around the | |
1515 feature itself. | |
1516 | |
1517 | |
1518 B<Specifying colors:> Colors can be expressed in either of two ways: | |
1519 as symbolic names such as "cyan" and as HTML-style #RRGGBB triples. | |
1520 The symbolic names are the 140 colors defined in the Netscape/Internet | |
1521 Explorer color cube, and can be retrieved using the | |
1522 Bio::Graphics::Panel-E<gt>color_names() method. | |
1523 | |
1524 B<Foreground color:> The -fgcolor option controls the foreground | |
1525 color, including the edges of boxes and the like. | |
1526 | |
1527 B<Background color:> The -bgcolor option controls the background used | |
1528 for filled boxes and other "solid" glyphs. The foreground color | |
1529 controls the color of lines and strings. The -tkcolor argument | |
1530 controls the background color of the entire track. | |
1531 | |
1532 B<Track color:> The -tkcolor option used to specify the background of | |
1533 the entire track. | |
1534 | |
1535 B<Font color:> The -fontcolor option controls the color of primary | |
1536 text, such as labels | |
1537 | |
1538 B<Secondary Font color:> The -font2color option controls the color of | |
1539 secondary text, such as descriptions. | |
1540 | |
1541 B<Labels:> The -label argument controls whether or not the ID of the | |
1542 feature should be printed next to the feature. It is accepted by all | |
1543 glyphs. By default, the label is printed just above the glyph and | |
1544 left aligned with it. | |
1545 | |
1546 -label can be a constant string or a code reference. Values can be | |
1547 any of: | |
1548 | |
1549 -label value Description | |
1550 ------------ ----------- | |
1551 | |
1552 0 Don't draw a label | |
1553 1 Calculate a label based on primary tag of sequence | |
1554 "a string" Use "a string" as the label | |
1555 code ref Invoke the code reference to compute the label | |
1556 | |
1557 A known bug with this naming scheme is that you can't label a feature | |
1558 with the string "1". To work around this, use "1 " (note the terminal | |
1559 space). | |
1560 | |
1561 B<Descriptions:> The -description argument controls whether or not a | |
1562 brief description of the feature should be printed next to it. By | |
1563 default, the description is printed just below the glyph and | |
1564 left-aligned with it. A value of 0 will suppress the description. A | |
1565 value of 1 will call the source_tag() method of the feature. A code | |
1566 reference will be invoked to calculate the description on the fly. | |
1567 Anything else will be treated as a string and used verbatim. | |
1568 | |
1569 B<Connectors:> A glyph can contain subglyphs, recursively. The top | |
1570 level glyph is the track, which contains one or more groups, which | |
1571 contain features, which contain subfeatures, and so forth. By | |
1572 default, the "group" glyph draws dotted lines between each of its | |
1573 subglyphs, the "segment" glyph draws a solid line between each of its | |
1574 subglyphs, and the "transcript" and "transcript2" glyphs draw | |
1575 hat-shaped lines between their subglyphs. All other glyphs do not | |
1576 connect their components. You can override this behavior by providing | |
1577 a -connector option, to explicitly set the type of connector. Valid | |
1578 options are: | |
1579 | |
1580 | |
1581 "hat" an upward-angling conector | |
1582 "solid" a straight horizontal connector | |
1583 "quill" a decorated line with small arrows indicating strandedness | |
1584 (like the UCSC Genome Browser uses) | |
1585 "dashed" a horizontal dashed line. | |
1586 | |
1587 The B<-connector_color> option controls the color of the connector, if | |
1588 any. | |
1589 | |
1590 B<Collision control:> The -bump argument controls what happens when | |
1591 glyphs collide. By default, they will simply overlap (value 0). A | |
1592 -bump value of +1 will cause overlapping glyphs to bump downwards | |
1593 until there is room for them. A -bump value of -1 will cause | |
1594 overlapping glyphs to bump upwards. The bump argument can also be a | |
1595 code reference; see below. | |
1596 | |
1597 B<Keys:> The -key argument declares that the track is to be shown in a | |
1598 key appended to the bottom of the image. The key contains a picture | |
1599 of a glyph and a label describing what the glyph means. The label is | |
1600 specified in the argument to -key. | |
1601 | |
1602 B<box_subparts:> Ordinarily, when you invoke the boxes() methods to | |
1603 retrieve the rectangles surrounding the glyphs (which you need to do | |
1604 to create clickable imagemaps, for example), the rectangles will | |
1605 surround the top level features. If you wish for the rectangles to | |
1606 surround subpieces of the glyph, such as the exons in a transcript, | |
1607 set box_subparts to a true value. | |
1608 | |
1609 B<strand_arrow:> If set to true, some glyphs will indicate their | |
1610 strandedness, usually by drawing an arrow. For this to work, the | |
1611 Bio::SeqFeature must have a strand of +1 or -1. The glyph will ignore | |
1612 this directive if the underlying feature has a strand of zero or | |
1613 undef. | |
1614 | |
1615 B<sort_order>: By default, features are drawn with a layout based only on the | |
1616 position of the feature, assuring a maximal "packing" of the glyphs | |
1617 when bumped. In some cases, however, it makes sense to display the | |
1618 glyphs sorted by score or some other comparison, e.g. such that more | |
1619 "important" features are nearer the top of the display, stacked above | |
1620 less important features. The -sort_order option allows a few | |
1621 different built-in values for changing the default sort order (which | |
1622 is by "left" position): "low_score" (or "high_score") will cause | |
1623 features to be sorted from lowest to highest score (or vice versa). | |
1624 "left" (or "default") and "right" values will cause features to be | |
1625 sorted by their position in the sequence. "longer" (or "shorter") | |
1626 will cause the longest (or shortest) features to be sorted first, and | |
1627 "strand" will cause the features to be sorted by strand: "+1" | |
1628 (forward) then "0" (unknown, or NA) then "-1" (reverse). | |
1629 | |
1630 In all cases, the "left" position will be used to break any ties. To | |
1631 break ties using another field, options may be strung together using a | |
1632 "|" character; e.g. "strand|low_score|right" would cause the features | |
1633 to be sorted first by strand, then score (lowest to highest), then by | |
1634 "right" position in the sequence. Finally, a subroutine coderef can | |
1635 be provided, which should expect to receive two feature objects (via | |
1636 the special sort variables $a and $b), and should return -1, 0 or 1 | |
1637 (see Perl's sort() function for more information); this subroutine | |
1638 will be used without further modification for sorting. For example, | |
1639 to sort a set of database search hits by bits (stored in the features' | |
1640 "score" fields), scaled by the log of the alignment length (with | |
1641 "left" position breaking any ties): | |
1642 | |
1643 sort_order = sub { ( $b->score/log($b->length) | |
1644 <=> | |
1645 $a->score/log($a->length) ) | |
1646 || | |
1647 ( $a->start <=> $b->start ) | |
1648 } | |
1649 | |
1650 B<bump_limit>: When bumping is chosen, colliding features will | |
1651 ordinarily move upward or downward without limit. When many features | |
1652 collide, this can lead to excessively high images. You can limit the | |
1653 number of levels that features will bump by providing a numeric | |
1654 B<bump_limit> option. | |
1655 | |
1656 =head2 Options and Callbacks | |
1657 | |
1658 Instead of providing a constant value to an option, you may subsitute | |
1659 a code reference. This code reference will be called every time the | |
1660 panel needs to configure a glyph. The callback will be called with | |
1661 three arguments like this: | |
1662 | |
1663 sub callback { | |
1664 my ($feature,$option_name,$part_no,$total_parts,$glyph) = @_; | |
1665 # do something which results in $option_value being set | |
1666 return $option_value; | |
1667 } | |
1668 | |
1669 The five arguments are C<$feature>, a reference to the IO::SeqFeatureI | |
1670 object, C<$option_name>, the name of the option to configure, | |
1671 C<$part_no>, an integer index indicating which subpart of the feature | |
1672 is being drawn, C<$total_parts>, an integer indicating the total | |
1673 number of subfeatures in the feature, and finally C<$glyph>, the Glyph | |
1674 object itself. The latter fields are useful in the case of treating | |
1675 the first or last subfeature differently, such as using a different | |
1676 color for the terminal exon of a gene. Usually you will only need to | |
1677 examine the first argument. This example shows a callback examining | |
1678 the score() attribute of a feature (possibly a BLAST hit) and return | |
1679 the color "red" for high-scoring features, and "green" for low-scoring | |
1680 features: | |
1681 | |
1682 sub callback { | |
1683 my $feature = shift; | |
1684 if ($feature->score > 90) { | |
1685 return 'red'; | |
1686 else { | |
1687 return 'green'; | |
1688 } | |
1689 } | |
1690 | |
1691 The callback should return a string indicating the desired value of | |
1692 the option. To tell the panel to use the default value for this | |
1693 option, return the string "*default*". | |
1694 | |
1695 When you install a callback for a feature that contains subparts, the | |
1696 callback will be invoked first for the top-level feature, and then for | |
1697 each of its subparts (recursively). You should make sure to examine | |
1698 the feature's type to determine whether the option is appropriate. | |
1699 | |
1700 Some glyphs deliberately disable this recursive feature. The "track", | |
1701 "group", "transcript", "transcript2" and "segments" glyphs selectively | |
1702 disable the -bump, -label and -description options. This is to avoid, | |
1703 for example, a label being attached to each exon in a transcript, or | |
1704 the various segments of a gapped alignment bumping each other. You | |
1705 can override this behavior and force your callback to be invoked by | |
1706 providing add_track() with a true B<-all_callbacks> argument. In this | |
1707 case, you must be prepared to handle configuring options for the | |
1708 "group" and "track" glyphs. | |
1709 | |
1710 In particular, this means that in order to control the -bump option | |
1711 with a callback, you should specify -all_callbacks=E<gt>1, and turn on | |
1712 bumping when the callback is in the track or group glyphs. | |
1713 | |
1714 =head2 ACCESSORS | |
1715 | |
1716 The following accessor methods provide access to various attributes of | |
1717 the panel object. Called with no arguments, they each return the | |
1718 current value of the attribute. Called with a single argument, they | |
1719 set the attribute and return its previous value. | |
1720 | |
1721 Note that in most cases you must change attributes prior to invoking | |
1722 gd(), png() or boxes(). These three methods all invoke an internal | |
1723 layout() method which places the tracks and the glyphs within them, | |
1724 and then caches the result. | |
1725 | |
1726 Accessor Name Description | |
1727 ------------- ----------- | |
1728 | |
1729 width() Get/set width of panel | |
1730 spacing() Get/set spacing between tracks | |
1731 key_spacing() Get/set spacing between keys | |
1732 length() Get/set length of segment (bp) | |
1733 flip() Get/set coordinate flipping | |
1734 pad_top() Get/set top padding | |
1735 pad_left() Get/set left padding | |
1736 pad_bottom() Get/set bottom padding | |
1737 pad_right() Get/set right padding | |
1738 start() Get the start of the sequence (bp; read only) | |
1739 end() Get the end of the sequence (bp; read only) | |
1740 left() Get the left side of the drawing area (pixels; read only) | |
1741 right() Get the right side of the drawing area (pixels; read only) | |
1742 | |
1743 =head2 COLOR METHODS | |
1744 | |
1745 The following methods are used internally, but may be useful for those | |
1746 implementing new glyph types. | |
1747 | |
1748 =over 4 | |
1749 | |
1750 =item @names = Bio::Graphics::Panel-E<gt>color_names | |
1751 | |
1752 Return the symbolic names of the colors recognized by the panel | |
1753 object. In a scalar context, returns an array reference. | |
1754 | |
1755 =item ($red,$green,$blue) = Bio::Graphics::Panel-E<gt>color_name_to_rgb($color) | |
1756 | |
1757 Given a symbolic color name, returns the red, green, blue components | |
1758 of the color. In a scalar context, returns an array reference to the | |
1759 rgb triplet. Returns undef for an invalid color name. | |
1760 | |
1761 =item @rgb = $panel-E<gt>rgb($index) | |
1762 | |
1763 Given a GD color index (between 0 and 140), returns the RGB triplet | |
1764 corresponding to this index. This method is only useful within a | |
1765 glyph's draw() routine, after the panel has allocated a GD::Image and | |
1766 is populating it. | |
1767 | |
1768 =item $index = $panel-E<gt>translate_color($color) | |
1769 | |
1770 Given a color, returns the GD::Image index. The color may be | |
1771 symbolic, such as "turquoise", or a #RRGGBB triple, as in #F0E0A8. | |
1772 This method is only useful within a glyph's draw() routine, after the | |
1773 panel has allocated a GD::Image and is populating it. | |
1774 | |
1775 =item $panel-E<gt>set_pen($width,$color) | |
1776 | |
1777 Changes the width and color of the GD drawing pen to the values | |
1778 indicated. This is called automatically by the GlyphFactory fgcolor() | |
1779 method. It returns the GD value gdBrushed, which should be used for | |
1780 drawing. | |
1781 | |
1782 =back | |
1783 | |
1784 =head1 BUGS | |
1785 | |
1786 Please report them. | |
1787 | |
1788 =head1 SEE ALSO | |
1789 | |
1790 L<Bio::Graphics::Glyph>, | |
1791 L<Bio::Graphics::Glyph::arrow>, | |
1792 L<Bio::Graphics::Glyph::cds>, | |
1793 L<Bio::Graphics::Glyph::crossbox>, | |
1794 L<Bio::Graphics::Glyph::diamond>, | |
1795 L<Bio::Graphics::Glyph::dna>, | |
1796 L<Bio::Graphics::Glyph::dot>, | |
1797 L<Bio::Graphics::Glyph::ellipse>, | |
1798 L<Bio::Graphics::Glyph::extending_arrow>, | |
1799 L<Bio::Graphics::Glyph::generic>, | |
1800 L<Bio::Graphics::Glyph::graded_segments>, | |
1801 L<Bio::Graphics::Glyph::heterogeneous_segments>, | |
1802 L<Bio::Graphics::Glyph::line>, | |
1803 L<Bio::Graphics::Glyph::pinsertion>, | |
1804 L<Bio::Graphics::Glyph::primers>, | |
1805 L<Bio::Graphics::Glyph::rndrect>, | |
1806 L<Bio::Graphics::Glyph::segments>, | |
1807 L<Bio::Graphics::Glyph::redgreen_box>, | |
1808 L<Bio::Graphics::Glyph::ruler_arrow>, | |
1809 L<Bio::Graphics::Glyph::toomany>, | |
1810 L<Bio::Graphics::Glyph::transcript>, | |
1811 L<Bio::Graphics::Glyph::transcript2>, | |
1812 L<Bio::Graphics::Glyph::translation>, | |
1813 L<Bio::Graphics::Glyph::triangle>, | |
1814 L<Bio::Graphics::Glyph::xyplot>, | |
1815 L<Bio::SeqI>, | |
1816 L<Bio::SeqFeatureI>, | |
1817 L<Bio::Das>, | |
1818 L<GD> | |
1819 | |
1820 =head1 AUTHOR | |
1821 | |
1822 Lincoln Stein E<lt>lstein@cshl.orgE<gt> | |
1823 | |
1824 Copyright (c) 2001 Cold Spring Harbor Laboratory | |
1825 | |
1826 This library is free software; you can redistribute it and/or modify | |
1827 it under the same terms as Perl itself. See DISCLAIMER.txt for | |
1828 disclaimers of warranty. | |
1829 | |
1830 =cut | |
1831 |