Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi all,

So here's what I'm trying to do. Pull back some data from a mysql database and graph the object in a circular format. I need the object to be selectable, clickable, and show their names on a mouse over. I ran into a problem playing with start & extent (arc features) last night and discovered something not good. Apparently, it will not properly draw an angle with an extent smaller that 0.08 degrees. If you use extent= 0.08, everything is cool, but if you use extent=0.07 then suddenly it draws an entire circle, erasing everything else that was there. Many of the central angles that I calculate (see scripts and comments below) come out to be < 0.07, so this becomes a roadblock. I've had to go back to my original idea of drawing full overlapping arcs and see if I can make it fit into you desired pattern that I need. This of course makes selection, mouse over hard. Any help ideas, greatly appreciated. Here's the code:

#!C:\Perl\bin # Test Widget to try and draw circular genome # by Mark # # Created 08.19.03 # Revised 08.20.03 # # ver. 0.02 use Cwd; use DBI; use Digest::MD5 qw(md5_hex); use LWP::Simple; use Text::Wrap; use lib 'lib'; use lib 'vg/lib'; use lib '../lib'; use Tk; use Tk::LabEntry; use Tk::Dialog; use Tk::DialogBox; use Tk::TableMatrix; use Tk::ProgressBar; use Tk::ROText; use Tk::Optionmenu; use Win32; use Win32::Process; use Import::Genbank qw(gbk_org_info gbk_write_orfs); use Functions qw( mysystem ); use Globals; use strict; use warnings; # DEBUG! # use RG::Fasta; use RG::DB::Protein; use RG::DB::Org; use RG::DB::Contig; use RG::GUI::Orfscan; use RG::GUI::ProteinInspector; use RG::DNA; use RG::Block; use RG::ButtonBar; use RG::Canvas; use RG::ContigAsm; use RG::ContigAsmP; use RG::ContigAsmS; use RG::ContigAsmY; use RG::Ephemera; use RG::FileIO; use RG::Menubar; use RG::Organism; use RG::PropTable; use RG::ScatterPlot; use Tk::MyBalloon; #use Math; our($dbh,$sth,%myorfs,@orfids); # Define database connection $dbh = DBI->connect('dbi:mysql:genomatik','genomatik','3369',{ RaiseEr +ror => 1,AutoCommit => 1 }); # grab protein positions for halodurans, org_id 106 $sth = $dbh->prepare ("select text_id,gene_name,protein5, protein3 fro +m protein where org_id=64 order by protein5 desc") or die "Can't prep +are SQL statement ", $dbh->errstr(),"\n"; $sth->execute() or die "Can't execute SQL statement: ", $sth->errstr() +, "\n"; my $count=0; while (my($text_id,$gene_name,$protein5,$protein3) = $sth->fetchrow_ar +ray()) { $myorfs{$count}= [$text_id,$gene_name,$protein5,$protein3]; $count++; } @orfids = keys(%myorfs); my $orfcount = $#orfids+1; print" There are $orfcount orfs in halodurans\n"; my $mw = MainWindow->new(); $mw ->title("Circular Genome View"); my $canvas = $mw->Canvas(-height=>600, -width=> 600, -background=> 'wh +ite')->pack(); # Create area to display ORF ID's my $message; my $orf_label = $mw->Label(-textvariable=> \$message, -borderwidth=> 2 +, -relief=> 'groove')->pack(-fill => 'x',-side=>'bottom'); my ($x1,$y1,$x2,$y2,$x_offset,$y_offset,$circumference,$pi,$genome_len +gth,$radius); my @colors = qw/grey purple pink blue turquoise green chartreuse yello +w gold orange/; # Mathmatical Basis # # For a circle with central angle A, arc length S and circumference C, # S/C = A/360 degrees. Therefore A = 360(S/2*pi*radius) # # Since we draw the longest arc (last orf) first, we just draw a full +circle. After that, # the calculated central_angle is added to drawn_angle. As we draw the + other orfs, the arc that is drawn # is 360 - drawn_angle. The central_angle is added to drawn_angle so t +hat the next one will be placed # correctly. $pi = 3.1417; $x_offset = 25; $y_offset = 25; $x1 = $x_offset; $y1 = $y_offset; $x2 = $x_offset + 650; $y2 = $y_offset + 650; $circumference = 2 * ($x2 - $x1) * $pi; # defi +ne circumference $radius = $circumference/2; # define r +adius my @orf_keys = keys %myorfs; my $drawn_angle=0; my ($remaining_angle,$actual_angle); $genome_length=0; foreach my $key(@orf_keys) { my $distance = $myorfs{$key}[3] - $myorfs{$key}[2]; # calc orf len +gth $genome_length = $genome_length + $distance; # calc total g +enome length } print "circum = $circumference\ngenome length= $genome_length\n"; foreach my $key(@orf_keys) { my $color = int($key % 10); my $orig_dist = $myorfs{$key}[3] - $myorfs{$key}[2]; # calc origin +al orf length my $orf_pct = $orig_dist/$genome_length; # convert orf + length to pct of genome length my $graph_arc_length = $circumference * $orf_pct; # calc equiva +lent arc length corresponding to same pct of circumference my $central_angle = 360 * ($graph_arc_length / $circumference); #(2 + * $pi * $radius)); # calc central angle for that arc if ($drawn_angle == 0) { $canvas->createArc($x1,$y1,$x2,$y2, -width=> 10, -fill=> $colors +[$color],-outline=> $colors[$color],-style=> 'arc', -start=>90, -exte +nt=> -359.99); &bind_message($canvas,"Edg-1"); # Display gene name when mou +se is over it. $drawn_angle = $central_angle; } elsif($drawn_angle < 359) { $actual_angle = 360 - $drawn_angle; $canvas->createArc($x1,$y1,$x2,$y2, -width=> 10, -fill=> $colors +[$color],-outline=> $colors[$color],-style=> 'arc', -start=>90, -exte +nt=> -$actual_angle); $drawn_angle = $drawn_angle + $central_angle; } } # Graph Label $canvas->createText($x_offset+375, $y_offset+375, -fill => 'black', -t +ext => 'Halodurans Genome'); $canvas->createText($x_offset+375, $y_offset+390, -fill => 'black', -t +ext => "$genome_length bp"); #$canvas->configure(-scrollregion=> [$canvas->bbox("all")]); $mw->deiconify(); $mw->raise(); MainLoop; # Displays value of $message in lower box when mouse is over item, goe +s back to null when mouse leaves. sub bind_message { my($widget, $msg) = @_; $widget->Tk::bind('<Enter>', [ sub { $message = $_[1]; }, $msg ]); $widget->Tk::bind('<Leave>', sub { $message = ""; }); }
Thanks again for any help.

