diff variant_effect_predictor/Bio/Graphics/Glyph/xyplot.pm @ 0:1f6dce3d34e0

Uploaded
author mahtabm
date Thu, 11 Apr 2013 02:01:53 -0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/variant_effect_predictor/Bio/Graphics/Glyph/xyplot.pm	Thu Apr 11 02:01:53 2013 -0400
@@ -0,0 +1,453 @@
+package Bio::Graphics::Glyph::xyplot;
+
+use strict;
+use Bio::Graphics::Glyph::segments;
+use vars '@ISA';
+use GD 'gdTinyFont';
+
+@ISA = 'Bio::Graphics::Glyph::segments';
+
+use constant DEFAULT_POINT_RADIUS=>1;
+
+my %SYMBOLS = (
+	       triangle => \&draw_triangle,
+	       square   => \&draw_square,
+	       disc     => \&draw_disc,
+	       point    => \&draw_point,
+	      );
+
+sub point_radius {
+  shift->option('point_radius') || DEFAULT_POINT_RADIUS;
+}
+
+sub pad_top { 0 }
+
+sub draw {
+  my $self = shift;
+  my ($gd,$dx,$dy) = @_;
+  my ($left,$top,$right,$bottom) = $self->calculate_boundaries($dx,$dy);
+
+  my @parts = $self->parts;
+  return $self->SUPER::draw(@_) unless @parts > 0;
+
+  # figure out the scale and such like
+  my $max_score = $self->option('max_score');
+  my $min_score = $self->option('min_score');
+
+  unless (defined $max_score && defined $min_score) {
+    my $first = $parts[0];
+    $max_score = $min_score = eval { $first->feature->score} || 0;
+    for my $part (@parts) {
+      my $s = eval { $part->feature->score };
+      next unless defined $s;
+      $max_score = $s if $s > $max_score;
+      $min_score = $s if $s < $min_score;
+    }
+  }
+
+  # if a scale is called for, then we adjust the max and min to be even
+  # multiples of a power of 10.
+  if ($self->option('scale')) {
+    $max_score = max10($max_score);
+    $min_score = min10($min_score);
+  }
+
+  my $height = $self->option('height');
+  my $scale  = $max_score > $min_score ? $height/($max_score-$min_score)
+                                       : 1;
+  my $x = $dx;
+  my $y = $dy + $self->top + $self->pad_top;
+
+  # now seed all the parts with the information they need to draw their positions
+  foreach (@parts) {
+    my $s = eval {$_->feature->score};
+    next unless defined $s;
+    my $position      = ($s-$min_score) * $scale;
+    $_->{_y_position} = $bottom - $position;
+  }
+
+  my $type = $self->option('graph_type');
+  $self->_draw_histogram($gd,$x,$y)  if $type eq 'histogram';
+  $self->_draw_boxes($gd,$x,$y)      if $type eq 'boxes';
+  $self->_draw_line ($gd,$x,$y)      if $type eq 'line'
+                                       or $type eq 'linepoints';
+  $self->_draw_points($gd,$x,$y)     if $type eq 'points'
+                                       or $type eq 'linepoints';
+
+  $self->_draw_scale($gd,$scale,$min_score,$max_score,$dx,$dy)      if $self->option('scale');
+}
+
+sub log10 { log(shift)/log(10) }
+sub max10 {
+  my $a = shift;
+  $a = 1 if $a <= 0;
+  my $l=int(log10($a)); 
+  $l = 10**$l; 
+  my $r = $a/$l; 
+  return $r*$l if int($r) == $r;
+  return $l*int(($a+$l)/$l);
+}
+sub min10 {
+  my $a = shift;
+  $a = 1 if $a <= 0;
+  my $l=int(log10($a));
+  $l = 10**$l; 
+  my $r = $a/$l; 
+  return $r*$l if int($r) == $r;
+  return $l*int($a/$l);
+}
+
+sub _draw_histogram {
+  my $self = shift;
+  my ($gd,$left,$top) = @_;
+
+  my @parts  = $self->parts;
+  my $fgcolor = $self->fgcolor;
+
+  # draw each of the component lines of the histogram surface
+  for (my $i = 0; $i < @parts; $i++) {
+    my $part = $parts[$i];
+    my $next = $parts[$i+1];
+    my ($x1,$y1,$x2,$y2) = $part->calculate_boundaries($left,$top);
+    $gd->line($x1,$part->{_y_position},$x2,$part->{_y_position},$fgcolor);
+    next unless $next;
+    my ($x3,$y3,$x4,$y4) = $next->calculate_boundaries($left,$top);
+    if ($x2 == $x3) {# connect vertically to next level
+      $gd->line($x2,$part->{_y_position},$x2,$next->{_y_position},$fgcolor); 
+    } else {
+      $gd->line($x2,$part->{_y_position},$x2,$y2,$fgcolor); # to bottom
+      $gd->line($x2,$y2,$x3,$y2,$fgcolor);                        # to right
+      $gd->line($x3,$y4,$x3,$next->{_y_position},$fgcolor);   # up
+    }
+  }
+
+  # end points: from bottom to first
+  my ($x1,$y1,$x2,$y2) = $parts[0]->calculate_boundaries($left,$top);
+  $gd->line($x1,$y2,$x1,$parts[0]->{_y_position},$fgcolor);
+  # from last to bottom
+  my ($x3,$y3,$x4,$y4) = $parts[-1]->calculate_boundaries($left,$top);
+  $gd->line($x4,$parts[-1]->{_y_position},$x4,$y4,$fgcolor);
+
+  # from left to right  -- don't like this
+  # $gd->line($x1,$y2,$x4,$y4,$fgcolor);
+
+  # That's it.  Not too hard.
+}
+
+sub _draw_boxes {
+  my $self = shift;
+  my ($gd,$left,$top) = @_;
+
+  my @parts  = $self->parts;
+  my $fgcolor = $self->fgcolor;
+  my $bgcolor = $self->bgcolor;
+  my $height  = $self->height;
+
+  # draw each of the component lines of the histogram surface
+  for (my $i = 0; $i < @parts; $i++) {
+    my $part = $parts[$i];
+    my $next = $parts[$i+1];
+    my ($x1,$y1,$x2,$y2) = $part->calculate_boundaries($left,$top);
+    $self->filled_box($gd,$x1,$part->{_y_position},$x2,$y2,$bgcolor,$fgcolor);
+    next unless $next;
+    my ($x3,$y3,$x4,$y4) = $next->calculate_boundaries($left,$top);
+    $gd->line($x2,$y2,$x3,$y4,$fgcolor) if $x2 < $x3;
+  }
+
+  # That's it.
+}
+
+sub _draw_line {
+  my $self = shift;
+  my ($gd,$left,$top) = @_;
+
+  my @parts  = $self->parts;
+  my $fgcolor = $self->fgcolor;
+  my $bgcolor = $self->bgcolor;
+
+  # connect to center positions of each interval
+  my $first_part = shift @parts;
+  my ($x1,$y1,$x2,$y2) = $first_part->calculate_boundaries($left,$top);
+  my $current_x = ($x1+$x2)/2;
+  my $current_y = $first_part->{_y_position};
+
+  for my $part (@parts) {
+    my ($x1,$y1,$x2,$y2) = $part->calculate_boundaries($left,$top);
+    my $next_x = ($x1+$x2)/2;
+    my $next_y = $part->{_y_position};
+    $gd->line($current_x,$current_y,$next_x,$next_y,$fgcolor);
+    ($current_x,$current_y) = ($next_x,$next_y);
+  }
+
+}
+
+sub _draw_points {
+  my $self = shift;
+  my ($gd,$left,$top) = @_;
+  my $symbol_name = $self->option('point_symbol') || 'point';
+  my $symbol_ref  = $SYMBOLS{$symbol_name};
+
+  my @parts   = $self->parts;
+  my $bgcolor = $self->bgcolor;
+  my $pr      = $self->point_radius;
+
+  for my $part (@parts) {
+    my ($x1,$y1,$x2,$y2) = $part->calculate_boundaries($left,$top);
+    my $x = ($x1+$x2)/2;
+    my $y = $part->{_y_position};
+    $symbol_ref->($gd,$x,$y,$pr,$bgcolor);
+  }
+}
+
+sub _draw_scale {
+  my $self = shift;
+  my ($gd,$scale,$min,$max,$dx,$dy) = @_;
+  my ($x1,$y1,$x2,$y2) = $self->calculate_boundaries($dx,$dy);
+
+  my $side = $self->option('scale');
+  return if $side eq 'none';
+  $side   ||= 'both';
+
+  my $fg    = $self->fgcolor;
+  my $half  = ($y1+$y2)/2;
+
+  $gd->line($x1+1,$y1,$x1+1,$y2,$fg) if $side eq 'left'  || $side eq 'both';
+  $gd->line($x2-2,$y1,$x2-2,$y2,$fg) if $side eq 'right' || $side eq 'both';
+
+  for ([$y1,$max],[$half,int(($max-$min)/2+0.5)]) {
+    $gd->line($x1,$_->[0],$x1+3,$_->[0],$fg) if $side eq 'left'  || $side eq 'both';
+    $gd->line($x2-4,$_->[0],$x2,$_->[0],$fg) if $side eq 'right' || $side eq 'both';
+    if ($side eq 'left' or $side eq 'both') {
+      $gd->string(gdTinyFont,
+		  $x1 + 5,$_->[0]-(gdTinyFont->height/3),
+		  $_->[1],
+		  $fg);
+    }
+    if ($side eq 'right' or $side eq 'both') {
+      $gd->string(gdTinyFont,
+		  $x2-5 - (length($_->[1])*gdTinyFont->width),$_->[0]-(gdTinyFont->height/3),
+		  $_->[1],
+		  $fg);
+    }
+  }
+}
+
+# we are unbumpable!
+sub bump {
+  return 0;
+}
+
+sub connector {
+  my $self = shift;
+  my $type = $self->option('graph_type');
+  return 1 if $type eq 'line' or $type eq 'linepoints';
+}
+
+sub height {
+  my $self = shift;
+  return $self->option('graph_height') || $self->SUPER::height;
+}
+
+sub draw_triangle {
+  my ($gd,$x,$y,$pr,$color) = @_;
+  my ($vx1,$vy1) = ($x-$pr,$y+$pr);
+  my ($vx2,$vy2) = ($x,  $y-$pr);
+  my ($vx3,$vy3) = ($x+$pr,$y+$pr);
+  $gd->line($vx1,$vy1,$vx2,$vy2,$color);
+  $gd->line($vx2,$vy2,$vx3,$vy3,$color);
+  $gd->line($vx3,$vy3,$vx1,$vy1,$color);
+}
+sub draw_square {
+  my ($gd,$x,$y,$pr,$color) = @_;
+  $gd->line($x-$pr,$y-$pr,$x+$pr,$y-$pr,$color);
+  $gd->line($x+$pr,$y-$pr,$x+$pr,$y+$pr,$color);
+  $gd->line($x+$pr,$y+$pr,$x-$pr,$y+$pr,$color);
+  $gd->line($x-$pr,$y+$pr,$x-$pr,$y-$pr,$color);
+}
+sub draw_disc {
+  my ($gd,$x,$y,$pr,$color) = @_;
+  $gd->arc($x,$y,$pr,$pr,0,360,$color);
+}
+sub draw_point {
+  my ($gd,$x,$y,$pr,$color) = @_;
+  $gd->setPixel($x,$y,$color);
+}
+
+sub _subseq {
+  my $class   = shift;
+  my $feature = shift;
+  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 $scale = 1/$self->scale;  # base pairs/pixel
+
+  my $feature =
+    Bio::Graphics::Feature->new(
+				-segments=>[ [ 0*$scale,9*$scale],
+					     [ 10*$scale,19*$scale],
+					     [ 20*$scale, 29*$scale]
+					   ],
+				-name => 'foo bar',
+				-strand => '+1');
+  ($feature->segments)[0]->score(10);
+  ($feature->segments)[1]->score(50);
+  ($feature->segments)[2]->score(25);
+  my $factory = $self->factory->clone;
+  $factory->set_option(label => 1);
+  $factory->set_option(bump  => 0);
+  $factory->set_option(connector  => 'solid');
+  my $glyph = $factory->make_glyph(0,$feature);
+  return $glyph;
+}
+
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bio::Graphics::Glyph::xyplot - The xyplot glyph
+
+=head1 SYNOPSIS
+
+  See L<Bio::Graphics::Panel> and L<Bio::Graphics::Glyph>.
+
+=head1 DESCRIPTION
+
+This glyph is used for drawing features that have a position on the
+genome and a numeric value.  It can be used to represent gene
+prediction scores, motif-calling scores, percent similarity,
+microarray intensities, or other features that require a line plot.
+
+The X axis represents the position on the genome, as per all other
+glyphs.  The Y axis represents the score.  Options allow you to set
+the height of the glyph, the maximum and minimum scores, the color of
+the line and axis, and the symbol to draw.
+
+The plot is designed to work on a single feature group that contains
+subfeatures.  It is the subfeatures that carry the score
+information. The best way to arrange for this is to create an
+aggregator for the feature.  We'll take as an example a histogram of
+repeat density in which interval are spaced every megabase and the
+score indicates the number of repeats in the interval; we'll assume
+that the database has been loaded in in such a way that each interval
+is a distinct feature with the method name "density" and the source
+name "repeat".  Furthermore, all the repeat features are grouped
+together into a single group (the name of the group is irrelevant).
+If you are using Bio::DB::GFF and Bio::Graphics directly, the sequence
+of events would look like this:
+
+  my $agg = Bio::DB::GFF::Aggregator->new(-method    => 'repeat_density',
+                                          -sub_parts => 'density:repeat');
+  my $db  = Bio::DB::GFF->new(-dsn=>'my_database',
+                              -aggregators => $agg);
+  my $segment  = $db->segment('Chr1');
+  my @features = $segment->features('repeat_density');
+
+  my $panel = Bio::Graphics::Panel->new;
+  $panel->add_track(\@features,
+                    -glyph => 'xyplot');
+
+If you are using Generic Genome Browser, you will add this to the
+configuration file:
+
+  aggregators = repeat_density{density:repeat}
+                clone alignment etc
+
+=head2 OPTIONS
+
+The following options are standard among all Glyphs.  See
+L<Bio::Graphics::Glyph> for a full explanation.
+
+  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
+
+  -label        Whether to draw a label	       0 (false)
+
+  -description  Whether to draw a description  0 (false)
+
+In addition, the alignment glyph recognizes the following
+glyph-specific options:
+
+  Option         Description                  Default
+  ------         -----------                  -------
+
+  -max_score   Maximum value of the	      Calculated
+               feature's "score" attribute
+
+  -min_score   Minimum value of the           Calculated
+               feature's "score" attribute
+
+  -graph_type  Type of graph to generate.     Histogram
+               Options are: "histogram",
+               "boxes", "line", "points",
+               or "linepoints".
+
+  -point_symbol Symbol to use. Options are    none
+                "triangle", "square", "disc",
+                "point", and "none".
+
+  -point_radius Radius of the symbol, in      1
+                pixels
+
+  -scale        Position where the Y axis     none
+                scale is drawn if any.
+                It should be one of
+                "left", "right" or "none"
+
+  -graph_height Specify height of the graph   Same as the
+                                              "height" option.
+
+=head1 BUGS
+
+Please report them.
+
+=head1 SEE ALSO
+
+L<Bio::Graphics::Panel>,
+L<Bio::Graphics::Track>,
+L<Bio::Graphics::Glyph::transcript2>,
+L<Bio::Graphics::Glyph::anchored_arrow>,
+L<Bio::Graphics::Glyph::arrow>,
+L<Bio::Graphics::Glyph::box>,
+L<Bio::Graphics::Glyph::primers>,
+L<Bio::Graphics::Glyph::segments>,
+L<Bio::Graphics::Glyph::toomany>,
+L<Bio::Graphics::Glyph::transcript>,
+
+=head1 AUTHOR
+
+Lincoln Stein E<lt>lstein@cshl.orgE<gt>
+
+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.
+
+=cut
+