]> git.donarmstrong.com Git - wheel.git/blob - wheel.pl
61655cf228f60c77a1536c001ef4a74d73c671ad
[wheel.git] / wheel.pl
1 #! /usr/bin/perl -w
2 # wheel.pl: Draw alpha helical wheel with hydrophobic moment using
3 # wif (modifiable to woct) scale.
4 # Copyright (C) 2001 Don Armstrong and Raphael Zidovetzki
5
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20
21
22
23 my $VERSION="0.10 p06 12/14/2001 DLA";
24
25 # Intial Released Version 0.10
26 # p01: Fixing displayed angle
27 # p02: Added arrowhead, fixed lack of return in xy2deg(), added no color option
28 # p03: Added round function, fixed rounding in angles, changed hm to line, added hm_up option
29 # p04: Removed bounding box
30 # p05: Changing user interface to allow simultaneous viewing of options and wheel
31 # p06: Released to public under GPL
32
33 use CGI::Carp qw(fatalsToBrowser);
34 use strict;
35 use CGI;
36
37 use Math::Trig;
38 use GD;
39 use GD::Text::Align;
40 use POSIX;
41
42
43 sub round($) {
44   my ($a) = @_;
45   return (floor $a+0.5);
46 }
47
48 sub min($$){
49   my ($a,$b)=@_;
50   if ($a>$b) {
51     return $b;
52   }
53   return $a;
54 }
55
56 sub max($$){
57   my ($a,$b)=@_;
58   if ($a<$b) {
59     return $b;
60   }
61   return $a;
62 }
63
64 my $q = new CGI;
65
66 sub xy2deg($$) {
67   my ($x,$y) = @_;
68   my $angle = rad2deg(atan($x/$y));
69   if ($y<0) {
70     $angle+=180;
71   }
72   elsif ($angle<0) {
73     $angle+=360;
74   }
75   return $angle;
76 }
77
78 sub calculate_hydrophobic_moment($$){
79   my ($sequence,$param)=@_;
80   my $phe=$param->{phe};
81   my $theta=$param->{theta};
82   my ($x,$y)=(0,0);
83   foreach my $amino_acid (split(//,$sequence)) {
84     $x+=-$param->{aa}->{$amino_acid}->{wif} * sin($phe);
85     $y+=+$param->{aa}->{$amino_acid}->{wif} * cos($phe);
86     $phe+=$theta;
87   }
88   return ($x,$y);
89 }
90
91
92 sub draw_wheel($$$){
93   my ($im,$aasequence,$param)=@_;
94   my $phe=$param->{phe};
95   my $aanumber=0;
96   my $point1;
97   my @points;
98   foreach my $aminoacid (split(//,$aasequence)) {
99     push @points, calculate_geometry($param,$phe);
100     $phe += $param->{theta};
101     $aanumber++;
102     last if ($aanumber>18);
103   }
104   for ($aanumber=0;$aanumber<19;$aanumber++) {
105     my $point = pop @points;
106     last if (!defined $point);
107     if ($aanumber>0) {
108       draw_connection($im,$aanumber,$point1,$point);
109     }
110     $point1 = $point;
111   }
112   $phe = $param->{phe};
113   $aanumber = 0;
114   foreach my $aminoacid (split(//,$aasequence)) {
115     $point1=calculate_geometry($param,$phe);
116     draw_aa($im,$aminoacid,
117             $param->{centerx}+($point1->{bx}-$param->{centerx})*
118             ($param->{d}+2.2*$param->{r}*POSIX::floor($aanumber/18))/
119             $param->{d},$param->{centery}+($point1->{by}-$param->{centery})*
120             ($param->{d}+2.2*$param->{r}*POSIX::floor($aanumber/18))/
121             $param->{d},$phe,$param,$aanumber);
122     $phe+=$param->{theta};
123     $aanumber++;
124   }
125   my ($hydro_x,$hydro_y) = calculate_hydrophobic_moment($aasequence,$param);
126   draw_hydrophobic_moment($im,$hydro_x,$hydro_y,$param);
127 }
128
129 sub draw_hydrophobic_moment($$$$){
130   my ($im,$x,$y,$param)=@_;
131   my $norm=($x*$x+$y*$y)**(0.5);
132   my $angle = xy2deg($x,-$y);
133   if ($norm !=0 and $param->{hmscale}!=0) {
134     $x=$x/$norm*$param->{hmscale};
135     $y=$y/$norm*$param->{hmscale};
136   }
137
138   # Draw Moment Line (Box, really)
139   my $poly = GD::Polygon->new;
140   print STDERR "$angle\n";
141   $poly->addPt($param->{centerx}-round(($param->{hmscale}/50)*sin(deg2rad($angle+90))),
142                $param->{centery}+round(($param->{hmscale}/50)*cos(deg2rad($angle+90))));
143   $poly->addPt($param->{centerx}+round($x*0.85-($param->{hmscale}/50)*sin(deg2rad($angle+90))),
144                $param->{centery}+round($y*0.85+($param->{hmscale}/50)*cos(deg2rad($angle+90))));
145   $poly->addPt($param->{centerx}+round($x*0.85-($param->{hmscale}/50)*sin(deg2rad($angle-90))),
146                $param->{centery}+round($y*0.85+($param->{hmscale}/50)*cos(deg2rad($angle-90))));
147   $poly->addPt($param->{centerx}-round(($param->{hmscale}/50)*sin(deg2rad($angle-90))),
148                $param->{centery}+round(($param->{hmscale}/50)*cos(deg2rad($angle-90))));
149   $im->filledPolygon($poly,$param->{black});
150
151   # Draw Arowhead
152   undef $poly;
153   $poly = GD::Polygon->new;
154   $poly->addPt($param->{centerx}+$x,$param->{centery}+$y);
155   $poly->addPt($param->{centerx}+$x-round(($param->{hmscale}/5)*sin(deg2rad($angle+20))),
156                $param->{centery}+$y+round(($param->{hmscale}/5)*cos(deg2rad($angle+20))));
157   $poly->addPt($param->{centerx}+$x-round(($param->{hmscale}/5)*sin(deg2rad($angle-20))),
158                $param->{centery}+$y+round(($param->{hmscale}/5)*cos(deg2rad($angle-20))));
159   $im->filledPolygon($poly,$param->{black});
160   my $text= GD::Text::Align->new($im,
161                                  valign => 'center',
162                                  halign => 'center',
163                                  color=> $param->{black},
164                                 );
165   $text->set_font('/usr/share/fonts/truetype/Florsn01.ttf',$param->{fontsize2});
166   if ($param->{disp_hm_angle}) {
167     $text->set_text(POSIX::floor($norm*100+.5)/100 . '@' . POSIX::floor(($angle*10+0.5))/10);
168   }
169   else {
170     $text->set_text(POSIX::floor($norm*100+.5)/100);
171   }
172   my $offset=-10-$param->{fontsize2}/2;
173   if ($y<0) {
174     $offset=-$offset;
175   }
176   $text->draw($param->{centerx},$param->{centery}+$offset);
177 }
178
179 sub draw_connection($$$$) {
180   my ($im,$aanumber,$point1,$point2) =  @_;
181   my $color=$im->colorAllocate(240*((18-$aanumber)/18),
182                                240*((18-$aanumber)/18),
183                                240*((18-$aanumber)/18)
184                               );
185   my $poly = GD::Polygon->new;
186   $poly->addPt($point1->{ex},$point1->{ey});
187   $poly->addPt($point2->{ex},$point2->{ey});
188   $poly->addPt($point2->{cx},$point2->{cy});
189   $poly->addPt($point1->{cx},$point1->{cy});
190   $im->filledPolygon($poly,$color);
191   return;
192 }
193
194 sub calculate_geometry($$){
195   my ($param,$phe)=@_;
196   return {bx=>($param->{d})*sin($phe)+$param->{centerx},
197           cx=>($param->{d}-($param->{w}/2)/sin((pi-$param->{theta})/2))*sin($phe)+$param->{centerx},
198           dx=>($param->{centerx}),
199           ex=>($param->{d}+($param->{w}/2)/sin((pi-$param->{theta})/2))*sin($phe)+$param->{centerx},
200           by=>-($param->{d})*cos($phe)+$param->{centery},
201           cy=>-($param->{d}-($param->{w}/2)/sin((pi-$param->{theta})/2))*cos($phe)+$param->{centery},
202           dy=>($param->{centery}),
203           ey=>-($param->{d}+($param->{w}/2)/sin((pi-$param->{theta})/2))*cos($phe)+$param->{centery},
204          };
205 }
206
207
208 sub draw_n_gon($$$$){
209   my ($x,$y,$r,$n)=@_;
210   my $ngon=GD::Polygon->new;
211   for (my $v = 0;$v<$n;$v++) {
212     $ngon->addPt($x+$r*sin((2*pi/$n)*$v),$y-$r*cos((2*pi/$n)*$v));
213   }
214   return($ngon);
215 }
216
217 sub draw_aa($$$$$$$){
218   my ($im,$aasymbol,$bx,$by,$phe,$param,$aanumber)=@_;
219   my $r=$param->{r};
220
221   my $ax=$bx;
222   my $ay=$by;
223   $_ = $param->{aa}->{$aasymbol}->{shape};
224   if (defined && /square/) {
225     $im->filledRectangle($ax-$r,$ay-$r,$ax+$r,$ay+$r,$param->{aa}->{$aasymbol}->{bcolor});
226     $im->rectangle($ax-$r,$ay-$r,$ax+$r,$ay+$r,$param->{aa}->{$aasymbol}->{fcolor});
227   }
228   elsif (defined && /triangle/) {
229     $im->filledPolygon(draw_n_gon($ax,$ay,1.25*$r,3),
230                        $param->{aa}->{$aasymbol}->{bcolor});
231     $im->polygon(draw_n_gon($ax,$ay,1.25*$r,3),
232                  $param->{aa}->{$aasymbol}->{fcolor});
233   }
234   elsif (defined && /hexagon/) {
235     $im->filledPolygon(draw_n_gon($ax,$ay,1.18*$r,6),
236                      $param->{aa}->{$aasymbol}->{bcolor});
237     $im->polygon(draw_n_gon($ax,$ay,1.18*$r,6),
238                  $param->{aa}->{$aasymbol}->{fcolor});
239   }
240   elsif (defined && /diamond/) {
241     $im->filledPolygon(draw_n_gon($ax,$ay,1.25*$r,4),
242                       $param->{aa}->{$aasymbol}->{bcolor});
243     $im->polygon(draw_n_gon($ax,$ay,1.25*$r,4),
244                  $param->{aa}->{$aasymbol}->{fcolor});
245   }
246   elsif (defined && /pentagon/) {
247     $im->filledPolygon(draw_n_gon($ax,$ay,1.2*$r,5),
248                       $param->{aa}->{$aasymbol}->{bcolor});
249     $im->polygon(draw_n_gon($ax,$ay,1.2*$r,5),
250                  $param->{aa}->{$aasymbol}->{fcolor});
251   }
252   elsif (defined && /octagon/){
253     $im->filledPolygon(draw_n_gon($ax,$ay,1.1*$r,8),
254                       $param->{aa}->{$aasymbol}->{bcolor});
255     $im->polygon(draw_n_gon($ax,$ay,1.1*$r,8),
256                  $param->{aa}->{$aasymbol}->{fcolor});
257   }
258   else {  #cicle
259     $im->filledPolygon(draw_n_gon($ax,$ay,$r*0.99,360),
260                       $param->{aa}->{$aasymbol}->{bcolor});
261     $im->arc($ax,$ay,2*$r,2*$r,0,360,$param->{aa}->{$aasymbol}->{fcolor});
262   }
263   $im->fill($ax,$ay,$param->{aa}->{$aasymbol}->{bcolor});
264   my $text= GD::Text::Align->new($im,
265                                  valign => 'center',
266                                  halign => 'center',
267                                  color=> $param->{black},
268                                 );
269   $text->set_font('/usr/share/fonts/truetype/Florsn01.ttf',$param->{fontsize});
270   my $label_text=$aasymbol  . abs($aanumber+$param->{indexaa});
271   $text->set_text($label_text);
272   $text->draw($ax,$ay,0);
273 }
274
275
276 if (defined $q->param('draw') and $q->param('draw')=~/yes/) {
277   my $param={
278              indexaa=>1,
279              d=>320,
280              centerx=>500,
281              centery=>500,
282              xsize=>1000,
283              ysize=>1000,
284              w=>14,
285              theta=>(100/180)*pi,
286              phe=>(0/180)*pi,
287              r=>40,
288              fontsize=>20,
289              fontsize2=>20,
290              hmscale=>50,
291              wifcolor=>1,
292              maxwif=>0.5802,
293              minwif=>-1.8502,
294              hmdisp=>'',
295             };
296   # Merge in query params
297   # DGwoct[woct] and DGwif[wif] are octanol and interface hydrophobicity values
298   # as seen on http://blanco.biomol.uci.edu/Whole_residue_HFscales.txt
299   # and used in MPEx.
300   # Wimley and White
301   # Nature Struc. Biol 3:842 (1996) [wif values]
302   # Wimley, Creamer and White
303   # Biochemistry 34:5108 (1996) [woct values]
304
305   $param->{aa} = {G=>{name=>'Glycine',
306                       abbr=>'gly',
307                       woct=>1.15,
308                       wif=>0.01,
309                      },
310                   A=>{name=>'Alanine',
311                       abbr=>'ala',
312                       woct=>0.50,
313                       wif=>0.17,
314                      },
315                   V=>{name=>'Valine',
316                       abbr=>'val',
317                       woct=>-0.46,
318                       wif=>0.07,
319                      },
320                   L=>{name=>'Leucine',
321                       abbr=>'leu',
322                       woct=>-1.25,
323                       wif=>-0.56,
324                       shape=>'diamond',
325                      },
326                   I=>{name=>'Isoleucine',
327                       abbr=>'ile',
328                       woct=>-1.12,
329                       wif=>-0.31,
330                       shape=>'diamond',
331                      },
332                   M=>{name=>'Methionine',
333                       abbr=>'met',
334                       woct=>-0.67,
335                       wif=>-0.23,
336                       shape=>'diamond',
337                      },
338                   P=>{name=>'Proline',
339                       abbr=>'pro',
340                       woct=>0.14,
341                       wif=>0.45,
342                      },
343                   F=>{name=>'Phenylalanine',
344                       abbr=>'phe',
345                       woct=>-1.71,
346                       wif=>-1.13,
347                       shape=>'diamond',
348                      },
349                   W=>{name=>'Tryptophan',
350                       abbr=>'trp',
351                       woct=>-2.09,
352                       wif=>-1.85,
353                       shape=>'diamond',
354                      },
355                   S=>{name=>'Serine',
356                       abbr=>'ser',
357                       woct=>0.46,
358                       wif=>0.13,
359                      },
360                   T=>{name=>'Threonine',
361                       abbr=>'thr',
362                       woct=>0.25,
363                       wif=>0.14,
364                      },
365                   N=>{name=>'Asparagine',
366                       abbr=>'asn',
367                       woct=>0.85,
368                       wif=>0.42,
369                       charged=>1,
370                       fill=>[187,187,255],
371                       border=>[187,187,255],
372                       shape=>'triangle',
373                      },
374                   Q=>{name=>'Glutamine',
375                       abbr=>'gln',
376                       woct=>0.77,
377                       wif=>0.58,
378                      },
379                   Y=>{name=>'Tyrosine',
380                       abbr=>'tyr',
381                       woct=>-0.71,
382                       wif=>-0.94,
383                       shape=>'diamond',
384                      },
385                   C=>{name=>'Cysteine',
386                       abbr=>'cys',
387                       woct=>-0.02,
388                       wif=>-0.24,
389                       shape=>'diamond',
390                      },
391                   K=>{name=>'Lysine',
392                       abbr=>'lys',
393                       woct=>2.80,
394                       wif=>0.99,
395                       shape=>'pentagon',
396                       fill=>[187,187,255],
397                       border=>[187,187,255],
398                      },
399                   R=>{name=>'Arginine',
400                       abbr=>'arg',
401                       woct=>1.81,
402                       wif=>0.81,
403                       shape=>'pentagon',
404                       fill=>[187,187,255],
405                       border=>[187,187,255],
406                      },
407                   H=>{name=>'Histidine',
408                       abbr=>'his',
409                       woct=>2.33,
410                       wif=>0.96,
411                       shape=>'pentagon',
412                       fill=>[187,187,255],
413                       border=>[187,187,255],
414                      },
415                   D=>{name=>'Aspartic Acid',
416                       abbr=>'asp',
417                       woct=>3.64,
418                       wif=>1.23,
419                       shape=>'triangle',
420                       fill=>[187,187,255],
421                       border=>[187,187,255],
422                      },
423                   E=>{name=>'Glutamic Acid',
424                       abbr=>'glu',
425                       woct=>3.63,
426                       wif=>2.02,
427                       shape=>'triangle',
428                       fill=>[187,187,255],
429                       border=>[187,187,255],
430                      },
431                  };
432   foreach my $param_key ($q->param) {
433     my $param_value=$q->param($param_key);
434     if ($param_value=~/^(\-{0,1}\d*\.{0,1}\d+)$/) {
435       $param->{$param_key}=$q->param($param_key);
436       if ($param_key=~/^(phe|theta|hmdisp)$/) {
437         $param->{$param_key}=$param->{$param_key}/180*pi;
438       }
439     }
440   }
441   if ($q->param('disp_hm_angle') =~ /on/) {
442     $param->{'disp_hm_angle'}=1;
443   }
444   else {
445     $param->{'disp_hm_angle'}=0;
446   }
447   if ($q->param('reverse_helix') =~ /on/) {
448     $param->{'reverse_helix'}=1;
449   }
450   else {
451     $param->{'reverse_helix'}=0;
452   }
453   if ($q->param('wo_color') =~ /on/) {
454     $param->{'wifcolor'}=0;
455   }
456   else {
457     $param->{'wifcolor'}=1;
458   }
459   my $im = new GD::Image($param->{xsize},$param->{ysize});
460   $param->{white} = $im->colorAllocate(255,255,255);
461   $param->{black} = $im->colorAllocate(0,0,0);
462   $param->{red} = $im->colorAllocate(255,0,0);
463   $param->{blue} = $im->colorAllocate(0,0,255);
464   foreach my $aminoacid (keys %{$param->{aa}}) {
465     if ($param->{wifcolor} && $param->{aa}->{$aminoacid}->{wif}<=$param->{maxwif} && !(defined $param->{aa}->{$aminoacid}->{charged} && $param->{aa}->{$aminoacid}->{charged})) {
466       $param->{aa}->{$aminoacid}->{fcolor} =
467         $im->colorAllocate(min(($param->{aa}->{$aminoacid}->{wif}-$param->{minwif})/
468                                (0-$param->{minwif})*255,255),
469                            255-max(($param->{aa}->{$aminoacid}->{wif})/
470                                    ($param->{maxwif}),0)*255,0);
471     }
472     elsif ($param->{wifcolor} && defined $param->{aa}->{$aminoacid}->{border}) {
473       $param->{aa}->{$aminoacid}->{fcolor} = $im->colorAllocate($param->{aa}->{$aminoacid}->{border}[0],
474                                                       $param->{aa}->{$aminoacid}->{border}[1],
475                                                       $param->{aa}->{$aminoacid}->{border}[2]);
476     }
477     else {
478       $param->{aa}->{$aminoacid}->{fcolor} = $param->{black};
479     }
480     if ($param->{wifcolor} && $param->{aa}->{$aminoacid}->{wif}<=$param->{maxwif} && !(defined $param->{aa}->{$aminoacid}->{charged} && $param->{aa}->{$aminoacid}->{charged})) {
481       $param->{aa}->{$aminoacid}->{bcolor} =
482         $im->colorAllocate(min(($param->{aa}->{$aminoacid}->{wif}-$param->{minwif})/
483                                (0-$param->{minwif})*255,255),
484                            255-max(($param->{aa}->{$aminoacid}->{wif})/
485                                    ($param->{maxwif}),0)*255,0);
486     }
487     elsif ($param->{wifcolor} && defined $param->{aa}->{$aminoacid}->{fill}) {
488       $param->{aa}->{$aminoacid}->{bcolor} = $im->colorAllocate($param->{aa}->{$aminoacid}->{fill}[0],
489                                                       $param->{aa}->{$aminoacid}->{fill}[1],
490                                                       $param->{aa}->{$aminoacid}->{fill}[2]);
491     }
492     else {
493       $param->{aa}->{$aminoacid}->{bcolor} = $param->{white};
494     }
495   }
496 # Draw Bounding Box
497 #  $im->rectangle(0,0,$param->{xsize}-1,$param->{ysize}-1,$param->{black});
498   my $aasequence = $q->param('sequence');
499   $aasequence =~ s/[^AC-IK-NP-TV-WY]//gs;
500   if ($param->{reverse_helix}) {
501     my $aaseq=$aasequence;
502     $param->{indexaa}*=-1;
503     my $numberofaa=0;
504     $aasequence='';
505     foreach my $aa(split(//,$aaseq)) {
506       $aasequence = $aa . $aasequence;
507       $numberofaa++;
508     }
509     $param->{indexaa}-=$numberofaa-1;
510     $param->{theta}*=-1;
511   }
512   print STDERR "hmdisp: $param->{hmdisp}\n";
513   if ($param->{'hmdisp'} =~ /^(\-{0,1}\d*\.{0,1}\d+)$/) {
514     my ($x,$y) = calculate_hydrophobic_moment($aasequence,$param);
515     $param->{phe} = - deg2rad(xy2deg($x,-$y)) + $param->{'hmdisp'};
516     print STDERR $param->{phe};
517   }
518   draw_wheel($im,$aasequence,$param);
519   print $q->header(-type=>'image/png');
520   print $im->png;
521
522 }
523
524 else {
525   print $q->header();
526   print $q->start_html('Helical Wheel Projections');
527   if (defined $q->param('submit') and $q->param('submit')=~/Submit/) {
528     print $q->h1('Wheel:'.$q->param('sequence'));
529     print $q->img({-src=>$q->self_url.'&draw=yes'});
530   }
531   print $q->h1('Helical Wheel Projections'),
532     $q->start_form(-method=>'GET'),
533       $q->table($q->Tr([
534                         $q->td({-bgcolor=>'#ddddff'},['Sequence:',
535                                                       $q->textarea(-name=>'sequence',
536                                                                    -rows=>5,
537                                                                    -columns=>50)
538                                                      ]),
539                         $q->td({-bgcolor=>'#bbbbff'},['Initial AA Number:',
540                                                       $q->textfield(-name=>'indexaa',
541                                                                     -size=>5,
542                                                                     -maxlength=>5
543                                                                    )
544                                                      ]),
545                         $q->td({-bgcolor=>'#ddddff'},['Initial AA Rotation:',
546                                                       $q->textfield(-name=>'phe',
547                                                                     -size=>6,
548                                                                     -maxlength=>6)
549                                                      ]),
550                         $q->td({-bgcolor=>'#ddddff'},['Per AA Rotation:',
551                                                       $q->textfield(-name=>'theta',
552                                                                     -size=>6,
553                                                                     -maxlength=>6)
554                                                      ]),
555                           $q->td({-bgcolor=>'#bbbbff'},['Xsize:',
556                                                         $q->textfield(-name=>'xsize',
557                                                                       -size=>5,
558                                                                       -maxlength=>5)
559                                                        ]),
560                           $q->td({-bgcolor=>'#ddddff'},['Ysize:',
561                                                         $q->textfield(-name=>'ysize',
562                                                                       -size=>5,
563                                                                       -maxlength=>5)
564                                                        ]),
565                           $q->td({-bgcolor=>'#bbbbff'},['CenterX:',
566                                                         $q->textfield(-name=>'centerx',
567                                                                       -size=>5,
568                                                                       -maxlength=>5)
569                                                        ]),
570                           $q->td({-bgcolor=>'#ddddff'},['CenterY:',
571                                                         $q->textfield(-name=>'centery',
572                                                                       -size=>5,
573                                                                       -maxlength=>5)
574                                                        ]),
575                           $q->td({-bgcolor=>'#bbbbff'},['Connection Width:',
576                                                         $q->textfield(-name=>'w',
577                                                                       -size=>5,
578                                                                       -maxlength=>5)
579                                                        ]),
580                           $q->td({-bgcolor=>'#ddddff'},['Symbol Size:',
581                                                         $q->textfield(-name=>'r',
582                                                                       -size=>5,
583                                                                       -maxlength=>5)
584                                                        ]),
585                           $q->td({-bgcolor=>'#bbbbff'},['Font Size:',
586                                                         $q->textfield(-name=>'fontsize',
587                                                                       -size=>5,
588                                                                       -maxlength=>5)
589                                                        ]),
590                           $q->td({-bgcolor=>'#ddddff'},['Graph Radius:',
591                                                         $q->textfield(-name=>'d',
592                                                                       -size=>5,
593                                                                       -maxlength=>5)
594                                                        ]),
595                           $q->td({-bgcolor=>'#bbbbff'},['HM Font Size:',
596                                                         $q->textfield(-name=>'fontsize2',
597                                                                       -size=>5,
598                                                                       -maxlength=>5)
599                                                        ]),
600                           $q->td({-bgcolor=>'#ddddff'},['HM Scale:',
601                                                         $q->textfield(-name=>'hmscale',
602                                                                       -size=>5,
603                                                                       -maxlength=>5)
604                                                        ]),
605                           $q->td({-bgcolor=>'#bbbbff'},['Display HM Angle:',
606                                                         $q->checkbox(-name=>'disp_hm_angle',
607                                                                     -checked=>'checked',
608                                                                     -label=>'')
609                                                        ]),
610                           $q->td({-bgcolor=>'#ddddff'},['Reverse Helix:',
611                                                       $q->checkbox(-name=>'reverse_helix',
612                                                                   -label=>'')
613                                                       ]),
614                           $q->td({-bgcolor=>'#bbbbff'},['No Color:',
615                                                       $q->checkbox(-name=>'wo_color',
616                                                                   -label=>'')
617                                                       ]),
618                           $q->td({-bgcolor=>'#ddddff'},['Hydrophobic Moment Displacement:',
619                                                       $q->textfield(-name=>'hmdisp',
620                                                                    -size=>5,
621                                                                    -maxlength=>5)
622                                                       ]),
623                           $q->td({-bgcolor=>'#bbbbff',-colspan=>2},
624                                  [$q->center($q->submit(-name=>'submit',-value=>'Submit'))
625                                  ]),
626                          ])
627                  ),
628           $q->endform,
629             $q->hr,$q->i("Created by ".$q->a({-href=>"mailto:don\@donarmstrong.com"},'Don Armstrong')." and Raphael Zidovetzki. Version: ".$q->b($VERSION));
630 }
631