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