-Mark

Replies are listed 'Best First'.
Re: drawing circles, arc help
by TomDLux (Vicar) on Aug 31, 2003 at 02:06 UTC

    sin( 0.08 ) = 0.001396263. Therefore, to get an arc one pixel wide at the widest point, ,the circle would need to be 1/ 0.001396263 = 716.1974766 pixels radius, call it 716 pixels.

    Any arc smaller would be indistinguishable from a straight line, frfom the center to the point on the cicumference .... if you are only drawing the arc, you would have a point for arc less that 0.08 degrees, when you switch to an arc of two points.

    --
    TTTATCGGTCGTTATATAGATGTTTGCA

Re: drawing circles, arc help
by herveus (Prior) on Aug 31, 2003 at 00:00 UTC
    Howdy!

    traveler The #! line identifies the system as Windows.

    I hacked together a test on MacOSX/XDarwin. Even with a angle down to 0.04, I still had a few pixels I could identify as being part of that segment (although nowhere near the full width of the band). I'd suspect limitations on your platform.

    I note that you have an ordering defined for your data (in the select statement), but you then stuff the data into a hash instead of an array. You then pull the keys out of the hash, losing your ordering. The arcs are in no particular order. I bet you didn't want that.

    Far simpler would be to push the data into an array.

    I've not dug into the details of why the mouse-over message doesn't work; you need to do your bind differently.

    I think you do have the basic idea there, but it has rough edges and some really pointy bits that ought not be pointy.

    yours,
    Michael

Re: drawing circles, arc help
by traveler (Parson) on Aug 30, 2003 at 22:47 UTC
    It would help if you would tell us what OS you are using (so we know what the underlying windowing system is) and what verssion of Tk you have. Also, a small program to demonstarte the problem would help: I do not have a database with the right data in it to test this program. If you could do a simple Tk program that shows the problem, it would sure help.

    I have heard of problems with some graphics libraries drawing incomplete circles when told to draw 360 degrees, but I think this is a different problem.

    --traveler