]> git.donarmstrong.com Git - biopieces.git/blob - code_perl/Maasha/UCSC/Wiggle.pm
6103a49902c814c7cbf8704c682ef228d468d43b
[biopieces.git] / code_perl / Maasha / UCSC / Wiggle.pm
1 package Maasha::UCSC::Wiggle;
2
3 # Copyright (C) 2007-2008 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 manipulation of wiggle data.
26
27 # http://genome.ucsc.edu/goldenPath/help/wiggle.html
28
29
30 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
31
32
33 use strict;
34
35 use Data::Dumper;
36 use Maasha::Common;
37 use Maasha::Filesys;
38 use Maasha::Calc;
39
40 use vars qw( @ISA @EXPORT_OK );
41
42 require Exporter;
43
44 @ISA = qw( Exporter );
45
46 @EXPORT_OK = qw(
47 );
48
49
50 use constant {
51     BITS        => 32,            # Number of bits in an integer
52     SEQ_MAX     => 200_000_000,   # Maximum sequence size
53     chrom       => 0,             # BED field names
54     chromStart  => 1,
55     chromEnd    => 2,
56     name        => 3,
57     score       => 4,
58     strand      => 5,
59     thickStart  => 6,
60     thickEnd    => 7,
61     itemRgb     => 8,
62     blockCount  => 9,
63     blockSizes  => 10,
64     blockStarts => 11,
65 };
66
67
68 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FixedStep format <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
69
70
71 sub fixedstep_entry_get
72 {
73     # Martin A. Hansen, December 2007.
74
75     # Given a file handle to a PhastCons file get the
76     # next entry which is all the lines after a "fixedStep"
77     # line and until the next "fixedStep" line or EOF.
78
79     my ( $fh,   # filehandle
80        ) = @_;
81
82     # Returns a list of lines
83
84     my ( $entry, @lines );
85
86     local $/ = "\nfixedStep ";
87
88     $entry = <$fh>;
89
90     chomp $entry;
91
92     @lines = split "\n", $entry;
93     
94     return if @lines == 0;
95
96     $lines[ 0 ] =~ s/fixedStep?\s*//;
97     $lines[ 0 ] = 'fixedStep ' . $lines[ 0 ];
98
99     return wantarray ? @lines : \@lines;
100 }
101
102
103 sub fixedstep_entry_put
104 {
105     # Martin A. Hansen, April 2008.
106
107     # Outputs a block of fixedStep values.
108     # Used for outputting wiggle data.
109
110     my ( $entry,    # fixedStep entry
111          $fh,       # filehandle - OPTIONAL
112        ) = @_;
113
114     # Returns nothing.
115
116     $fh ||= \*STDOUT;
117
118     print $fh join( "\n", @{ $entry } ), "\n";
119 }
120
121
122 sub fixedstep2biopiece
123 {
124     # Martin A. Hansen, November 2008.
125
126     # Converts a fixedstep entry to a Biopiece record.
127
128     my ( $entry,   # fixedstep entry arrayref
129        ) = @_;
130
131     # Returns a hashref
132
133     my ( $head, %record );
134
135     $head = shift @{ $entry };
136
137     if ( $head =~ /^fixedStep chrom=([^ ]+) start=(\d+) step=(\d+)$/ )
138     {
139         $record{ "REC_TYPE" } = "fixed_step";
140         $record{ "CHR" }      = $1;
141         $record{ "CHR_BEG" }  = $2 - 1;  # fixedStep is 1-based
142         $record{ "STEP" }     = $3;
143         $record{ "VALS" }     = join ";", @{ $entry };
144     }
145     else
146     {
147         Maasha::Common::error( qq(could not convert fixedStep entry to Biopiece record) );
148     }
149
150     return wantarray ? %record : \%record;
151 }
152
153
154 sub biopiece2fixedstep
155 {
156     # Martin A. Hansen, November 2008.
157
158     # Converts a Biopiece record to a fixedStep entry.
159     
160     my ( $record,   # Biopiece record
161        ) = @_;
162
163     # Returns a list
164
165     my ( @entry, $beg, $vals );
166
167     if ( exists $record->{ "REC_TYPE" } and $record->{ "REC_TYPE" } eq 'fixed_step' )
168     {
169         if ( exists $record->{ 'CHR' } and exists $record->{ 'CHR_BEG' } and exists $record->{ 'STEP' } )
170         {
171             $beg = $record->{ 'CHR_BEG' } + 1;   # fixedStep is 1-based
172             push @entry, "fixedStep chrom=$record->{ 'CHR' } start=$beg step=$record->{ 'STEP' }";
173
174             $vals = $record->{ 'VALS' };
175
176             map { push @entry, $_ } split ";", $vals;
177         }
178         else
179         {
180             Maasha::Common::error( qq(could not convert Biopiece record to fixedStep) );
181         }
182     }
183
184     return wantarray ? @entry : \@entry;
185 }
186
187
188 sub fixedstep_calc
189 {
190     # Martin A. Hansen, November 2008.
191
192     # Calculates fixedstep entries for a given BED file.
193     # Implemented using large Perl arrays to avoid sorting.
194     # Returns path to the fixedstep file.
195
196     my ( $bed_file,   # path to BED file
197          $chr,        # chromosome name
198          $use_score,  # flag indicating that the score field should be used - OPTIONAL
199          $use_log10,  # flag indicating that the score should be in log10   - OPTIONAL
200        ) = @_;
201
202     # Returns a string
203
204     my ( $fixedstep_file, $fh_in, $fh_out, $array, $beg, $end, @block, $i );
205
206     $fixedstep_file = "$bed_file.fixedstep";
207
208     $fh_in = Maasha::Filesys::file_read_open( $bed_file );
209
210     $array = fixedstep_calc_array( $fh_in, $use_score );
211
212     close $fh_in;
213
214     $fh_out = Maasha::Filesys::file_write_open( $fixedstep_file );
215
216     $beg = 0;
217
218     while ( ( $beg, $end ) = fixedstep_scan( $array, $beg ) and $beg != -1 )
219     {
220         @block = "fixedStep chrom=$chr start=" . ( $beg + 1 ) . " step=1";
221
222         for ( $i = $beg; $i <= $end; $i++ )
223         {
224             if ( $use_log10 ) {
225                 push @block, sprintf "%.4f", Maasha::Calc::log10( $array->[ $i ] );
226             } else {
227                 push @block, $array->[ $i ];
228             }
229         }
230
231         fixedstep_entry_put( \@block, $fh_out );
232
233         $beg = $end + 1;
234     }
235
236     close $fh_out;
237
238     undef $array;
239
240     return $fixedstep_file;
241 }
242
243
244 sub fixedstep_calc_array
245 {
246     # Martin A. Hansen, November 2008.
247
248     # Given a filehandle to a BED file for a single
249     # chromosome fills an array with scores based on
250     # clone count (or sequence read count) for the
251     # begin position through the end position of each
252     # BED entry.
253
254     my ( $fh_in,       # filehandle to BED file
255          $use_score,   # flag indicating that the score field should be used - OPTIONAL
256        ) = @_;
257
258     # Returns a bitarray.
259
260     my ( $bed, $clones, @begs, @lens, $i, @array );
261
262     while ( $bed = Maasha::UCSC::BED::bed_entry_get( $fh_in ) )
263     {
264         if ( $use_score ) {
265             $clones = $bed->[ score ];
266         } elsif ( $bed->[ name ] =~ /_(\d+)$/ ) {
267             $clones = $1;
268         } else {
269             $clones = 1;
270         }
271
272         if ( $bed->[ blockCount ] and $bed->[ blockCount ] > 1 )
273         {
274             @begs = split ",", $bed->[ blockStarts ];
275             @lens = split ",", $bed->[ blockSizes ];
276
277             for ( $i = 0; $i < @begs; $i++ ) {
278                 map { $array[ $_ ] += $clones } ( $bed->[ chromStart ] + $begs[ $i ] .. $bed->[ chromStart ] + $begs[ $i ] + $lens[ $i ] - 1 );
279             }
280         }
281         else
282         {
283             map { $array[ $_ ] += $clones } ( $bed->[ chromStart ] .. $bed->[ chromEnd ] - 1 );
284         }
285     }
286
287     return wantarray ? @array : \@array;
288 }
289
290
291 sub fixedstep_scan
292 {
293     # Martin A. Hansen, November 2008.
294
295     # Given a fixedstep array locates the next block of
296     # non-zero elements from a given begin position.
297     # A [ begin end ] tuple of the block posittion is returned 
298     # if a block was found otherwise and empty tuple is returned.
299
300     my ( $array,   # array to scan
301          $beg,     # position to start scanning from
302        ) = @_;
303
304     # Returns an arrayref.
305
306     my ( $end );
307
308     while ( $beg < scalar @{ $array } and not $array->[ $beg ] ) { $beg++ }
309
310     $end = $beg;
311
312     while ( $array->[ $end ] ) { $end++ }
313
314     if ( $end > $beg ) {
315         return wantarray ? ( $beg, $end ) : [ $beg, $end ];
316     } else {
317         return wantarray ? () : [];
318     }
319 }
320
321
322 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
323
324
325 1;
326
327
328 __END__