4
4
use Bio::Graphics::Glyph::segments;
5
5
use Bio::Graphics::Util qw(frame_and_offset);
6
6
use Bio::Tools::CodonTable;
7
use Bio::Graphics::Glyph::translation;
9
@ISA = qw(Bio::Graphics::Glyph::segmented_keyglyph Bio::Graphics::Glyph::translation);
7
use base qw(Bio::Graphics::Glyph::segmented_keyglyph Bio::Graphics::Glyph::translation);
11
9
my %default_colors = qw(
10
frame0f cornflowerblue
18
my %swap_phase = ( 0 => 0,
20
23
sub connector { 0 };
34
$self->{sixframe} = $self->option('sixframe')
35
unless exists $self->{sixframe};
36
return $self->{sixframe};
37
return $self->{sixframe} if exists $self->{sixframe};
38
my $sixframe = $self->option('sixframe');
39
$sixframe = $self->option('translation') eq '6frame' unless defined $sixframe;
40
return $self->{sixframe} = $sixframe;
39
45
sub require_subparts {
41
47
my $rs = $self->option('require_subparts');
52
70
@parts = $self if !@parts && $self->level == 0 && !$self->require_subparts;
54
72
my $fits = $self->protein_fits;
73
my $strand = $self->feature->strand || 1;
56
75
# draw the staff (musically speaking)
57
my ($x1,$y1,$x2,$y2) = $self->bounds($left,$top);
58
my $line_count = $self->sixframe ? 6 : 3;
59
my $height = ($y2-$y1)/$line_count;
60
my $grid = $self->gridcolor;
61
for (0..$line_count-1) {
62
my $offset = $y1+$height*$_+1;
63
$gd->line($x1,$offset,$x2,$offset,$grid);
76
if ($self->level == 0) {
77
my ($x1,$y1,$x2,$y2) = $self->bounds($left,$top);
78
my $line_count = $self->sixframe ? 6 : 3;
79
my $height = ($y2-$y1)/$line_count;
80
my $grid = $self->gridcolor;
81
for (0..$line_count-1) {
82
my $offset = $y1+$height*$_+1;
83
$gd->line($x1,$offset,$x2,$offset,$grid);
84
# with three-frame translation, the position of the arrows changes depending on
85
# the strand of the feature. With six-frame translation, we draw the first three
86
# staff lines with an arrow to the right, and the second three to the left
87
my $forward = ($line_count == 6) ? ($_ < 3) : ($strand > 0);
89
$gd->line($x2,$offset,$x2-2,$offset-2,$grid);
90
$gd->line($x2,$offset,$x2-2,$offset+2,$grid);
92
$gd->line($x1,$offset,$x1+2,$offset-2,$grid);
93
$gd->line($x1,$offset,$x1+2,$offset+2,$grid);
66
98
$self->{cds_part2color} ||= {};
67
99
my $fill = $self->bgcolor;
68
my $strand = $self->feature->strand;
70
101
# figure out the colors of each part
71
102
# sort minus strand features backward
77
108
$codon_table = 1 unless defined $codon_table;
78
109
my $translate_table = Bio::Tools::CodonTable->new(-id=>$codon_table);
111
my $ignore_undef_phase = $self->ignore_undef_phase;
112
my $ignore_non_cds = $self->ignore_non_cds;
113
my $broken_phase = $self->phase_style eq '021';
80
115
for (my $i=0; $i < @parts; $i++) {
81
116
my $part = $parts[$i];
82
117
my $feature = $part->feature;
83
my $pos = $strand > 0 ? $feature->start : $feature->end;
84
my $phase = eval {$feature->phase} || 0;
119
my $type = $feature->method;
120
next if ($self->option('sub_part') && $type ne $self->option('sub_part'));
122
next if $ignore_non_cds && lc($type) ne 'cds';
124
my $pos = $feature->strand >= 0 ? $feature->start : $feature->end;
125
my $phase = $feature->can('phase') ? $feature->phase # bioperl uses "frame" but this is incorrect usage
126
:$feature->can('frame') ? $feature->frame
128
next if $ignore_undef_phase && !defined($phase);
130
$phase = $swap_phase{$phase} if $broken_phase;
131
my $strand = $feature->strand;
85
132
my ($frame,$offset) = frame_and_offset($pos,
88
135
my $suffix = $strand < 0 ? 'r' : 'f';
89
136
my $key = "frame$frame$suffix";
90
137
$self->{cds_frame2color}{$key} ||= $self->color($key) || $self->default_color($key) || $fill;
97
144
# do in silico splicing in order to find the codon that
98
145
# arises from the splice
99
my $protein = $part->feature->translate(undef,undef,$phase,$codon_table)->seq;
146
my $seq = $self->get_seq($part->feature->seq);
147
my $protein = $seq->translate(undef,undef,$phase,$codon_table)->seq;
100
148
$part->{cds_translation} = $protein;
103
151
length $protein >= $feature->length/3 and last BLOCK;
104
152
($feature->length - $phase) % 3 == 0 and last BLOCK;
106
154
my $next_part = $parts[$i+1]
108
156
$part->{cds_splice_residue} = '?';
111
159
my $next_feature = $next_part->feature or last BLOCK;
112
160
my $next_phase = eval {$next_feature->phase} or last BLOCK;
113
161
my $splice_codon = '';
114
my $left_of_splice = substr($feature->seq,-$next_phase,$next_phase);
115
my $right_of_splice = substr($next_feature->seq,0,3-$next_phase);
162
my $left_of_splice = substr($self->get_seq($feature->seq), -$next_phase, $next_phase);
163
my $right_of_splice = substr($self->get_seq($next_feature->seq),0 , 3-$next_phase);
116
164
$splice_codon = $left_of_splice . $right_of_splice;
117
165
length $splice_codon == 3 or last BLOCK;
118
166
my $amino_acid = $translate_table->translate($splice_codon);
140
188
my $height = ($y2-$y1)/$linecount;
141
189
my $offset = $y1 + $height*$frame;
142
190
$offset += ($y2-$y1)/2 if $self->sixframe && $self->strand < 0;
191
$offset = $y1 + (($y2-$y1) - ($offset-$y1))-$height if $self->{flip}; # ugh. This works, but I don't know why
143
192
$gd->filledRectangle($x1,$offset,$x2,$offset+2,$color);
157
207
# 2) correct for the phase offset
158
208
my $start = $self->map_no_trunc($feature->start + $self->{cds_offset});
159
209
my $stop = $self->map_no_trunc($feature->end + $self->{cds_offset});
160
($start,$stop) = ($stop,$start) if $self->{flip};
211
($start,$stop) = ($stop,$start) if $stop < $start; # why does this keep happening?
212
# ($start,$stop) = ($stop,$start) if $self->{flip};
162
214
my @residues = split '',$self->{cds_translation};
166
218
my $x = $strand > 0 ? $start + $i * $pixels_per_residue
167
219
: $stop - $i * $pixels_per_residue;
168
220
next unless ($x >= $x1 && $x <= $x2);
221
$x -= $fontwidth + 1 if $self->{flip}; # align right when flipped
169
222
$gd->char($font,$x+1,$y,$residues[$i],$color);
268
321
-hilite Highlight color undef (no color)
270
In addition, the alignment glyph recognizes the following
271
glyph-specific options:
273
Option Description Default
274
------ ----------- -------
276
-frame0f Color for first (+) frame background color
278
-frame1f Color for second (+) frame background color
280
-frame2f Color for third (+) frame background color
282
-frame0r Color for first (-) frame background color
284
-frame1r Color for second (-) frame background color
286
-frame2r Color for third (-) frame background color
288
-gridcolor Color for the "staff" lightslategray
290
-sixframe Draw a six-frame staff 0 (false; usually draws 3 frame)
323
In addition, the cds glyph recognizes the following glyph-specific
326
Option Description Default
327
------ ----------- -------
329
-frame0f Color for first (+) frame background color
331
-frame1f Color for second (+) frame background color
333
-frame2f Color for third (+) frame background color
335
-frame0r Color for first (-) frame background color
337
-frame1r Color for second (-) frame background color
339
-frame2r Color for third (-) frame background color
341
-gridcolor Color for the "staff" lightslategray
343
-translation Number of lines of reading 3frame
344
frames to show. One of
345
"3frame", or "6frame".
346
For 6frame, specify a height
347
of at least 30 pixels.
349
-sixframe Draw a six-frame staff 0 (false; usually draws 3 frame)
351
-translation, which essentially
292
354
-require_subparts
293
Don't draw the reading frame 0 (false)
355
Don't draw the reading frame 0 false
294
356
unless it is a feature
297
-codontable Codon table to use 1 (see Bio::Tools::CodonTable)
359
-sub_part For objects with multiple undef
360
subpart types, defines which
363
-codontable Codon table to use 1 (see Bio::Tools::CodonTable)
365
-phase_style The way phase is to be
366
interpreted. One of "012"
368
-ignore_empty_phase false
369
Only draw features that have
372
-cds_only Only draw features of type false
375
This glyph is more sensitive to the underlying data model than usual,
376
so there are a few additional options to use to help adapt the glyph
377
to different environments.
299
379
The -require_subparts option is suggested when rendering spliced
300
380
transcripts which contain multiple CDS subparts. Otherwise, the glyph
302
382
phantom reading frame will appear). For unspliced sequences, do *not*
303
383
use -require_subparts.
385
The -phase_style controls how the value returned by the phase() or
386
frame() methods is to be interpreted. The official interpretation is
387
that the phase value indicates the offset into the feature at which
388
the reading frame starts -- e.g. a phase of "2" means the reading
389
frame starts after skipping two bases from the beginning of the
390
feature. However, many GFF2 format feature files interpret this field
391
to mean the position reading frame of the first base of the feature --
392
e.g. a phase of "2" means that the reading frame starts after skipping
393
just one base from the beginning of the feature. Specify "012" to
394
interpret the phase field in the correct way, and "021" to interpret
395
the phase field in the legacy way. The default is "012."
397
Here is how the option names were chosen:
399
* * * Base the reading frame starts on
401
0 1 2 PHASE REPRESENTED CORRECTLY
402
0 2 1 PHASE REPRESENTED IN THE LEGACY WAY
404
Set the -ignore_empty_phase option to true if you wish to skip
405
subfeatures that do not have a defined phase() or frame(). This is useful
406
if you are rendering exons that have both translated and untranslated
407
parts, and you wish to skip the untranslated parts.
409
Set the -cds_only option to true if you wish to draw the glyph only
410
for subfeatures of type 'CDS'. This is recommended.
305
412
=head1 SUGGESTED STANZA FOR GENOME BROWSER
307
414
Using the "coding" aggregator, this produces a nice gbrowse display.