comparison variant_effect_predictor/Bio/Graphics/Glyph/arrow.pm @ 0:1f6dce3d34e0

Uploaded
author mahtabm
date Thu, 11 Apr 2013 02:01:53 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1f6dce3d34e0
1 package Bio::Graphics::Glyph::arrow;
2 # package to use for drawing an arrow
3
4 use strict;
5 use vars '@ISA';
6 use Bio::Graphics::Glyph::generic;
7 @ISA = 'Bio::Graphics::Glyph::generic';
8
9 my %UNITS = (n => 1e-12,
10 n => 1e-9,
11 u => 1e-6,
12 m => 0.001,
13 c => 0.01,
14 k => 1000,
15 M => 1_000_000,
16 G => 1_000_000_000);
17
18 sub pad_bottom {
19 my $self = shift;
20 my $val = $self->SUPER::pad_bottom(@_);
21 $val += $self->font->height if $self->option('tick');
22 $val;
23 }
24
25 # override draw method
26 sub draw {
27 my $self = shift;
28 my $parallel = $self->option('parallel');
29 $parallel = 1 unless defined $parallel;
30 $self->draw_parallel(@_) if $parallel;
31 $self->draw_perpendicular(@_) unless $parallel;
32 }
33
34 sub draw_perpendicular {
35 my $self = shift;
36 my $gd = shift;
37 my ($dx,$dy) = @_;
38 my ($x1,$y1,$x2,$y2) = $self->bounds(@_);
39
40 my $ne = $self->option('northeast');
41 my $sw = $self->option('southwest');
42 $ne = $sw = 1 unless defined($ne) || defined($sw);
43
44 # draw a perpendicular arrow at position indicated by $x1
45 my $fg = $self->set_pen;
46 my $a2 = ($y2-$y1)/4;
47
48 my @positions = $x1 == $x2 ? ($x1) : ($x1,$x2);
49 for my $x (@positions) {
50 if ($ne) {
51 $gd->line($x,$y1,$x,$y2,$fg);
52 $gd->line($x-$a2,$y1+$a2,$x,$y1,$fg);
53 $gd->line($x+$a2,$y1+$a2,$x,$y1,$fg);
54 }
55 if ($sw) {
56 $gd->line($x,$y1,$x,$y2,$fg);
57 $gd->line($x-$a2,$y2-$a2,$x,$y2,$fg);
58 $gd->line($x+$a2,$y2-$a2,$x,$y2,$fg);
59 }
60 }
61
62 # add a label if requested
63 $self->draw_label($gd,$dx,$dy) if $self->option('label'); # this draws the label aligned to the left
64 }
65
66 sub draw_parallel {
67 my $self = shift;
68 my $gd = shift;
69 my ($dx,$dy) = @_;
70 my ($x1,$y1,$x2,$y2) = $self->bounds(@_);
71
72 my $fg = $self->set_pen;
73 my $a2 = ($self->height)/2;
74 my $center = $y1+$a2;
75
76 my $trunc_left = $x1 < $self->panel->left;
77 my $trunc_right = $x2 > $self->panel->right;
78
79 $x1 = $self->panel->left if $trunc_left;
80 $x2 = $self->panel->right if $trunc_right;
81
82 $trunc_left = 0 if $self->no_trunc;
83 $trunc_right = 0 if $self->no_trunc;
84
85 my ($sw,$ne,$base_w,$base_e) = $self->arrowheads;
86 $gd->line($x1,$center,$x2,$center,$fg);
87 $self->arrowhead($gd,$x1,$center,$a2,-1) if $sw && !$trunc_left; # west arrow
88 $self->arrowhead($gd,$x2,$center,$a2,+1) if $ne && !$trunc_right; # east arrow
89 $gd->line($x1,$center-$a2,$x1,$center+$a2,$fg) if $base_w && !$trunc_left; #west base
90 $gd->line($x2,$center-$a2,$x2,$center+$a2,$fg) if $base_e && !$trunc_right; #east base
91
92 # turn on ticks
93 if ($self->option('tick')) {
94 local $^W = 0; # dumb uninitialized variable warning
95 my $font = $self->font;
96 my $width = $font->width;
97 my $font_color = $self->fontcolor;
98 my $height = $self->height;
99
100 my $relative = $self->option('relative_coords');
101 my $relative_coords_offset = $self->option('relative_coords_offset');
102 $relative_coords_offset = 1 unless ($relative_coords_offset);
103
104 my $start = $relative ? $relative_coords_offset : $self->feature->start-1;
105 my $stop = $start + $self->feature->length - 1;
106
107 my $offset = $relative ? ($self->feature->start - $relative_coords_offset) : 0;
108 my $reversed = exists $self->{flip} || ($relative && $self->feature->strand < 0);
109
110 my $unit_label = $self->option('units') || '';
111 my $unit_divider = $self->option('unit_divider') || 1;
112
113 my $units = $self->calculate_units($start/$unit_divider,$self->feature->length/$unit_divider);
114 my $divisor = $UNITS{$units} || 1;
115
116 $divisor *= $unit_divider;
117
118 my $format = min($self->feature->length,$self->panel->length)/$divisor > 10
119 ? "%d$units%s" : "%.6g$units%s";
120
121 my $scale = $self->option('scale') || 1; ## Does the user want to override the internal scale?
122
123 my $model = sprintf("$format ",$stop/($divisor*$scale),$unit_label);
124 my $minlen = $width * length($model);
125
126 my ($major_interval,$minor_interval) = $self->panel->ticks(($stop-$start+1)/$unit_divider,$minlen);
127
128 my $left = $sw ? $x1+$height : $x1;
129 my $right = $ne ? $x2-$height : $x2;
130
131 # adjust for portions of arrow that are outside panel
132 $start += $self->panel->start - $self->feature->start
133 if $self->feature->start < $self->panel->start;
134 $stop -= $self->feature->end - $self->panel->end
135 if $self->feature->end > $self->panel->end;
136
137 my $first_tick = $major_interval * int(0.5 + $start/$major_interval);
138 my $last_tick = $major_interval * int(0.5 + $stop/$major_interval);
139
140 for (my $i = $first_tick; $i <= $last_tick; $i += $major_interval) {
141
142 my $tickpos = $dx + ($reversed ? $self->map_pt($stop - $i + $offset)
143 : $self->map_pt($i + $offset));
144 next if $tickpos < $left or $tickpos > $right;
145
146 $gd->line($tickpos,$center-$a2,$tickpos,$center+$a2,$fg);
147 my $label = $scale ? $i / $scale : $i;
148 my $scaled = $label/$divisor;
149 $label = sprintf($format,$scaled,$unit_label);
150
151 my $middle = $tickpos - (length($label) * $width)/2;
152 next if $middle < $left or $middle > $right;
153
154 $gd->string($font,$middle,$center+$a2-1,$label,$font_color)
155 unless ($self->option('no_tick_label'));
156 }
157
158 if ($self->option('tick') >= 2) {
159
160 $first_tick = $minor_interval * int(0.5 + $start/$minor_interval);
161 $last_tick = $minor_interval * int(0.5 + $stop/$minor_interval);
162
163 my $a4 = $self->height/4;
164 for (my $i = $first_tick; $i <= $last_tick; $i += $minor_interval) {
165 my $tickpos = $dx + ($reversed ? $self->map_pt($stop - $i + $offset)
166 : $self->map_pt($i + $offset));
167 next if $tickpos < $left or $tickpos > $right;
168
169 $gd->line($tickpos,$center-$a4,$tickpos,$center+$a4,$fg);
170 }
171 }
172 }
173
174 # add a label if requested
175 $self->draw_label($gd,$dx,$dy) if $self->option('label');
176 $self->draw_description($gd,$dx,$dy) if $self->option('description');
177 }
178
179 sub arrowheads {
180 my $self = shift;
181 my ($ne,$sw,$base_e,$base_w);
182 if ($self->option('double')) {
183 $ne = $sw = 1;
184 } else {
185 $ne = $self->option('northeast') || $self->option('east');
186 $sw = $self->option('southwest') || $self->option('west');
187 }
188 # otherwise use strandedness to define the arrow
189 unless (defined($ne) || defined($sw)) {
190 # turn on both if neither specified
191 $ne = 1 if $self->feature->strand > 0;
192 $sw = 1 if $self->feature->strand < 0;
193 ($ne,$sw) = ($sw,$ne) if $self->{flip};
194 }
195 return ($sw,$ne,0,0) unless $self->option('base');
196 return ($sw,$ne,
197 (!$sw && $self->feature->start>= $self->panel->start),
198 (!$ne && $self->feature->end <= $self->panel->end));
199 }
200
201 sub no_trunc { 0; }
202
203 sub calculate_units {
204 my $self = shift;
205 my ($start,$length) = @_;
206 return 'G' if $length >= 1e9;
207 return 'M' if $length >= 1e6;
208 return 'k' if $length >= 1e3;
209 return '' if $length >= 1;
210 return 'c' if $length >= 1e-2;
211 return 'm' if $length >= 1e-3;
212 return 'u' if $length >= 1e-6;
213 return 'n' if $length >= 1e-9;
214 return 'p';
215 }
216
217 sub min { $_[0]<$_[1] ? $_[0] : $_[1] }
218
219 1;
220
221 __END__
222
223 =head1 NAME
224
225 Ace::Graphics::Glyph::arrow - The "arrow" glyph
226
227 =head1 SYNOPSIS
228
229 See L<Ace::Graphics::Panel> and L<Ace::Graphics::Glyph>.
230
231 =head1 DESCRIPTION
232
233 This glyph draws arrows. Depending on options, the arrows can be
234 labeled, be oriented vertically or horizontally, or can contain major
235 and minor ticks suitable for use as a scale.
236
237 =head2 OPTIONS
238
239 The following options are standard among all Glyphs. See
240 L<Bio::Graphics::Glyph> for a full explanation.
241
242 Option Description Default
243 ------ ----------- -------
244
245 -fgcolor Foreground color black
246
247 -outlinecolor Synonym for -fgcolor
248
249 -bgcolor Background color turquoise
250
251 -fillcolor Synonym for -bgcolor
252
253 -linewidth Line width 1
254
255 -height Height of glyph 10
256
257 -font Glyph font gdSmallFont
258
259 -connector Connector type 0 (false)
260
261 -connector_color
262 Connector color black
263
264 -label Whether to draw a label 0 (false)
265
266 -description Whether to draw a description 0 (false)
267
268 In addition to the common options, the following glyph-specific
269 options are recognized:
270
271 Option Description Default
272 ------ ----------- -------
273
274 -tick Whether to draw major 0
275 and minor ticks.
276 0 = no ticks
277 1 = major ticks
278 2 = minor ticks
279
280 -parallel Whether to draw the arrow 1 (true)
281 parallel to the sequence
282 or perpendicular to it.
283
284 -northeast Force a north or east 1 (true)
285 arrowhead(depending
286 on orientation)
287
288 -east synonym of above
289
290 -southwest Force a south or west 1 (true)
291 arrowhead(depending
292 on orientation)
293
294 -west synonym of above
295
296 -double force-doubleheaded arrow 0 (false)
297
298 -base Draw a vertical base at the 0 (false)
299 non-arrowhead side
300
301 -scale Reset the labels on the arrow 0 (false)
302 to reflect an externally
303 established scale.
304
305 -arrowstyle "regular" to create a simple regular
306 arrowhead. "filled" to create
307 a thick filled arrowhead
308
309 -units add units to the tick labels none
310 e.g. bp
311
312 -unit_divider 1
313 divide tick labels by the
314 indicated amount prior to
315 displaying (use, for example
316 if you want to display in
317 cR units)
318
319 Set -parallel to 0 (false) to display a point-like feature such as a
320 polymorphism, or to indicate an important location. If the feature
321 start == end, then the glyph will draw a single arrow at the
322 designated location:
323
324 ^
325 |
326
327 Otherwise, there will be two arrows at the start and end:
328
329 ^ ^
330 | |
331
332 Scale: Pass in a externally established scale to reset the labels on
333 the arrow. This is particularly useful for manually constructed
334 images where the founding parameters of the panel are not 1-based.
335 For example, a genetic map interval ranging from 0.1 - 0.3 can be
336 constructed by first multiplying every value by 100. Passing
337
338 arrow(-scale=>100);
339
340 will draw tick marks labelled appropriately to your external scale.
341
342 =head1 BUGS
343
344 Please report them.
345
346 =head1 SEE ALSO
347
348 L<Bio::Graphics::Panel>,
349 L<Bio::Graphics::Glyph>,
350 L<Bio::Graphics::Glyph::arrow>,
351 L<Bio::Graphics::Glyph::cds>,
352 L<Bio::Graphics::Glyph::crossbox>,
353 L<Bio::Graphics::Glyph::diamond>,
354 L<Bio::Graphics::Glyph::dna>,
355 L<Bio::Graphics::Glyph::dot>,
356 L<Bio::Graphics::Glyph::ellipse>,
357 L<Bio::Graphics::Glyph::extending_arrow>,
358 L<Bio::Graphics::Glyph::generic>,
359 L<Bio::Graphics::Glyph::graded_segments>,
360 L<Bio::Graphics::Glyph::heterogeneous_segments>,
361 L<Bio::Graphics::Glyph::line>,
362 L<Bio::Graphics::Glyph::pinsertion>,
363 L<Bio::Graphics::Glyph::primers>,
364 L<Bio::Graphics::Glyph::rndrect>,
365 L<Bio::Graphics::Glyph::segments>,
366 L<Bio::Graphics::Glyph::ruler_arrow>,
367 L<Bio::Graphics::Glyph::toomany>,
368 L<Bio::Graphics::Glyph::transcript>,
369 L<Bio::Graphics::Glyph::transcript2>,
370 L<Bio::Graphics::Glyph::translation>,
371 L<Bio::Graphics::Glyph::triangle>,
372 L<Bio::DB::GFF>,
373 L<Bio::SeqI>,
374 L<Bio::SeqFeatureI>,
375 L<Bio::Das>,
376 L<GD>
377
378 =head1 AUTHOR
379
380 Lincoln Stein E<lt>lstein@cshl.orgE<gt>.
381
382 Copyright (c) 2001 Cold Spring Harbor Laboratory
383
384 This library is free software; you can redistribute it and/or modify
385 it under the same terms as Perl itself. See DISCLAIMER.txt for
386 disclaimers of warranty.
387
388 =cut