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 / 2) ] = '+'; # mean
46 $barmark[ -$minval * $size ] = '|' if $minval < 0; # zero
47 defined and $opt{color} and $_ = "\e[36m$_\e[0m" for @barmark;
50 for my $nr (0 .. $#lines) {
51 my $val = $values[$nr];
53 my $color = !$opt{color} ? 0 :
54 $val == $order[0] ? 32 : # max
55 $val == $order[-1] ? 31 : # min
57 printf "\e[%sm", $color if $color;
58 printf "%*s", $lenval, $val;
59 print "\e[0m" if $color;
61 printf '%-*s', $len, $lines[$nr];
62 print $barmark[$_] // '-' for 1 .. (($val || 0) - $minval) * $size;
70 graph - append bar chart to input numbers
74 B<graph> [<options>] [<input>]
78 Each line starting with a number is given a bar to visualise relative sizes.
86 Disable colored output of values and bar markers.
88 =item -l, --length=[-]<size>
90 Trim line contents (between number and bars)
91 to a maximum number of characters.
92 The exceeding part is replaced by an abbreviation sign,
95 Prepend a dash (i.e. make negative) to enforce padding
96 regardless of encountered contents.
100 Statistical positions to indicate on bars.
101 Cannot be customized yet,
102 only disabled by providing an empty argument.
104 Any value enables all marker characters:
111 the sum of all values divided by the number of counted lines.
116 the middle value or average between middle values.
120 =item -w, --width=<columns>
122 Override the maximum number of columns to use.
123 Appended graphics will extend to fill up the entire screen.
129 Commonly used after counting, such as users on the current server:
131 users | sed 's/ /\n/g' | sort | uniq -c | graph
133 Letter frequencies in text files:
135 cat /usr/share/games/fortunes/*.u8 |
136 perl -CO -nE 'say for grep length, split /\PL*/, uc' |
137 sort | uniq -c | graph
139 Memory usage of user processes:
141 ps xo %mem,pid,cmd | graph -l40
143 Sizes (in megabytes) of all root files and directories:
147 Number of HTTP requests per day:
149 cat log/access.log | cut -d\ -f4 | cut -d: -f1 | uniq -c | graph
151 Any kind of database query with leading counts:
153 echo 'SELECT count(*),schemaname FROM pg_tables GROUP BY 2' |
156 Git statistics, such commit count by year:
158 git log --pretty=%ci | cut -b-4 | uniq -c | graph
160 Or the most frequent authors:
162 git shortlog -sn | graph | head -3
166 Mischa POSLAWSKY <perl@shiar.org>