comparison dir_plugins/Draw.pm @ 0:e545d0a25ffe draft

Uploaded
author dvanzessen
date Mon, 15 Jul 2019 05:17:17 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:e545d0a25ffe
1 =head1 LICENSE
2
3 Copyright [1999-2015] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute
4 Copyright [2016-2018] EMBL-European Bioinformatics Institute
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17
18 =head1 CONTACT
19
20 Ensembl <http://www.ensembl.org/info/about/contact/index.html>
21
22 =cut
23
24 =head1 NAME
25
26 Draw
27
28 =head1 SYNOPSIS
29
30 mv Draw.pm ~/.vep/Plugins
31 ./vep -i variations.vcf --plugin Draw
32
33 =head1 DESCRIPTION
34
35 A VEP plugin that draws pictures of the transcript model showing the
36 variant location. Can take five optional paramters:
37
38 1) File name stem for images
39 2) Image width in pixels (default: 1000px)
40 3) Image height in pixels (default: 100px)
41 4) Transcript ID - only draw images for this transcript
42 5) Variant ID - only draw images for this variant
43
44 e.g.
45
46 ./vep -i variations.vcf --plugin Draw,myimg,2000,100
47
48 Images are written to [file_stem]_[transcript_id]_[variant_id].png
49
50 Requires GD library installed to run.
51
52 =cut
53
54 package Draw;
55
56 use strict;
57 use warnings;
58
59 use Bio::EnsEMBL::Variation::Utils::BaseVepPlugin;
60
61 # GD libraries for image creating
62 use GD;
63 use GD::Polygon;
64
65 use Bio::EnsEMBL::Variation::Utils::VariationEffect qw(MAX_DISTANCE_FROM_TRANSCRIPT);
66
67 use base qw(Bio::EnsEMBL::Variation::Utils::BaseVepPlugin);
68
69
70 sub new {
71 my $class = shift;
72
73 my $self = $class->SUPER::new(@_);
74
75 # configure
76 my @params = @{$self->params};
77
78 $self->{prefix} = $params[0] || $self->{config}->{output_file};
79 $self->{width} = $params[1] || 1000;
80 $self->{height} = $params[2] || 100;
81 $self->{transcript} = $params[3] || undef;
82 $self->{variant} = $params[4] || undef;
83
84 return $self;
85 }
86
87 sub version {
88 return '2.4';
89 }
90
91 sub feature_types {
92 return ['Transcript'];
93 }
94
95 sub variant_feature_types {
96 return ['BaseVariationFeature'];
97 }
98
99 sub get_header_info {
100 return {};
101 }
102
103 sub run {
104 my ($self, $tva) = @_;
105
106 my $main_tr = $tva->feature;
107 my $vf = $tva->base_variation_feature;
108
109 return {} if defined($self->{transcript}) && $main_tr->stable_id ne $self->{transcript};
110 return {} if defined($self->{variant}) && $vf->variation_name ne $self->{variant};
111
112 # if we're showing a gene fusion, get
113 my $second_tr = $tva->{_fusion_transcripts}->[0] if grep {$_->SO_term =~ /gene_fusion/} @{$tva->get_all_OverlapConsequences};
114
115 # set up scales etc
116 my $width = $main_tr->feature_Slice->length + (2 * MAX_DISTANCE_FROM_TRANSCRIPT);
117 my $tr_start = $main_tr->start - MAX_DISTANCE_FROM_TRANSCRIPT;
118 my $tr_end = $main_tr->end + MAX_DISTANCE_FROM_TRANSCRIPT;
119
120 if(defined($second_tr)) {
121 $width = (max(($main_tr->end, $second_tr->end)) - min(($main_tr->start, $second_tr->start))) + 1 + (2 * MAX_DISTANCE_FROM_TRANSCRIPT);
122 $tr_start = min(($main_tr->start, $second_tr->start)) - MAX_DISTANCE_FROM_TRANSCRIPT;
123 $tr_end = max(($main_tr->end, $second_tr->end)) + MAX_DISTANCE_FROM_TRANSCRIPT;
124 }
125
126 my $x_scale = ($self->{width} - 20) / $width;
127 my $y_scale = ($self->{height} - 30) / 100;
128 my $x_off = 10;
129 my $y_off = 20;
130
131 # create GD image object
132 my $img = GD::Image->new($self->{width}, $self->{height});
133
134 # set up some colours
135 my %colours = (
136 white => $img->colorAllocate(255,255,255),
137 black => $img->colorAllocate(0,0,0),
138 grey => $img->colorAllocate(200,200,200),
139 darkgrey => $img->colorAllocate(150,150,150),
140 vlightgrey => $img->colorAllocate(235,235,235),
141 blue => $img->colorAllocate(0,0,200),
142 lightblue => $img->colorAllocate(200,200,255),
143 red => $img->colorAllocate(200,0,0),
144 lightred => $img->colorAllocate(255,200,200),
145 green => $img->colorAllocate(0,200,0),
146 lightgreen => $img->colorAllocate(220,255,220),
147 yellow => $img->colorAllocate(236,164,26),
148 purple => $img->colorAllocate(195,50,212),
149 );
150
151 # scale bar
152 my $zero_string = '0' x (length(int(100 / $x_scale)) - 1);
153 my $bases_per_bar = '1'.$zero_string;
154
155 my $start = int($tr_start / $bases_per_bar) * $bases_per_bar;
156 my $end = (int($tr_start / $bases_per_bar) + 1) * $bases_per_bar;
157 my $colour = 0;
158
159 while($start < $tr_end) {
160 my $method = $colour ? 'rectangle' : 'filledRectangle';
161
162 $img->$method(
163 $x_off + (($start - $tr_start) * $x_scale),
164 $self->{height} - 15,
165 $x_off + (($end - $tr_start) * $x_scale),
166 $self->{height} - 10,
167 $colours{grey},
168 );
169
170 # tick and label
171 if($start =~ /(5|0)$zero_string$/) {
172 my $string = $start;
173 1 while $string =~ s/^(-?\d+)(\d\d\d)/$1,$2/;
174
175 $img->string(
176 gdTinyFont,
177 $x_off + (($start - $tr_start) * $x_scale) + 2,
178 $self->{height} - 8,
179 $string,
180 $colours{black}
181 );
182
183 $img->line(
184 $x_off + (($start - $tr_start) * $x_scale),
185 $self->{height} - 15,
186 $x_off + (($start - $tr_start) * $x_scale),
187 $self->{height},
188 $start =~ /5$zero_string$/ ? $colours{grey} : $colours{black}
189 );
190
191 $img->dashedLine(
192 $x_off + (($start - $tr_start) * $x_scale),
193 0,
194 $x_off + (($start - $tr_start) * $x_scale),
195 $self->{height} - 15,
196 $start =~ /5$zero_string$/ ? $colours{vlightgrey} : $colours{grey}
197 )
198 }
199
200 $colour = 1 - $colour;
201 $start += $bases_per_bar;
202 $end += $bases_per_bar;
203 }
204
205 # render transcripts
206 foreach my $tr($main_tr, $second_tr) {
207 next unless defined($tr);
208
209 # render introns
210 foreach my $intron(@{$tr->get_all_Introns}) {
211 $img->line(
212 $x_off + (($intron->start - $tr_start) * $x_scale),
213 $y_off + (20 * $y_scale),
214 $x_off + (((($intron->start + $intron->end) / 2) - $tr_start) * $x_scale),
215 $y_off + (10 * $y_scale),
216 $colours{lightblue}
217 );
218
219 $img->line(
220 $x_off + (((($intron->start + $intron->end) / 2) - $tr_start) * $x_scale),
221 $y_off + (10 * $y_scale),
222 $x_off + (($intron->end - $tr_start) * $x_scale),
223 $y_off + (20 * $y_scale),
224 $colours{lightblue}
225 );
226 }
227
228 # render exons
229 foreach my $exon(@{$tr->get_all_Exons}) {
230
231 # non-coding part
232 $img->rectangle(
233 $x_off + (($exon->start - $tr_start) * $x_scale),
234 $y_off + (10 * $y_scale),
235 $x_off + (($exon->end - $tr_start) * $x_scale),
236 $y_off + (30 * $y_scale),
237 $colours{lightblue}
238 );
239
240 # coding part
241 $img->filledRectangle(
242 $x_off + (($exon->coding_region_start($tr) - $tr_start) * $x_scale),
243 $y_off + (0 * $y_scale),
244 $x_off + (($exon->coding_region_end($tr) - $tr_start) * $x_scale),
245 $y_off + (40 * $y_scale),
246 $colours{blue}
247 ) if defined $exon->coding_region_start($tr) && defined $exon->coding_region_end($tr);
248 }
249
250 # add transcript direction indicator
251 if($tr->strand == 1) {
252
253 # vertical line
254 $img->line(
255 $x_off + (($tr->start - $tr_start) * $x_scale),
256 $y_off + (-5 * $y_scale),
257 $x_off + (($tr->start - $tr_start) * $x_scale),
258 $y_off + (20 * $y_scale),
259 $colours{lightblue},
260 );
261
262 # horizontal line
263 $img->line(
264 $x_off + (($tr->start - $tr_start) * $x_scale),
265 $y_off + (-5 * $y_scale),
266 $x_off + (($tr->start - $tr_start) * $x_scale) + 20,
267 $y_off + (-5 * $y_scale),
268 $colours{lightblue},
269 );
270
271 # top arrow part
272 $img->line(
273 $x_off + (($tr->start - $tr_start) * $x_scale) + 17,
274 $y_off + (-8 * $y_scale),
275 $x_off + (($tr->start - $tr_start) * $x_scale) + 20,
276 $y_off + (-5 * $y_scale),
277 $colours{lightblue},
278 );
279
280 # bottom arrow part
281 $img->line(
282 $x_off + (($tr->start - $tr_start) * $x_scale) + 17,
283 $y_off + (-1 * $y_scale),
284 $x_off + (($tr->start - $tr_start) * $x_scale) + 20,
285 $y_off + (-5 * $y_scale),
286 $colours{lightblue},
287 );
288
289 # label
290 $img->string(gdTinyFont, $x_off + (($tr->start - $tr_start) * $x_scale) + 25, $y_off + (-12 * $y_scale), $tr->stable_id, $colours{blue});
291 }
292
293 else {
294
295 # vertical line
296 $img->line(
297 $x_off + (($tr->end - $tr_start) * $x_scale),
298 $y_off + (20 * $y_scale),
299 $x_off + (($tr->end - $tr_start) * $x_scale),
300 $y_off + (47 * $y_scale),
301 $colours{lightblue},
302 );
303
304 # horizontal line
305 $img->line(
306 $x_off + (($tr->end - $tr_start) * $x_scale),
307 $y_off + (47 * $y_scale),
308 $x_off + (($tr->end - $tr_start) * $x_scale) - 20,
309 $y_off + (47 * $y_scale),
310 $colours{lightblue},
311 );
312
313 # top arrow part
314 $img->line(
315 $x_off + (($tr->end - $tr_start) * $x_scale) - 17,
316 $y_off + (50 * $y_scale),
317 $x_off + (($tr->end - $tr_start) * $x_scale) - 20,
318 $y_off + (47 * $y_scale),
319 $colours{lightblue},
320 );
321
322 # bottom arrow part
323 $img->line(
324 $x_off + (($tr->end - $tr_start) * $x_scale) - 17,
325 $y_off + (43 * $y_scale),
326 $x_off + (($tr->end - $tr_start) * $x_scale) - 20,
327 $y_off + (47 * $y_scale),
328 $colours{lightblue},
329 );
330
331 # label
332 $img->string(gdTinyFont, $x_off + (($tr->end - $tr_start) * $x_scale) - 100, $y_off + (43 * $y_scale), $tr->stable_id, $colours{blue});
333 }
334 }
335
336 # render variant
337 my $var_colour = 'green';
338
339 if($vf->class_SO_term =~ /deletion/) {
340 $var_colour = 'red';
341 }
342
343 $img->filledRectangle(
344 $x_off + (($vf->start - $tr_start) * $x_scale),
345 $y_off + (60 * $y_scale),
346 $x_off + (($vf->end - $tr_start) * $x_scale),
347 $y_off + (70 * $y_scale),
348 $colours{$var_colour},
349 );
350
351 # variant label
352 $img->string(
353 gdTinyFont,
354 $x_off + (($vf->start - $tr_start) * $x_scale),
355 $y_off + (75 * $y_scale),
356 $vf->variation_name,
357 $colours{$var_colour}
358 );
359
360 my $vname = $vf->variation_name;
361 $vname =~ s/\//\_/g;
362 my $file = $self->{prefix}."_".$main_tr->stable_id."_".(defined($second_tr) ? $second_tr->stable_id."_" : "").$vname."\.png";
363
364 # check we're allowed to write to it
365 if(!defined($self->{config}->{force_overwrite}) && -e $file) {
366 die "ERROR: Image file $file already exists - choose a different file name stem or use --force_overwrite\n";
367 return;
368 }
369
370 open IM, ">$file" or die "ERROR: Could not write to file $file\n";
371 binmode IM;
372 print IM $img->png;
373 close IM;
374
375 return {};
376 }
377
378 sub max {
379 return (sort {$a <=> $b} @_)[-1];
380 }
381
382 sub min {
383 return (sort {$a <=> $b} @_)[0];
384 }
385
386 1;
387