Bio::Graphics
Glyph
Summary
Bio::Graphics::Glyph - Base class for Bio::Graphics::Glyph objects
Package variables
Globals (from "use vars" definitions)
$VERSION = '1.01'
Privates (from "my" definitions)
%LAYOUT_COUNT;
Included modules
Carp ' croak '
GD
constant BUMP_SPACING => 2
Synopsis
Description
Bio::Graphics::Glyph is the base class for all glyph objects. Each
glyph is a wrapper around an Bio:SeqFeatureI object, knows how to
render itself on an Bio::Graphics::Panel, and has a variety of
configuration variables.
End developers will not ordinarily work directly with
Bio::Graphics::Glyph objects, but with Bio::Graphics::Glyph::generic
and its subclasses. Similarly, most glyph developers will want to
subclass from Bio::Graphics::Glyph::generic because the latter
provides labeling and arrow-drawing facilities.
Methods
| new | No description | Code |
| parts | No description | Code |
| feature | No description | Code |
| factory | No description | Code |
| panel | No description | Code |
| point | No description | Code |
| scale | No description | Code |
| start | No description | Code |
| stop | No description | Code |
| end | No description | Code |
| map_pt | No description | Code |
| add_feature | No description | Code |
| add_group | No description | Code |
| top | No description | Code |
| left | No description | Code |
| right | No description | Code |
| bottom | No description | Code |
| height | No description | Code |
| width | No description | Code |
| layout_height | No description | Code |
| layout_width | No description | Code |
| calculate_boundaries | No description | Code |
| bounds | No description | Code |
| box | No description | Code |
| unfilled_box | No description | Code |
| boxes | No description | Code |
| pad_top | No description | Code |
| pad_bottom | No description | Code |
| pad_left | No description | Code |
| pad_right | No description | Code |
| move | No description | Code |
| option | No description | Code |
| configure | No description | Code |
| color | No description | Code |
| connector | No description | Code |
| bump | No description | Code |
| fgcolor | No description | Code |
| fillcolor | No description | Code |
| bgcolor | No description | Code |
| font | No description | Code |
| fontcolor | No description | Code |
| font2color | No description | Code |
| tkcolor | No description | Code |
| connector_color | No description | Code |
| layout | No description | Code |
| draw | No description | Code |
| level | No description | Code |
| draw_connectors | No description | Code |
| _connector | No description | Code |
| draw_connector | No description | Code |
| draw_hat_connector | No description | Code |
| draw_solid_connector | No description | Code |
| draw_dashed_connector | No description | Code |
| filled_box | No description | Code |
| filled_oval | No description | Code |
| oval | No description | Code |
| filled_arrow | No description | Code |
| linewidth | No description | Code |
| fill | No description | Code |
| set_pen | No description | Code |
| draw_component | No description | Code |
| subseq | No description | Code |
| _subseq | No description | Code |
| keyglyph | No description | Code |
| make_key_feature | No description | Code |
| all_callbacks | No description | Code |
| default_factory | No description | Code |
Methods description
None available.
Methods code
sub new
{ my $class = shift;
my %arg = @_;
my $feature = $arg{-feature} or die "No feature";
my $factory = $arg{-factory} || $class->default_factory;
my $level = $arg{-level} || 0;
my $self = bless {},$class;
$self->{feature} = $feature;
$self->{factory} = $factory;
$self->{level} = $level;
$self->{top} = 0;
my @subglyphs;
my @subfeatures = $self->subseq($feature);
if (@subfeatures) {
@subglyphs = sort { $a->left <=> $b->left } $factory->make_glyph($level+1,@subfeatures);
$self->{parts} =\@ subglyphs;
}
if (defined $self->start && defined $self->stop) {
my ($left,$right) = $factory->map_pt($self->start,$self->stop);
($left,$right) = ($right,$left) if $left > $right; $self->{left} = $left;
$self->{width} = $right - $left + 1;
}
if (@subglyphs) {
my $l = $subglyphs[0]->left;
$self->{left} = $l if !defined($self->{left}) || $l < $self->{left};
my $right = (sort { $b<=>$a } map {$_->right} @subglyphs)[0];
my $w = $right - $self->{left} + 1;
$self->{width} = $w if !defined($self->{width}) || $w > $self->{width};
}
$self->{point} = $arg{-point} ? $self->height : undef;
if($self->option('point')){
my ($left,$right) = $factory->map_pt($self->start,$self->stop);
my $center = int(($left+$right)/2);
$self->{width} = $self->height;
$self->{left} = $center - ($self->{width});
$self->{right} = $center + ($self->{width});
}
return $self;} |
sub parts
{ my $self = shift;
return unless $self->{parts};
return wantarray ? @{$self->{parts}} : $self->{parts};} |
sub feature
{ shift->{feature}} |
sub factory
{ shift->{factory}} |
sub panel
{ shift->factory->panel } |
sub point
{ shift->{point}} |
sub scale
{ shift->factory->scale } |
sub start
{ my $self = shift;
return $self->{start} if exists $self->{start};
$self->{start} = $self->{feature}->start;
$self->{start} = $self->panel->offset - 1 unless defined $self->{start};
return $self->{start};} |
sub stop
{ my $self = shift;
return $self->{stop} if exists $self->{stop};
$self->{stop} = $self->{feature}->end;
$self->{stop} = $self->panel->offset + $self->panel->length + 1 unless defined $self->{stop};
return $self->{stop}} |
sub map_pt
{ shift->{factory}->map_pt(@_)} |
sub add_feature
{ my $self = shift;
my $factory = $self->factory;
for my $feature (@_) {
if (ref $feature eq 'ARRAY') {
$self->add_group(@$feature);
} else {
push @{$self->{parts}},$factory->make_glyph(0,$feature);
}
}} |
sub add_group
{ my $self = shift;
my @features = ref($_[0]) eq 'ARRAY' ? @{$_[0]} : @_;
my $f = Bio::Graphics::Feature->new(
-segments=>\@features,
-type => 'group'
);
$self->add_feature($f);} |
sub top
{ my $self = shift;
my $g = $self->{top};
$self->{top} = shift if @_;
$g;} |
sub left
{ my $self = shift;
return $self->{left} - $self->pad_left; } |
sub right
{ my $self = shift;
return $self->left + $self->layout_width - 1; } |
sub bottom
{ my $self = shift;
$self->top + $self->layout_height - 1; } |
sub height
{ my $self = shift;
return $self->{height} if exists $self->{height};
my $baseheight = $self->option('height'); return $self->{height} = $baseheight;} |
sub width
{ my $self = shift;
my $g = $self->{width};
$self->{width} = shift if @_;
$g;} |
sub layout_height
{ my $self = shift;
return $self->layout; } |
sub layout_width
{ my $self = shift;
return $self->width + $self->pad_left + $self->pad_right; } |
sub calculate_boundaries
{return shift->bounds(@_); } |
sub bounds
{ my $self = shift;
my ($dx,$dy) = @_;
$dx += 0; $dy += 0;
($dx + $self->{left},
$dy + $self->top + $self->pad_top,
$dx + $self->{left} + $self->{width} - 1,
$dy + $self->bottom - $self->pad_bottom);} |
sub box
{ my $self = shift;
return ($self->left,$self->top,$self->right,$self->bottom); } |
sub unfilled_box
{ my $self = shift;
my $gd = shift;
my ($x1,$y1,$x2,$y2) = @_;
my $fg = $self->fgcolor;
my $bg = $self->bgcolor;
my $linewidth = $self->option('linewidth') || 1;
$fg = $self->set_pen($linewidth,$fg) if $linewidth > 1;
$gd->rectangle($x1,$y1,$x2,$y2,$fg);
my ($width) = $gd->getBounds;
$bg = $self->set_pen($linewidth,$bg) if $linewidth > 1;
$gd->line($x1,$y1+$linewidth,$x1,$y2-$linewidth,$bg)
if $x1 < $self->panel->pad_left;
$gd->line($x2,$y1+$linewidth,$x2,$y2-$linewidth,$bg)
if $x2 > $width - $self->panel->pad_right;} |
sub boxes
{ my $self = shift;
my ($left,$top) = @_;
$top += 0; $left += 0;
my @result;
$self->layout;
for my $part ($self->parts) {
if (eval{$part->feature->primary_tag} eq 'group') {
push @result,$part->boxes($left+$self->left,$top+$self->top);
} else {
my ($x1,$y1,$x2,$y2) = $part->box;
push @result,[$part->feature,$x1,$top+$self->top+$y1,$x2,$top+$self->top+$y2];
}
}
return wantarray ? @result :\@ result;} |
sub pad_top
{ my $self = shift;
return 0; } |
sub pad_bottom
{ my $self = shift;
return 0; } |
sub pad_left
{ my $self = shift;
return 0; } |
sub pad_right
{ my $self = shift;
my @parts = $self->parts or return 0;
my $max = 0;
foreach (@parts) {
my $pr = $_->pad_right;
$max = $pr if $max < $pr;
}
$max; } |
sub move
{ my $self = shift;
my ($dx,$dy) = @_;
$self->{left} += $dx;
$self->{top} += $dy;
$_->move($dx,0) foreach $self->parts;} |
sub option
{ my $self = shift;
my $option_name = shift;
my $factory = $self->factory;
return unless $factory;
$factory->option($self,$option_name,@{$self}{qw(partno total_parts)});} |
sub configure
{ my $self = shift;
my $factory = $self->factory;
my $option_map = $factory->option_map;
while (@_) {
my $option_name = shift;
my $option_value = shift;
($option_name = lc $option_name) =~ s/^-//;
$option_map->{$option_name} = $option_value;
}} |
sub color
{ my $self = shift;
my $color = shift;
my $index = $self->option($color);
return $self->factory->translate_color($index) if defined $index;
return 0; } |
sub connector
{ return shift->option('connector',@_);} |
sub bump
{ my $self = shift;
return $self->option('bump');} |
sub fgcolor
{ my $self = shift;
my $index = $self->option('fgcolor') || $self->option('color') || return 0;
$self->factory->translate_color($index);} |
sub fillcolor
{ my $self = shift;
return $self->bgcolor;} |
sub bgcolor
{ my $self = shift;
my $index = $self->option('bgcolor') || $self->option('fillcolor') || return 0;
$self->factory->translate_color($index);} |
sub font
{ shift->option('font');} |
sub fontcolor
{ my $self = shift;
$self->color('fontcolor') || $self->fgcolor;} |
sub font2color
{ my $self = shift;
$self->color('font2color') || $self->fontcolor;} |
sub tkcolor
{ $self->option('tkcolor') or return;
return $self->color('tkcolor') } |
sub connector_color
{ my $self = shift;
$self->color('connector_color') || $self->fgcolor;} |
sub layout
{ my $self = shift;
return $self->{layout_height} if exists $self->{layout_height};
(my @parts = $self->parts)
|| return $self->{layout_height} = $self->height + $self->pad_top + $self->pad_bottom;
my $bump_direction = $self->bump;
$_->layout foreach @parts;
if (@parts == 1 || !$bump_direction) {
my $highest = 0;
foreach (@parts) {
my $height = $_->layout_height;
$highest = $height > $highest ? $height : $highest;
}
return $self->{layout_height} = $highest + $self->pad_top + $self->pad_bottom;
}
my %occupied;
for my $g (sort { $a->left <=> $b->left } @parts) {
my $pos = 0;
while (1) {
my $bottom = $pos + $g->{layout_height};
my $collision;
for my $old (sort {$b->[2]<=> $a->[2]} values %occupied) {
last if $old->[2] + 2 < $g->left;
next if $old->[3] < $pos;
next if $old->[1] > $bottom;
$collision = $old;
last;
}
last unless $collision;
if ($bump_direction > 0) {
$pos += $collision->[3]-$collision->[1] + BUMP_SPACING;
} else {
$pos -= BUMP_SPACING;
}
}
$g->move(0,$pos);
$occupied{$g} = [$g->left,$g->top,$g->right,$g->bottom];
}
if ($bump_direction < 0) {
my ($topmost) = sort {$a->top <=> $b->top} @parts;
my $offset = 0 - $topmost->top;
$_->move(0,$offset) foreach @parts;
}
my $bottom = 0;
foreach (@parts) {
$bottom = $_->bottom if $_->bottom > $bottom;
}
return $self->{layout_height} = $self->pad_bottom + $self->pad_top + $bottom - $self->top + 1;} |
sub draw
{ my $self = shift;
my $gd = shift;
my ($left,$top,$partno,$total_parts) = @_;
local($self->{partno},$self->{total_parts});
@{$self}{qw(partno total_parts)} = ($partno,$total_parts);
my $connector = $self->connector;
if (my @parts = $self->parts) {
my $x = $left;
my $y = $top + $self->top + $self->pad_top;
$self->draw_connectors($gd,$x,$y) if $connector && $connector ne 'none';
my $last_x;
for (my $i=0; $i<@parts; $i++) {
my $fake_x = $x;
$fake_x-- if defined $last_x && $parts[$i]->left - $last_x == 1;
$parts[$i]->draw($gd,$fake_x,$y,$i,scalar(@parts));
$last_x = $parts[$i]->right;
}
}
else { $self->draw_connectors($gd,$left,$top)
if $connector && $connector ne 'none' && $self->{level} == 0;
$self->draw_component($gd,$left,$top);
}} |
sub level
{ shift->{level};} |
sub draw_connectors
{ my $self = shift;
my $gd = shift;
my ($dx,$dy) = @_;
my @parts = sort { $a->left <=> $b->left } $self->parts;
for (my $i = 0; $i < @parts-1; $i++) {
$self->_connector($gd,$dx,$dy,$parts[$i]->bounds,$parts[$i+1]->bounds);
}
if (@parts) {
my($x1,$y1,$x2,$y2) = $self->bounds(0,0);
my($xl,$xt,$xr,$xb) = $parts[0]->bounds;
$self->_connector($gd,$dx,$dy,$x1,$xt,$x1,$xb,$xl,$xt,$xr,$xb);
($xl,$xt,$xr,$xb) = $parts[-1]->bounds;
$self->_connector($gd,$dx,$dy,$parts[-1]->bounds,$x2,$xt,$x2,$xb);
}} |
sub _connector
{ my $self = shift;
my ($gd,
$dx,$dy,
$xl,$xt,$xr,$xb,
$yl,$yt,$yr,$yb) = @_;
my $left = $dx + $xr;
my $right = $dx + $yl;
my $top1 = $dy + $xt;
my $bottom1 = $dy + $xb;
my $top2 = $dy + $yt;
my $bottom2 = $dy + $yb;
$self->draw_connector($gd,
$top1,$bottom1,$left,
$top2,$bottom2,$right,
);} |
sub draw_connector
{ my $self = shift;
my $gd = shift;
my $color = $self->connector_color;
my $connector_type = $self->connector or return;
if ($connector_type eq 'hat') {
$self->draw_hat_connector($gd,$color,@_);
} elsif ($connector_type eq 'solid') {
$self->draw_solid_connector($gd,$color,@_);
} elsif ($connector_type eq 'dashed') {
$self->draw_dashed_connector($gd,$color,@_);
} else {
; }} |
sub draw_hat_connector
{ my $self = shift;
my $gd = shift;
my $color = shift;
my ($top1,$bottom1,$left,$top2,$bottom2,$right) = @_;
my $center1 = ($top1 + $bottom1)/2; my $quarter1 = $top1 + ($bottom1-$top1)/4; my $center2 = ($top2 + $bottom2)/2; my $quarter2 = $top2 + ($bottom2-$top2)/4;
if ($center1 != $center2) {
$self->draw_solid_connector($gd,$color,@_);
return;
}
if ($right - $left > 4) { my $middle = $left + int(($right - $left)/2); $gd->line($left,$center1,$middle,$top1,$color);
$gd->line($middle,$top1,$right-1,$center1,$color);
} elsif ($right-$left > 1) { $gd->line($left,$quarter1,$right-1,$quarter1,$color);
} } |
sub draw_solid_connector
{ my $self = shift;
my $gd = shift;
my $color = shift;
my ($top1,$bottom1,$left,$top2,$bottom2,$right) = @_;
my $center1 = ($top1 + $bottom1)/2; my $center2 = ($top2 + $bottom2)/2;
$gd->line($left,$center1,$right,$center2,$color); } |
sub draw_dashed_connector
{ my $self = shift;
my $gd = shift;
my $color = shift;
my ($top1,$bottom1,$left,$top2,$bottom2,$right) = @_;
my $center1 = ($top1 + $bottom1)/2; my $center2 = ($top2 + $bottom2)/2;
$gd->setStyle($color,$color,gdTransparent,gdTransparent,);
$gd->line($left,$center1,$right,$center2,gdStyled); } |
sub filled_box
{ my $self = shift;
my $gd = shift;
my ($x1,$y1,$x2,$y2,$bg,$fg) = @_;
$bg ||= $self->bgcolor;
$fg ||= $self->fgcolor;
my $linewidth = $self->option('linewidth') || 1;
$gd->filledRectangle($x1,$y1,$x2,$y2,$bg);
$fg = $self->set_pen($linewidth,$fg) if $linewidth > 1;
$gd->rectangle($x1,$y1,$x2,$y2,$fg);
my ($width) = $gd->getBounds;
$bg = $self->set_pen($linewidth,$bg) if $linewidth > 1;
$gd->line($x1,$y1+$linewidth,$x1,$y2-$linewidth,$bg)
if $x1 < $self->panel->pad_left;
$gd->line($x2,$y1+$linewidth,$x2,$y2-$linewidth,$bg)
if $x2 > $width - $self->panel->pad_right;} |
sub filled_oval
{ my $self = shift;
my $gd = shift;
my ($x1,$y1,$x2,$y2,$bg,$fg) = @_;
my $cx = ($x1+$x2)/2; my $cy = ($y1+$y2)/2;
$fg ||= $self->fgcolor;
$bg ||= $self->bgcolor;
my $linewidth = $self->linewidth;
$fg = $self->set_pen($linewidth) if $linewidth > 1;
$gd->arc($cx,$cy,$x2-$x1,$y2-$y1,0,360,$fg);
$gd->fill($cx,$cy,$bg); } |
sub oval
{ my $self = shift;
my $gd = shift;
my ($x1,$y1,$x2,$y2) = @_;
my $cx = ($x1+$x2)/2; my $cy = ($y1+$y2)/2;
my $fg = $self->fgcolor;
my $linewidth = $self->linewidth;
$fg = $self->set_pen($linewidth) if $linewidth > 1;
$gd->arc($cx,$cy,$x2-$x1,$y2-$y1,0,360,$fg); } |
sub filled_arrow
{ my $self = shift;
my $gd = shift;
my $orientation = shift;
my ($x1,$y1,$x2,$y2) = @_;
my ($width) = $gd->getBounds;
my $indent = $y2-$y1 < $x2-$x1 ? $y2-$y1 : ($x2-$x1)/2;
return $self->filled_box($gd,@_)
if ($orientation == 0)
or ($x1 < 0 && $orientation < 0)
or ($x2 > $width && $orientation > 0)
or ($indent <= 0)
or ($x2 - $x1 < 3);
my $fg = $self->fgcolor;
if ($orientation >= 0) {
$gd->line($x1,$y1,$x2-$indent,$y1,$fg);
$gd->line($x2-$indent,$y1,$x2,($y2+$y1)/2,$fg); $gd->line($x2,($y2+$y1)/2,$x2-$indent,$y2,$fg); $gd->line($x2-$indent,$y2,$x1,$y2,$fg);
$gd->line($x1,$y2,$x1,$y1,$fg);
my $left = $self->panel->left > $x1 ? $self->panel->left : $x1;
$gd->fillToBorder($left+1,($y1+$y2)/2,$fg,$self->bgcolor); } else {
$gd->line($x1,($y2+$y1)/2,$x1+$indent,$y1,$fg); $gd->line($x1+$indent,$y1,$x2,$y1,$fg);
$gd->line($x2,$y2,$x1+$indent,$y2,$fg);
$gd->line($x1+$indent,$y2,$x1,($y1+$y2)/2,$fg); $gd->line($x2,$y1,$x2,$y2,$fg);
my $right = $self->panel->right < $x2 ? $self->panel->right : $x2;
$gd->fillToBorder($right-1,($y1+$y2)/2,$fg,$self->bgcolor); } } |
sub linewidth
{ shift->option('linewidth') || 1;} |
sub fill
{ my $self = shift;
my $gd = shift;
my ($x1,$y1,$x2,$y2) = @_;
if ( ($x2-$x1) >= 2 && ($y2-$y1) >= 2 ) {
$gd->fill($x1+1,$y1+1,$self->bgcolor);
}} |
sub set_pen
{ my $self = shift;
my ($linewidth,$color) = @_;
$linewidth ||= $self->linewidth;
$color ||= $self->fgcolor;
return $color unless $linewidth > 1;
$self->panel->set_pen($linewidth,$color); } |
sub draw_component
{ my $self = shift;
my $gd = shift;
my($x1,$y1,$x2,$y2) = $self->bounds(@_);
my $panel = $self->panel;
return unless $x2 >= $panel->left and $x1 <= $panel->right;
if ($self->option('strand_arrow')) {
$self->filled_arrow($gd,$self->feature->strand,
$x1, $y1,
$x2, $y2)
} else {
$self->filled_box($gd,
$x1, $y1,
$x2, $y2)
} } |
sub subseq
{ my $self = shift;
my $feature = shift;
return $self->_subseq($feature) unless ref $self;
return @{$self->{cached_subseq}{$feature}} if $self->{cached_subseq}{$feature};
my @ss = $self->_subseq($feature);
$self->{cached_subseq}{$feature} =\@ ss;
@ss;} |
sub _subseq
{ my $class = shift;
my $feature = shift;
return $feature->merged_segments if $feature->can('merged_segments');
return $feature->segments if $feature->can('segments');
my @split = eval { my $id = $feature->location->seq_id;
my @subs = $feature->location->sub_Location;
grep {$id eq $_->seq_id} @subs};
return @split if @split;
return $feature->sub_SeqFeature if $feature->can('sub_SeqFeature');
return;} |
sub keyglyph
{ my $self = shift;
my $feature = $self->make_key_feature;
my $factory = $self->factory->clone;
$factory->set_option(label => 1);
$factory->set_option(bump => 0);
$factory->set_option(connector => 'solid');
return $factory->make_glyph(0,$feature); } |
sub make_key_feature
{ my $self = shift;
my $scale = 1/$self->scale; # base pairs/pixel
my $offset = $self->panel->offset;
my $feature =
Bio::Graphics::Feature->new(-start =>0 * $scale +$offset,
-end =>80*$scale+$offset,
-name => $self->option('key'),
-strand => '+1');
return $feature; } |
sub all_callbacks
{ my $self = shift;
my $track_level = $self->option('all_callbacks');
return $track_level if defined $track_level;
return $self->panel->all_callbacks;} |
| default_factory | description | prev | next | Top |
sub default_factory
{ croak "no default factory implemented"; } |
General documentation
Bio::Graphics::Glyph objects are constructed automatically by an
Bio::Graphics::Glyph::Factory, and are not usually created by
end-developer code.
$glyph = Bio::Graphics::Glyph-E<gt>new(-feature=E<gt>$feature,-factory=>$factory)
Given a sequence feature, creates an
Bio::Graphics::Glyph object to
display it. The
-feature argument points to the Bio:SeqFeatureI
object to display, and
-factory indicates an
Bio::Graphics::Glyph::Factory object from which the glyph will fetch
all its run-time configuration information. Factories are created and
manipulated by the Bio::Graphics::Panel object.
A standard set of options are recognized. See
OPTIONS.
Once a glyph is created, it responds to a large number of methods. In
this section, these methods are grouped into related categories.
Retrieving glyph context:
$factory = $glyph->factory
Get the Bio::Graphics::Glyph::Factory associated with this object.
This cannot be changed once it is set.
$panel = $glyph->panel
Get the Bio::Graphics::Panel associated with this object. This cannot
be changed once it is set.
$feature = $glyph->feature
Get the sequence feature associated with this object. This cannot be
changed once it is set.
$feature = $glyph->add_feature(@features)
Add the list of features to the glyph, creating subparts. This is
most common done with the track glyph returned by
Ace::Graphics::Panel->add_track().
$feature = $glyph->add_group(@features)
This is similar to add_feature(), but the list of features is treated
as a group and can be configured as a set.
Retrieving glyph options:
$fgcolor = $glyph->fgcolor
$bgcolor = $glyph->bgcolor
$fontcolor = $glyph->fontcolor
$fontcolor = $glyph->font2color
$fillcolor = $glyph->fillcolor
These methods return the configured foreground, background, font,
alternative font, and fill colors for the glyph in the form of a
GD::Image color index.
$color = $glyph->tkcolor
This method returns a color to be used to flood-fill the entire glyph
before drawing (currently used by the "track" glyph).
$width = $glyph->width([$newwidth])
Return the width of the glyph, not including left or right padding.
This is ordinarily set internally based on the size of the feature and
the scale of the panel.
$width = $glyph->layout_width
Returns the width of the glyph including left and right padding.
$width = $glyph->height
Returns the height of the glyph, not including the top or bottom
padding. This is calculated from the "height" option and cannot be
changed.
$font = $glyph->font
Return the font for the glyph.
$option = $glyph->option($option)
Return the value of the indicated option.
$index = $glyph->color($color)
Given a symbolic or #RRGGBB-form color name, returns its GD index.
$level = $glyph->level
The "level" is the nesting level of the glyph.
Groups are level -1, top level glyphs are level 0,
subparts (e.g. exons) are level 1 and so forth.
Setting an option:
$glyph-E<gt>configure(-name=>$value)
You may change a glyph option after it is created using set_option().
This is most commonly used to configure track glyphs.
Retrieving information about the sequence:
$start = $glyph->start
$end = $glyph->end
These methods return the start and end of the glyph in base pair
units.
$offset = $glyph->offset
Returns the offset of the segment (the base pair at the far left of
the image).
$length = $glyph->length
Returns the length of the sequence segment.
Retrieving formatting information:
$top = $glyph->top
$left = $glyph->left
$bottom = $glyph->bottom
$right = $glyph->right
These methods return the top, left, bottom and right of the glyph in
pixel coordinates.
$height = $glyph->height
Returns the height of the glyph. This may be somewhat larger or
smaller than the height suggested by the GlyphFactory, depending on
the type of the glyph.
$scale = $glyph->scale
Get the scale for the glyph in pixels/bp.
$height = $glyph->labelheight
Return the height of the label, if any.
$label = $glyph->label
Return a human-readable label for the glyph.
These methods are called by Bio::Graphics::Track during the layout
process:
$glyph->move($dx,$dy)
Move the glyph in pixel coordinates by the indicated delta-x and
delta-y values.
($x1,$y1,$x2,$y2) = $glyph->box
Return the current position of the glyph.
These methods are intended to be overridden in subclasses:
$glyph->calculate_height
Calculate the height of the glyph.
$glyph->calculate_left
Calculate the left side of the glyph.
$glyph->calculate_right
Calculate the right side of the glyph.
$glyph->draw($gd,$left,$top)
Optionally offset the glyph by the indicated amount and draw it onto
the GD::Image object.
$glyph->draw_label($gd,$left,$top)
Draw the label for the glyph onto the provided GD::Image object,
optionally offsetting by the amounts indicated in $left and $right.
These methods are useful utility routines:
$pixels = $glyph->map_pt($bases);
Map the indicated base position, given in base pair units, into
pixels, using the current scale and glyph position.
$glyph->filled_box($gd,$x1,$y1,$x2,$y2)
Draw a filled rectangle with the appropriate foreground and fill
colors, and pen width onto the GD::Image object given by $gd, using
the provided rectangle coordinates.
$glyph->filled_oval($gd,$x1,$y1,$x2,$y2)
As above, but draws an oval inscribed on the rectangle.
The following options are standard among all Glyphs. See individual
glyph pages for more options.
Option Description Default
------ ----------- -------
-fgcolor Foreground color black
-outlinecolor Synonym for -fgcolor
-bgcolor Background color turquoise
-fillcolor Synonym for -bgcolor
-linewidth Line width 1
-height Height of glyph 10
-font Glyph font gdSmallFont
-connector Connector type 0 (false)
-connector_color
Connector color black
-strand_arrow Whether to indicate 0 (false)
strandedness
-label Whether to draw a label 0 (false)
-description Whether to draw a description 0 (false)
For glyphs that consist of multiple segments, the -connector option
controls what's drawn between the segments. The default is 0 (no
connector). Options include "hat", an upward-angling conector,
"solid", a straight horizontal connector, and "dashed", for a
horizontal dashed line. The -connector_color option controls the
color of the connector, if any.
The label is printed above the glyph. You may pass an anonymous
subroutine to -label, in which case the subroutine will be invoked
with the feature as its single argument. The subroutine must return a
string to render as the label. Otherwise, you may return the number
"1", in which case the feature's info(), seqname() and primary_tag()
methods will be called (in that order) until a suitable name is found.
The description is printed below the glyph. You may pass an anonymous
subroutine to -label, in which case the subroutine will be invoked
with the feature as its single argument. The subroutine must return a
string to render as the label. Otherwise, you may return the number
"1", in which case the feature's source_tag() method will be invoked.
In the case of ACEDB Ace::Sequence feature objects, the feature's
info(), Brief_identification() and Locus() methods will be called to
create a suitable description.
The -strand_arrow option, if true, requests that the glyph indicate
which strand it is on, usually by drawing an arrowhead. Not all
glyphs can respond appropriately to this request.
| SUBCLASSING Bio::Graphics::Glyph | Top |
By convention, subclasses are all lower-case. Begin each subclass
with a preamble like this one:
package Bio::Graphics::Glyph::crossbox;
use strict;
use vars '@ISA';
@ISA = 'Bio::Graphics::Glyph';
Then override the methods you need to. Typically, just the draw()
method will need to be overridden. However, if you need additional
room in the glyph, you may override calculate_height(),
calculate_left() and calculate_right(). Do not directly override
height(), left() and right(), as their purpose is to cache the values
returned by their calculating cousins in order to avoid time-consuming
recalculation.
A simple draw() method looks like this:
sub draw {
my $self = shift;
$self->SUPER::draw(@_);
my $gd = shift;
# and draw a cross through the box
my ($x1,$y1,$x2,$y2) = $self->calculate_boundaries(@_);
my $fg = $self->fgcolor;
$gd->line($x1,$y1,$x2,$y2,$fg);
$gd->line($x1,$y2,$x2,$y1,$fg);
}
This subclass draws a simple box with two lines criss-crossed through
it. We first call our inherited draw() method to generate the filled
box and label. We then call calculate_boundaries() to return the
coordinates of the glyph, disregarding any extra space taken by
labels. We call fgcolor() to return the desired foreground color, and
then call $gd->line() twice to generate the criss-cross.
For more complex draw() methods, see Bio::Graphics::Glyph::transcript
and Bio::Graphics::Glyph::segments.
Please report them.
Bio::DB::GFF::Feature,
Ace::Sequence,
Bio::Graphics::Panel,
Bio::Graphics::Track,
Bio::Graphics::Glyph::anchored_arrow,
Bio::Graphics::Glyph::arrow,
Bio::Graphics::Glyph::box,
Bio::Graphics::Glyph::dna,
Bio::Graphics::Glyph::graded_segments,
Bio::Graphics::Glyph::primers,
Bio::Graphics::Glyph::segments,
Bio::Graphics::Glyph::toomany,
Bio::Graphics::Glyph::transcript,
Bio::Graphics::Glyph::transcript2,
Bio::Graphics::Glyph::wormbase_transcript
Lincoln Stein <lstein@cshl.org>
Copyright (c) 2001 Cold Spring Harbor Laboratory
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself. See DISCLAIMER.txt for
disclaimers of warranty.