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;
28 my $trimpos = abs $opt{trim};
29 length > $trimpos and substr($_, $trimpos - 1) = '…' for @lines;
32 my $maxval = $order[0];
33 my $minval = min $order[-1], 0;
34 my $lenval = max map { length } @order;
35 my $len = defined $opt{trim} && $opt{trim} < 0 ? -$opt{trim} + 1 :
36 1 + max map { length } @lines; # left padding
37 my $size = ($maxval - $minval) &&
38 ($opt{width} - $lenval - $len) / ($maxval - $minval); # bar multiplication
41 if ($opt{markers} // 1) {
42 sub orderpos { (($order[$_[0]] + $order[$_[0] + .5]) / 2 - $minval) * $size }
43 $barmark[ (sum(@order) / @order - $minval) * $size ] = '='; # average
44 $barmark[ orderpos($#order / 2) ] = '+'; # mean
45 $barmark[ -$minval * $size ] = '|' if $minval < 0; # zero
46 defined and $opt{color} and $_ = "\e[36m$_\e[0m" for @barmark;
49 for my $nr (0 .. $#lines) {
50 my $val = $values[$nr];
52 my $color = !$opt{color} ? 0 :
53 $val == $order[0] ? 32 : # max
54 $val == $order[-1] ? 31 : # min
56 printf "\e[%sm", $color if $color;
57 printf "%*s", $lenval, $val;
58 print "\e[0m" if $color;
60 printf '%-*s', $len, $lines[$nr];
61 print $barmark[$_] // '-' for 1 .. (($val || 0) - $minval) * $size;
69 graph - append bar chart to input numbers
73 B<graph> [<options>] [<input>]
77 Each line starting with a number is given a bar to visualise relative sizes.
85 Disable colored output of values and bar markers.
87 =item -l, --length=[-]<size>
89 Trim line contents (between number and bars)
90 to a maximum number of characters.
91 The exceeding part is replaced by an abbreviation sign.
93 Prepend a dash (i.e. make negative) to enforce padding
94 regardless of encountered contents.
98 Statistical positions to indicate on bars.
99 Cannot be customized yet,
100 only disabled by providing an empty argument.
102 Any value enables all marker characters:
109 the sum of all values divided by the number of counted lines.
114 the middle value or average between middle values.
118 =item -w, --width=<columns>
120 Override the maximum number of columns to use.
121 Appended graphics will extend to fill up the entire screen.
127 Commonly used after counting, such as users on the current server:
129 users | sed 's/ /\n/g' | sort | uniq -c | graph
131 Letter frequencies in text files:
133 cat /usr/share/games/fortunes/*.u8 |
134 perl -CO -nE 'say for grep length, split /\PL*/, uc' |
135 sort | uniq -c | graph
137 Memory usage of user processes:
139 ps xo %mem,pid,cmd | graph -l40
141 Sizes (in megabytes) of all root files and directories:
145 Number of HTTP requests per day:
147 cat log/access.log | cut -d\ -f4 | cut -d: -f1 | uniq -c | graph
149 Any kind of database query with leading counts:
151 echo 'SELECT count(*),schemaname FROM pg_tables GROUP BY 2' |
154 Git statistics, such commit count by year:
156 git log --pretty=%ci | cut -b-4 | uniq -c | graph
158 Or the most frequent authors:
160 git shortlog -sn | graph | head -3
164 Mischa POSLAWSKY <perl@shiar.org>