diff dir_plugins/Draw.pm @ 0:e545d0a25ffe draft

Uploaded
author dvanzessen
date Mon, 15 Jul 2019 05:17:17 -0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dir_plugins/Draw.pm	Mon Jul 15 05:17:17 2019 -0400
@@ -0,0 +1,387 @@
+=head1 LICENSE
+
+Copyright [1999-2015] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute
+Copyright [2016-2018] EMBL-European Bioinformatics Institute
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+=head1 CONTACT
+
+ Ensembl <http://www.ensembl.org/info/about/contact/index.html>
+    
+=cut
+
+=head1 NAME
+
+ Draw
+
+=head1 SYNOPSIS
+
+ mv Draw.pm ~/.vep/Plugins
+ ./vep -i variations.vcf --plugin Draw
+
+=head1 DESCRIPTION
+
+ A VEP plugin that draws pictures of the transcript model showing the
+ variant location. Can take five optional paramters:
+ 
+ 1) File name stem for images
+ 2) Image width in pixels (default: 1000px)
+ 3) Image height in pixels (default: 100px)
+ 4) Transcript ID - only draw images for this transcript
+ 5) Variant ID - only draw images for this variant
+ 
+ e.g.
+ 
+ ./vep -i variations.vcf --plugin Draw,myimg,2000,100
+ 
+ Images are written to [file_stem]_[transcript_id]_[variant_id].png
+ 
+ Requires GD library installed to run.
+
+=cut
+
+package Draw;
+
+use strict;
+use warnings;
+
+use Bio::EnsEMBL::Variation::Utils::BaseVepPlugin;
+
+# GD libraries for image creating
+use GD;
+use GD::Polygon;
+
+use Bio::EnsEMBL::Variation::Utils::VariationEffect qw(MAX_DISTANCE_FROM_TRANSCRIPT);
+
+use base qw(Bio::EnsEMBL::Variation::Utils::BaseVepPlugin);
+
+
+sub new {
+    my $class = shift;
+
+    my $self = $class->SUPER::new(@_);
+    
+    # configure
+    my @params = @{$self->params};
+    
+    $self->{prefix}     = $params[0] || $self->{config}->{output_file};
+    $self->{width}      = $params[1] || 1000;
+    $self->{height}     = $params[2] || 100;
+    $self->{transcript} = $params[3] || undef;
+    $self->{variant}    = $params[4] || undef;
+
+    return $self;
+}
+
+sub version {
+    return '2.4';
+}
+
+sub feature_types {
+    return ['Transcript'];
+}
+
+sub variant_feature_types {
+    return ['BaseVariationFeature'];
+}
+
+sub get_header_info {
+    return {};
+}
+
+sub run {
+    my ($self, $tva) = @_;
+    
+    my $main_tr = $tva->feature;
+    my $vf = $tva->base_variation_feature;
+    
+    return {} if defined($self->{transcript}) && $main_tr->stable_id ne $self->{transcript};
+    return {} if defined($self->{variant}) && $vf->variation_name ne $self->{variant};
+    
+    # if we're showing a gene fusion, get 
+    my $second_tr = $tva->{_fusion_transcripts}->[0] if grep {$_->SO_term =~ /gene_fusion/} @{$tva->get_all_OverlapConsequences};
+    
+    # set up scales etc
+    my $width    = $main_tr->feature_Slice->length + (2 * MAX_DISTANCE_FROM_TRANSCRIPT);
+    my $tr_start = $main_tr->start - MAX_DISTANCE_FROM_TRANSCRIPT;
+    my $tr_end   = $main_tr->end + MAX_DISTANCE_FROM_TRANSCRIPT;
+    
+    if(defined($second_tr)) {
+        $width    = (max(($main_tr->end, $second_tr->end)) - min(($main_tr->start, $second_tr->start))) + 1 + (2 * MAX_DISTANCE_FROM_TRANSCRIPT);
+        $tr_start = min(($main_tr->start, $second_tr->start)) - MAX_DISTANCE_FROM_TRANSCRIPT;
+        $tr_end   = max(($main_tr->end, $second_tr->end)) + MAX_DISTANCE_FROM_TRANSCRIPT;
+    }
+    
+    my $x_scale  = ($self->{width} - 20)  / $width;
+    my $y_scale  = ($self->{height} - 30) / 100;
+    my $x_off    = 10;
+    my $y_off    = 20;
+    
+    # create GD image object
+    my $img = GD::Image->new($self->{width}, $self->{height});
+    
+    # set up some colours
+    my %colours = (
+        white      => $img->colorAllocate(255,255,255),
+        black      => $img->colorAllocate(0,0,0),
+        grey       => $img->colorAllocate(200,200,200),
+        darkgrey   => $img->colorAllocate(150,150,150),
+        vlightgrey => $img->colorAllocate(235,235,235),
+        blue       => $img->colorAllocate(0,0,200),
+        lightblue  => $img->colorAllocate(200,200,255),
+        red        => $img->colorAllocate(200,0,0),
+        lightred   => $img->colorAllocate(255,200,200),
+        green      => $img->colorAllocate(0,200,0),
+        lightgreen => $img->colorAllocate(220,255,220),
+        yellow     => $img->colorAllocate(236,164,26),
+        purple     => $img->colorAllocate(195,50,212),  
+    );
+    
+    # scale bar
+    my $zero_string = '0' x (length(int(100 / $x_scale)) - 1);
+    my $bases_per_bar = '1'.$zero_string;
+    
+    my $start = int($tr_start / $bases_per_bar) * $bases_per_bar;
+    my $end = (int($tr_start / $bases_per_bar) + 1) * $bases_per_bar;
+    my $colour = 0;
+    
+    while($start < $tr_end) {
+        my $method = $colour ? 'rectangle' : 'filledRectangle';
+        
+        $img->$method(
+            $x_off + (($start - $tr_start) * $x_scale),
+            $self->{height} - 15,
+            $x_off + (($end - $tr_start) * $x_scale),
+            $self->{height} - 10,
+            $colours{grey},
+        );
+        
+        # tick and label
+        if($start =~ /(5|0)$zero_string$/) {
+            my $string = $start;
+            1 while $string =~ s/^(-?\d+)(\d\d\d)/$1,$2/;
+            
+            $img->string(
+                gdTinyFont,
+                $x_off + (($start - $tr_start) * $x_scale) + 2,
+                $self->{height} - 8,
+                $string,
+                $colours{black}
+            );
+            
+            $img->line(
+                $x_off + (($start - $tr_start) * $x_scale),
+                $self->{height} - 15,
+                $x_off + (($start - $tr_start) * $x_scale),
+                $self->{height},
+                $start =~ /5$zero_string$/ ? $colours{grey} : $colours{black}
+            );
+            
+            $img->dashedLine(
+                $x_off + (($start - $tr_start) * $x_scale),
+                0,
+                $x_off + (($start - $tr_start) * $x_scale),
+                $self->{height} - 15,
+                $start =~ /5$zero_string$/ ? $colours{vlightgrey} : $colours{grey}
+            )
+        }
+        
+        $colour = 1 - $colour;
+        $start += $bases_per_bar;
+        $end += $bases_per_bar;
+    }
+    
+    # render transcripts
+    foreach my $tr($main_tr, $second_tr) {
+        next unless defined($tr);
+        
+        # render introns
+        foreach my $intron(@{$tr->get_all_Introns}) {
+            $img->line(
+                $x_off + (($intron->start - $tr_start) * $x_scale),
+                $y_off + (20 * $y_scale),
+                $x_off + (((($intron->start + $intron->end) / 2) - $tr_start) * $x_scale),
+                $y_off + (10 * $y_scale),
+                $colours{lightblue}
+            );
+            
+            $img->line(
+                $x_off + (((($intron->start + $intron->end) / 2) - $tr_start) * $x_scale),
+                $y_off + (10 * $y_scale),
+                $x_off + (($intron->end - $tr_start) * $x_scale),
+                $y_off + (20 * $y_scale),
+                $colours{lightblue}
+            );
+        }
+        
+        # render exons
+        foreach my $exon(@{$tr->get_all_Exons}) {
+            
+            # non-coding part
+            $img->rectangle(
+                $x_off + (($exon->start - $tr_start) * $x_scale),
+                $y_off + (10 * $y_scale),
+                $x_off + (($exon->end - $tr_start) * $x_scale),
+                $y_off + (30 * $y_scale),
+                $colours{lightblue}
+            );
+            
+            # coding part
+            $img->filledRectangle(
+                $x_off + (($exon->coding_region_start($tr) - $tr_start) * $x_scale),
+                $y_off + (0 * $y_scale),
+                $x_off + (($exon->coding_region_end($tr) - $tr_start) * $x_scale),
+                $y_off + (40 * $y_scale),
+                $colours{blue}
+            ) if defined $exon->coding_region_start($tr) && defined $exon->coding_region_end($tr);
+        }
+        
+        # add transcript direction indicator
+        if($tr->strand == 1) {
+            
+            # vertical line
+            $img->line(
+                $x_off + (($tr->start - $tr_start) * $x_scale),
+                $y_off + (-5 * $y_scale),
+                $x_off + (($tr->start - $tr_start) * $x_scale),
+                $y_off + (20 * $y_scale),
+                $colours{lightblue},
+            );
+            
+            # horizontal line
+            $img->line(
+                $x_off + (($tr->start - $tr_start) * $x_scale),
+                $y_off + (-5 * $y_scale),
+                $x_off + (($tr->start - $tr_start) * $x_scale) + 20,
+                $y_off + (-5 * $y_scale),
+                $colours{lightblue},
+            );
+            
+            # top arrow part
+            $img->line(
+                $x_off + (($tr->start - $tr_start) * $x_scale) + 17,
+                $y_off + (-8 * $y_scale),
+                $x_off + (($tr->start - $tr_start) * $x_scale) + 20,
+                $y_off + (-5 * $y_scale),
+                $colours{lightblue},
+            );
+            
+            # bottom arrow part
+            $img->line(
+                $x_off + (($tr->start - $tr_start) * $x_scale) + 17,
+                $y_off + (-1 * $y_scale),
+                $x_off + (($tr->start - $tr_start) * $x_scale) + 20,
+                $y_off + (-5 * $y_scale),
+                $colours{lightblue},
+            );
+            
+            # label
+            $img->string(gdTinyFont, $x_off + (($tr->start - $tr_start) * $x_scale) + 25, $y_off + (-12 * $y_scale), $tr->stable_id, $colours{blue});
+        }
+        
+        else {        
+            
+            # vertical line
+            $img->line(
+                $x_off + (($tr->end - $tr_start) * $x_scale),
+                $y_off + (20 * $y_scale),
+                $x_off + (($tr->end - $tr_start) * $x_scale),
+                $y_off + (47 * $y_scale),
+                $colours{lightblue},
+            );
+            
+            # horizontal line
+            $img->line(
+                $x_off + (($tr->end - $tr_start) * $x_scale),
+                $y_off + (47 * $y_scale),
+                $x_off + (($tr->end - $tr_start) * $x_scale) - 20,
+                $y_off + (47 * $y_scale),
+                $colours{lightblue},
+            );
+            
+            # top arrow part
+            $img->line(
+                $x_off + (($tr->end - $tr_start) * $x_scale) - 17,
+                $y_off + (50 * $y_scale),
+                $x_off + (($tr->end - $tr_start) * $x_scale) - 20,
+                $y_off + (47 * $y_scale),
+                $colours{lightblue},
+            );
+            
+            # bottom arrow part
+            $img->line(
+                $x_off + (($tr->end - $tr_start) * $x_scale) - 17,
+                $y_off + (43 * $y_scale),
+                $x_off + (($tr->end - $tr_start) * $x_scale) - 20,
+                $y_off + (47 * $y_scale),
+                $colours{lightblue},
+            );
+            
+            # label
+            $img->string(gdTinyFont, $x_off + (($tr->end - $tr_start) * $x_scale) - 100, $y_off + (43 * $y_scale), $tr->stable_id, $colours{blue});
+        }
+    }
+    
+    # render variant
+    my $var_colour = 'green';
+    
+    if($vf->class_SO_term =~ /deletion/) {
+        $var_colour = 'red';
+    }
+    
+    $img->filledRectangle(
+        $x_off + (($vf->start - $tr_start) * $x_scale),
+        $y_off + (60 * $y_scale),
+        $x_off + (($vf->end - $tr_start) * $x_scale),
+        $y_off + (70 * $y_scale),
+        $colours{$var_colour},
+    );
+    
+    # variant label
+    $img->string(
+        gdTinyFont,
+        $x_off + (($vf->start - $tr_start) * $x_scale),
+        $y_off + (75 * $y_scale),
+        $vf->variation_name,
+        $colours{$var_colour}
+    );
+    
+    my $vname = $vf->variation_name;
+    $vname =~ s/\//\_/g;
+    my $file = $self->{prefix}."_".$main_tr->stable_id."_".(defined($second_tr) ? $second_tr->stable_id."_" : "").$vname."\.png";
+    
+    # check we're allowed to write to it
+    if(!defined($self->{config}->{force_overwrite}) && -e $file) {
+        die "ERROR: Image file $file already exists - choose a different file name stem or use --force_overwrite\n";
+        return;
+    }
+    
+    open IM, ">$file" or die "ERROR: Could not write to file $file\n";
+    binmode IM;
+    print IM $img->png;
+    close IM;
+    
+    return {};
+}
+
+sub max {
+    return (sort {$a <=> $b} @_)[-1];
+}
+
+sub min {
+    return (sort {$a <=> $b} @_)[0];
+}
+
+1;
+