]> git.donarmstrong.com Git - biopieces.git/blob - code_perl/Maasha/BBrowser/Track.pm
removed KISS directory
[biopieces.git] / code_perl / Maasha / BBrowser / Track.pm
1 package Maasha::BBrowser::Track;
2
3 # Copyright (C) 2009 Martin A. Hansen.
4
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
19 # http://www.gnu.org/copyleft/gpl.html
20
21
22 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> DESCRIPTION <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
23
24
25 # Routines for creating Biopieces Browser tracks.
26
27
28 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
29
30
31 use warnings;
32 use strict;
33 use Data::Dumper;
34 use Maasha::Common;
35 use Maasha::Calc;
36 use Maasha::Filesys;
37 use Maasha::KISS;
38
39 use vars qw( @ISA @EXPORT );
40
41 @ISA = qw( Exporter );
42
43
44 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
45
46
47 sub track_ruler
48 {
49     my ( $cookie,         # browser cookie
50        ) = @_;
51
52     my ( $beg, $end, $factor, $step, $i, $txt, $x, @ruler );
53
54     $beg    = $cookie->{ 'NAV_START' };
55     $end    = $cookie->{ 'NAV_END' };
56     $factor = $cookie->{ 'IMG_WIDTH' } / ( $end - $beg );
57     
58     $step = 10;
59
60     while ( ( $end - $beg ) / $step > 20 )
61     {
62         $step *= 5;
63     }
64
65     for ( $i = $beg; $i < $end; $i++ )
66     {
67         if ( ( $i % $step ) == 0 )
68         {
69             $txt = Maasha::Calc::commify( $i ) . "|";
70             $x   = sprintf( "%.0f", ( $i - $beg - length $txt ) * $factor );
71
72             if ( $x > 0 and $x + ( $cookie->{ 'RULER_FONT_SIZE' } * length $txt ) < $cookie->{ 'IMG_WIDTH' } )
73             {
74                 push @ruler, {
75                     type      => 'text',
76                     txt       => $txt,
77                     font_size => $cookie->{ 'RULER_FONT_SIZE' },
78                     color     => $cookie->{ 'RULER_COLOR' },
79                     x1        => $x,
80                     y1        => $cookie->{ 'TRACK_OFFSET' },
81                 };
82             }
83         }
84     }
85
86     $cookie->{ 'TRACK_OFFSET' } += $cookie->{ 'TRACK_SPACE' };
87
88     return wantarray ? @ruler : \@ruler;
89 }
90
91
92 sub track_seq
93 {
94     my ( $cookie,   # browser cookie
95        ) = @_;
96
97     my ( $file, $fh, $seq, @chars, $factor, $i, @seq_list );
98
99     if ( $cookie->{ 'NAV_END' } - $cookie->{ 'NAV_START' } + 1 <= 220 )
100     {
101         $file = path_seq( $cookie );
102         $fh   = Maasha::Filesys::file_read_open( $file );
103         $seq  = Maasha::Filesys::file_read( $fh, $cookie->{ 'NAV_START' } - 1, $cookie->{ 'NAV_END' } - $cookie->{ 'NAV_START' } + 1 );
104         close $fh;
105
106         @chars = split //, $seq;
107
108         $factor = $cookie->{ 'IMG_WIDTH' } / @chars;
109
110         for ( $i = 0; $i < @chars; $i++ ) {
111             push @seq_list, {
112                 type      => 'text',
113                 txt       => $chars[ $i ],
114                 font_size => $cookie->{ 'SEQ_FONT_SIZE' },
115                 color     => $cookie->{ 'SEQ_COLOR' },
116                 x1        => sprintf( "%.0f", $i * $factor ),
117                 y1        => $cookie->{ 'TRACK_OFFSET' },
118             };
119         }
120
121         $cookie->{ 'TRACK_OFFSET' } += $cookie->{ 'TRACK_SPACE' };
122
123         return wantarray ? @seq_list : \@seq_list;
124     }
125     else
126     {
127         return;
128     }
129 }
130
131
132 sub track_feature
133 {
134     my ( $track,
135          $cookie,
136        ) = @_;
137
138     # Returns a list.
139
140     my ( $index, $count, $track_name, $start, $end, $entries, $features );
141
142     $start = $cookie->{ 'NAV_START' };
143     $end   = $cookie->{ 'NAV_END' };
144
145     $index = Maasha::KISS::kiss_index_retrieve( "$track/track_data.kiss.index" );
146     $count = Maasha::KISS::kiss_index_count( $index, $start, $end );
147
148     $track_name = ( split "/", $track )[ -1 ];
149     $track_name =~ s/^\d+_//;
150     $track_name =~ s/_/ /g;
151
152     $features = [ {
153         type      => 'text',
154         txt       => $track_name,
155         font_size => $cookie->{ 'SEQ_FONT_SIZE' },
156         color     => $cookie->{ 'SEQ_COLOR' },
157         x1        => 0,
158         y1        => $cookie->{ 'TRACK_OFFSET' },
159     } ];
160
161     $cookie->{ 'TRACK_OFFSET' } += 10;
162
163     if ( $count > 5000 )
164     {
165         $entries  = Maasha::KISS::kiss_index_get_blocks( $index, $start, $end );
166         push @{ $features }, track_feature_histogram( $cookie, $start, $end, $entries );
167     }  
168     else
169     {
170         $entries  = Maasha::KISS::kiss_index_get_entries( "$track/track_data.kiss", $index, $start, $end );
171         push @{ $features }, track_feature_linear( $cookie, $start, $end, $entries );
172     }  
173
174     return wantarray ? @{ $features } : $features;
175 }
176
177
178 sub track_feature_linear
179 {
180     my ( $cookie,    # hashref with image draw metrics
181          $beg,       # base window beg
182          $end,       # base window end
183          $entries,   # list of unsorted KISS entries 
184        ) = @_;
185
186     # Returns a list.
187     
188     my ( $factor, $entry, $y_step, @ladder, $y_max, $w, $x1, $y1, $x2, $y2, @features );
189
190     @{ $entries } = sort { $a->{ 'S_BEG' } <=> $b->{ 'S_BEG' } or $a->{ 'S_END' } <=> $b->{ 'S_END' } } @{ $entries };
191
192     $factor = $cookie->{ 'IMG_WIDTH' } / ( $end - $beg );
193     $y_step = 0;
194     $y_max  = 0;
195
196     foreach $entry ( @{ $entries } )
197     {
198         $w = sprintf( "%.0f", ( $entry->{ 'S_END' } - $entry->{ 'S_BEG' } + 1 ) * $factor );
199
200         if ( $w >= 1 )
201         {
202             $x1 = sprintf( "%.0f", ( $entry->{ 'S_BEG' } - $beg ) * $factor );
203
204             for ( $y_step = 0; $y_step < @ladder; $y_step++ ) {
205                 last if $x1 >= $ladder[ $y_step ] + 1; 
206             }
207
208             $y1 = $cookie->{ 'TRACK_OFFSET' } + ( $cookie->{ 'FEAT_WIDTH' } * $y_step );
209
210             push @features, {
211                 type       => 'rect',
212                 line_width => $cookie->{ 'FEAT_WIDTH' },
213                 color      => $cookie->{ 'FEAT_COLOR' },
214                 title      => "Q_ID: $entry->{ 'Q_ID' } S_BEG: $entry->{ 'S_BEG' } S_END: $entry->{ 'S_END' } STRAND: $entry->{ 'STRAND' }",
215                 id         => $entry->{ 'Q_ID' },
216                 x1         => $x1,
217                 y1         => $y1,
218                 x2         => $x1 + $w,
219                 y2         => $y1 + $cookie->{ 'FEAT_WIDTH' },
220             };
221
222             $y_max = Maasha::Calc::max( $y_max, $y_step * $cookie->{ 'FEAT_WIDTH' } );
223
224             push @features, feature_align( $entry, $beg, $y1, $factor, $cookie->{ 'FEAT_WIDTH' } ) if $entry->{ 'ALIGN' } ne '.';
225
226             $ladder[ $y_step ] = $x1 + $w;
227         }
228     }
229
230     $cookie->{ 'TRACK_OFFSET' } += $y_max + $cookie->{ 'TRACK_SPACE' };
231
232     return wantarray ? @features : \@features;
233 }
234
235
236 sub feature_align
237 {
238     # 17:A>T
239
240     my ( $entry,         # Partial KISS entry
241          $beg,           # base window beg
242          $y_offset,      # y axis draw offset
243          $factor,        # scale factor
244          $feat_height,   # hight of feature in pixels
245        ) = @_;
246
247     # Returns a list.
248
249     my ( $w, $align, $pos, $nt_before, $nt_after, $x1, @features );
250
251     $w = sprintf( "%.0f", 1 * $factor );
252
253     if ( $w >= 1 )
254     {
255         foreach $align ( split /,/, $entry->{ 'ALIGN' } )
256         {
257             if ( $align =~ /(\d+):([ATCGN-])>([ATCGN-])/ )
258             {
259                 $pos       = $1;
260                 $nt_before = $2;
261                 $nt_after  = $3;
262             }
263             else
264             {
265                 Maasha::Common::error( qq(BAD align descriptor: "$align") );
266             }
267
268             $x1 = sprintf( "%.0f", ( $entry->{ 'S_BEG' } + $pos - $beg ) * $factor );
269
270             push @features, {
271                 type       => 'rect',
272                 line_width => $feat_height,
273                 color      => [ 1, 0, 0 ],
274                 title      => $align,
275                 x1         => $x1,
276                 y1         => $y_offset,
277                 x2         => $x1 + $w,
278                 y2         => $y_offset + $feat_height,
279             };
280
281             if ( $w > $feat_height )
282             {
283                 push @features, {
284                     type       => 'text',
285                     font_size  => $feat_height + 2,
286                     color      => [ 0, 0, 0 ],
287                     txt        => $nt_after,
288                     x1         => $x1 + sprintf( "%.0f", ( $w / 2 ) ) - $feat_height / 2,
289                     y1         => $y_offset + $feat_height,
290                 };
291             }
292         }
293     }
294
295     return wantarray ? @features : \@features;
296 }
297
298
299 sub track_feature_histogram
300 {
301     my ( $cookie,   # hashref with image draw metrics
302          $min,            # minimum base position
303          $max,            # maximum base position
304          $blocks,         # list of blocks
305        ) = @_;
306
307     # Returns a list.
308
309     my ( $hist_height, $bucket_width, $bucket_count, $min_bucket, $factor, $factor_heigth, $max_height, $block, $bucket_beg, $bucket_end, $i, @buckets, $h, $x, @hist );
310
311     return if $max <= $min;
312
313     $hist_height  = 100;   # pixels
314     $bucket_width = 5;
315     $bucket_count = $cookie->{ 'IMG_WIDTH' } / $bucket_width;
316     $factor       = ( $cookie->{ 'IMG_WIDTH' } / $bucket_width ) / ( $max - $min + 1 );
317
318     $min_bucket = 999999999;
319     $max_height = 0;
320
321     foreach $block ( @{ $blocks } )
322     {
323         $bucket_beg = int( $block->{ 'BEG' } * $factor );
324         $bucket_end = int( $block->{ 'END' } * $factor );
325
326         $min_bucket = Maasha::Calc::min( $min_bucket, $bucket_beg );
327
328         for ( $i = $bucket_beg; $i <= $bucket_end; $i++ )
329         {
330             $buckets[ $i ] += $block->{ 'COUNT' };
331
332             $max_height = Maasha::Calc::max( $max_height, $buckets[ $i ] );
333         }
334     }
335
336     if ( $max_height > 0 )
337     {
338         $factor_heigth = $hist_height / $max_height;
339
340         $x = 0;
341
342         for ( $i = $min_bucket; $i < @buckets; $i++ )
343         {
344             if ( defined $buckets[ $i ] )
345             {
346                 $h = sprintf( "%.0f", $buckets[ $i ] * $factor_heigth );
347
348                 if ( $h >= 1 )
349                 {
350                     push @hist, {
351                         type       => 'line',
352                         line_width => $bucket_width,
353                         color      => $cookie->{ 'FEAT_COLOR' },
354                         title      => "Features: $buckets[ $i ]",
355                         x1         => $x,
356                         y1         => $cookie->{ 'TRACK_OFFSET' } + $hist_height,
357                         x2         => $x,
358                         y2         => $cookie->{ 'TRACK_OFFSET' } + $hist_height - $h,
359                     };
360                 }
361             }
362
363             $x += $bucket_width;
364         }
365     }
366
367     $cookie->{ 'TRACK_OFFSET' } += $hist_height + $cookie->{ 'TRACK_SPACE' };
368
369     return wantarray ? @hist : \@hist;
370 }
371
372
373 sub path_seq
374 {
375     my ( $cookie,
376        ) = @_;
377
378     # Returns a string.
379
380     my ( $path );
381
382     die qq(ERROR: no USER in cookie.\n)     if not $cookie->{ 'USER' };
383     die qq(ERROR: no CLADE in cookie.\n)    if not $cookie->{ 'CLADE' };
384     die qq(ERROR: no GENOME in cookie.\n)   if not $cookie->{ 'GENOME' };
385     die qq(ERROR: no ASSEMBLY in cookie.\n) if not $cookie->{ 'ASSEMBLY' };
386     die qq(ERROR: no CONTIG in cookie.\n)   if not $cookie->{ 'CONTIG' };
387
388     $path = join( "/",
389         $cookie->{ 'DATA_DIR' },
390         "Users",
391         $cookie->{ 'USER' },
392         $cookie->{ 'CLADE' },
393         $cookie->{ 'GENOME' },
394         $cookie->{ 'ASSEMBLY' },
395         $cookie->{ 'CONTIG' },
396         "Sequence",
397         "sequence.txt"
398     );
399     
400     die qq(ERROR: no such file: "$path".\n) if not -e $path;
401
402     return $path;
403 }
404
405
406 sub path_tracks
407 {
408     my ( $cookie,
409        ) = @_;
410
411     # Returns a list.
412     #
413     my ( $path, @tracks );
414
415     die qq(ERROR: no USER in cookie.\n)     if not $cookie->{ 'USER' };
416     die qq(ERROR: no CLADE in cookie.\n)    if not $cookie->{ 'CLADE' };
417     die qq(ERROR: no GENOME in cookie.\n)   if not $cookie->{ 'GENOME' };
418     die qq(ERROR: no ASSEMBLY in cookie.\n) if not $cookie->{ 'ASSEMBLY' };
419     die qq(ERROR: no CONTIG in cookie.\n)   if not $cookie->{ 'CONTIG' };
420
421     $path = join( "/",
422         $cookie->{ 'DATA_DIR' },
423         "Users",
424         $cookie->{ 'USER' },
425         $cookie->{ 'CLADE' },
426         $cookie->{ 'GENOME' },
427         $cookie->{ 'ASSEMBLY' },
428         $cookie->{ 'CONTIG' },
429         "Tracks",
430     );
431
432     if ( -d $path )
433     {
434         @tracks = Maasha::Filesys::ls_dirs( $path );
435
436         @tracks = grep { $_ !~ /\/\.\.?$/ } @tracks;
437
438         return wantarray ? @tracks : \@tracks;
439     }
440     else
441     {
442         return wantarray ? () : [];
443     }
444 }
445
446 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
447
448 1;
449