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';
57 my @order = sort { $b <=> $a } grep { length } @values;
58 my $maxval = $order[0];
59 my $minval = min $order[-1], 0;
60 my $lenval = max map { length } @order;
61 my $len = defined $opt{trim} && $opt{trim} <= 0 ? -$opt{trim} + 1 :
62 1 + max map { length } @lines; # left padding
63 my $size = ($maxval - $minval) &&
64 ($opt{width} - $lenval - $len) / ($maxval - $minval); # bar multiplication
67 if ($opt{markers} // 1 and $size > 0) {
68 my sub orderpos { (($order[$_[0]] + $order[$_[0] + .5]) / 2 - $minval) * $size }
69 $barmark[ (sum(@order) / @order - $minval) * $size ] = '='; # average
70 $barmark[ orderpos($#order * .31731) ] = '>';
71 $barmark[ orderpos($#order * .68269) ] = '<';
72 $barmark[ orderpos($#order / 2) ] = '+'; # mean
73 $barmark[ -$minval * $size ] = '|' if $minval < 0; # zero
74 defined and $opt{color} and $_ = "\e[36m$_\e[0m" for @barmark;
78 while ($nr <= $#lines) {
79 my $val = $values[$nr];
81 my $color = !$opt{color} ? 0 :
82 $val == $order[0] ? 32 : # max
83 $val == $order[-1] ? 31 : # min
85 printf "\e[%sm", $color if $color;
86 printf "%*s", $lenval, $val;
87 print "\e[0m" if $color;
89 printf '%-*s', $len, $lines[$nr];
90 print $barmark[$_] // '-' for 1 .. $size && (($val || 0) - $minval) * $size;
102 graph - append bar chart to input numbers
106 B<graph> [<options>] [<input>]
110 Each line starting with a number is given a bar to visualise relative sizes.
116 =item -c, --[no-]color
118 Force colored output of values and bar markers.
119 Defaults on if output is a tty,
120 disabled otherwise such as when piped or redirected.
122 =item -f, --follow[=<seconds>]
124 Interval to output partial progress.
126 =item -l, --length=[-]<size>
128 Trim line contents (between number and bars)
129 to a maximum number of characters.
130 The exceeding part is replaced by an abbreviation sign,
131 unless C<--length=0>.
133 Prepend a dash (i.e. make negative) to enforce padding
134 regardless of encountered contents.
138 Statistical positions to indicate on bars.
139 Cannot be customized yet,
140 only disabled by providing an empty argument.
142 Any value enables all marker characters:
149 the sum of all values divided by the number of counted lines.
154 the middle value or average between middle values.
158 Standard deviation left of the mean.
159 Only 16% of all values are lower.
163 Standard deviation right of the mean.
164 The part between B<< <--> >> encompass all I<normal> results,
165 or 68% of all entries.
169 =item -w, --width=<columns>
171 Override the maximum number of columns to use.
172 Appended graphics will extend to fill up the entire screen.
178 Commonly used after counting, such as users on the current server:
180 users | sed 's/ /\n/g' | sort | uniq -c | graph
182 Letter frequencies in text files:
184 cat /usr/share/games/fortunes/*.u8 |
185 perl -CO -nE 'say for grep length, split /\PL*/, uc' |
186 sort | uniq -c | graph
188 Memory usage of user processes:
190 ps xo %mem,pid,cmd | graph -l40
192 Sizes (in megabytes) of all root files and directories:
196 Number of HTTP requests per day:
198 cat log/access.log | cut -d\ -f4 | cut -d: -f1 | uniq -c | graph
200 Any kind of database query with leading counts:
202 echo 'SELECT count(*),schemaname FROM pg_tables GROUP BY 2' |
205 Git statistics, such commit count by year:
207 git log --pretty=%ci | cut -b-4 | uniq -c | graph
209 Or the most frequent authors:
211 git shortlog -sn | graph | head -3
216 perl -pe '$|=1; print s/ time=(.*)// ? "$1 for " : "> "' | graph -f
220 Mischa POSLAWSKY <perl@shiar.org>