# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-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.
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' } );
}
use warnings;
use strict;
use Data::Dumper;
+use Maasha::Common;
use Maasha::Filesys;
use Maasha::SQL;
use vars qw( @ISA @EXPORT );
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 );
}
+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
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 );
$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
+ };
+ }
}
}
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 );
$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;
$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' };
$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,
};
}
}
type => 'line',
line_width => $bucket_width,
color => 'green',
+ title => "Features: $buckets[ $i ]",
x1 => $x,
y1 => $y_offset + $hist_height,
x2 => $x,
}
-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;
-
-
}
+sub area
+{
+ # Martin A. Hansen, October 2009.
+
+ # HTML <area> 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 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
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;
$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 ),
] );
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" ),
] );
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" );
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';
$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();
# 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";
$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;
}