From: martinahansen Date: Wed, 28 Oct 2009 17:19:29 +0000 (+0000) Subject: KISS browser working, but slow X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=f79ee71d49e20ebe6f52aa953d88756c862db3cd;p=biopieces.git KISS browser working, but slow git-svn-id: http://biopieces.googlecode.com/svn/trunk@714 74ccb610-7750-0410-82ae-013aeee3265d --- diff --git a/code_perl/Maasha/KISS/Draw.pm b/code_perl/Maasha/KISS/Draw.pm index 90ed4f6..6a8bc52 100644 --- a/code_perl/Maasha/KISS/Draw.pm +++ b/code_perl/Maasha/KISS/Draw.pm @@ -42,41 +42,13 @@ use vars qw( @ISA @EXPORT ); # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< -sub track_text -{ - # Given a sequence list add this to - # a Cairo::Context object. - - my ( $cr, # Cairo::Context object - $text, # List of hashrefs { txt =>, x => y => } - $color, # Color of features - ) = @_; - - # Returns nothing. - - $cr->set_source_rgb( color_name2rgb( $color ) ); - - my ( $txt ); - - $cr->set_font_size( 10 ); - - foreach $txt ( @{ $text } ) - { - $cr->move_to( $txt->{ 'x' }, $txt->{ 'y' } ); - $cr->show_text( $txt->{ 'txt' } ); - $cr->stroke(); - } -} - - -sub track_feature +sub draw_feature { # Given a list of features add these to # a Cairo::Context object. my ( $cr, # Cairo::Context object $features, # List of features - $color, # Color of features ) = @_; # Returns nothing. @@ -86,15 +58,27 @@ sub track_feature foreach $feature ( @{ $features } ) { $cr->set_source_rgb( color_name2rgb( $feature->{ 'color' } ) ); - $cr->move_to( $feature->{ 'x1' }, $feature->{ 'y1' } ); if ( $feature->{ 'type' } eq 'line' ) { $cr->set_line_width( $feature->{ 'line_width' } ); + $cr->move_to( $feature->{ 'x1' }, $feature->{ 'y1' } ); $cr->line_to( $feature->{ 'x2' }, $feature->{ 'y2' } ); } + elsif ( $feature->{ 'type' } eq 'rect' ) + { + $cr->rectangle( + $feature->{ 'x1' }, + $feature->{ 'y1' }, + $feature->{ 'x2' } - $feature->{ 'x1' }, + $feature->{ 'y2' } - $feature->{ 'y1' }, + ); + + $cr->fill; + } elsif ( $feature->{ 'type' } eq 'text' ) { + $cr->move_to( $feature->{ 'x1' }, $feature->{ 'y1' } ); $cr->set_font_size( $feature->{ 'font_size' } ); $cr->show_text( $feature->{ 'txt' } ); } diff --git a/code_perl/Maasha/KISS/IO.pm b/code_perl/Maasha/KISS/IO.pm index 15f4292..4c3ac14 100644 --- a/code_perl/Maasha/KISS/IO.pm +++ b/code_perl/Maasha/KISS/IO.pm @@ -31,6 +31,7 @@ package Maasha::KISS::IO; use warnings; use strict; use Data::Dumper; +use Maasha::Common; use Maasha::Filesys; use Maasha::SQL; use vars qw( @ISA @EXPORT ); @@ -155,7 +156,7 @@ sub kiss_sql_get my ( $sql, $entries ); # $sql = "SELECT * FROM $table WHERE S_BEG >= $s_beg AND S_END <= $s_end ORDER BY S_BEG,S_END"; - $sql = "SELECT S_BEG,S_END,ALIGN FROM $table WHERE S_BEG >= $s_beg AND S_END <= $s_end"; + $sql = "SELECT S_BEG,S_END,Q_ID,ALIGN FROM $table WHERE S_BEG >= $s_beg AND S_END <= $s_end"; $entries = Maasha::SQL::query_hashref_list( $dbh, $sql ); @@ -163,6 +164,143 @@ sub kiss_sql_get } +sub kiss_index +{ + # Martin A, Hansen, October 2009. + + # Creates an index of a sorted KISS file that + # allowing the location of the byte position + # from where records can be read given a + # specific S_BEG position. The index consists of + # triples: [ beg, end, bytepos ], where beg and + # end denotes the interval where the next KISS + # record begins at bytepos. + + my ( $fh, # filehandle to KISS file + ) = @_; + + # Returns a list. + + my ( $line, @fields, $beg, $end, $pos, @index ); + + $beg = 0; + $pos = 0; + + while ( $line = <$fh> ) + { + chomp $line; + + @fields = split /\t/, $line, 3; + + $end = $fields[ S_BEG ]; + + if ( $end == 0 ) + { + push @index, [ $beg, $end, $pos ]; + $beg = 1; + } + elsif ( $end > $beg ) + { + push @index, [ $beg, $end - 1, $pos ]; + $beg = $end; + } + elsif( $end < $beg ) + { + Maasha::Common::error( qq(KISS file not sorted: $end < $beg) ); + } + + $pos += 1 + length $line; + } + + return wantarray ? @index : \@index; +} + + +sub kiss_index_store +{ + my ( $path, + $index, + ) = @_; + + Maasha::Filesys::file_store( $path, $index ); +} + + +sub kiss_index_retrieve +{ + my ( $path, + ) = @_; + + my $index; + + $index = Maasha::Filesys::file_retrieve( $path ); + + return wantarray ? @{ $index } : $index; +} + + +sub kiss_index_search +{ + my ( $index, + $num, + ) = @_; + + # Returns a number. + + my ( $high, $low, $try ); + + $low = 0; + $high = scalar @{ $index }; + + while ( $low <= $high ) + { + $try = int( ( $high + $low ) / 2 ); + + # print "low: $low high: $high try: $try\n"; + + if ( $num < $index->[ $try ]->[ 0 ] ) { + $high = $try; + } elsif ( $num > $index->[ $try ]->[ 1 ] ) { + $low = $try + 1; + } else { + return $index->[ $try ]->[ 2 ]; + } + } + + Maasha::Common::error( "Could not find number->$num in index" ); +} + + +sub kiss_index_get +{ + my ( $file, + $beg, + $end, + ) = @_; + + my ( $index, $offset, $fh, $entry, @entries ); + + $index = Maasha::KISS::IO::kiss_index_retrieve( "$file.index" ); + + $offset = Maasha::KISS::IO::kiss_index_search( $index, $beg ); + + $fh = Maasha::Filesys::file_read_open( $file ); + + sysseek( $fh, $offset, 0 ); + + while ( $entry = kiss_entry_get( $fh ) ) + { + push @entries, $entry; + + last if $entry->{ 'S_END' } > $end; + } + + close $fh; + + return wantarray ? @entries : \@entries; +} + + sub kiss2biopiece { my ( $entry, # KISS entry diff --git a/code_perl/Maasha/KISS/Track.pm b/code_perl/Maasha/KISS/Track.pm index d0c7162..a815dfe 100644 --- a/code_perl/Maasha/KISS/Track.pm +++ b/code_perl/Maasha/KISS/Track.pm @@ -42,10 +42,12 @@ use vars qw( @ISA @EXPORT ); sub track_ruler { - my ( $width, # draw window width - $y_offset, # y axis draw offset - $beg, # base window beg - $end, # base window end + my ( $width, # draw window width + $y_offset, # y axis draw offset + $beg, # base window beg + $end, # base window end + $font_size, # font size + $color, # font color ) = @_; my ( $factor, $step, $i, $txt, $x, @ruler ); @@ -66,7 +68,17 @@ sub track_ruler $txt = "$i|"; $x = sprintf( "%.0f", ( $i - $beg - length $txt ) * $factor ); - push @ruler, { txt => $txt, x => $x, y => $y_offset }; + if ( $x > 0 and $x + ( $font_size * length $txt ) < $width ) + { + push @ruler, { + type => 'text', + txt => $txt, + font_size => $font_size, + color => $color, + x1 => $x, + y1 => $y_offset + }; + } } } @@ -76,9 +88,11 @@ sub track_ruler sub track_seq { - my ( $width, # draw window width - $y_offset, # y axis draw offset - $seq, # sequence to draw + my ( $width, # draw window width + $y_offset, # y axis draw offset + $seq, # sequence to draw + $font_size, # font size + $color, # font color ) = @_; my ( @chars, $factor, $i, @seq_list ); @@ -88,7 +102,14 @@ sub track_seq $factor = $width / @chars; for ( $i = 0; $i < @chars; $i++ ) { - push @seq_list, { txt => $chars[ $i ], x => sprintf( "%.0f", $i * $factor ), y => $y_offset }; + push @seq_list, { + type => 'text', + txt => $chars[ $i ], + font_size => $font_size, + color => $color, + x1 => sprintf( "%.0f", $i * $factor ), + y1 => $y_offset, + }; } return wantarray ? @seq_list : \@seq_list; @@ -130,13 +151,14 @@ sub track_feature $y1 = $y_offset + ( $feat_height * $y_step ); push @features, { - type => 'line', + type => 'rect', line_width => $feat_height, color => 'green', + title => $entry->{ 'Q_ID' }, x1 => $x1, y1 => $y1, x2 => $x1 + $w, - y2 => $y1, + y2 => $y1 + $feat_height, }; push @features, feature_align( $entry, $beg, $y1, $factor, $feat_height ) if defined $entry->{ 'ALIGN' }; @@ -184,24 +206,25 @@ sub feature_align $x1 = sprintf( "%.0f", ( $entry->{ 'S_BEG' } + $pos - $beg ) * $factor ); push @features, { - type => 'line', + type => 'rect', line_width => $feat_height, color => 'red', + title => $align, x1 => $x1, y1 => $y_offset, x2 => $x1 + $w, - y2 => $y_offset, + y2 => $y_offset + $feat_height, }; - if ( $w > 5 ) + if ( $w > $feat_height ) { push @features, { type => 'text', - font_size => $feat_height, + font_size => $feat_height + 2, color => 'black', txt => $nt_after, x1 => $x1 + sprintf( "%.0f", ( $w / 2 ) ) - $feat_height / 2, - y1 => $y_offset, + y1 => $y_offset + $feat_height, }; } } @@ -267,6 +290,7 @@ sub track_histogram type => 'line', line_width => $bucket_width, color => 'green', + title => "Features: $buckets[ $i ]", x1 => $x, y1 => $y_offset + $hist_height, x2 => $x, @@ -283,27 +307,6 @@ sub track_histogram } -sub bucket_round -{ - my ( $num, - $bucket_size, - ) = @_; - - my ( $div, $int ); - - $div = $num / $bucket_size; - $int = int $div; - - if ( $div - $int >= 0.5 ) { - return $bucket_size * ( $int + 1 ); - } else { - return $bucket_size * $int; - } -} - - # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 1; - - diff --git a/code_perl/Maasha/XHTML.pm b/code_perl/Maasha/XHTML.pm index 44a72ba..3a97af1 100755 --- a/code_perl/Maasha/XHTML.pm +++ b/code_perl/Maasha/XHTML.pm @@ -734,6 +734,23 @@ sub map_end } +sub area +{ + # Martin A. Hansen, October 2009. + + # HTML element + + my ( %args, + ) = @_; + + warn qq(WARNING: no area href given\n) if not $args{ "href" }; + warn qq(WARNING: no area shape given \n) if not $args{ "shape" }; + warn qq(WARNING: no area coords given \n) if not $args{ "coords" }; + + return tag_single( "area", \%args ) +} + + # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PRE <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< diff --git a/www/cgi-bin/index.cgi b/www/cgi-bin/index.cgi index 15bb1de..1b327bc 100755 --- a/www/cgi-bin/index.cgi +++ b/www/cgi-bin/index.cgi @@ -54,18 +54,18 @@ $script = Maasha::Common::get_scriptname(); push @html, Maasha::XHTML::html_header( cgi_header => 1, title => "KISS Genome Browser", -# css_file => "test.css", + css_file => "kiss.css", author => "Martin A. Hansen, mail\@maasha.dk", description => "Biopieces bacterial genome browser - KISS", keywords => [ qw( KISS Biopieces biopiece genome browser viewer bacterium bacteria prokaryote prokaryotes ) ], no_cache => 1, ); -push @html, Maasha::XHTML::h1( txt => "KISS Genome Browser", class => "center" ); +push @html, Maasha::XHTML::h1( txt => "KISS Genome Browser", class => 'center' ); push @html, Maasha::XHTML::form_beg( action => $script, method => "get", enctype => "multipart/form-data" ); push @html, sec_navigate( $cgi ); -push @html, sec_browse( $dbh, $cgi->param( 'nav_start' ), $cgi->param( 'nav_end' ) ); +push @html, sec_browse( $dbh, $cgi ); push @html, Maasha::XHTML::form_end; push @html, Maasha::XHTML::body_end; @@ -101,7 +101,7 @@ sub sec_navigate $def_start = nav_def_start( $cgi ); $def_end = nav_def_end( $cgi ); - push @html, Maasha::XHTML::table_beg( summary => "Navigation table" ); + push @html, Maasha::XHTML::table_beg( summary => "Navigation table", align => 'center' ); push @html, Maasha::XHTML::table_row_simple( tr => [ qw( Clade Genome Assembly Contig Start End ) ], align => 'center' ); push @html, Maasha::XHTML::table_row_simple( tr => [ Maasha::XHTML::menu( name => "nav_clade", options => $list_clade, selected => $def_clade ), @@ -114,7 +114,7 @@ sub sec_navigate ] ); push @html, Maasha::XHTML::table_end; - push @html, Maasha::XHTML::table_beg( summary => "Zoom table" ); + push @html, Maasha::XHTML::table_beg( summary => "Zoom table", align => 'center' ); push @html, Maasha::XHTML::table_row_simple( tr => [ Maasha::XHTML::p( txt => 'Move:' ), Maasha::XHTML::submit( name => "move_left3", value => "<<<", title => "move 95% to the left" ), @@ -134,22 +134,26 @@ sub sec_navigate ] ); push @html, Maasha::XHTML::table_end; + @html = Maasha::XHTML::div( txt => join( "\n", @html ), class => 'navigate' ); + return wantarray ? @html : \@html; } sub sec_browse { - my ( $dbh, # Database handle - $start, # Browse start position - $end, # Browse end position + my ( $dbh, # Database handle + $cgi, # CGI object ) = @_; # Returns a list. - my ( $t0, $t1, $ruler, $index, $index_beg, $index_len, $fh, $seq, $dna, $table, $entries, $features, $surface, $cr, $file, @html ); + my ( $t0, $t1, @stats, $start, $end, $ruler, $index, $index_beg, $index_len, $fh, $seq, $dna, $table, $entries, $features, $surface, $cr, $file, @html, @img ); + + $start = $cgi->param( 'nav_start' ); + $end = $cgi->param( 'nav_end' ); - $ruler = Maasha::KISS::Track::track_ruler( 1200, 25, $start, $end ); + $ruler = Maasha::KISS::Track::track_ruler( 1200, 25, $start, $end, 10, 'black' ); $index = Maasha::Fasta::index_retrieve( "$ENV{ 'BP_DATA' }/genomes/S_aur_COL/fasta/S_aur_COL.index" ); @@ -161,7 +165,7 @@ sub sec_browse close $fh; - $dna = Maasha::KISS::Track::track_seq( 1200, 50, $seq ) if length $seq <= 220; + $dna = Maasha::KISS::Track::track_seq( 1200, 50, $seq, 10, 'black' ) if length $seq <= 220; $table = 'Solexa'; @@ -169,9 +173,8 @@ sub sec_browse $entries = Maasha::KISS::IO::kiss_sql_get( $dbh, $table, $start, $end ); $t1 = Time::HiRes::gettimeofday(); - push @html, Maasha::XHTML::p( txt => "Feature count: " . Maasha::Calc::commify( scalar @$entries ) ); - - push @html, Maasha::XHTML::p( txt => "Time SQL: " . ( $t1 - $t0 ) ); + push @stats, "Feature count: " . Maasha::Calc::commify( scalar @$entries ); + push @stats, "Time SQL: " . sprintf( "%.4f", $t1 - $t0 ); $t0 = Time::HiRes::gettimeofday(); @@ -188,7 +191,7 @@ sub sec_browse # push @html, Maasha::KISS::Draw::hdump( $entries ); # push @html, Maasha::KISS::Draw::hdump( $features ); - push @html, Maasha::XHTML::p( txt => "Time Track: " . ( $t1 - $t0 ) ); + push @stats, "Time Track: " . sprintf( "%.4f", $t1 - $t0 ); $file = "fisk.png"; @@ -197,18 +200,29 @@ sub sec_browse $t0 = Time::HiRes::gettimeofday(); - Maasha::KISS::Draw::track_text( $cr, $ruler, "black" ) if $ruler; - Maasha::KISS::Draw::track_text( $cr, $dna, "black" ) if $dna; - - Maasha::KISS::Draw::track_feature( $cr, $features, 'green' ) if $features; + Maasha::KISS::Draw::draw_feature( $cr, $ruler ) if $ruler; + Maasha::KISS::Draw::draw_feature( $cr, $dna ) if $dna; + Maasha::KISS::Draw::draw_feature( $cr, $features ) if $features; Maasha::KISS::Draw::file_png( $surface, $file ); $t1 = Time::HiRes::gettimeofday(); - push @html, Maasha::XHTML::p( txt => "Time Draw: " . ( $t1 - $t0 ) ); + push @stats, "Time Draw: " . sprintf( "%.4f", $t1 - $t0 ); + + push @html, Maasha::XHTML::p( txt => join( " ", @stats ) ); + + push @img, Maasha::XHTML::img( src => $file, alt => "Browser Tracks", height => 800, width => 1200, id => "browser_map", usemap => "#browser_map" ); + + push @img, Maasha::XHTML::map_beg( name => "browser_map", id => "browser_map" ); + + map { push @img, Maasha::XHTML::area( href => "www.dmi.dk", shape => "rect", coords => "$_->{ x1 }, $_->{ y1 }, $_->{ x2 }, $_->{ y2 }", title => "$_->{ title }" ) } @{ $features }; + + push @img, Maasha::XHTML::map_beg(); + + push @html, Maasha::XHTML::p( txt => join( "\n", @img ) ); - push @html, Maasha::XHTML::p( txt => Maasha::XHTML::img( src => $file, alt => "Browser Tracks", height => 800, width => 1200, class => "foo", id => "pix_id", usemap => "map" ) ); + @html = Maasha::XHTML::div( txt => join( "\n", @html ), class => 'browse' ); return wantarray ? @html : \@html; }