~ubuntu-branches/ubuntu/saucy/bioperl/saucy-proposed

« back to all changes in this revision

Viewing changes to Bio/Graphics/Glyph/generic.pm

  • Committer: Bazaar Package Importer
  • Author(s): Charles Plessy
  • Date: 2009-03-10 07:19:11 UTC
  • mfrom: (1.2.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20090310071911-fukqzw54pyb1f0bd
Tags: 1.6.0-2
* Removed patch system (not used):
  - removed instuctions in debian/rules;
  - removed quilt from Build-Depends in debian/control.
* Re-enabled tests:
  - uncommented test command in debian/rules;
  - uncommented previously missing build-dependencies in debian/control.
  - Re-enabled tests and uncommented build-dependencies accordingly.
* Removed libmodule-build-perl and libtest-harness-perl from
  Build-Depends-Indep (provided by perl-modules).
* Better cleaning of empty directories using find -type d -empty -delete
  instead of rmdir in debian/rules (LP: #324001).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
package Bio::Graphics::Glyph::generic;
2
 
 
3
 
use strict;
4
 
use Bio::Graphics::Util qw(frame_and_offset);
5
 
use base qw(Bio::Graphics::Glyph);
6
 
 
7
 
my %complement = (g=>'c',a=>'t',t=>'a',c=>'g',
8
 
                  G=>'C',A=>'T',T=>'A',C=>'G');
9
 
 
10
 
# new options are 'label'       -- short label to print over glyph
11
 
#                 'description'  -- long label to print under glyph
12
 
# label and description can be flags or coderefs.
13
 
# If a flag, label will be taken from seqname, if it exists or primary_tag().
14
 
#            description will be taken from source_tag().
15
 
 
16
 
sub height {
17
 
  my $self = shift;
18
 
  my $h    = $self->SUPER::height;
19
 
  return $h unless
20
 
    $self->option('draw_translation') && $self->protein_fits
21
 
      or
22
 
        $self->option('draw_dna') && $self->dna_fits;
23
 
  my $fh = $self->font->height + 2;
24
 
  return $h > $fh ? $h : $fh;
25
 
}
26
 
 
27
 
sub pad_top {
28
 
  my $self = shift;
29
 
  my $top  = $self->option('pad_top');
30
 
  return $top if defined $top;
31
 
  my $pad = $self->SUPER::pad_top;
32
 
  $pad   += $self->labelheight if $self->label && $self->label_position eq 'top';
33
 
  $pad;
34
 
}
35
 
sub pad_bottom {
36
 
  my $self = shift;
37
 
  my $bottom  = $self->option('pad_bottom');
38
 
  return $bottom if defined $bottom;
39
 
  my $pad = $self->SUPER::pad_bottom;
40
 
  $pad   += $self->labelheight if $self->description;
41
 
  $pad   += $self->labelheight if $self->part_labels && $self->label_position eq 'top';
42
 
  $pad;
43
 
}
44
 
sub pad_right {
45
 
  my $self = shift;
46
 
  my $pad = $self->SUPER::pad_right;
47
 
  my $label_width       = $self->label_position eq 'top' ? $self->labelwidth : 0;
48
 
  my $description_width = $self->descriptionwidth;
49
 
  my $max = $label_width > $description_width ? $label_width : $description_width;
50
 
  my $right = $max - $self->width;
51
 
  return $pad > $right ? $pad : $right;
52
 
}
53
 
sub pad_left {
54
 
  my $self = shift;
55
 
  my $pad = $self->SUPER::pad_left;
56
 
  return $pad unless $self->label_position eq 'left' && $self->label;
57
 
  $pad += $self->labelwidth;
58
 
  $pad;
59
 
}
60
 
sub labelfont {
61
 
  my $self = shift;
62
 
  return $self->getfont('label_font',$self->font);
63
 
}
64
 
sub descfont {
65
 
  my $self = shift;
66
 
  return $self->getfont('desc_font',$self->font);
67
 
}
68
 
sub labelwidth {
69
 
  my $self = shift;
70
 
  return $self->{labelwidth} ||= length($self->label||'') * $self->font->width;
71
 
}
72
 
sub descriptionwidth {
73
 
  my $self = shift;
74
 
  return $self->{descriptionwidth} ||= length($self->description||'') * $self->font->width;
75
 
}
76
 
sub labelheight {
77
 
  my $self = shift;
78
 
  return $self->{labelheight} ||= $self->font->height;
79
 
}
80
 
sub label_position {
81
 
  my $self = shift;
82
 
  return $self->{labelposition} ||= $self->option('label_position') || 'top';
83
 
}
84
 
sub label {
85
 
  my $self = shift;
86
 
  return if $self->{overbumped};  # set by the bumper when we have hit bump limit
87
 
  return unless $self->subpart_callbacks;  # returns true if this is level 0 or if subpart callbacks allowed
88
 
  return $self->_label if $self->{level} >= 0;
89
 
  return exists $self->{label} ? $self->{label}
90
 
                               : ($self->{label} = $self->_label);
91
 
}
92
 
sub description {
93
 
  my $self = shift;
94
 
  return if $self->{overbumped}; # set by the bumper when we have hit bump limit
95
 
  return unless $self->subpart_callbacks;  # returns true if this is level 0 or if subpart callbacks allowed
96
 
  return $self->_description if $self->{level} > 0;
97
 
  return exists $self->{description} ? $self->{description}
98
 
                                     : ($self->{description} = $self->_description);
99
 
}
100
 
 
101
 
sub part_labels {
102
 
  my $self = shift;
103
 
  my @parts = $self->parts;
104
 
  return ($self->{level} == 0) && @parts && @parts>1 && $self->option('part_labels');
105
 
}
106
 
 
107
 
sub part_label_merge {
108
 
  shift->option('part_label_merge');
109
 
}
110
 
 
111
 
sub maxdepth {
112
 
  my $self = shift;
113
 
  my $maxdepth =  $self->option('maxdepth');
114
 
  return $maxdepth if defined $maxdepth;
115
 
  return 1;
116
 
}
117
 
 
118
 
sub _label {
119
 
  my $self = shift;
120
 
 
121
 
  # allow caller to specify the label
122
 
  my $label = $self->option('label');
123
 
 
124
 
  return unless defined $label;
125
 
  return "1"    if $label eq '1 '; # 1 with a space
126
 
  return $label unless $label eq '1';
127
 
 
128
 
  # figure it out ourselves
129
 
  my $f = $self->feature;
130
 
 
131
 
  return $f->display_name if $f->can('display_name');
132
 
  return $f->info         if $f->can('info');   # deprecated API
133
 
  return $f->seq_id       if $f->can('seq_id');
134
 
  return eval{$f->primary_tag};
135
 
}
136
 
sub _description {
137
 
  my $self = shift;
138
 
 
139
 
  # allow caller to specify the long label
140
 
  my $label = $self->option('description');
141
 
  return unless defined $label;
142
 
  return "1"   if $label eq '1 ';
143
 
  return $label unless $label eq '1';
144
 
 
145
 
  return $self->{_description} if exists $self->{_description};
146
 
  return $self->{_description} = $self->get_description($self->feature);
147
 
}
148
 
 
149
 
sub get_description {
150
 
  my $self = shift;
151
 
  my $feature = shift;
152
 
 
153
 
  # common places where we can get descriptions
154
 
  return join '; ',$feature->notes if $feature->can('notes');
155
 
  return $feature->desc            if $feature->can('desc');
156
 
 
157
 
  if ($feature->can('has_tag')) {
158
 
    return join '; ',$feature->get_tag_values('note')        if $feature->has_tag('note');
159
 
    return join '; ',$feature->get_tag_values('description') if $feature->has_tag('description');
160
 
  }
161
 
 
162
 
  my $tag = $feature->source_tag;
163
 
  return if $tag eq '';
164
 
  $tag;
165
 
}
166
 
 
167
 
sub draw {
168
 
  my $self = shift;
169
 
  my ($gd,$left,$top,$partno,$total_parts) = @_;
170
 
 
171
 
  local($self->{partno},$self->{total_parts});
172
 
  @{$self}{qw(partno total_parts)} = ($partno,$total_parts);
173
 
 
174
 
  $self->calculate_cds()      if $self->option('draw_translation') && $self->protein_fits;
175
 
 
176
 
  $self->SUPER::draw(@_);
177
 
  $self->draw_label(@_)       if $self->option('label');
178
 
  $self->draw_description(@_) if $self->option('description');
179
 
  $self->draw_part_labels(@_) if $self->option('label') && $self->option('part_labels');
180
 
}
181
 
 
182
 
sub draw_component {
183
 
  my $self = shift;
184
 
  $self->SUPER::draw_component(@_);
185
 
  $self->draw_translation(@_) if $self->{cds_translation}; # created earlier by calculate_cds()
186
 
  $self->draw_sequence(@_)    if $self->option('draw_dna') && $self->dna_fits;
187
 
}
188
 
 
189
 
# mostly stolen from cds.pm -- draw the protein translation
190
 
sub draw_translation {
191
 
  my $self = shift;
192
 
  my $gd = shift;
193
 
  my ($x1,$y1,$x2,$y2) = $self->bounds(@_);
194
 
 
195
 
  my $feature = $self->feature;
196
 
  my $strand = $feature->strand;
197
 
 
198
 
  my $font    = $self->font;
199
 
  my $pixels_per_residue = $self->scale * 3;
200
 
 
201
 
  my $y         = $y1 + ($self->height - $font->height)/2;
202
 
  my $fontwidth = $font->width;
203
 
  my $color     = $self->fontcolor;
204
 
 
205
 
  $strand *= -1 if $self->{flip};
206
 
 
207
 
  # have to remap feature start and end into pixel coords in order to:
208
 
  # 1) correctly align the amino acids with the nucleotide seq
209
 
  # 2) correct for the phase offset
210
 
  my $start = $self->map_no_trunc($feature->start + $self->{cds_offset});
211
 
  my $stop  = $self->map_no_trunc($feature->end   + $self->{cds_offset});
212
 
 
213
 
  ($start,$stop) = ($stop,$start) if $stop < $start;  # why does this keep happening?
214
 
  my $x_fudge    = $self->{flip} ? 1 : 2;
215
 
  my $right      = $self->panel->right;
216
 
  my $left       = $self->panel->left;
217
 
 
218
 
  my @residues = split '',$self->{cds_translation};
219
 
  push @residues,$self->{cds_splice_residue} if $self->{cds_splice_residue};
220
 
  for (my $i=0;$i<@residues;$i++) {
221
 
    my $x = $strand > 0 ? $start + $i * $pixels_per_residue
222
 
                        : $stop  - $i * $pixels_per_residue;
223
 
    next unless ($x >= $x1 && $x <= $x2);
224
 
    $x -= $fontwidth + 1 if $self->{flip}; # align right when flipped
225
 
    last if $x+$fontwidth >= $right;
226
 
    last if $x            <= $left;
227
 
    $gd->char($font,$x+$x_fudge,$y,$residues[$i],$color);
228
 
  }
229
 
}
230
 
 
231
 
sub draw_sequence {
232
 
  my $self = shift;
233
 
  my $gd = shift;
234
 
  my ($x1,$y1,$x2,$y2) = $self->bounds(@_);
235
 
 
236
 
  my $feature = $self->feature;
237
 
  my $strand = $feature->strand;
238
 
 
239
 
  my $font            = $self->font;
240
 
  my $pixels_per_base = $self->scale;
241
 
 
242
 
  my $y         = $y1 + ($self->height - $font->height)/2 - 1;
243
 
  my $fontwidth = $font->width;
244
 
  my $color     = $self->fontcolor;
245
 
 
246
 
  $strand *= -1 if $self->{flip};
247
 
 
248
 
  # have to remap feature start and end into pixel coords in order to:
249
 
  my $start = $self->map_no_trunc($feature->start);
250
 
  my $stop  = $self->map_no_trunc($feature->end);
251
 
 
252
 
  ($start,$stop) = ($stop,$start) if $stop < $start;  # why does this keep happening?
253
 
  my $x_fudge    = $self->{flip} ? 1 : 2;
254
 
  my $right      = $self->panel->right;
255
 
  my $left       = $self->panel->left;
256
 
 
257
 
  my $seq   = $self->get_seq($self->feature->seq);
258
 
  $seq      = $seq->seq if $seq;   # get the dna
259
 
 
260
 
  my $canonical = $self->option('canonical_strand');
261
 
 
262
 
  my @bases = split '',$seq;
263
 
  for (my $i=0;$i<@bases;$i++) {
264
 
    my $x = $strand >= 0 ? $start + $i * $pixels_per_base
265
 
                         : $stop  - $i * $pixels_per_base;
266
 
    next unless ($x >= $x1 && $x <= $x2);
267
 
    $x -= $fontwidth + 1 if $self->{flip}; # align right when flipped
268
 
    if ($strand >= 0) {
269
 
      last if $x + $fontwidth > $right;
270
 
    } else {
271
 
      next if $x >= $right;
272
 
      last if $x < $left;
273
 
    }
274
 
    my $base = $self->{flip} ? $complement{$bases[$i]} : $bases[$i];
275
 
    $base    = $complement{$base} if $canonical && $strand < 0;
276
 
    $gd->char($font,$x+$x_fudge,$y,$base,$color);
277
 
  }
278
 
}
279
 
 
280
 
sub min { $_[0] <= $_[1] ? $_[0] : $_[1] }
281
 
sub max { $_[0] >= $_[1] ? $_[0] : $_[1] }
282
 
 
283
 
sub draw_label {
284
 
  my $self = shift;
285
 
  my ($gd,$left,$top,$partno,$total_parts) = @_;
286
 
  my $label = $self->label or return;
287
 
  my $x    = $self->left + $left; # valid for both "top" and "left" because the left-hand side is defined by pad_left
288
 
  my $font = $self->labelfont;
289
 
  if ($self->label_position eq 'top') {
290
 
    $x += $self->pad_left;  # offset to beginning of the drawn part of the feature
291
 
    $x = $self->panel->left + 1 if $x <= $self->panel->left;
292
 
    $gd->string($font,
293
 
                $x,
294
 
                $self->top + $top - 1,
295
 
                $label,
296
 
                $self->fontcolor);
297
 
  }
298
 
  elsif ($self->label_position eq 'left') {
299
 
    $gd->string($font,
300
 
                $x,
301
 
                $self->{top} + ($self->height - $font->height)/2 + $top,
302
 
                $label,
303
 
                $self->fontcolor);
304
 
  }
305
 
}
306
 
sub draw_description {
307
 
  my $self = shift;
308
 
  my ($gd,$left,$top,$partno,$total_parts) = @_;
309
 
  my $label = $self->description or return;
310
 
  my $x = $self->left + $left;
311
 
  $x   += $self->pad_left;  # offset to beginning of drawn part of feature
312
 
  $x = $self->panel->left + 1 if $x <= $self->panel->left;
313
 
  my $dy= $self->part_labels ? $self->font->height : 0;
314
 
  $gd->string($self->descfont,
315
 
              $x,
316
 
              $self->bottom - $self->pad_bottom + $top + $dy,
317
 
              $label,
318
 
              $self->font2color);
319
 
}
320
 
 
321
 
sub draw_part_labels {
322
 
  my $self = shift;
323
 
  my ($gd,$left,$top,$partno,$total_parts) = @_;
324
 
  return unless $self->{level} == 0;
325
 
  my @p = $self->parts or return;
326
 
  @p > 1 or return;
327
 
  @p = reverse @p if $self->flip;
328
 
 
329
 
  my $font  = $self->font;
330
 
  my $width = $font->width;
331
 
  my $color = $self->fontcolor;
332
 
 
333
 
  my $y     = $top + $self->bottom - $self->pad_bottom;
334
 
  my $merge_em = $self->part_label_merge;
335
 
 
336
 
  my @parts;
337
 
  my $previous;
338
 
 
339
 
  if ($merge_em) {
340
 
    my $current_contig = [];
341
 
 
342
 
    for my $part (@p) {
343
 
      if (!$previous || $part->feature->start - $previous->feature->end <= 1) {
344
 
        push @$current_contig,$part;
345
 
      } else {
346
 
        push @parts,$current_contig;
347
 
        $current_contig = [$part];
348
 
      }
349
 
      $previous = $part;
350
 
    }
351
 
    push @parts,$current_contig;
352
 
  }
353
 
 
354
 
  else {
355
 
    @parts = map {[$_]} @p;
356
 
  }
357
 
 
358
 
  my $last_x;  # avoid overlapping labels
359
 
  for (my $i=0; $i<@parts; $i++) {
360
 
    my $x1     = $parts[$i][0]->left;
361
 
    my $x2     = $parts[$i][-1]->right;
362
 
 
363
 
    my $string = $self->part_label($i,scalar @parts);
364
 
    my $x    = $left + $x1 + ($x2 - $x1 - $width*length($string))/2;
365
 
    my $w    = $width * length($string);
366
 
    next if defined $last_x && $self->flip ?  $x + $w > $last_x : $x < $last_x;
367
 
    $gd->string($font,
368
 
                $x,$y,
369
 
                $string,
370
 
                $color);
371
 
    $last_x = $x + ($self->flip ? 0 : $w);
372
 
  }
373
 
}
374
 
 
375
 
sub part_label {
376
 
  my $self = shift;
377
 
  my ($part,$total)  = @_;
378
 
 
379
 
  local $self->{partno} = $self->feature->strand < 0 ? $total - $part -1 : $part;
380
 
  my $label = $self->option('part_labels');
381
 
  return unless defined $label;
382
 
  return "1"   if $label eq '1 ';
383
 
  return $label unless $label eq '1';
384
 
  return $self->{partno}+1;
385
 
}
386
 
 
387
 
sub dna_fits {
388
 
  my $self = shift;
389
 
 
390
 
  my $pixels_per_base = $self->scale;
391
 
  my $font            = $self->font;
392
 
  my $font_width      = $font->width;
393
 
 
394
 
  return $pixels_per_base >= $font_width;
395
 
}
396
 
 
397
 
sub protein_fits {
398
 
  my $self = shift;
399
 
  my $font               = $self->font;
400
 
 
401
 
  # return unless $font->height <= $self->height;
402
 
 
403
 
  my $font_width         = $font->width;
404
 
  my $pixels_per_residue = $self->scale * 3;
405
 
 
406
 
  return $pixels_per_residue >= $font_width;
407
 
}
408
 
 
409
 
sub arrowhead {
410
 
  my $self = shift;
411
 
  my $image = shift;
412
 
  my ($x,$y,$height,$orientation) = @_;
413
 
 
414
 
  my $fg = $self->set_pen;
415
 
  my $style = $self->option('arrowstyle') || 'regular';
416
 
 
417
 
  if ($style eq 'filled') {
418
 
    my $poly_pkg = $self->polygon_package;
419
 
    my $poly = $poly_pkg->new();
420
 
    if ($orientation >= 0) {
421
 
      $poly->addPt($x-$height,$y-$height);
422
 
      $poly->addPt($x,$y);
423
 
      $poly->addPt($x-$height,$y+$height,$y);
424
 
    } else {
425
 
      $poly->addPt($x+$height,$y-$height);
426
 
      $poly->addPt($x,$y);
427
 
      $poly->addPt($x+$height,$y+$height,$y);
428
 
    }
429
 
    $image->filledPolygon($poly,$fg);
430
 
  }
431
 
  else {
432
 
    if ($orientation >= 0) {
433
 
      $image->line($x,$y,$x-$height,$y-$height,$fg);
434
 
      $image->line($x,$y,$x-$height,$y+$height,$fg);
435
 
    } else {
436
 
      $image->line($x,$y,$x+$height,$y-$height,$fg);
437
 
      $image->line($x,$y,$x+$height,$y+$height,$fg);
438
 
    }
439
 
  }
440
 
}
441
 
 
442
 
sub arrow {
443
 
  my $self  = shift;
444
 
  my $image = shift;
445
 
  my ($x1,$x2,$y) = @_;
446
 
 
447
 
  my $fg     = $self->set_pen;
448
 
  my $height = $self->height/3;
449
 
 
450
 
  $image->line($x1,$y,$x2,$y,$fg);
451
 
  $self->arrowhead($image,$x2,$y,$height,+1) if $x1 < $x2;
452
 
  $self->arrowhead($image,$x2,$y,$height,-1) if $x2 < $x1;
453
 
}
454
 
 
455
 
sub reversec {
456
 
  my $self = shift;
457
 
  my $dna  = shift;
458
 
  $dna =~ tr/gatcGATC/ctagCTAG/;
459
 
  $dna = reverse $dna;
460
 
  return $dna;
461
 
}
462
 
 
463
 
# this gets invoked if the user has requested that the protein translation
464
 
# gets drawn using the draw_translation option and protein_fits() returns
465
 
# true. It is a rather specialized function and possibly belongs somewhere else,
466
 
# but putting it here makes it possible for any feature to display its protein
467
 
# translation.
468
 
sub calculate_cds {
469
 
  my $self = shift;
470
 
  my @parts = $self->feature_has_subparts ? $self->parts : $self;
471
 
 
472
 
  my $codon_table = $self->option('codontable');
473
 
  $codon_table    = 1 unless defined $codon_table;
474
 
  require Bio::Tools::CodonTable unless Bio::Tools::CodonTable->can('new');
475
 
  my $translate_table = Bio::Tools::CodonTable->new(-id=>$codon_table);
476
 
 
477
 
  for (my $i=0; $i < @parts; $i++) {
478
 
    my $part    = $parts[$i];
479
 
    my $feature = $part->feature;
480
 
 
481
 
    my $pos     = $feature->strand >= 0 ? $feature->start : $feature->end;
482
 
    my $phase   = eval {$feature->phase};
483
 
    next unless defined $phase;
484
 
    my $seq     = $feature->seq;
485
 
    next unless defined $seq;
486
 
 
487
 
    my $strand          = $feature->strand;
488
 
    my ($frame,$offset) = frame_and_offset($pos,
489
 
                                           $strand,
490
 
                                           -$phase);
491
 
    $strand *= -1 if $self->{flip};
492
 
    $part->{cds_frame}     = $frame;
493
 
    $part->{cds_offset}    = $offset;
494
 
 
495
 
    # do in silico splicing in order to find the codon that
496
 
    # arises from the splice
497
 
    my $protein = $seq->translate(undef,undef,$phase,$codon_table)->seq;
498
 
    $part->{cds_translation}  = $protein;
499
 
 
500
 
  BLOCK: {
501
 
      length $protein >= $feature->length/3           and last BLOCK;
502
 
      ($feature->length - $phase) % 3 == 0            and last BLOCK;
503
 
        
504
 
      my $next_part    = $parts[$i+1]
505
 
        or do {
506
 
          $part->{cds_splice_residue} = '?';
507
 
          last BLOCK; };
508
 
 
509
 
      my $next_feature = $next_part->feature         or  last BLOCK;
510
 
      my $next_phase   = eval {$next_feature->phase} or  last BLOCK;
511
 
      my $splice_codon = '';
512
 
      my $left_of_splice  = substr($self->get_seq($feature->seq),     -$next_phase, $next_phase);
513
 
      my $right_of_splice = substr($self->get_seq($next_feature->seq),0           , 3-$next_phase);
514
 
      $splice_codon = $left_of_splice . $right_of_splice;
515
 
      length $splice_codon == 3                      or last BLOCK;
516
 
      my $amino_acid = $translate_table->translate($splice_codon);
517
 
      $part->{cds_splice_residue} = $amino_acid;
518
 
    }
519
 
  }
520
 
}
521
 
 
522
 
# hack around changed feature API
523
 
sub get_seq {
524
 
  my $self = shift;
525
 
  my $seq = shift;
526
 
  return $seq if ref $seq && $seq->can('translate');
527
 
  require Bio::PrimarySeq unless Bio::PrimarySeq->can('new');
528
 
  return Bio::PrimarySeq->new(-seq=>$seq);
529
 
}
530
 
 
531
 
1;
532
 
 
533
 
=head1 NAME
534
 
 
535
 
Bio::Graphics::Glyph::generic - The "generic" glyph
536
 
 
537
 
=head1 SYNOPSIS
538
 
 
539
 
  See L<Bio::Graphics::Panel> and L<Bio::Graphics::Glyph>.
540
 
 
541
 
=head1 DESCRIPTION
542
 
 
543
 
This is identical to the "box" glyph except that it will draw the
544
 
subparts of features that contain subfeatures.  The subparts are not
545
 
connected -- use the "segments" glyph for that.  "Generic" is the
546
 
default glyph used when not otherwise specified.
547
 
 
548
 
=head2 METHODS
549
 
 
550
 
This module overrides the maxdepth() method to return 0 unless the
551
 
-maxdepth option is provided explicitly. This means that any module
552
 
that inherits from generic will need to override maxdepth() again in
553
 
order to draw subfeatures. In general, those implementing
554
 
multi-segmented feature glyphs should inherit from
555
 
Bio::Graphics::Glyph::segments, which allows for one level of descent.
556
 
 
557
 
In addition, the following new methods are implemented:
558
 
 
559
 
=over 4
560
 
 
561
 
=item labelfont(), descfont(), labelwidth(), descriptionwidth()
562
 
 
563
 
Return the font, width for the label or description.
564
 
 
565
 
=item label()
566
 
 
567
 
Return the glyph label text (printed above the glyph).
568
 
 
569
 
=item description()
570
 
 
571
 
Return the glyph description text (printed below the glyph).
572
 
 
573
 
=item draw_translation()
574
 
 
575
 
Draw the protein translation of the feature (assumes that the feature is attached to a DNA sequence).
576
 
 
577
 
=item draw_sequence()
578
 
 
579
 
Draw the sequence of the feature (either DNA or protein).
580
 
 
581
 
=back
582
 
 
583
 
=head2 OPTIONS
584
 
 
585
 
The following options are standard among all Glyphs.  See
586
 
L<Bio::Graphics::Glyph> for a full explanation.
587
 
 
588
 
  Option      Description                      Default
589
 
  ------      -----------                      -------
590
 
 
591
 
  -fgcolor      Foreground color               black
592
 
 
593
 
  -outlinecolor Synonym for -fgcolor
594
 
 
595
 
  -bgcolor      Background color               turquoise
596
 
 
597
 
  -fillcolor    Synonym for -bgcolor
598
 
 
599
 
  -linewidth    Line width                     1
600
 
 
601
 
  -height       Height of glyph                10
602
 
 
603
 
  -font         Default font                   gdSmallFont
604
 
 
605
 
  -label_font   Font used for label            gdSmallFont
606
 
 
607
 
  -desc_font    Font used for description      gdSmallFont
608
 
 
609
 
  -connector    Connector type                 0 (false)
610
 
 
611
 
  -connector_color
612
 
                Connector color                black
613
 
 
614
 
  -pad_top      Top padding                    0
615
 
 
616
 
  -pad_bottom   Bottom padding                 0
617
 
 
618
 
  -label        Whether to draw a label        0 (false)
619
 
 
620
 
  -label_position Where to draw the label      "top" (default) or "left"
621
 
 
622
 
  -description  Whether to draw a description  0 (false)
623
 
 
624
 
  -strand_arrow Whether to indicate            0 (false)
625
 
                 strandedness
626
 
 
627
 
  -hilite       Highlight color                undef (no color)
628
 
 
629
 
  -draw_dna     If true, draw the dna residues        0 (false)
630
 
                 when magnification level
631
 
                 allows.
632
 
 
633
 
  -canonical_strand If true, draw the dna residues        0 (false)
634
 
                 as they appear on the plus strand
635
 
                 even if the feature is on the minus
636
 
                 strand.
637
 
 
638
 
-pad_top and -pad_bottom allow you to insert some blank space between
639
 
the glyph's boundary and its contents.  This is useful if you are
640
 
changing the glyph's height dynamically based on its feature's score.
641
 
 
642
 
=head1 BUGS
643
 
 
644
 
Please report them.
645
 
 
646
 
=head1 SEE ALSO
647
 
 
648
 
L<Bio::Graphics::Panel>,
649
 
L<Bio::Graphics::Glyph>,
650
 
L<Bio::Graphics::Glyph::arrow>,
651
 
L<Bio::Graphics::Glyph::cds>,
652
 
L<Bio::Graphics::Glyph::crossbox>,
653
 
L<Bio::Graphics::Glyph::diamond>,
654
 
L<Bio::Graphics::Glyph::dna>,
655
 
L<Bio::Graphics::Glyph::dot>,
656
 
L<Bio::Graphics::Glyph::ellipse>,
657
 
L<Bio::Graphics::Glyph::extending_arrow>,
658
 
L<Bio::Graphics::Glyph::generic>,
659
 
L<Bio::Graphics::Glyph::graded_segments>,
660
 
L<Bio::Graphics::Glyph::heterogeneous_segments>,
661
 
L<Bio::Graphics::Glyph::line>,
662
 
L<Bio::Graphics::Glyph::pinsertion>,
663
 
L<Bio::Graphics::Glyph::primers>,
664
 
L<Bio::Graphics::Glyph::rndrect>,
665
 
L<Bio::Graphics::Glyph::segments>,
666
 
L<Bio::Graphics::Glyph::ruler_arrow>,
667
 
L<Bio::Graphics::Glyph::toomany>,
668
 
L<Bio::Graphics::Glyph::transcript>,
669
 
L<Bio::Graphics::Glyph::transcript2>,
670
 
L<Bio::Graphics::Glyph::translation>,
671
 
L<Bio::Graphics::Glyph::triangle>,
672
 
L<Bio::Graphics::Glyph::xyplot>,
673
 
L<Bio::DB::GFF>,
674
 
L<Bio::SeqI>,
675
 
L<Bio::SeqFeatureI>,
676
 
L<Bio::Das>,
677
 
L<GD>
678
 
 
679
 
=head1 AUTHOR
680
 
p
681
 
Allen Day E<lt>day@cshl.orgE<gt>.
682
 
 
683
 
Copyright (c) 2001 Cold Spring Harbor Laboratory
684
 
 
685
 
This library is free software; you can redistribute it and/or modify
686
 
it under the same terms as Perl itself.  See DISCLAIMER.txt for
687
 
disclaimers of warranty.
688
 
 
689
 
=cut