5 use List::Util qw( min max sum );
6 use open qw( :std :utf8 );
10 use Getopt::Long '2.33', qw( :config gnu_getopt );
13 Pod::Usage::pod2usage(-exitval => 0, -perldocopt => '-oman', @_);
22 'usage|h' => sub { podexit() },
23 'help' => sub { podexit(-verbose => 2) },
24 ) or exit 64; # EX_USAGE
26 $opt{width} ||= $ENV{COLUMNS} || 80;
27 $opt{color} //= -t *STDOUT; # enable on tty
29 if (defined $opt{follow}) {
38 $SIG{INT} = 'IGNORE'; # continue after assumed eof
43 s/^\h*// unless $opt{unclean};
44 push @values, s/^ ( \h* -? [0-9]* \.? [0-9]+ |)//x && $1;
45 if (defined $opt{trim}) {
46 my $trimpos = abs $opt{trim};
50 elsif (length > $trimpos) {
51 substr($_, $trimpos - 1) = '…';
58 $SIG{INT} = 'DEFAULT';
64 my @order = sort { $b <=> $a } grep { length } @values;
65 my $maxval = $order[0];
66 my $minval = min $order[-1], 0;
67 my $lenval = max map { length } @order;
68 my $len = defined $opt{trim} && $opt{trim} <= 0 ? -$opt{trim} + 1 :
69 1 + max map { length } @lines; # left padding
70 my $size = ($maxval - $minval) &&
71 ($opt{width} - $lenval - $len) / ($maxval - $minval); # bar multiplication
74 if ($opt{markers} // 1 and $size > 0) {
75 my sub orderpos { (($order[$_[0]] + $order[$_[0] + .5]) / 2 - $minval) * $size }
76 $barmark[ (sum(@order) / @order - $minval) * $size ] = '='; # average
77 $barmark[ orderpos($#order * .31731) ] = '>';
78 $barmark[ orderpos($#order * .68269) ] = '<';
79 $barmark[ orderpos($#order / 2) ] = '+'; # mean
80 $barmark[ -$minval * $size ] = '|' if $minval < 0; # zero
81 defined and $opt{color} and $_ = "\e[36m$_\e[0m" for @barmark;
83 state $lastmax = $maxval;
84 if ($maxval > $lastmax) {
85 print ' ' x ($lenval + $len);
86 printf "\e[90m" if $opt{color};
88 ($lastmax - $minval) * $size + .5,
89 '-' x (($values[$nr - 1] - $minval) * $size);
90 print "\e[92m" if $opt{color};
91 say '+' x (($maxval - $lastmax - $minval) * $size + .5);
92 print "\e[0m" if $opt{color};
97 while ($nr <= $#lines) {
98 my $val = $values[$nr];
100 my $color = !$opt{color} ? 0 :
101 $val == $order[0] ? 32 : # max
102 $val == $order[-1] ? 31 : # min
104 printf "\e[%sm", $color if $color;
105 printf "%*s", $lenval, $val;
106 print "\e[0m" if $color;
108 printf '%-*s', $len, $lines[$nr];
109 print $barmark[$_] // '-' for 1 .. $size && (($val || 0) - $minval) * $size;
121 graph - append bar chart to input numbers
125 B<graph> [<options>] [<input>]
129 Each line starting with a number is given a bar to visualise relative sizes.
135 =item -c, --[no-]color
137 Force colored output of values and bar markers.
138 Defaults on if output is a tty,
139 disabled otherwise such as when piped or redirected.
141 =item -f, --follow[=<seconds>]
143 Interval to output partial progress.
145 =item -l, --length=[-]<size>
147 Trim line contents (between number and bars)
148 to a maximum number of characters.
149 The exceeding part is replaced by an abbreviation sign,
150 unless C<--length=0>.
152 Prepend a dash (i.e. make negative) to enforce padding
153 regardless of encountered contents.
157 Statistical positions to indicate on bars.
158 Cannot be customized yet,
159 only disabled by providing an empty argument.
161 Any value enables all marker characters:
168 the sum of all values divided by the number of counted lines.
173 the middle value or average between middle values.
177 Standard deviation left of the mean.
178 Only 16% of all values are lower.
182 Standard deviation right of the mean.
183 The part between B<< <--> >> encompass all I<normal> results,
184 or 68% of all entries.
190 =item -w, --width=<columns>
192 Override the maximum number of columns to use.
193 Appended graphics will extend to fill up the entire screen.
199 Commonly used after counting, such as users on the current server:
201 users | sed 's/ /\n/g' | sort | uniq -c | graph
203 Letter frequencies in text files:
205 cat /usr/share/games/fortunes/*.u8 |
206 perl -CO -nE 'say for grep length, split /\PL*/, uc' |
207 sort | uniq -c | graph
209 Memory usage of user processes:
211 ps xo %mem,pid,cmd | graph -l40
213 Sizes (in megabytes) of all root files and directories:
217 Number of HTTP requests per day:
219 cat log/access.log | cut -d\ -f4 | cut -d: -f1 | uniq -c | graph
221 Any kind of database query with leading counts:
223 echo 'SELECT count(*),schemaname FROM pg_tables GROUP BY 2' |
226 Git statistics, such commit count by year:
228 git log --pretty=%ci | cut -b-4 | uniq -c | graph
230 Or the most frequent authors:
232 git shortlog -sn | graph | head -3
237 perl -pe '$|=1; print s/ time=(.*)// ? "$1 for " : "> "' | graph -f
241 Mischa POSLAWSKY <perl@shiar.org>