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, @_) }
18 'usage|h' => sub { podexit() },
19 'help' => sub { podexit(-verbose => 2) },
20 ) or exit 64; # EX_USAGE
22 $opt{width} ||= $ENV{COLUMNS} || 80;
23 $opt{color} //= -t *STDOUT; # enable on tty
25 if (defined $opt{follow}) {
34 $SIG{INT} = 'IGNORE'; # continue after assumed eof
39 push @values, s/^\h* ( -? [0-9]* (?:\.[0-9]+)? )//x && $1;
40 if (defined $opt{trim}) {
41 my $trimpos = abs $opt{trim};
45 elsif (length > $trimpos) {
46 substr($_, $trimpos - 1) = '…';
53 $SIG{INT} = 'DEFAULT';
59 my @order = sort { $b <=> $a } grep { length } @values;
60 my $maxval = $order[0];
61 my $minval = min $order[-1], 0;
62 my $lenval = max map { length } @order;
63 my $len = defined $opt{trim} && $opt{trim} <= 0 ? -$opt{trim} + 1 :
64 1 + max map { length } @lines; # left padding
65 my $size = ($maxval - $minval) &&
66 ($opt{width} - $lenval - $len) / ($maxval - $minval); # bar multiplication
69 if ($opt{markers} // 1 and $size > 0) {
70 my sub orderpos { (($order[$_[0]] + $order[$_[0] + .5]) / 2 - $minval) * $size }
71 $barmark[ (sum(@order) / @order - $minval) * $size ] = '='; # average
72 $barmark[ orderpos($#order * .31731) ] = '>';
73 $barmark[ orderpos($#order * .68269) ] = '<';
74 $barmark[ orderpos($#order / 2) ] = '+'; # mean
75 $barmark[ -$minval * $size ] = '|' if $minval < 0; # zero
76 defined and $opt{color} and $_ = "\e[36m$_\e[0m" for @barmark;
78 state $lastmax = $maxval;
79 if ($maxval > $lastmax) {
80 print ' ' x ($lenval + $len);
81 printf "\e[90m" if $opt{color};
83 ($lastmax - $minval) * $size + .5,
84 '-' x (($values[$nr - 1] - $minval) * $size);
85 print "\e[92m" if $opt{color};
86 say '+' x (($maxval - $lastmax - $minval) * $size + .5);
87 print "\e[0m" if $opt{color};
92 while ($nr <= $#lines) {
93 my $val = $values[$nr];
95 my $color = !$opt{color} ? 0 :
96 $val == $order[0] ? 32 : # max
97 $val == $order[-1] ? 31 : # min
99 printf "\e[%sm", $color if $color;
100 printf "%*s", $lenval, $val;
101 print "\e[0m" if $color;
103 printf '%-*s', $len, $lines[$nr];
104 print $barmark[$_] // '-' for 1 .. $size && (($val || 0) - $minval) * $size;
116 graph - append bar chart to input numbers
120 B<graph> [<options>] [<input>]
124 Each line starting with a number is given a bar to visualise relative sizes.
130 =item -c, --[no-]color
132 Force colored output of values and bar markers.
133 Defaults on if output is a tty,
134 disabled otherwise such as when piped or redirected.
136 =item -f, --follow[=<seconds>]
138 Interval to output partial progress.
140 =item -l, --length=[-]<size>
142 Trim line contents (between number and bars)
143 to a maximum number of characters.
144 The exceeding part is replaced by an abbreviation sign,
145 unless C<--length=0>.
147 Prepend a dash (i.e. make negative) to enforce padding
148 regardless of encountered contents.
152 Statistical positions to indicate on bars.
153 Cannot be customized yet,
154 only disabled by providing an empty argument.
156 Any value enables all marker characters:
163 the sum of all values divided by the number of counted lines.
168 the middle value or average between middle values.
172 Standard deviation left of the mean.
173 Only 16% of all values are lower.
177 Standard deviation right of the mean.
178 The part between B<< <--> >> encompass all I<normal> results,
179 or 68% of all entries.
183 =item -w, --width=<columns>
185 Override the maximum number of columns to use.
186 Appended graphics will extend to fill up the entire screen.
192 Commonly used after counting, such as users on the current server:
194 users | sed 's/ /\n/g' | sort | uniq -c | graph
196 Letter frequencies in text files:
198 cat /usr/share/games/fortunes/*.u8 |
199 perl -CO -nE 'say for grep length, split /\PL*/, uc' |
200 sort | uniq -c | graph
202 Memory usage of user processes:
204 ps xo %mem,pid,cmd | graph -l40
206 Sizes (in megabytes) of all root files and directories:
210 Number of HTTP requests per day:
212 cat log/access.log | cut -d\ -f4 | cut -d: -f1 | uniq -c | graph
214 Any kind of database query with leading counts:
216 echo 'SELECT count(*),schemaname FROM pg_tables GROUP BY 2' |
219 Git statistics, such commit count by year:
221 git log --pretty=%ci | cut -b-4 | uniq -c | graph
223 Or the most frequent authors:
225 git shortlog -sn | graph | head -3
230 perl -pe '$|=1; print s/ time=(.*)// ? "$1 for " : "> "' | graph -f
234 Mischa POSLAWSKY <perl@shiar.org>