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