5 use List::Util qw( min max sum );
6 use open qw( :std :utf8 );
10 use Getopt::Long '2.33', qw( :config gnu_getopt );
11 sub podexit { require Pod::Usage; Pod::Usage::pod2usage(-exitval => 0, @_) }
17 'usage|h' => sub { podexit() },
18 'help' => sub { podexit(-verbose => 2) },
19 ) or exit 64; # EX_USAGE
20 $opt{width} ||= $ENV{COLUMNS} || 80;
23 my @lines = readline or exit;
25 my @values = map { s/^\h* ( -? [0-9]* (?:\.[0-9]+)? )//x and $1 } @lines;
26 my @order = sort { $b <=> $a } grep { length } @values;
27 if (defined $opt{trim}) {
28 my $trimpos = abs $opt{trim};
29 $trimpos <= 1 ? ($_ = substr($_, 0, 1)) :
30 (length > $trimpos and substr($_, $trimpos - 1) = '…') for @lines;
33 my $maxval = $order[0];
34 my $minval = min $order[-1], 0;
35 my $lenval = max map { length } @order;
36 my $len = defined $opt{trim} && $opt{trim} <= 0 ? -$opt{trim} + 1 :
37 1 + max map { length } @lines; # left padding
38 my $size = ($maxval - $minval) &&
39 ($opt{width} - $lenval - $len) / ($maxval - $minval); # bar multiplication
42 if ($opt{markers} // 1 and $size > 0) {
43 sub orderpos { (($order[$_[0]] + $order[$_[0] + .5]) / 2 - $minval) * $size }
44 $barmark[ (sum(@order) / @order - $minval) * $size ] = '='; # average
45 $barmark[ orderpos($#order * .31731) ] = '>';
46 $barmark[ orderpos($#order * .68269) ] = '<';
47 $barmark[ orderpos($#order / 2) ] = '+'; # mean
48 $barmark[ -$minval * $size ] = '|' if $minval < 0; # zero
49 defined and $opt{color} and $_ = "\e[36m$_\e[0m" for @barmark;
52 for my $nr (0 .. $#lines) {
53 my $val = $values[$nr];
55 my $color = !$opt{color} ? 0 :
56 $val == $order[0] ? 32 : # max
57 $val == $order[-1] ? 31 : # min
59 printf "\e[%sm", $color if $color;
60 printf "%*s", $lenval, $val;
61 print "\e[0m" if $color;
63 printf '%-*s', $len, $lines[$nr];
64 print $barmark[$_] // '-' for 1 .. (($val || 0) - $minval) * $size;
72 graph - append bar chart to input numbers
76 B<graph> [<options>] [<input>]
80 Each line starting with a number is given a bar to visualise relative sizes.
88 Disable colored output of values and bar markers.
90 =item -l, --length=[-]<size>
92 Trim line contents (between number and bars)
93 to a maximum number of characters.
94 The exceeding part is replaced by an abbreviation sign,
97 Prepend a dash (i.e. make negative) to enforce padding
98 regardless of encountered contents.
102 Statistical positions to indicate on bars.
103 Cannot be customized yet,
104 only disabled by providing an empty argument.
106 Any value enables all marker characters:
113 the sum of all values divided by the number of counted lines.
118 the middle value or average between middle values.
122 Standard deviation left of the mean.
123 Only 16% of all values are lower.
127 Standard deviation right of the mean.
128 The part between B<< <--> >> encompass all I<normal> results,
129 or 68% of all entries.
133 =item -w, --width=<columns>
135 Override the maximum number of columns to use.
136 Appended graphics will extend to fill up the entire screen.
142 Commonly used after counting, such as users on the current server:
144 users | sed 's/ /\n/g' | sort | uniq -c | graph
146 Letter frequencies in text files:
148 cat /usr/share/games/fortunes/*.u8 |
149 perl -CO -nE 'say for grep length, split /\PL*/, uc' |
150 sort | uniq -c | graph
152 Memory usage of user processes:
154 ps xo %mem,pid,cmd | graph -l40
156 Sizes (in megabytes) of all root files and directories:
160 Number of HTTP requests per day:
162 cat log/access.log | cut -d\ -f4 | cut -d: -f1 | uniq -c | graph
164 Any kind of database query with leading counts:
166 echo 'SELECT count(*),schemaname FROM pg_tables GROUP BY 2' |
169 Git statistics, such commit count by year:
171 git log --pretty=%ci | cut -b-4 | uniq -c | graph
173 Or the most frequent authors:
175 git shortlog -sn | graph | head -3
179 Mischa POSLAWSKY <perl@shiar.org>