line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
1
|
|
|
1
|
|
52260
|
use 5.008001; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
40
|
|
2
|
1
|
|
|
1
|
|
6
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
28
|
|
3
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
54
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
package Text::BoxPlot; |
6
|
|
|
|
|
|
|
# ABSTRACT: Render ASCII box and whisker charts |
7
|
|
|
|
|
|
|
our $VERSION = '0.001'; # VERSION |
8
|
|
|
|
|
|
|
|
9
|
1
|
|
|
1
|
|
1988
|
use Moo; |
|
1
|
|
|
|
|
27402
|
|
|
1
|
|
|
|
|
7
|
|
10
|
1
|
|
|
1
|
|
3894
|
use MooX::Types::MooseLike::Base qw/Bool/; |
|
1
|
|
|
|
|
9699
|
|
|
1
|
|
|
|
|
232
|
|
11
|
1
|
|
|
1
|
|
1159
|
use MooX::Types::MooseLike::Numeric qw/PositiveNum/; |
|
1
|
|
|
|
|
2040
|
|
|
1
|
|
|
|
|
134
|
|
12
|
1
|
|
|
1
|
|
1276
|
use List::AllUtils qw/min max/; |
|
1
|
|
|
|
|
8430
|
|
|
1
|
|
|
|
|
125
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
use constant { |
15
|
1
|
|
|
|
|
1422
|
NAME => 0, |
16
|
|
|
|
|
|
|
MIN => 1, |
17
|
|
|
|
|
|
|
Q1 => 2, |
18
|
|
|
|
|
|
|
MED => 3, |
19
|
|
|
|
|
|
|
Q3 => 4, |
20
|
|
|
|
|
|
|
MAX => 5, |
21
|
1
|
|
|
1
|
|
11
|
}; |
|
1
|
|
|
|
|
2
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
has width => ( |
26
|
|
|
|
|
|
|
is => 'ro', |
27
|
|
|
|
|
|
|
isa => PositiveNum, |
28
|
|
|
|
|
|
|
default => sub { 72 }, |
29
|
|
|
|
|
|
|
); |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
has label_width => ( |
33
|
|
|
|
|
|
|
is => 'ro', |
34
|
|
|
|
|
|
|
isa => PositiveNum, |
35
|
|
|
|
|
|
|
default => sub { 10 }, |
36
|
|
|
|
|
|
|
); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
has box_weight => ( |
40
|
|
|
|
|
|
|
is => 'ro', |
41
|
|
|
|
|
|
|
isa => PositiveNum, |
42
|
|
|
|
|
|
|
default => sub { 1 }, |
43
|
|
|
|
|
|
|
); |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
has with_scale => ( |
47
|
|
|
|
|
|
|
is => 'ro', |
48
|
|
|
|
|
|
|
isa => Bool, |
49
|
|
|
|
|
|
|
); |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub render { |
53
|
122
|
|
|
122
|
1
|
72965
|
my ( $self, @datasets ) = @_; |
54
|
122
|
|
50
|
|
|
612
|
my $gamma = 2 * max( 0, $self->box_weight || 1 ); |
55
|
122
|
|
|
|
|
340
|
my $adj_width = $self->width - $self->label_width - 2; |
56
|
|
|
|
|
|
|
|
57
|
122
|
|
|
|
|
190
|
my $smallest_min = min( map { $_->[MIN] } @datasets ); |
|
183
|
|
|
|
|
545
|
|
58
|
122
|
|
|
|
|
190
|
my $smallest_q1 = min( map { $_->[Q1] } @datasets ); |
|
183
|
|
|
|
|
468
|
|
59
|
122
|
|
|
|
|
193
|
my $biggest_q3 = max( map { $_->[Q3] } @datasets ); |
|
183
|
|
|
|
|
437
|
|
60
|
122
|
|
|
|
|
189
|
my $biggest_max = max( map { $_->[MAX] } @datasets ); |
|
183
|
|
|
|
|
424
|
|
61
|
|
|
|
|
|
|
|
62
|
122
|
|
50
|
|
|
295
|
my $span = ( $biggest_q3 - $smallest_q1 ) || 1; |
63
|
122
|
|
|
|
|
270
|
my $factor = $adj_width * $gamma / ( 2 + $gamma ) / $span; |
64
|
|
|
|
|
|
|
|
65
|
122
|
|
|
|
|
229
|
my $origin = int( $factor * ( $smallest_q1 - $span / $gamma ) ); |
66
|
122
|
|
|
|
|
220
|
my $edge = int( $factor * ( $biggest_q3 + $span / $gamma ) ); |
67
|
|
|
|
|
|
|
## warn "SPAN: $span; FACTOR: $factor; ORIGIN: $origin; EDGE: $edge; AW: $adj_width (" . ($edge - $origin) . ")\n"; |
68
|
|
|
|
|
|
|
|
69
|
122
|
|
|
|
|
135
|
my @str; |
70
|
122
|
50
|
|
|
|
306
|
if ( $self->with_scale ) { |
71
|
0
|
|
|
|
|
0
|
push @str, |
72
|
|
|
|
|
|
|
( " " x ($self->label_width) ) |
73
|
|
|
|
|
|
|
. sprintf( " |%-*g%*g|", |
74
|
|
|
|
|
|
|
$adj_width / 2, |
75
|
|
|
|
|
|
|
$origin / $factor, |
76
|
|
|
|
|
|
|
$adj_width / 2, |
77
|
|
|
|
|
|
|
$edge / $factor ); |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
122
|
|
|
|
|
203
|
for my $d (@datasets) { |
81
|
183
|
|
|
|
|
544
|
my ( $name, @copy ) = @$d; |
82
|
|
|
|
|
|
|
## warn "PRECOPY: @copy\n"; |
83
|
183
|
|
|
|
|
279
|
my @scaled = ( $name, map { int( $factor * $_ ) } @copy ); |
|
915
|
|
|
|
|
1737
|
|
84
|
|
|
|
|
|
|
## warn "POSTCOPY: @scaled\n"; |
85
|
183
|
|
|
|
|
569
|
push @str, _render_one( \@scaled, $origin, $edge, $adj_width, $self->label_width ); |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
122
|
50
|
|
|
|
551
|
return wantarray ? @str : $str[0]; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub _render_one { |
92
|
183
|
|
|
183
|
|
264
|
my ( $data, $origin, $edge, $frame_size, $label_width ) = @_; |
93
|
|
|
|
|
|
|
## warn "DATA: @$data\n"; |
94
|
183
|
|
|
|
|
239
|
my $str = ''; |
95
|
183
|
|
|
|
|
534
|
$str .= q{ } x ( max( $data->[MIN] - $origin, 0 ) ); |
96
|
183
|
|
|
|
|
474
|
$str .= q{-} x ( $data->[Q1] - max( $data->[MIN], $origin ) ); |
97
|
183
|
|
|
|
|
317
|
$str .= q{=} x ( $data->[MED] - $data->[Q1] ); |
98
|
183
|
|
|
|
|
206
|
$str .= "O"; |
99
|
183
|
|
|
|
|
280
|
$str .= q{=} x ( $data->[Q3] - $data->[MED] ); |
100
|
183
|
|
|
|
|
442
|
$str .= q{-} x ( min( $data->[MAX], $edge ) - $data->[Q3] ); |
101
|
183
|
|
|
|
|
386
|
$str .= q{ } x ( max( $edge - $data->[MAX], 0 ) ); |
102
|
|
|
|
|
|
|
## warn "STR: " . length($str) . "\n"; |
103
|
183
|
|
|
|
|
376
|
$str = substr( $str, 0, $frame_size ); |
104
|
|
|
|
|
|
|
## $str =~ s{^(.{0,$frame_size})}{$1}; |
105
|
|
|
|
|
|
|
## warn "STR: " . length($str) . "\n"; |
106
|
|
|
|
|
|
|
|
107
|
183
|
100
|
|
|
|
408
|
if ( substr( $str, 0, 1 ) eq '-' ) { |
108
|
61
|
|
|
|
|
101
|
substr( $str, 0, 1, "<" ); |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
183
|
100
|
|
|
|
383
|
if ( substr( $str, -1, 1 ) eq '-' ) { |
112
|
122
|
|
|
|
|
196
|
substr( $str, -1, 1, "->" ); |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
183
|
|
|
|
|
584
|
$str =~ s{\s+$}{}; |
116
|
183
|
|
|
|
|
322
|
my $name = substr($data->[NAME],0, $label_width); |
117
|
183
|
|
|
|
|
1147
|
return sprintf( "%*s %s", $label_width, $name, $str ); |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
1; |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# vim: ts=4 sts=4 sw=4 et: |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
__END__ |