File Coverage

blib/lib/App/RL/Command/stat2.pm
Criterion Covered Total %
statement 121 128 94.5
branch 28 40 70.0
condition n/a
subroutine 12 12 100.0
pod 5 6 83.3
total 166 186 89.2


line stmt bran cond sub pod time code
1             package App::RL::Command::stat2;
2 14     14   9415 use strict;
  14         35  
  14         374  
3 14     14   63 use warnings;
  14         28  
  14         322  
4 14     14   62 use autodie;
  14         26  
  14         76  
5              
6 14     14   69353 use App::RL -command;
  14         32  
  14         139  
7 14     14   4552 use App::RL::Common;
  14         32  
  14         349  
8              
9 14     14   73 use constant abstract => 'coverage statistics on another runlist for runlists';
  14         25  
  14         18458  
10              
11             sub opt_spec {
12             return (
13 8     8 1 105 [ "outfile|o=s", "Output filename. [stdout] for screen" ],
14             [ "op=s", "Operations: intersect, union, diff or xor", { default => "intersect" } ],
15             [ "size|s=s", "chr.sizes", { required => 1 } ],
16             [ "base|b=s", "basename of infile2", ],
17             [ "remove|r", "Remove 'chr0' from chromosome names" ],
18             [ "mk", "First YAML file contains multiple sets of runlists" ],
19             [ "all", "Only write whole genome stats" ],
20             { show_defaults => 1, }
21             );
22             }
23              
24             sub usage_desc {
25 8     8 1 62500 return "runlist stat2 [options] ";
26             }
27              
28             sub description {
29 1     1 1 1659 my $desc;
30 1         3 $desc .= ucfirst(abstract) . ".\n";
31 1         4 return $desc;
32             }
33              
34             sub validate_args {
35 6     6 1 11240 my ( $self, $opt, $args ) = @_;
36              
37 6 100       15 if ( @{$args} != 2 ) {
  6         28  
38 2         5 my $message = "This command need two input files.\n\tIt found";
39 2         4 $message .= sprintf " [%s]", $_ for @{$args};
  2         8  
40 2         7 $message .= ".\n";
41 2         11 $self->usage_error($message);
42             }
43 4         11 for ( @{$args} ) {
  4         24  
44 7 50       267 next if lc $_ eq "stdin";
45 7 100       31 if ( !Path::Tiny::path($_)->is_file ) {
46 1         124 $self->usage_error("The input file [$_] doesn't exist.");
47             }
48             }
49              
50 3 50       129 if ( $opt->{op} =~ /^dif/i ) {
    50          
    50          
    0          
51 0         0 $opt->{op} = 'diff';
52             }
53             elsif ( $opt->{op} =~ /^uni/i ) {
54 0         0 $opt->{op} = 'union';
55             }
56             elsif ( $opt->{op} =~ /^int/i ) {
57 3         11 $opt->{op} = 'intersect';
58             }
59             elsif ( $opt->{op} =~ /^xor/i ) {
60 0         0 $opt->{op} = 'xor';
61             }
62             else {
63 0         0 Carp::confess "[@{[$opt->{op}]}] invalid\n";
  0         0  
64             }
65              
66 3 50       9 if ( !exists $opt->{base} ) {
67 3         13 $opt->{base} = Path::Tiny::path( $args->[1] )->basename( ".yaml", ".yml" );
68             }
69              
70 3 50       302 if ( !exists $opt->{outfile} ) {
71 0         0 $opt->{outfile} = Path::Tiny::path( $args->[0] )->absolute . $opt->{op} . ".csv";
72             }
73             }
74              
75             sub execute {
76 3     3 1 20 my ( $self, $opt, $args ) = @_;
77              
78             #----------------------------#
79             # Loading
80             #----------------------------#
81 3         22 my $length_of = App::RL::Common::read_sizes( $opt->{size}, $opt->{remove} );
82              
83             # file1
84 3         9 my $s1_of = {};
85 3         7 my @keys;
86 3 100       10 if ( $opt->{mk} ) {
87 1         6 my $yml = YAML::Syck::LoadFile( $args->[0] );
88 1         143 @keys = sort keys %{$yml};
  1         6  
89              
90 1         5 for my $key (@keys) {
91 5         22 $s1_of->{$key} = App::RL::Common::runlist2set( $yml->{$key}, $opt->{remove} );
92             }
93             }
94             else {
95 2         6 @keys = ("__single");
96             $s1_of->{__single}
97 2         14 = App::RL::Common::runlist2set( YAML::Syck::LoadFile( $args->[0] ), $opt->{remove} );
98             }
99              
100             # file2
101 3         36 my $s2 = App::RL::Common::runlist2set( YAML::Syck::LoadFile( $args->[1] ), $opt->{remove} );
102              
103             #----------------------------#
104             # Operating
105             #----------------------------#
106 3         18 my $op_result_of = { map { $_ => {} } @keys };
  7         21  
107              
108 3         10 for my $key (@keys) {
109 7         14 my $s1 = $s1_of->{$key};
110              
111             # give empty set to non-existing chrs
112 7         15 for my $s ( $s1, $s2 ) {
113 14         85 for my $chr ( sort keys %{$length_of} ) {
  14         64  
114 114 100       383 if ( !exists $s->{$chr} ) {
115 23         51 $s->{$chr} = App::RL::Common::new_set();
116             }
117             }
118             }
119              
120             # operate on each chr
121 7         20 for my $chr ( sort keys %{$length_of} ) {
  7         24  
122 57         104 my $op = $opt->{op};
123 57         173 my $op_set = $s1->{$chr}->$op( $s2->{$chr} );
124 57         21630 $op_result_of->{$key}{$chr} = $op_set;
125             }
126             }
127              
128             # warn YAML::Syck::Dump $s2;
129             # warn YAML::Syck::Dump $op_result_of;
130              
131             #----------------------------#
132             # Calcing
133             #----------------------------#
134 3         4 my $out_fh;
135 3 50       16 if ( lc( $opt->{outfile} ) eq "stdout" ) {
136 3         16 $out_fh = *STDOUT;
137             }
138             else {
139 0         0 open $out_fh, ">", $opt->{outfile};
140             }
141              
142             my $header = sprintf "key,chr,chr_length,size,%s_length,%s_size,c1,c2,ratio\n",
143 3         25 $opt->{base}, $opt->{base};
144 3 100       40 if ( $opt->{mk} ) {
145 1 50       5 if ( $opt->{all} ) {
146 1         8 $header =~ s/chr\,//;
147             }
148 1         4 my @lines = ($header);
149              
150 1         4 for my $key (@keys) {
151             my @key_lines
152 5         13 = csv_lines( $s1_of->{$key}, $length_of, $s2, $op_result_of->{$key}, $opt->{all} );
153 5         16 $_ = "$key,$_" for @key_lines;
154 5         13 push @lines, @key_lines;
155             }
156              
157 1         3 print {$out_fh} $_ for @lines;
  6         80  
158             }
159             else {
160 2         18 $header =~ s/key\,//;
161 2 100       22 if ( $opt->{all} ) {
162 1         4 $header =~ s/chr\,//;
163             }
164 2         10 my @lines = ($header);
165              
166             push @lines,
167             csv_lines( $s1_of->{__single}, $length_of, $s2, $op_result_of->{__single},
168 2         14 $opt->{all} );
169              
170 2         7 print {$out_fh} $_ for @lines;
  20         405  
171             }
172              
173 3         48 close $out_fh;
174             }
175              
176             sub csv_lines {
177 7     7 0 15 my $set_of = shift;
178 7         10 my $length_of = shift;
179 7         12 my $s2 = shift;
180 7         13 my $op_result_of = shift;
181 7         11 my $all = shift;
182              
183 7         12 my @lines;
184 7         14 my ( $all_length, $all_size, $all_s2_length, $all_s2_size, );
185 7         10 for my $chr ( sort keys %{$length_of} ) {
  7         60  
186 57         99 my $length = $length_of->{$chr};
187 57         140 my $size = $set_of->{$chr}->size;
188              
189 57         10541 my $s2_length = $s2->{$chr}->size;
190 57         1377 my $s2_size = $op_result_of->{$chr}->size;
191              
192 57         882 $all_length += $length;
193 57         79 $all_size += $size;
194 57         75 $all_s2_length += $s2_length;
195 57         103 $all_s2_size += $s2_size;
196              
197 57         90 my $c1 = $size / $length;
198 57 100       123 my $c2 = $s2_length == 0 ? 0 : $s2_size / $s2_length;
199 57 100       112 my $ratio = $c1 == 0 ? 0 : $c2 / $c1;
200              
201 57         412 my $line = sprintf "%s,%d,%d,%d,%d,%.4f,%.4f,%.4f\n", $chr, $length, $size, $s2_length,
202             $s2_size, $c1, $c2, $ratio;
203 57         202 push @lines, $line;
204             }
205              
206 7         17 my $all_c1 = $all_size / $all_length;
207 7 50       20 my $all_c2 = $all_s2_length == 0 ? 0 : $all_s2_size / $all_s2_length;
208 7 50       23 my $all_ratio = $all_c1 == 0 ? 0 : $all_c2 / $all_c1;
209              
210             # only keep whole genome
211 7         42 my $all_line = sprintf "all,%d,%d,%d,%d,%.4f,%.4f,%.4f\n", $all_length, $all_size,
212             $all_s2_length, $all_s2_size, $all_c1, $all_c2, $all_ratio;
213 7 100       20 if ($all) {
214 6         15 @lines = ();
215 6         23 $all_line =~ s/all,//;
216             }
217 7         13 push @lines, $all_line;
218              
219 7         25 return @lines;
220             }
221              
222             1;