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;
26 push @values, s/^\h* ( -? [0-9]* (?:\.[0-9]+)? )//x && $1;
27 if (defined $opt{trim}) {
28 my $trimpos = abs $opt{trim};
32 elsif (length > $trimpos) {
33 substr($_, $trimpos - 1) = '…';
40 my @order = sort { $b <=> $a } grep { length } @values;
41 my $maxval = $order[0];
42 my $minval = min $order[-1], 0;
43 my $lenval = max map { length } @order;
44 my $len = defined $opt{trim} && $opt{trim} <= 0 ? -$opt{trim} + 1 :
45 1 + max map { length } @lines; # left padding
46 my $size = ($maxval - $minval) &&
47 ($opt{width} - $lenval - $len) / ($maxval - $minval); # bar multiplication
50 if ($opt{markers} // 1 and $size > 0) {
51 sub orderpos { (($order[$_[0]] + $order[$_[0] + .5]) / 2 - $minval) * $size }
52 $barmark[ (sum(@order) / @order - $minval) * $size ] = '='; # average
53 $barmark[ orderpos($#order * .31731) ] = '>';
54 $barmark[ orderpos($#order * .68269) ] = '<';
55 $barmark[ orderpos($#order / 2) ] = '+'; # mean
56 $barmark[ -$minval * $size ] = '|' if $minval < 0; # zero
57 defined and $opt{color} and $_ = "\e[36m$_\e[0m" for @barmark;
60 for my $nr (0 .. $#lines) {
61 my $val = $values[$nr];
63 my $color = !$opt{color} ? 0 :
64 $val == $order[0] ? 32 : # max
65 $val == $order[-1] ? 31 : # min
67 printf "\e[%sm", $color if $color;
68 printf "%*s", $lenval, $val;
69 print "\e[0m" if $color;
71 printf '%-*s', $len, $lines[$nr];
72 print $barmark[$_] // '-' for 1 .. $size && (($val || 0) - $minval) * $size;
80 graph - append bar chart to input numbers
84 B<graph> [<options>] [<input>]
88 Each line starting with a number is given a bar to visualise relative sizes.
96 Disable colored output of values and bar markers.
98 =item -l, --length=[-]<size>
100 Trim line contents (between number and bars)
101 to a maximum number of characters.
102 The exceeding part is replaced by an abbreviation sign,
103 unless C<--length=0>.
105 Prepend a dash (i.e. make negative) to enforce padding
106 regardless of encountered contents.
110 Statistical positions to indicate on bars.
111 Cannot be customized yet,
112 only disabled by providing an empty argument.
114 Any value enables all marker characters:
121 the sum of all values divided by the number of counted lines.
126 the middle value or average between middle values.
130 Standard deviation left of the mean.
131 Only 16% of all values are lower.
135 Standard deviation right of the mean.
136 The part between B<< <--> >> encompass all I<normal> results,
137 or 68% of all entries.
141 =item -w, --width=<columns>
143 Override the maximum number of columns to use.
144 Appended graphics will extend to fill up the entire screen.
150 Commonly used after counting, such as users on the current server:
152 users | sed 's/ /\n/g' | sort | uniq -c | graph
154 Letter frequencies in text files:
156 cat /usr/share/games/fortunes/*.u8 |
157 perl -CO -nE 'say for grep length, split /\PL*/, uc' |
158 sort | uniq -c | graph
160 Memory usage of user processes:
162 ps xo %mem,pid,cmd | graph -l40
164 Sizes (in megabytes) of all root files and directories:
168 Number of HTTP requests per day:
170 cat log/access.log | cut -d\ -f4 | cut -d: -f1 | uniq -c | graph
172 Any kind of database query with leading counts:
174 echo 'SELECT count(*),schemaname FROM pg_tables GROUP BY 2' |
177 Git statistics, such commit count by year:
179 git log --pretty=%ci | cut -b-4 | uniq -c | graph
181 Or the most frequent authors:
183 git shortlog -sn | graph | head -3
187 Mischa POSLAWSKY <perl@shiar.org>