| 0 | 1 package Bio::Graphics::Glyph::dna; | 
|  | 2 | 
|  | 3 use strict; | 
|  | 4 use Bio::Graphics::Glyph::generic; | 
|  | 5 use vars '@ISA'; | 
|  | 6 @ISA = qw(Bio::Graphics::Glyph::generic); | 
|  | 7 | 
|  | 8 my %complement = (g=>'c',a=>'t',t=>'a',c=>'g',n=>'n', | 
|  | 9 		  G=>'C',A=>'T',T=>'A',C=>'G',N=>'N'); | 
|  | 10 | 
|  | 11 # turn off description | 
|  | 12 sub description { 0 } | 
|  | 13 | 
|  | 14 # turn off label | 
|  | 15 # sub label { 1 } | 
|  | 16 | 
|  | 17 sub height { | 
|  | 18   my $self = shift; | 
|  | 19   my $font = $self->font; | 
|  | 20   return $self->dna_fits ? 2*$font->height | 
|  | 21        : $self->do_gc    ? $self->SUPER::height | 
|  | 22        : 0; | 
|  | 23 } | 
|  | 24 | 
|  | 25 sub do_gc { | 
|  | 26   my $self = shift; | 
|  | 27   my $do_gc = $self->option('do_gc'); | 
|  | 28   return  if defined($do_gc) && !$do_gc; | 
|  | 29   return  1; | 
|  | 30 } | 
|  | 31 | 
|  | 32 sub draw_component { | 
|  | 33   my $self = shift; | 
|  | 34   my $gd = shift; | 
|  | 35   my ($x1,$y1,$x2,$y2) = $self->bounds(@_); | 
|  | 36 | 
|  | 37   my $dna        = eval { $self->feature->seq }; | 
|  | 38   $dna           = $dna->seq if ref($dna) and $dna->can('seq'); # to catch Bio::PrimarySeqI objects | 
|  | 39   $dna or return; | 
|  | 40 | 
|  | 41   # workaround for my misreading of interface -- LS | 
|  | 42   $dna = $dna->seq if ref($dna) && $dna->can('seq'); | 
|  | 43 | 
|  | 44   if ($self->dna_fits) { | 
|  | 45     $self->draw_dna($gd,$dna,$x1,$y1,$x2,$y2); | 
|  | 46   } elsif ($self->do_gc) { | 
|  | 47     $self->draw_gc_content($gd,$dna,$x1,$y1,$x2,$y2); | 
|  | 48   } | 
|  | 49 } | 
|  | 50 | 
|  | 51 sub draw_dna { | 
|  | 52   my $self = shift; | 
|  | 53 | 
|  | 54   my ($gd,$dna,$x1,$y1,$x2,$y2) = @_; | 
|  | 55   my $pixels_per_base = $self->scale; | 
|  | 56 | 
|  | 57   my $feature = $self->feature; | 
|  | 58 | 
|  | 59   my $strand = $feature->strand; | 
|  | 60   $strand *= -1 if $self->{flip}; | 
|  | 61 | 
|  | 62   my @bases = split '',$strand >= 0 ? $dna : $self->reversec($dna); | 
|  | 63   my $color = $self->fgcolor; | 
|  | 64   my $font  = $self->font; | 
|  | 65   my $lineheight = $font->height; | 
|  | 66   $y1 -= $lineheight/2 - 3; | 
|  | 67   my $strands = $self->option('strand') || 'auto'; | 
|  | 68 | 
|  | 69   my ($forward,$reverse); | 
|  | 70   if ($strands eq 'auto') { | 
|  | 71     $forward = $feature->strand >= 0; | 
|  | 72     $reverse = $feature->strand <= 0; | 
|  | 73   } elsif ($strands eq 'both') { | 
|  | 74     $forward = $reverse = 1; | 
|  | 75   } elsif ($strands eq 'reverse') { | 
|  | 76     $reverse = 1; | 
|  | 77   } else { | 
|  | 78     $forward = 1; | 
|  | 79   } | 
|  | 80 | 
|  | 81   my $start  = $self->map_no_trunc($feature->start); | 
|  | 82   my $end    = $self->map_no_trunc($feature->end); | 
|  | 83 | 
|  | 84   my $offset  = int(($x1-$start-1)/$pixels_per_base); | 
|  | 85 | 
|  | 86   for (my $i=$offset;$i<@bases;$i++) { | 
|  | 87     my $x = $start + $i * $pixels_per_base; | 
|  | 88     next if $x+1 < $x1; | 
|  | 89     last if $x > $x2; | 
|  | 90     $gd->char($font,$x+1,$y1,$bases[$i],$color)                                      if $forward; | 
|  | 91     $gd->char($font,$x+1,$y1+($forward ? $lineheight:0),$complement{$bases[$i]}||$bases[$i],$color) if $reverse; | 
|  | 92   } | 
|  | 93 | 
|  | 94 } | 
|  | 95 | 
|  | 96 sub draw_gc_content { | 
|  | 97   my $self     = shift; | 
|  | 98   my $gd       = shift; | 
|  | 99   my $dna = shift; | 
|  | 100   my ($x1,$y1,$x2,$y2) = @_; | 
|  | 101 | 
|  | 102   my $bin_size = length($dna) / ($self->option('gc_bins') || 100); | 
|  | 103   $bin_size = 100 if $bin_size < 100; | 
|  | 104 | 
|  | 105   my @bins; | 
|  | 106   for (my $i = 0; $i < length($dna) - $bin_size; $i+= $bin_size) { | 
|  | 107     my $subseq  = substr($dna,$i,$bin_size); | 
|  | 108     my $gc      = $subseq =~ tr/gcGC/gcGC/; | 
|  | 109     my $content = $gc/$bin_size; | 
|  | 110     push @bins,$content; | 
|  | 111   } | 
|  | 112   push @bins,0.5 unless @bins;  # avoid div by zero | 
|  | 113   my $bin_width  = ($x2-$x1)/@bins; | 
|  | 114   my $bin_height = $y2-$y1; | 
|  | 115   my $fgcolor    = $self->fgcolor; | 
|  | 116   my $bgcolor    = $self->factory->translate_color($self->panel->gridcolor); | 
|  | 117   my $axiscolor  = $self->color('axis_color') || $fgcolor; | 
|  | 118 | 
|  | 119   $gd->line($x1,  $y1,        $x1,  $y2,        $axiscolor); | 
|  | 120   $gd->line($x2-2,$y1,        $x2-2,$y2,        $axiscolor); | 
|  | 121   $gd->line($x1,  $y1,        $x1+3,$y1,        $axiscolor); | 
|  | 122   $gd->line($x1,  $y2,        $x1+3,$y2,        $axiscolor); | 
|  | 123   $gd->line($x1,  ($y2+$y1)/2,$x1+3,($y2+$y1)/2,$axiscolor); | 
|  | 124   $gd->line($x2-4,$y1,        $x2-1, $y1,       $axiscolor); | 
|  | 125   $gd->line($x2-4,$y2,        $x2-1, $y2,       $axiscolor); | 
|  | 126   $gd->line($x2-4,($y2+$y1)/2,$x2-1,($y2+$y1)/2,$axiscolor); | 
|  | 127   $gd->line($x1+5,$y2,        $x2-5,$y2,        $bgcolor); | 
|  | 128   $gd->line($x1+5,($y2+$y1)/2,$x2-5,($y2+$y1)/2,$bgcolor); | 
|  | 129   $gd->line($x1+5,$y1,        $x2-5,$y1,        $bgcolor); | 
|  | 130   $gd->string($self->font,$x1+5,$y1,'% gc',$axiscolor) if $bin_height > $self->font->height*2; | 
|  | 131 | 
|  | 132   for (my $i = 0; $i < @bins; $i++) { | 
|  | 133     my $bin_start  = $x1+$i*$bin_width; | 
|  | 134     my $bin_stop   = $bin_start + $bin_width; | 
|  | 135     my $y          = $y2 - ($bin_height*$bins[$i]); | 
|  | 136     $gd->line($bin_start,$y,$bin_stop,$y,$fgcolor); | 
|  | 137     $gd->line($bin_stop,$y,$bin_stop,$y2 - ($bin_height*$bins[$i+1]),$fgcolor) | 
|  | 138       if $i < @bins-1; | 
|  | 139   } | 
|  | 140 } | 
|  | 141 | 
|  | 142 sub make_key_feature { | 
|  | 143   my $self = shift; | 
|  | 144   my @gatc = qw(g a t c); | 
|  | 145   my $offset = $self->panel->offset; | 
|  | 146   my $scale = 1/$self->scale;  # base pairs/pixel | 
|  | 147 | 
|  | 148   my $start = $offset+1; | 
|  | 149   my $stop  = $offset+100*$scale; | 
|  | 150   my $feature = | 
|  | 151     Bio::Graphics::Feature->new(-start=> $start, | 
|  | 152 				-stop => $stop, | 
|  | 153 				-seq  => join('',map{$gatc[rand 4]} (1..500)), | 
|  | 154 				-name => $self->option('key'), | 
|  | 155 				-strand => '+1', | 
|  | 156 			       ); | 
|  | 157   $feature; | 
|  | 158 } | 
|  | 159 | 
|  | 160 1; | 
|  | 161 | 
|  | 162 __END__ | 
|  | 163 | 
|  | 164 =head1 NAME | 
|  | 165 | 
|  | 166 Bio::Graphics::Glyph::dna - The "dna" glyph | 
|  | 167 | 
|  | 168 =head1 SYNOPSIS | 
|  | 169 | 
|  | 170   See L<Bio::Graphics::Panel> and L<Bio::Graphics::Glyph>. | 
|  | 171 | 
|  | 172 =head1 DESCRIPTION | 
|  | 173 | 
|  | 174 This glyph draws DNA sequences.  At high magnifications, this glyph | 
|  | 175 will draw the actual base pairs of the sequence (both strands).  At | 
|  | 176 low magnifications, the glyph will plot the GC content. | 
|  | 177 | 
|  | 178 For this glyph to work, the feature must return a DNA sequence string | 
|  | 179 in response to the dna() method. | 
|  | 180 | 
|  | 181 =head2 OPTIONS | 
|  | 182 | 
|  | 183 The following options are standard among all Glyphs.  See | 
|  | 184 L<Bio::Graphics::Glyph> for a full explanation. | 
|  | 185 | 
|  | 186   Option      Description                      Default | 
|  | 187   ------      -----------                      ------- | 
|  | 188 | 
|  | 189   -fgcolor      Foreground color	       black | 
|  | 190 | 
|  | 191   -outlinecolor	Synonym for -fgcolor | 
|  | 192 | 
|  | 193   -bgcolor      Background color               turquoise | 
|  | 194 | 
|  | 195   -fillcolor    Synonym for -bgcolor | 
|  | 196 | 
|  | 197   -linewidth    Line width                     1 | 
|  | 198 | 
|  | 199   -height       Height of glyph		       10 | 
|  | 200 | 
|  | 201   -font         Glyph font		       gdSmallFont | 
|  | 202 | 
|  | 203   -connector    Connector type                 0 (false) | 
|  | 204 | 
|  | 205   -connector_color | 
|  | 206                 Connector color                black | 
|  | 207 | 
|  | 208   -label        Whether to draw a label	       0 (false) | 
|  | 209 | 
|  | 210   -description  Whether to draw a description  0 (false) | 
|  | 211 | 
|  | 212 In addition to the common options, the following glyph-specific | 
|  | 213 options are recognized: | 
|  | 214 | 
|  | 215   Option      Description               Default | 
|  | 216   ------      -----------               ------- | 
|  | 217 | 
|  | 218   -do_gc      Whether to draw the GC      true | 
|  | 219               graph at low mags | 
|  | 220 | 
|  | 221   -gc_bins    Fixed number of intervals   100 | 
|  | 222               to sample across the | 
|  | 223               panel. | 
|  | 224 | 
|  | 225   -axis_color Color of the vertical axes  fgcolor | 
|  | 226               in the GC content graph | 
|  | 227 | 
|  | 228   -strand      Show both forward and      auto | 
|  | 229               reverse strand, one of | 
|  | 230               "forward", "reverse", | 
|  | 231               "both" or "auto". | 
|  | 232               In "auto" mode, | 
|  | 233               +1 strand features will | 
|  | 234               show the plus strand | 
|  | 235               -1 strand features will | 
|  | 236               show the reverse complement | 
|  | 237               and strandless features will | 
|  | 238               show both | 
|  | 239 | 
|  | 240 =head1 BUGS | 
|  | 241 | 
|  | 242 Please report them. | 
|  | 243 | 
|  | 244 =head1 SEE ALSO | 
|  | 245 | 
|  | 246 L<Bio::Graphics::Panel>, | 
|  | 247 L<Bio::Graphics::Glyph>, | 
|  | 248 L<Bio::Graphics::Glyph::arrow>, | 
|  | 249 L<Bio::Graphics::Glyph::cds>, | 
|  | 250 L<Bio::Graphics::Glyph::crossbox>, | 
|  | 251 L<Bio::Graphics::Glyph::diamond>, | 
|  | 252 L<Bio::Graphics::Glyph::dna>, | 
|  | 253 L<Bio::Graphics::Glyph::dot>, | 
|  | 254 L<Bio::Graphics::Glyph::ellipse>, | 
|  | 255 L<Bio::Graphics::Glyph::extending_arrow>, | 
|  | 256 L<Bio::Graphics::Glyph::generic>, | 
|  | 257 L<Bio::Graphics::Glyph::graded_segments>, | 
|  | 258 L<Bio::Graphics::Glyph::heterogeneous_segments>, | 
|  | 259 L<Bio::Graphics::Glyph::line>, | 
|  | 260 L<Bio::Graphics::Glyph::pinsertion>, | 
|  | 261 L<Bio::Graphics::Glyph::primers>, | 
|  | 262 L<Bio::Graphics::Glyph::rndrect>, | 
|  | 263 L<Bio::Graphics::Glyph::segments>, | 
|  | 264 L<Bio::Graphics::Glyph::ruler_arrow>, | 
|  | 265 L<Bio::Graphics::Glyph::toomany>, | 
|  | 266 L<Bio::Graphics::Glyph::transcript>, | 
|  | 267 L<Bio::Graphics::Glyph::transcript2>, | 
|  | 268 L<Bio::Graphics::Glyph::translation>, | 
|  | 269 L<Bio::Graphics::Glyph::triangle>, | 
|  | 270 L<Bio::DB::GFF>, | 
|  | 271 L<Bio::SeqI>, | 
|  | 272 L<Bio::SeqFeatureI>, | 
|  | 273 L<Bio::Das>, | 
|  | 274 L<GD> | 
|  | 275 | 
|  | 276 =head1 AUTHOR | 
|  | 277 | 
|  | 278 Lincoln Stein E<lt>lstein@cshl.orgE<gt>. | 
|  | 279 | 
|  | 280 Copyright (c) 2001 Cold Spring Harbor Laboratory | 
|  | 281 | 
|  | 282 This library is free software; you can redistribute it and/or modify | 
|  | 283 it under the same terms as Perl itself.  See DISCLAIMER.txt for | 
|  | 284 disclaimers of warranty. | 
|  | 285 | 
|  | 286 =cut |