5 use List::Util qw( min max sum );
6 use open qw( :std :utf8 );
10 use Getopt::Long '2.33', qw( :config gnu_getopt );
13 Pod::Usage::pod2usage(-exitval => 0, -perldocopt => '-oman', @_);
22 'usage|h' => sub { podexit() },
23 'help' => sub { podexit(-verbose => 2) },
24 ) or exit 64; # EX_USAGE
26 $opt{width} ||= $ENV{COLUMNS} || 80;
27 $opt{color} //= -t *STDOUT; # enable on tty
29 if (defined $opt{follow}) {
38 $SIG{INT} = 'IGNORE'; # continue after assumed eof
43 s/^\h*// unless $opt{unmodified};
44 push @values, s/^ ( \h* -? [0-9]* \.? [0-9]+ |)//x && $1;
45 if (defined $opt{trim}) {
46 my $trimpos = abs $opt{trim};
50 elsif (length > $trimpos) {
51 substr($_, $trimpos - 1) = '…';
58 $SIG{INT} = 'DEFAULT';
64 my @order = sort { $b <=> $a } grep { length } @values;
65 my $maxval = $order[0];
66 my $minval = min $order[-1], 0;
67 my $lenval = max map { length } @order;
68 my $len = defined $opt{trim} && $opt{trim} <= 0 ? -$opt{trim} + 1 :
69 1 + max map { length } @lines; # left padding
70 my $size = ($maxval - $minval) &&
71 ($opt{width} - $lenval - $len) / ($maxval - $minval); # bar multiplication
74 if ($opt{markers} // 1 and $size > 0) {
75 my sub orderpos { (($order[$_[0]] + $order[$_[0] + .5]) / 2 - $minval) * $size }
76 $barmark[ (sum(@order) / @order - $minval) * $size ] = '='; # average
77 $barmark[ orderpos($#order * .31731) ] = '>';
78 $barmark[ orderpos($#order * .68269) ] = '<';
79 $barmark[ orderpos($#order / 2) ] = '+'; # mean
80 $barmark[ -$minval * $size ] = '|' if $minval < 0; # zero
81 defined and $opt{color} and $_ = "\e[36m$_\e[0m" for @barmark;
83 state $lastmax = $maxval;
84 if ($maxval > $lastmax) {
85 print ' ' x ($lenval + $len);
86 printf "\e[90m" if $opt{color};
88 ($lastmax - $minval) * $size + .5,
89 '-' x (($values[$nr - 1] - $minval) * $size);
90 print "\e[92m" if $opt{color};
91 say '+' x (($maxval - $lastmax - $minval) * $size + .5);
92 print "\e[0m" if $opt{color};
97 while ($nr <= $#lines) {
98 my $val = $values[$nr];
100 my $color = !$opt{color} ? 0 :
101 $val == $order[0] ? 32 : # max
102 $val == $order[-1] ? 31 : # min
104 printf "\e[%sm", $color if $color;
105 printf "%*s", $lenval, $val;
106 print "\e[0m" if $color;
108 printf '%-*s', $len, $lines[$nr];
109 print $barmark[$_] // '-' for 1 .. $size && (($val || 0) - $minval) * $size;
121 graph - append bar chart to input numbers
125 B<graph> [<options>] [<input>]
129 Each line starting with a number is given a bar to visualise relative sizes.
135 =item -c, --[no-]color
137 Force colored output of values and bar markers.
138 Defaults on if output is a tty,
139 disabled otherwise such as when piped or redirected.
141 =item -f, --follow[=<seconds>]
143 Interval to output partial progress.
145 =item -l, --length=[-]<size>
147 Trim line contents (between number and bars)
148 to a maximum number of characters.
149 The exceeding part is replaced by an abbreviation sign,
150 unless C<--length=0>.
152 Prepend a dash (i.e. make negative) to enforce padding
153 regardless of encountered contents.
157 Statistical positions to indicate on bars.
158 Cannot be customized yet,
159 only disabled by providing an empty argument.
161 Any value enables all marker characters:
168 the sum of all values divided by the number of counted lines.
173 the middle value or average between middle values.
177 Standard deviation left of the mean.
178 Only 16% of all values are lower.
182 Standard deviation right of the mean.
183 The part between B<< <--> >> encompass all I<normal> results,
184 or 68% of all entries.
188 =item -u, --unmodified
190 Do not strip leading whitespace.
191 Keep original value alignment, which may be significant in some programs.
193 =item -w, --width=<columns>
195 Override the maximum number of columns to use.
196 Appended graphics will extend to fill up the entire screen.
202 Commonly used after counting, such as users on the current server:
204 users | sed 's/ /\n/g' | sort | uniq -c | graph
206 Letter frequencies in text files:
208 cat /usr/share/games/fortunes/*.u8 |
209 perl -CO -nE 'say for grep length, split /\PL*/, uc' |
210 sort | uniq -c | graph
212 Memory usage of user processes:
214 ps xo %mem,pid,cmd | graph -l40
216 Sizes (in megabytes) of all root files and directories:
220 Number of HTTP requests per day:
222 cat log/access.log | cut -d\ -f4 | cut -d: -f1 | uniq -c | graph
224 Any kind of database query with leading counts:
226 echo 'SELECT count(*),schemaname FROM pg_tables GROUP BY 2' |
229 Git statistics, such commit count by year:
231 git log --pretty=%ci | cut -b-4 | uniq -c | graph
233 Or the most frequent authors:
235 git shortlog -sn | graph | head -3
240 perl -pe '$|=1; print s/ time=(.*)// ? "$1 for " : "> "' | graph -f
244 Mischa POSLAWSKY <perl@shiar.org>