1package Bio::Graphics::DrawTransmembrane; 2 3use strict; 4use warnings; 5use GD; 6use base 'Bio::Root::Root'; 7 8my %DRAWOPTIONS = ( 9 ## general parameters 10 'topology' => { 'private' => 'topology_array', 11 'default' => []}, 12 'topology_string' => { 'private' => 'topology_string', 13 'default' => 0}, 14 'n_terminal' => { 'private' => 'n_term', 15 'default' => 'out', }, 16 'title' => { 'private' => 'title', 17 'default' => ''}, 18 'inside_label' => { 'private' => 'in', 19 'default' => "Cytoplasmic"}, 20 'outside_label' => { 'private' => 'out', 21 'default' => "Extracellular"}, 22 'membrane_label' => { 'private' => 'membrane', 23 'default' => "Plasma Membrane"}, 24 ## dimensions 25 'helix_height' => { 'private' => 'helix_height', 26 'default' => 130}, 27 'helix_width' => { 'private' => 'helix_width', 28 'default' => 50}, 29 'loop_width' => { 'private' => 'loop_width', 30 'default' => 20}, 31 'vertical_padding' => { 'private' => 'vertical_padding', 32 'default' => 140}, 33 'horizontal_padding' => { 'private' => 'horizontal_padding', 34 'default' => 150}, 35 'membrane_offset' => { 'private' => 'offset', 36 'default' => 6}, 37 ## loop lengths and limits 38 'short_loop_height' => { 'private' => 'short_loop', 39 'default' => 90}, 40 'medium_loop_height' => { 'private' => 'medium_loop', 41 'default' => 120}, 42 'long_loop_height' => { 'private' => 'long_loop', 43 'default' => 150}, 44 'short_loop_limit' => { 'private' => 'short_loop_limit', 45 'default' => 15}, 46 'long_loop_limit' => { 'private' => 'long_loop_limit', 47 'default' => 30}, 48 'n_terminal_height' => { 'private' => 'n_terminal_height', 49 'default' => 150}, 50 'c_terminal_height' => { 'private' => 'c_terminal_height', 51 'default' => 80}, 52 'loop_heights' => { 'private' => 'loop_heights', 53 'default' => {}}, 54 'n_terminal_offset' => { 'private' => 'n_term_offset', 55 'default' => 0}, 56 'c_terminal_offset' => { 'private' => 'c_term_offset', 57 'default' => 0}, 58 ## colour scheme & display options 59 'show_labels' => { 'private' => 'labels', 60 'default' => 'on'}, 61 'bold_helices' => { 'private' => 'bold_helices', 62 'default' => 1}, 63 'bold_labels' => { 'private' => 'bold_labels', 64 'default' => 0}, 65 'colour_scheme' => { 'private' => 'scheme', 66 'default' => 'yellow'}, 67 'draw_cytosol' => { 'private' => 'draw_cytosol', 68 'default' => 0}, 69 'draw_bilayer' => { 'private' => 'draw_bilayer', 70 'default' => 1}, 71 'draw_loops' => { 'private' => 'draw_loops', 72 'default' => 1}, 73 'draw_terminai' => { 'private' => 'draw_terminai', 74 'default' => 1}, 75 'draw_helices' => { 'private' => 'draw_helices', 76 'default' => 1}, 77 ## labeling options 78 'labels' => { 'private' => 'loop_labels', 79 'default' => {}}, 80 'text_offset' => { 'private' => 'text_offset', 81 'default' => 0}, 82 'helix_label' => { 'private' => 'helix_label', 83 'default' => 'S'}, 84 'n_term_label' => { 'private' => 'n_term_label', 85 'default' => 'N-Terminal'}, 86 'c_term_label' => { 'private' => 'c_term_label', 87 'default' => 'C-Terminal'}, 88 'dontsort' => { 'private' => 'dontsort', 89 'default' => 0}, 90 'ttf_font' => { 'private' => 'ttf_font', 91 'default' => 0}, 92 'ttf_font_size' => { 'private' => 'ttf_font_size', 93 'default' => 8}, 94); 95 96sub new { 97 my ($class, @args) = @_; 98 my $self = $class->SUPER::new(@args); 99 my %opt = @args; 100 %opt = map {my $k = $_; 101 $k =~ s{^-}{}; 102 $k => $opt{$_}} keys %opt; 103 104 # need to shore up private variables, check for req'd parameters 105 for my $param (sort keys %DRAWOPTIONS) { 106 my ($priv, $def) = ($DRAWOPTIONS{$param}->{'private'},$DRAWOPTIONS{$param}->{'default'}); 107 $self->{$priv} = (exists $opt{$param}) ? $opt{$param} : $def; 108 } 109 110 $self->{'loop_count'} = 1; 111 112 return $self; 113} 114 115sub png { 116 117 my $self = shift; 118 119 my @numeric = ('helix_height','helix_width','loop_width','vertical_padding','horizontal_padding','short_length','medium_loop_length','long_loop_length','short_loop_limit','long_loop_limit','n_terminal_height','membrane_offset','text_offset','n_term_offset','c_term_offset'); 120 121 foreach (@numeric){ 122 die "\nParameter $_ must be numeric.\n\n" if exists $self->{$_} && $self->{$_} =~ /-{?}\D+/; 123 } 124 125 foreach (keys %{$self->{'loop_labels'}}){ 126 die "\nLabel position $_ must be numeric.\n\n" if $_ =~ /\D+/; 127 } 128 129 foreach (keys %{$self->{'loop_heights'}}){ 130 die "\nLoop number $_ must be numeric.\n\n" if $_ =~ /\D+/; 131 } 132 133 foreach (values %{$self->{'loop_heights'}}){ 134 die "\nLoop height $_ must be numeric.\n\n" if $_ =~ /\D+/; 135 } 136 137 ## n-terminal defaults to outside in it's not in,inside,out,outside 138 $self->{'n_term'} = 'out' if (($self->{'n_term'} ne 'in')&&($self->{'n_term'} ne 'inside')&&($self->{'n_term'} ne 'out')||$self->{'n_term'} eq 'outside'); 139 $self->{'n_term'} = 'in' if $self->{'n_term'} eq 'inside'; 140 141 if ($self->{'topology_string'}){ 142 $self->{'topology_string'} =~ s/\D\.//g; 143 $self->{'topology_string'} =~ s/;/,/g; 144 @{$self->{'topology_array'}} = split(/,/,$self->{'topology_string'}); 145 } 146 147 ## check to make sure we have pairs of helix boundaries and that data is numeric otherwise quit 148 if (scalar @{$self->{'topology_array'}} % 2){ 149 die "\nUneven number of helix boundaries.\n\n"; 150 } 151 152 foreach (@{$self->{'topology_array'}}){ 153 if ($_ =~ /\D/){ 154 die "\nTopology data is not numeric. $_\n\n"; 155 156 } 157 } 158 159 ## check to make sure the TTF font exists, otherwise use gdSmallFont 160 if ($self->{'ttf_font'}){ 161 unless (-e $self->{'ttf_font'}){ 162 print "\nCan't find font ".$self->{'ttf_font'}.".\n"; 163 $self->{'ttf_font'} = 0; 164 } 165 } 166 167 my @sorted_topology = sort {$a <=> $b} @{$self->{'topology_array'}}; 168 169 ## Don't automatically sort the topology array 170 @sorted_topology = @{$self->{'topology_array'}} if $self->{'dontsort'}; 171 172 $self->{'helix_count'} = scalar @{$self->{'topology_array'}} / 2; 173 174 unless ($self->{'helix_count'}){ 175 die "\nNo topology data found.\n\n"; 176 } 177 178 ## put helix start/stop points in $self->{'helix_span'} and loop lengths in $self->{'loop_length'} 179 foreach (0..($self->{'helix_count'} - 1)){ 180 my $count = $_ * 2; 181 $self->{'helix_span'}{$_ + 1}{'start'} = $sorted_topology[$count]; 182 $self->{'helix_span'}{$_ + 1}{'stop'} = $sorted_topology[$count + 1]; 183 $self->{'loop_length'}{$_ + 1} = scalar ($sorted_topology[$count + 2] - $sorted_topology[$count + 1]) unless ($_ + 1 == $self->{'helix_count'}); 184 } 185 186 $self->{'width'} = ($self->{'horizontal_padding'} * 2) + ($self->{'helix_width'} * $self->{'helix_count'}) + ($self->{'loop_width'} * ($self->{'helix_count'} - 1)); 187 $self->{'height'} = $self->{'helix_height'} + ($self->{'vertical_padding'} * 2); 188 189 ## create a new image 190 $self->{'im'} = new GD::Image($self->{'width'},$self->{'height'}); 191 192 $self->{'black'} = $self->{'im'}->colorAllocate(0,0,0); 193 $self->{'white'} = $self->{'im'}->colorAllocate(255,255,255); 194 $self->{'im'}->fill(0,0,$self->{'white'}); 195 196 ## write title 197 if ($self->{'ttf_font'}){ 198 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,4,12,$self->{'title'},{linespacing=>0.6,charmap => 'Unicode',}) if $self->{'title'}; 199 }else{ 200 $self->{'im'}->string(gdSmallFont,4,3,$self->{'title'},$self->{'black'}) if $self->{'title'}; 201 } 202 203 $self->draw_cytosol if $self->{'draw_cytosol'}; 204 $self->draw_bilayer if $self->{'draw_bilayer'}; 205 $self->draw_loops if $self->{'draw_loops'}; 206 $self->draw_terminai if $self->{'draw_terminai'}; 207 $self->draw_helices if $self->{'draw_helices'}; 208 209 ## use GD to convert to png 210 return $self->{'im'}->GD::Image::png; 211 212} 213 214sub add_tmhmm_feat { 215 216 my $self = shift; 217 my $feat = shift; 218 219 #print Dumper $feat; 220 221 ## add a helix from a tmhmm feature 222 if ($feat->{'_primary_tag'} eq 'transmembrane'){ 223 push @{$self->{'topology_array'}},$feat->{'_location'}{'_start'}; 224 push @{$self->{'topology_array'}},$feat->{'_location'}{'_end'}; 225 } 226 227 ## i've made a few changes to TmHmm.pm to include the inside/outside loops. 228 ## this bit looks for the topology of the 1st residue so we can now position the n-terminal 229 if ($feat->{'_location'}{'_start'} == 1){ 230 if ($feat->{'_primary_tag'} =~ /(\w+)_loop/){ 231 $self->{'n_term'} = $1; 232 } 233 } 234 235 return $self; 236 237} 238 239sub draw_cytosol { 240 241 my $self = shift; 242 243 my $cytosol_offset = 5; 244 my $light_grey = $self->{'im'}->colorAllocate(164,164,164); 245 246 ## draw cytosol 247 $self->{'im'}->filledRectangle(($self->{'horizontal_padding'} / 3) ,($self->{'vertical_padding'} + $self->{'helix_height'} - $cytosol_offset),($self->{'width'} - ($self->{'horizontal_padding'} / 3)),($self->{'vertical_padding'} + ($self->{'helix_height'} * 2 ) + $cytosol_offset),$light_grey); 248 249 return $self; 250} 251 252sub draw_bilayer { 253 254 my $self = shift; 255 256 my $dark_grey = $self->{'im'}->colorAllocate(40,40,40); 257 my $dark_grey1 = $self->{'im'}->colorAllocate(50,50,50); 258 my $dark_grey2 = $self->{'im'}->colorAllocate(60,60,60); 259 my $dark_grey3 = $self->{'im'}->colorAllocate(70,70,70); 260 261 ## label either side of membrane 262 if ($self->{'ttf_font'}){ 263 264 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($self->{'horizontal_padding'} / 3) + 2,($self->{'vertical_padding'} + $self->{'offset'} - 3),$self->{'out'},{linespacing=>0.6,charmap => 'Unicode',}) if $self->{'labels'}; 265 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($self->{'horizontal_padding'} / 3) + 2,($self->{'vertical_padding'} + $self->{'helix_height'} - $self->{'offset'} + 12),$self->{'in'},{linespacing=>0.6,charmap => 'Unicode',}) if $self->{'labels'}; 266 }else{ 267 $self->{'im'}->string(gdSmallFont,($self->{'horizontal_padding'} / 3) + 2,($self->{'vertical_padding'} + $self->{'offset'} - 14),$self->{'out'},$self->{'black'}) if $self->{'labels'}; 268 $self->{'im'}->string(gdSmallFont,($self->{'horizontal_padding'} / 3) + 2,($self->{'vertical_padding'} + $self->{'helix_height'} - $self->{'offset'} + 1),$self->{'in'},$self->{'black'}) if $self->{'labels'}; 269 } 270 271 272 273 ## draw membrane with graded fill 274 $self->{'im'}->filledRectangle(($self->{'horizontal_padding'} / 3),($self->{'vertical_padding'} + $self->{'offset'}),($self->{'width'} - $self->{'horizontal_padding'} / 3),($self->{'vertical_padding'} + $self->{'helix_height'} - $self->{'offset'}),$dark_grey); 275 $self->{'im'}->filledRectangle(($self->{'horizontal_padding'} / 3) + 1,($self->{'vertical_padding'} + $self->{'offset'}) + 1,($self->{'width'} - $self->{'horizontal_padding'} / 3) - 1,($self->{'vertical_padding'} + $self->{'helix_height'} - $self->{'offset'}) - 1,$dark_grey1); 276 $self->{'im'}->filledRectangle(($self->{'horizontal_padding'} / 3) + 2,($self->{'vertical_padding'} + $self->{'offset'}) + 2,($self->{'width'} - $self->{'horizontal_padding'} / 3) - 2,($self->{'vertical_padding'} + $self->{'helix_height'} - $self->{'offset'}) - 2,$dark_grey2); 277 $self->{'im'}->filledRectangle(($self->{'horizontal_padding'} / 3) + 3,($self->{'vertical_padding'} + $self->{'offset'}) + 3,($self->{'width'} - $self->{'horizontal_padding'} / 3) - 3,($self->{'vertical_padding'} + $self->{'helix_height'} - $self->{'offset'}) - 3,$dark_grey3); 278 279 ## label membrane 280 if ($self->{'ttf_font'}){ 281 $self->{'im'}->stringFT($self->{'white'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($self->{'horizontal_padding'} + ($self->{'helix_count'} * $self->{'helix_width'}) + (($self->{'helix_count'} - 1) * $self->{'loop_width'}) + 4) + 1,($self->{'vertical_padding'} + $self->{'helix_height'} - $self->{'offset'} - 3),$self->{'membrane'},{linespacing=>0.6,charmap => 'Unicode',}) if $self->{'labels'}; 282 }else{ 283 $self->{'im'}->string(gdSmallFont,($self->{'horizontal_padding'} + ($self->{'helix_count'} * $self->{'helix_width'}) + (($self->{'helix_count'} - 1) * $self->{'loop_width'}) + 4) + 1,($self->{'vertical_padding'} + $self->{'helix_height'} - $self->{'offset'} - 14),$self->{'membrane'},$self->{'white'}) if $self->{'labels'}; 284 } 285 286 287 return $self; 288 289} 290 291sub draw_helices { 292 293 my $self = shift; 294 295 my $x = $self->{'horizontal_padding'}; 296 my $y = $self->{'vertical_padding'}; 297 298 my ($colour,$colour1,$colour2,$colour3,$colour4,$colour5,$colour6); 299 300 if($self->{'scheme'} eq 'blue'){ 301 302 $colour = $self->{'im'}->colorAllocate(90,160,255); 303 $colour1 = $self->{'im'}->colorAllocate(80,150,255); 304 $colour2 = $self->{'im'}->colorAllocate(70,140,255); 305 $colour3 = $self->{'im'}->colorAllocate(60,130,255); 306 $colour4 = $self->{'im'}->colorAllocate(50,120,255); 307 $colour5 = $self->{'im'}->colorAllocate(40,110,255); 308 $colour6 = $self->{'im'}->colorAllocate(30,100,255); 309 310 }elsif($self->{'scheme'} eq 'pink'){ 311 312 $colour = $self->{'im'}->colorAllocate(255,1,255); 313 $colour1 = $self->{'im'}->colorAllocate(240,1,255); 314 $colour2 = $self->{'im'}->colorAllocate(230,1,255); 315 $colour3 = $self->{'im'}->colorAllocate(220,1,255); 316 $colour4 = $self->{'im'}->colorAllocate(200,1,255); 317 $colour5 = $self->{'im'}->colorAllocate(180,1,255); 318 $colour6 = $self->{'im'}->colorAllocate(160,1,255); 319 320 }elsif($self->{'scheme'} eq 'green'){ 321 322 $colour = $self->{'im'}->colorAllocate(5,240,0); 323 $colour1 = $self->{'im'}->colorAllocate(5,230,0); 324 $colour2 = $self->{'im'}->colorAllocate(5,220,0); 325 $colour3 = $self->{'im'}->colorAllocate(5,205,0); 326 $colour4 = $self->{'im'}->colorAllocate(5,195,0); 327 $colour5 = $self->{'im'}->colorAllocate(5,185,0); 328 $colour6 = $self->{'im'}->colorAllocate(5,155,0); 329 330 }elsif($self->{'scheme'} eq 'red'){ 331 332 $colour = $self->{'im'}->colorAllocate(240,0,0); 333 $colour1 = $self->{'im'}->colorAllocate(230,0,0); 334 $colour2 = $self->{'im'}->colorAllocate(220,0,0); 335 $colour3 = $self->{'im'}->colorAllocate(205,0,0); 336 $colour4 = $self->{'im'}->colorAllocate(190,0,0); 337 $colour5 = $self->{'im'}->colorAllocate(170,0,0); 338 $colour6 = $self->{'im'}->colorAllocate(150,0,0); 339 340 }elsif($self->{'scheme'} eq 'white'){ 341 342 $colour = $self->{'white'}; 343 $colour1 = $self->{'white'}; 344 $colour2 = $self->{'white'}; 345 $colour3 = $self->{'white'}; 346 $colour4 = $self->{'white'}; 347 $colour5 = $self->{'black'}; 348 $colour6 = $self->{'black'}; 349 350 }else{ 351 352 ## default is yellow 353 354 $colour = $self->{'im'}->colorAllocate(255,235,55); 355 $colour1 = $self->{'im'}->colorAllocate(255,230,50); 356 $colour2 = $self->{'im'}->colorAllocate(255,220,40); 357 $colour3 = $self->{'im'}->colorAllocate(255,210,30); 358 $colour4 = $self->{'im'}->colorAllocate(255,200,20); 359 $colour5 = $self->{'im'}->colorAllocate(255,190,10); 360 $colour6 = $self->{'im'}->colorAllocate(255,180,0); 361 } 362 363 364 for (1..$self->{'helix_count'}){ 365 366 ## draw helix, with graduated fill 367 $self->{'im'}->filledRectangle($x,$y,($x + $self->{'helix_width'})-1,($y + $self->{'helix_height'})-1,$colour6); 368 $self->{'im'}->filledRectangle($x+1,$y+1,($x + $self->{'helix_width'})-1,($y + $self->{'helix_height'})-1,$colour5); 369 $self->{'im'}->filledRectangle($x+2,$y+2,($x + $self->{'helix_width'})-2,($y + $self->{'helix_height'})-2,$colour4); 370 $self->{'im'}->filledRectangle($x+3,$y+3,($x + $self->{'helix_width'})-3,($y + $self->{'helix_height'})-3,$colour3); 371 $self->{'im'}->filledRectangle($x+4,$y+4,($x + $self->{'helix_width'})-4,($y + $self->{'helix_height'})-4,$colour2); 372 $self->{'im'}->filledRectangle($x+5,$y+5,($x + $self->{'helix_width'})-5,($y + $self->{'helix_height'})-5,$colour1); 373 $self->{'im'}->filledRectangle($x+6,$y+6,($x + $self->{'helix_width'})-6,($y + $self->{'helix_height'})-6,$colour); 374 375 ## draw a white box around it 376 if ($self->{'bold_helices'}){ 377 $self->{'im'}->rectangle($x,$y,($x + $self->{'helix_width'}),($y + $self->{'helix_height'}),$self->{'black'}); 378 $self->{'im'}->rectangle($x - 1,$y - 1,($x + $self->{'helix_width'} + 1),($y + $self->{'helix_height'} + 1),$self->{'white'}); 379 }else{ 380 $self->{'im'}->rectangle($x,$y,($x + $self->{'helix_width'}),($y + $self->{'helix_height'}),$self->{'white'}); 381 } 382 383 ## this is the text on each helix 384 my $text = substr($self->{'helix_label'},0,1).$_; 385 386 ## draw a white box in the centre and label the helix 387 my $x_offset = 5; 388 $x_offset = 8 if $_ >= 10; 389 390 my $white_box = 12; 391 $white_box = 17 if $_ >= 10; 392 393 $self->{'im'}->filledRectangle(($x + ($self->{'helix_width'} / 2) - $x_offset) - 5,($y + ($self->{'helix_height'} / 2) - 7) - 3,$white_box + ($x + ($self->{'helix_width'} / 2) - $x_offset) + 3,12 + ($y + ($self->{'helix_height'} / 2) - 4),$colour1) if $self->{'labels'}; 394 $self->{'im'}->filledRectangle(($x + ($self->{'helix_width'} / 2) - $x_offset) - 4,($y + ($self->{'helix_height'} / 2) - 7) - 2,$white_box + ($x + ($self->{'helix_width'} / 2) - $x_offset) + 2,12 + ($y + ($self->{'helix_height'} / 2) - 5),$colour2) if $self->{'labels'}; 395 $self->{'im'}->filledRectangle(($x + ($self->{'helix_width'} / 2) - $x_offset) - 3,($y + ($self->{'helix_height'} / 2) - 7) - 1,$white_box + ($x + ($self->{'helix_width'} / 2) - $x_offset) + 1,12 + ($y + ($self->{'helix_height'} / 2) - 6),$colour3) if $self->{'labels'}; 396 397 398 $self->{'im'}->filledRectangle(($x + ($self->{'helix_width'} / 2) - $x_offset) - 2,($y + ($self->{'helix_height'} / 2) - 7),$white_box + ($x + ($self->{'helix_width'} / 2) - $x_offset),12 + ($y + ($self->{'helix_height'} / 2) - 7),$self->{'white'}) if $self->{'labels'}; 399 400 if ($self->{'ttf_font'}){ 401 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($x + ($self->{'helix_width'} / 2) - $x_offset - 1),($y + ($self->{'helix_height'} / 2) + 4),$text,{linespacing=>0.6,charmap => 'Unicode',}) if $self->{'labels'}; 402 }else{ 403 $self->{'im'}->string(gdSmallFont,($x + ($self->{'helix_width'} / 2) - $x_offset),($y + ($self->{'helix_height'} / 2) - 7),$text,$self->{'black'}) if $self->{'labels'}; 404 } 405 406 ## label start and end positions of helices 407 408 $self->{'x'} = $x; 409 $self->{'y'} = $y; 410 411 if ($self->{'labels'}){ 412 413 if (($self->{'n_term'} eq 'out')&&($_ % 2)){ 414 415 $self->label_helix_o_i(); 416 417 }elsif($self->{'n_term'} eq 'out'){ 418 419 $self->label_helix_i_o(); 420 421 }elsif(($self->{'n_term'} eq 'in')&&($_ % 2)){ 422 423 $self->label_helix_i_o(); 424 425 }else{ 426 427 $self->label_helix_o_i(); 428 429 } 430 } 431 432 $x = $self->{'horizontal_padding'} + ($_ * ($self->{'helix_width'} + $self->{'loop_width'})); 433 434 } 435 436 if ($self->{'labels'}){ 437 438 $x = $self->{'horizontal_padding'}; 439 $y = $self->{'vertical_padding'}; 440 441 for (1..$self->{'helix_count'}){ 442 443 my $y_mod = 0; 444 445 foreach my $l (sort {$b <=> $a} keys %{$self->{'loop_labels'}}){ 446 447 if (($l >= $self->{'helix_span'}{$_}{'start'})&&($l <= $self->{'helix_span'}{$_}{'stop'})){ 448 449 my $label_length = 0; 450 if ($self->{'ttf_font'}){ 451 ## Might need to fiddle with this 452 my $size_dif = $self->{'ttf_font_size'} - 8; 453 $label_length = 6 + (6 * (length $self->{'loop_labels'}{$l}) + (8 * $size_dif)); 454 }else{ 455 $label_length = 9 + (6 * length $self->{'loop_labels'}{$l}); 456 } 457 458 if ($_ % 2){ 459 460 if ($self->{'bold_labels'}){ 461 $self->{'im'}->filledRectangle(($x + ($self->{'helix_width'} / 2)) + 5,($y + ($self->{'helix_height'} / 2) - 30) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2)) + 2,12 + ($y + ($self->{'helix_height'} / 2) - 24) + $y_mod,$self->{'black'}); 462 my $b = new GD::Polygon; 463 $b->addPt(($x + ($self->{'helix_width'} / 2)) + 4,($y + ($self->{'helix_height'} / 2) - 30) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2))); 464 $b->addPt(($x + ($self->{'helix_width'} / 2)) - 5,($y + ($self->{'helix_height'} / 2) - 21) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2))); 465 $b->addPt(($x + ($self->{'helix_width'} / 2)) + 4,($y + ($self->{'helix_height'} / 2) - 12) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2))); 466 $self->{'im'}->filledPolygon($b,$self->{'black'}); 467 } 468 469 ## add darker box 470 $self->{'im'}->filledRectangle(($x + ($self->{'helix_width'} / 2)) + 6,($y + ($self->{'helix_height'} / 2) - 29) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2)) + 1,12 + ($y + ($self->{'helix_height'} / 2) - 25) + $y_mod,$colour6); 471 ## add white box 472 $self->{'im'}->filledRectangle(($x + ($self->{'helix_width'} / 2)) + 7,($y + ($self->{'helix_height'} / 2) - 28) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2)),12 + ($y + ($self->{'helix_height'} / 2) - 26) + $y_mod,$self->{'white'}); 473 474 475 ## draw darker arrowhead 476 my $poly = new GD::Polygon; 477 $poly->addPt(($x + ($self->{'helix_width'} / 2)) + 5,($y + ($self->{'helix_height'} / 2) - 29) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2))); 478 $poly->addPt(($x + ($self->{'helix_width'} / 2)) - 3,($y + ($self->{'helix_height'} / 2) - 21) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2))); 479 $poly->addPt(($x + ($self->{'helix_width'} / 2)) + 5,($y + ($self->{'helix_height'} / 2) - 13) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2))); 480 $self->{'im'}->filledPolygon($poly,$colour6); 481 482 ## draw white arrowhead 483 my $poly2 = new GD::Polygon; 484 $poly2->addPt(($x + ($self->{'helix_width'} / 2)) + 6,($y + ($self->{'helix_height'} / 2) - 28) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2))); 485 $poly2->addPt(($x + ($self->{'helix_width'} / 2)) - 1,($y + ($self->{'helix_height'} / 2) - 21) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2))); 486 $poly2->addPt(($x + ($self->{'helix_width'} / 2)) + 6,($y + ($self->{'helix_height'} / 2) - 14) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2))); 487 $self->{'im'}->filledPolygon($poly2,$self->{'white'}); 488 489 ## add label 490 if ($self->{'ttf_font'}){ 491 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($x + ($self->{'helix_width'} / 2)) + 10,($y + ($self->{'helix_height'} / 2) - 16) + $y_mod,$self->{'loop_labels'}{$l},{linespacing=>0.6,charmap => 'Unicode',}); 492 }else{ 493 $self->{'im'}->string(gdSmallFont,($x + ($self->{'helix_width'} / 2)) + 9,($y + ($self->{'helix_height'} / 2) - 27) + $y_mod,$self->{'loop_labels'}{$l},$self->{'black'}); 494 } 495 496 $y_mod = $y_mod - 19; 497 498 }else{ 499 500 if ($self->{'bold_labels'}){ 501 $self->{'im'}->filledRectangle(($x + ($self->{'helix_width'} / 2)) + 5,($y + ($self->{'helix_height'} / 2) + 9) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2)) + 2,13 + ($y + ($self->{'helix_height'} / 2) + 15) + $y_mod,$self->{'black'}); 502 my $b = new GD::Polygon; 503 $b->addPt(($x + ($self->{'helix_width'} / 2)) + 4,($y + ($self->{'helix_height'} / 2) + 10) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2))); 504 $b->addPt(($x + ($self->{'helix_width'} / 2)) - 5,($y + ($self->{'helix_height'} / 2) + 19) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2))); 505 $b->addPt(($x + ($self->{'helix_width'} / 2)) + 4,($y + ($self->{'helix_height'} / 2) + 28) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2))); 506 $self->{'im'}->filledPolygon($b,$self->{'black'}); 507 } 508 509 ## add darker box 510 $self->{'im'}->filledRectangle(($x + ($self->{'helix_width'} / 2)) + 6,($y + ($self->{'helix_height'} / 2) + 11) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2)) + 1,12 + ($y + ($self->{'helix_height'} / 2) + 15) + $y_mod,$colour6); 511 512 ## add white box 513 $self->{'im'}->filledRectangle(($x + ($self->{'helix_width'} / 2)) + 7,($y + ($self->{'helix_height'} / 2) + 12) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2)),12 + ($y + ($self->{'helix_height'} / 2) + 14) + $y_mod,$self->{'white'}); 514 515 ## draw darker arrowhead 516 my $poly = new GD::Polygon; 517 $poly->addPt(($x + ($self->{'helix_width'} / 2)) + 5,($y + ($self->{'helix_height'} / 2) + 11) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2))); 518 $poly->addPt(($x + ($self->{'helix_width'} / 2)) - 3,($y + ($self->{'helix_height'} / 2) + 19) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2))); 519 $poly->addPt(($x + ($self->{'helix_width'} / 2)) + 5,($y + ($self->{'helix_height'} / 2) + 27) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2))); 520 $self->{'im'}->filledPolygon($poly,$colour6); 521 522 ## draw white arrowhead 523 my $poly2 = new GD::Polygon; 524 $poly2->addPt(($x + ($self->{'helix_width'} / 2)) + 6,($y + ($self->{'helix_height'} / 2) + 12) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2))); 525 $poly2->addPt(($x + ($self->{'helix_width'} / 2)) - 1,($y + ($self->{'helix_height'} / 2) + 19) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2))); 526 $poly2->addPt(($x + ($self->{'helix_width'} / 2)) + 6,($y + ($self->{'helix_height'} / 2) + 26) + $y_mod,$label_length + ($x + ($self->{'helix_width'} / 2))); 527 $self->{'im'}->filledPolygon($poly2,$self->{'white'}); 528 529 ## add label 530 if ($self->{'ttf_font'}){ 531 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($x + ($self->{'helix_width'} / 2)) + 10,($y + ($self->{'helix_height'} / 2) + 24) + $y_mod,$self->{'loop_labels'}{$l},{linespacing=>0.6,charmap => 'Unicode',}); 532 }else{ 533 $self->{'im'}->string(gdSmallFont,($x + ($self->{'helix_width'} / 2)) + 9,($y + ($self->{'helix_height'} / 2) + 12) + $y_mod,$self->{'loop_labels'}{$l},$self->{'black'}); 534 } 535 536 $y_mod = $y_mod + 19; 537 } 538 } 539 } 540 541 $x = $self->{'horizontal_padding'} + ($_ * ($self->{'helix_width'} + $self->{'loop_width'})); 542 } 543 } 544 545 return $self; 546} 547 548sub draw_terminai { 549 550 my $self = shift; 551 552 my $loop_number = ($self->{'helix_count'} - 1); 553 554 ## width of terminal 555 $self->{'w'} = $self->{'helix_width'} + $self->{'loop_width'}; 556 $self->{'cx'} = $self->{'horizontal_padding'} - ($self->{'loop_width'} / 2); 557 $self->{'cy'} = $self->{'vertical_padding'}; 558 559 ## draw N-terminal 560 if ($self->{'n_term'} eq 'out'){ 561 562 $self->{'im'}->arc(($self->{'cx'} - $self->{'n_term_offset'}),$self->{'cy'},($self->{'w'} + (2 * $self->{'n_term_offset'})),$self->{'n_terminal_height'},270,360,$self->{'black'}); 563 if ($self->{'ttf_font'}){ 564 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($self->{'horizontal_padding'} - ($self->{'w'} / 2) - 33 - $self->{'n_term_offset'}),($self->{'cy'} - ($self->{'n_terminal_height'} / 2) + 5),$self->{'n_term_label'},{linespacing=>0.6,charmap => 'Unicode',}) if $self->{'labels'}; 565 }else{ 566 $self->{'im'}->string(gdSmallFont,($self->{'horizontal_padding'} - ($self->{'w'} / 2) - 40 - $self->{'n_term_offset'}),($self->{'cy'} - ($self->{'n_terminal_height'} / 2) - 6),$self->{'n_term_label'},$self->{'black'}) if $self->{'labels'}; 567 } 568 569 570 571 ## label n-terminal 572 my $y_mod = 0; 573 foreach (sort {$b <=> $a} keys %{$self->{'loop_labels'}}){ 574 if ($_ <= $self->{'helix_span'}{1}{'start'}){ 575 576 if ($self->{'ttf_font'}){ 577 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($self->{'horizontal_padding'} - ($self->{'w'} / 2) - 33 - $self->{'n_term_offset'}),($self->{'cy'} - ($self->{'n_terminal_height'} / 2) - 6) - 4 + $y_mod,$self->{'loop_labels'}{$_},{linespacing=>0.6,charmap => 'Unicode',}) if $self->{'labels'}; 578 }else{ 579 $self->{'im'}->string(gdSmallFont,($self->{'horizontal_padding'} - ($self->{'w'} / 2) - 40 - $self->{'n_term_offset'}),($self->{'cy'} - ($self->{'n_terminal_height'} / 2) - 6) - 15 + $y_mod,$self->{'loop_labels'}{$_},$self->{'black'}) if $self->{'labels'}; 580 } 581 582 $y_mod = $y_mod - 15; 583 } 584 } 585 586 }else{ 587 $self->{'cy'} = $self->{'cy'} + $self->{'helix_height'}; 588 $self->{'im'}->arc(($self->{'cx'} - $self->{'n_term_offset'}),$self->{'cy'},($self->{'w'} + (2 * $self->{'n_term_offset'})),$self->{'n_terminal_height'},0,90,$self->{'black'}); 589 590 if ($self->{'ttf_font'}){ 591 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($self->{'horizontal_padding'} - ($self->{'w'} / 2) - 33 - $self->{'n_term_offset'}),($self->{'cy'} + ($self->{'n_terminal_height'} / 2) + 5),$self->{'n_term_label'},{linespacing=>0.6,charmap => 'Unicode',}) if $self->{'labels'}; 592 }else{ 593 $self->{'im'}->string(gdSmallFont,($self->{'horizontal_padding'} - ($self->{'w'} / 2) - 40 - $self->{'n_term_offset'}),($self->{'cy'} + ($self->{'n_terminal_height'} / 2) - 6),$self->{'n_term_label'},$self->{'black'}) if $self->{'labels'}; 594 } 595 596 ## label n-terminal 597 my $y_mod = 0; 598 foreach (sort {$a <=> $b} keys %{$self->{'loop_labels'}}){ 599 if ($_ <= $self->{'helix_span'}{1}{'start'}){ 600 601 if ($self->{'ttf_font'}){ 602 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($self->{'horizontal_padding'} - ($self->{'w'} / 2) - 33 - $self->{'n_term_offset'}),($self->{'cy'} + ($self->{'n_terminal_height'} / 2) - 6) + 26 + $y_mod,$self->{'loop_labels'}{$_},{linespacing=>0.6,charmap => 'Unicode',}) if $self->{'labels'}; 603 }else{ 604 $self->{'im'}->string(gdSmallFont,($self->{'horizontal_padding'} - ($self->{'w'} / 2) - 40 - $self->{'n_term_offset'}),($self->{'cy'} + ($self->{'n_terminal_height'} / 2) - 6) + 15 + $y_mod,$self->{'loop_labels'}{$_},$self->{'black'}) if $self->{'labels'}; 605 } 606 607 $y_mod = $y_mod + 15; 608 } 609 } 610 611 } 612 613 $self->{'cx'} = ($self->{'helix_count'} * $self->{'helix_width'}) + (($self->{'helix_count'} - 1) * $self->{'loop_width'}) + $self->{'horizontal_padding'} + ($self->{'loop_width'} / 2); 614 615 ## draw C-terminal 616 if (($self->{'n_term'} eq 'out')&&($loop_number % 2)){ 617 618 $self->draw_ext_c_term; 619 620 }elsif($self->{'n_term'} eq 'out'){ 621 622 $self->draw_int_c_term; 623 624 }elsif(($self->{'n_term'} eq 'in')&&($loop_number % 2)){ 625 626 $self->draw_int_c_term; 627 628 }elsif($self->{'n_term'} eq 'in'){ 629 630 $self->draw_ext_c_term; 631 632 } 633 634 return $self; 635} 636 637sub draw_loops { 638 639 my $self = shift; 640 641 $self->{'x'} = $self->{'horizontal_padding'} + ($self->{'helix_width'} / 2); 642 $self->{'h'} = $self->{'medium_loop'}; 643 $self->{'w'} = $self->{'helix_width'} + $self->{'loop_width'}; 644 645 for (1..($self->{'helix_count'} - 1)){ 646 647 ## Alter loop height according to its actual length 648 if ($self->{'loop_length'}{$_} < $self->{'short_loop_limit'}){ 649 $self->{'h'} = $self->{'short_loop'}; 650 }elsif($self->{'loop_length'}{$_} > $self->{'long_loop_limit'}){ 651 $self->{'h'} = $self->{'long_loop'}; 652 } 653 654 $self->{'l_start'} = $self->{'helix_span'}{$_}{'stop'}; 655 $self->{'l_stop'} = $self->{'helix_span'}{$_ + 1}{'start'}; 656 657 if (($self->{'n_term'} eq 'out')&&($_ % 2)){ 658 659 $self->draw_int_loop; 660 661 }elsif($self->{'n_term'} eq 'out'){ 662 $self->draw_ext_loop; 663 664 }elsif(($self->{'n_term'} eq 'in')&&($_ % 2)){ 665 $self->draw_ext_loop; 666 667 }elsif($self->{'n_term'} eq 'in'){ 668 669 $self->draw_int_loop; 670 671 } 672 673 $self->{'x'} = $self->{'x'} + $self->{'helix_width'} + $self->{'loop_width'}; 674 $self->{'x'} = $self->{'horizontal_padding'} if $_ == ($self->{'helix_count'} - 1); 675 676 } 677 678 return $self; 679} 680 681sub label_helix_o_i { 682 683 my $self = shift; 684 685 my $offset = 6; 686 $offset = 3 if $self->{'helix_span'}{$_}{'start'} < 100; 687 if ($self->{'ttf_font'}){ 688 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($self->{'x'} + ($self->{'helix_width'} / 2) - $offset) - 1,$self->{'y'} + 13,$self->{'helix_span'}{$_}{'start'},{linespacing=>0.6,charmap => 'Unicode',}); 689 }else{ 690 $self->{'im'}->string(gdSmallFont,($self->{'x'} + ($self->{'helix_width'} / 2) - $offset) - 1,$self->{'y'} + 1,$self->{'helix_span'}{$_}{'start'},$self->{'black'}); 691 } 692 693 $offset = 3 if $self->{'helix_span'}{$_}{'stop'} < 100; 694 $offset = 6 if $self->{'helix_span'}{$_}{'stop'} >= 100; 695 696 if ($self->{'ttf_font'}){ 697 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($self->{'x'} + ($self->{'helix_width'} / 2) - $offset) - 1,($self->{'y'} + $self->{'helix_height'} - 3),$self->{'helix_span'}{$_}{'stop'},{linespacing=>0.6,charmap => 'Unicode',}); 698 }else{ 699 $self->{'im'}->string(gdSmallFont,($self->{'x'} + ($self->{'helix_width'} / 2) - $offset) - 1,($self->{'y'} + $self->{'helix_height'} - 14),$self->{'helix_span'}{$_}{'stop'},$self->{'black'}); 700 } 701 702 return $self; 703} 704 705sub label_helix_i_o { 706 707 my $self = shift; 708 709 my $offset = 6; 710 $offset = 3 if $self->{'helix_span'}{$_}{'stop'} < 100; 711 if ($self->{'ttf_font'}){ 712 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($self->{'x'} + ($self->{'helix_width'} / 2) - $offset) - 1,$self->{'y'} + 13,$self->{'helix_span'}{$_}{'stop'},{linespacing=>0.6,charmap => 'Unicode',}); 713 }else{ 714 $self->{'im'}->string(gdSmallFont,($self->{'x'} + ($self->{'helix_width'} / 2) - $offset) - 1,$self->{'y'} + 1,$self->{'helix_span'}{$_}{'stop'},$self->{'black'}); 715 } 716 717 $offset = 3 if $self->{'helix_span'}{$_}{'start'} < 100; 718 719 if ($self->{'ttf_font'}){ 720 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($self->{'x'} + ($self->{'helix_width'} / 2) - $offset) - 1,($self->{'y'} + $self->{'helix_height'} - 3),$self->{'helix_span'}{$_}{'start'},{linespacing=>0.6,charmap => 'Unicode',}); 721 }else{ 722 $self->{'im'}->string(gdSmallFont,($self->{'x'} + ($self->{'helix_width'} / 2) - $offset) - 1,($self->{'y'} + $self->{'helix_height'} - 14),$self->{'helix_span'}{$_}{'start'},$self->{'black'}); 723 } 724 725 return $self; 726} 727 728sub draw_int_c_term { 729 730 my $self = shift; 731 732 ## draw internal c-terminal 733 $self->{'im'}->arc(($self->{'cx'} + $self->{'c_term_offset'}),($self->{'vertical_padding'} + $self->{'helix_height'}),($self->{'w'} + (2 * $self->{'c_term_offset'})),$self->{'c_terminal_height'},90,180,$self->{'black'}); 734 735 if ($self->{'ttf_font'}){ 736 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($self->{'cx'} + 4 + $self->{'c_term_offset'}),(($self->{'vertical_padding'} + $self->{'helix_height'}) + ($self->{'c_terminal_height'} / 2) + 5),$self->{'c_term_label'},{linespacing=>0.6,charmap => 'Unicode',}) if $self->{'labels'}; 737 }else{ 738 $self->{'im'}->string(gdSmallFont,($self->{'cx'} + 3 + $self->{'c_term_offset'}),(($self->{'vertical_padding'} + $self->{'helix_height'}) + ($self->{'c_terminal_height'} / 2) - 6),$self->{'c_term_label'},$self->{'black'}) if $self->{'labels'}; 739 } 740 741 ## label terminal 742 if ($self->{'labels'}){ 743 my $y_mod = 0; 744 foreach (sort {$a <=> $b} keys %{$self->{'loop_labels'}}){ 745 if ($_ >= $self->{'helix_span'}{$self->{'helix_count'}}{'stop'}){ 746 747 if ($self->{'ttf_font'}){ 748 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($self->{'cx'} + 4 + $self->{'c_term_offset'}),(($self->{'vertical_padding'} + $self->{'helix_height'}) + ($self->{'c_terminal_height'} / 2) - 6) + 26 + $y_mod,$self->{'loop_labels'}{$_},{linespacing=>0.6,charmap => 'Unicode',}) if $self->{'labels'}; 749 }else{ 750 $self->{'im'}->string(gdSmallFont,($self->{'cx'} + 3 + $self->{'c_term_offset'}),(($self->{'vertical_padding'} + $self->{'helix_height'}) + ($self->{'c_terminal_height'} / 2) - 6) + 15 + $y_mod,$self->{'loop_labels'}{$_},$self->{'black'}); 751 } 752 $y_mod = $y_mod + 15; 753 } 754 } 755 } 756 return $self; 757} 758 759sub draw_ext_c_term { 760 761 my $self = shift; 762 763 ## draw external c-terminal 764 $self->{'im'}->arc(($self->{'cx'} + $self->{'c_term_offset'}),$self->{'vertical_padding'},($self->{'w'} + (2 * $self->{'c_term_offset'})),$self->{'c_terminal_height'},180,270,$self->{'black'}); 765 766 if ($self->{'ttf_font'}){ 767 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,,($self->{'cx'} + 3 + $self->{'c_term_offset'}),($self->{'vertical_padding'} - ($self->{'c_terminal_height'} / 2) + 5),$self->{'c_term_label'},{linespacing=>0.6,charmap => 'Unicode',}) if $self->{'labels'}; 768 }else{ 769 $self->{'im'}->string(gdSmallFont,($self->{'cx'} + 3 + $self->{'c_term_offset'}),($self->{'vertical_padding'} - ($self->{'c_terminal_height'} / 2) - 6),$self->{'c_term_label'},$self->{'black'}) if $self->{'labels'}; 770 } 771 772 773 ## label terminal 774 if ($self->{'labels'}){ 775 my $y_mod = 0; 776 foreach (sort {$b <=> $a} keys %{$self->{'loop_labels'}}){ 777 if ($_ >= $self->{'helix_span'}{$self->{'helix_count'}}{'stop'}){ 778 779 if ($self->{'ttf_font'}){ 780 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($self->{'cx'} + 3 + $self->{'c_term_offset'}),($self->{'vertical_padding'} - ($self->{'c_terminal_height'} / 2) - 6) - 4 - $y_mod,$self->{'loop_labels'}{$_},{linespacing=>0.6,charmap => 'Unicode',}) if $self->{'labels'}; 781 }else{ 782 $self->{'im'}->string(gdSmallFont,($self->{'cx'} + 3 + $self->{'c_term_offset'}),($self->{'vertical_padding'} - ($self->{'c_terminal_height'} / 2) - 6) - 15 - $y_mod,$self->{'loop_labels'}{$_},$self->{'black'}); 783 } 784 $y_mod = $y_mod + 15; 785 } 786 } 787 } 788 return $self; 789} 790 791sub draw_int_loop { 792 793 my $self = shift; 794 795 ## draw internal loop 796 $self->{'cx'} = $self->{'x'} + ($self->{'helix_width'} / 2) + ($self->{'loop_width'} / 2); 797 798 ## this sets the height to the value given by the loop_heights hash 799 foreach (sort {$a <=> $b} keys %{$self->{'loop_heights'}}){ 800 $self->{'h'} = $self->{'loop_heights'}{$_} if $_ == $self->{'loop_count'}; 801 } 802 803 $self->{'im'}->arc($self->{'cx'},($self->{'vertical_padding'} + $self->{'helix_height'}),$self->{'w'},$self->{'h'},0,180,$self->{'black'}); 804 805 ## label loop 806 if ($self->{'labels'}){ 807 my $y_mod = 0; 808 foreach (sort {$a <=> $b} keys %{$self->{'loop_labels'}}){ 809 if (($_ >= $self->{'l_start'})&&($_ <= $self->{'l_stop'})){ 810 $self->{'im'}->line($self->{'cx'},($self->{'vertical_padding'} + $self->{'helix_height'} + ($self->{'h'} / 2)),$self->{'cx'},($self->{'vertical_padding'} + $self->{'helix_height'} + ($self->{'h'} / 2) + 5),$self->{'black'}) unless $y_mod; 811 812 if ($self->{'ttf_font'}){ 813 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($self->{'cx'} + $self->{'text_offset'} - 3),($self->{'vertical_padding'} + $self->{'helix_height'} + ($self->{'h'} / 2) + 17) + $y_mod,$self->{'loop_labels'}{$_},{linespacing=>0.6,charmap => 'Unicode',}) if $self->{'labels'}; 814 }else{ 815 $self->{'im'}->string(gdSmallFont,($self->{'cx'} + $self->{'text_offset'}),($self->{'vertical_padding'} + $self->{'helix_height'} + ($self->{'h'} / 2) + 6) + $y_mod,$self->{'loop_labels'}{$_},$self->{'black'}) ; 816 } 817 $y_mod = $y_mod + 15; 818 } 819 } 820 } 821 $self->{'loop_count'}++; 822 return $self; 823} 824 825sub draw_ext_loop { 826 827 my $self = shift; 828 829 ## draw external loop 830 $self->{'cx'} = $self->{'x'} + ($self->{'helix_width'} / 2) + ($self->{'loop_width'} / 2); 831 832 ## this sets the height to the value given by the loop_heights hash 833 foreach (sort {$a <=> $b} keys %{$self->{'loop_heights'}}){ 834 $self->{'h'} = $self->{'loop_heights'}{$_} if $_ == $self->{'loop_count'}; 835 } 836 837 $self->{'im'}->arc($self->{'cx'},$self->{'vertical_padding'},$self->{'w'},$self->{'h'},180,360,$self->{'black'}); 838 839 ## label loop 840 if ($self->{'labels'}){ 841 my $y_mod = 0; 842 foreach (sort {$b <=> $a} keys %{$self->{'loop_labels'}}){ 843 if (($_ >= $self->{'l_start'})&&($_ <= $self->{'l_stop'})){ 844 $self->{'im'}->line($self->{'cx'},($self->{'vertical_padding'} - ($self->{'h'} / 2)),$self->{'cx'},($self->{'vertical_padding'} - ($self->{'h'} / 2) - 5),$self->{'black'}) unless $y_mod; 845 846 if ($self->{'ttf_font'}){ 847 $self->{'im'}->stringFT($self->{'black'},$self->{'ttf_font'},$self->{'ttf_font_size'},0,($self->{'cx'} + $self->{'text_offset'} - 3),($self->{'vertical_padding'} - ($self->{'h'} / 2) - 8) + $y_mod,$self->{'loop_labels'}{$_},{linespacing=>0.6,charmap => 'Unicode',}) if $self->{'labels'}; 848 }else{ 849 $self->{'im'}->string(gdSmallFont,($self->{'cx'} + $self->{'text_offset'}),($self->{'vertical_padding'} - ($self->{'h'} / 2) - 19) + $y_mod,$self->{'loop_labels'}{$_},$self->{'black'}); 850 } 851 852 $y_mod = $y_mod - 15; 853 } 854 } 855 } 856 $self->{'loop_count'}++; 857 return $self; 858} 859 8601; 861 862=head1 NAME 863 864Bio::Graphics::DrawTransmembrane - draw a cartoon of an Alpha-helical transmembrane protein. 865 866=head1 SYNOPSIS 867 868 use Bio::Graphics::DrawTransmembrane; 869 my @topology = (20,45,59,70,86,109,145,168,194,220); 870 871 ## Simple use - -topology is the only option that is required 872 873 my $im = Bio::Graphics::DrawTransmembrane->new( 874 -title => 'This is a cartoon displaying transmembrane helices.', 875 -topology => \@topology); 876 877 ## More advanced use 878 my %labels = (5 => '5 - Sulphation Site', 879 21 => '1st Helix', 880 47 => '40 - Mutation', 881 60 => 'Voltage Sensor', 882 72 => '72 - Mutation 2', 883 73 => '73 - Mutation 3', 884 138 => '138 - Glycosylation Site', 885 170 => '170 - Phosphorylation Site', 886 200 => 'Last Helix'); 887 888 my $im = Bio::Graphics::DrawTransmembrane->new(-n_terminal=> 'out', 889 -topology => \@topology, 890 -bold_helices=> 1, 891 -labels=> \%labels, 892 -text_offset=> -15, 893 -outside_label=>'Lumen', 894 -inside_label=>'Cytoplasm', 895 -membrane_label=>'Membrane', 896 -vertical_padding=> 155); 897 898 ## Parse Tmhmm data 899 use Bio::Tools::Tmhmm; 900 my $im = Bio::Graphics::DrawTransmembrane->new( 901 -title=>'Let\'s parse some Tmhmm output...', 902 -bold_helices=> 1); 903 open(FILE, 'tmhmm.out'); 904 my $parser = new Bio::Tools::Tmhmm(-fh => \*FILE ); 905 while(my $tmhmm_feat = $parser->next_result ) { 906 ## Load features into DrawTransmembrane object 907 $im->add_tmhmm_feat($tmhmm_feat); 908 } 909 close FILE; 910 911 ## Now write the image to a .png file 912 open(OUTPUT, ">output.png"); 913 binmode OUTPUT; 914 print OUTPUT $im->png; 915 close OUTPUT; 916 917=head1 DESCRIPTION 918 919A module to draw a cartoon of an alpha-helical transmembrane 920protein. It uses GD and allows the image to be written to a .png file. 921 922The options are a set of tag/value pairs as follows: 923 924 Option Value Default 925 ------ ----- ------- 926 927 -topology Array containing transmembrane helix none 928 boundaries. This is the only option that 929 is required 930 931 -topology_string Alternative to -topology, provide a string none 932 containing the topology data in the form 933 A.11,31;B.41,59;C.86,107;D.145,166 934 935 -n_terminal Location of the N-terminal of the sequence, out 936 either 'in' or 'out' 937 938 -title Title to add to the image none 939 940 -inside_label Label for the inside of the membrane Cytoplasmic 941 942 -outside_label Label for the outside of the membrane Extracellular 943 944 -membrane_label Label for the membrane Plasma Membrane 945 946 -colour_scheme Colour scheme to use. Current choices are blue 947 blue, yellow, red, green, pink or white. 948 949 -labels Label loops and helices using data from a none 950 hash, e.g. 951 952 %labels = (138 => 'Glycosylation Site', 953 190 => 'Binding Site'); 954 955 The hash key must be numeric, ranges are 956 not allowed. 957 958 -bold_helices Draws black boxes round helices 1 959 960 -bold_labels Draws black boxes round labels 0 961 962 -text_offset Shift the text labeling the loops. Use a 0 963 negative value to shift it left, a positive 964 value to shift it right 965 966 -helix_height Transmembrane helix height 130 967 968 -helix_width Transmembrane helix width 50 969 970 -loop_width Loop width 20 971 972 -vertical_padding Vertical padding 140 973 974 -horizontal_padding Horizontal Padding 150 975 976 -membrane_offset Offest between helix end and membrane 6 977 978 -short_loop_height Height of short loops 90 979 980 -medium_loop_height Height of medium loops 120 981 982 -long_loop_height Height of long loops 150 983 984 -short_loop_limit Length in residues below which a loop is 15 985 classed as short 986 987 -long_loop_limit Length in residues above which a loop is 30 988 classed as long 989 990 -loop_heights Explicitly set heights of each loop, e.g. 991 992 %loop_heights = (1 => 45, 993 2 => 220, 994 3 => 50, 995 4 => 220, 996 9 => 70); 997 998 The key corresponds to the loop number. Both 999 key and value must be numeric. If you use 1000 -loop_height and there is a defined height 1001 for the current loop then other height values 1002 will be overridden 1003 1004 -n_terminal_height Height of N-terminal 150 1005 1006 -c_terminal_height Height of C-terminal 80 1007 1008 -n_terminal_offset Shift the N-terminal left by this amount 0 1009 1010 -c_terminal_offset Shift the C-terminal right by this amount 0 1011 1012 -helix_label Change the 'S' label on each helix. Only 1 S 1013 character is allowed 1014 1015 -show_labels Display text labels on 1016 1017 -draw_cytosol Show the cytosol false 1018 1019 -draw_bilayer Show the membrane true 1020 1021 -draw_loops Show the loops true 1022 1023 -draw_terminai Show the terminai true 1024 1025 -draw_helices Show the helices true 1026 1027 -dontsort Don't automatically sort the topology array 0 1028 1029 -ttf_font Path to TTF font, e.g. none 1030 /usr/share/fonts/msttcorefonts/arial.ttf 1031 1032 -ttf_font_size Default size for TTF font. Use 7-9 with 8 1033 Arial for best results 1034 1035 1036Height, width, padding and other numerical values can gernerally be 1037left alone. They are useful if your labels consists of a lot of text 1038as this may lead to them overlapping. In this case try increasing the 1039loop_width or helix_width options. -text_offset is also very useful 1040for avoiding overlapping. 1041 1042=head1 AUTHOR 1043 1044Tim Nugent E<lt>timnugent@gmail.comE<gt> 1045 1046=cut 1047