5 use List::Util qw( min max sum );
6 use open qw( :std :utf8 );
14 Getopt::Long->import('2.33', qw( :config gnu_getopt ));
18 'M' => sub { $opt{color} = 0 },
22 s/\A[0-9]+\z/(?:\\S*\\h+){$_}\\K/;
24 (!!$1 && '(?:\d+\D+\b){'.$1.'}\K') . '\s* (?=\d)'
26 $opt{anchor} = qr/$_/;
27 } or die $@ =~ s/(?:\ at\ \N+)?\Z/ for option $_[0]/r;
34 'trim|length|l=s' => sub {
35 my ($optname, $optval) = @_;
36 $optval =~ s/%$// and $opt{trimpct}++;
37 $optval =~ m/\A-?[0-9]+\z/ or die(
38 "Value \"$optval\" invalid for option $optname",
39 " (number or percentage expected)\n"
47 my ($optname, $optval) = @_;
49 $optval =~ /\A-[0-9]+\z/ and $optval .= '-'; # tail shorthand
52 $optval =~ m/\A (?: (-? [0-9]+)? - )? (-? [0-9]+)? \z/ or die(
53 "Value \"$optval\" invalid for option limit",
58 s/\A-0*\z// and $_ ||= undef for $end // ();
63 return max(0, $lines + $start + 2);
68 my ($limit, $offset) = @_;
70 return $offset - $end - 1; # count
73 return $limit - $end + 1; # bottom
75 elsif ($end <= $limit) {
76 return $end - 1; # less
84 'graph-format=s' => sub {
85 $opt{'graph-format'} = substr $_[1], 0, 1;
92 fire => [qw( 90 31 91 33 93 97 96 )],
93 fire256=> [map {"38;5;$_"} qw(
95 202 208 214 220 226 227 228 229 230 231 159
97 whites => [qw( 1;30 0;37 1;37 )],
98 grays => [map {"38;5;$_"} 0, 232..255, 15],
99 random => [map {"38;5;$_"} List::Util::shuffle(17..231)],
100 rainbow=> [map {"38;5;$_"}
102 (map { 196 + $_*6 } 0..4), # +g
103 (map { 226 - $_*6*6 } 0..4), # -r
104 (map { 46 + $_ } 0..4), # +b
105 (map { 51 - $_*6 } 0..4), # -g
106 (map { 21 + $_*6*6 } 0..4), # +r
107 (map { 201 - $_ } 0..4), # -b
111 my @vals = split /[^0-9;]/, $_[1]
112 or die "Empty palette resulting from \"$_[1]\"\n";
122 my $mascot = $opt{ascii} ? '=^,^=' : 'ฅ^•ﻌ•^ฅ';
123 say "barcat $mascot version $VERSION";
127 /^=/ ? last : print for readline *DATA; # text between __END__ and pod
132 Pod::Usage::pod2usage(
133 -exitval => 0, -perldocopt => '-oman', -verbose => 2,
136 ) or exit 64; # EX_USAGE
139 $opt{width} ||= $ENV{COLUMNS} || qx(tput cols) || 80 unless $opt{spark};
140 $opt{color} //= $ENV{NO_COLOR} ? 0 : -t *STDOUT; # enable on tty
141 $opt{'graph-format'} //= '-';
142 $opt{trim} *= $opt{width} / 100 if $opt{trimpct};
143 $opt{units} = [split //, ' kMGTPEZYRQqryzafpn'.($opt{ascii} ? 'u' : 'μ').'m']
144 if $opt{'human-readable'};
145 $opt{'value-length'} = 4 if $opt{units};
146 $opt{'value-length'} = 1 if $opt{unmodified};
147 $opt{'signal-stat'} //= exists $SIG{INFO} ? 'INFO' : 'QUIT';
148 $opt{markers} //= '=avg >31.73v <68.27v +50v |0';
149 $opt{report} //= join('',
150 '${partsum+; $_ .= " of "}',
151 '${sum+; color(1); $_ .= " total in "}',
153 '${lines#; $_ = $_ != @order && " over $_ lines"}',
154 sprintf('${count: (%s)}', join ', ',
155 '${min; color(31)} min',
156 '${avg; $opt{reformat} or $_ = sprintf "%0.2f", $_; color(36)} avg',
157 '${max; color(32)} max',
160 $opt{palette} //= $opt{color} && [31, 90, 32];
161 $opt{indicators} = [split //, $opt{indicators} ||
162 ($opt{ascii} ? ' .oO' : $opt{spark} ? ' ▁▂▃▄▅▆▇█' : ' ▏▎▍▌▋▊▉█')
163 ] if defined $opt{indicators} or $opt{spark};
164 $opt{input} = (@ARGV && $ARGV[0] =~ m/\A[-0-9]/) ? \@ARGV : undef
165 and undef $opt{interval};
167 $opt{'calc-format'} = sub { sprintf '%*.*f', 0, 2, $_[0] };
168 $opt{'value-format'} = $opt{sexagesimal} ? sub {
169 my $s = abs($_[0]) + .5;
170 sprintf('%s%d:%02d:%02d', $_[0] < 0 && '-', $s/3600, $s/60%60, $s%60);
171 } : $opt{units} && sub {
173 log(abs $_[0] || 1) / log(10)
174 - 3 * (abs($_[0]) < .9995) # shift to smaller unit if below 1
175 + 1e-15 # float imprecision
177 my $decimal = ($unit % 3) == ($unit < 0);
178 $unit -= log($decimal ? .995 : .9995) / log(10); # rounded
179 $decimal = ($unit % 3) == ($unit < 0);
180 $decimal &&= $_[0] !~ /^-?0*[0-9]{1,3}$/; # integer 0..999
182 3 + ($_[0] < 0), # digits plus optional negative sign
184 $_[0] / 1000 ** int($unit/3), # number
185 $#{$opt{units}} * 1.5 < abs $unit ? sprintf('e%d', $unit) :
186 $opt{units}->[$unit/3] # suffix
188 } and $opt{reformat}++;
189 $opt{'value-format'} ||= sub { sprintf '%.8g', $_[0] };
192 my (@lines, @values, @order, %uniq);
194 $SIG{$_} = \&show_stat for $opt{'signal-stat'} || ();
197 alarm $opt{interval} if defined $opt{interval} and $opt{interval} > 0;
199 $SIG{INT} = \&show_exit;
201 if (defined $opt{interval}) {
202 $opt{interval} ||= 1;
203 alarm $opt{interval} if $opt{interval} > 0;
206 require Tie::Array::Sorted;
207 tie @order, 'Tie::Array::Sorted', sub { $_[1] <=> $_[0] };
208 } or warn $@, "Expect slowdown with large datasets!\n"
212 my $float = qr<[0-9]* [.]? [0-9]+ (?: e[+-]?[0-9]+ )?>; # positive numberish
213 my $valmatch = $opt{anchor} // qr/\A/;
214 $valmatch .= !$opt{count} ? qr/( \h* -? $float |)/ :
215 $opt{anchor} ? qr/(\S*)/ : qr/(.*)/;
217 while (defined ($_ = $opt{input} ? shift @{ $opt{input} } : readline)) {
221 $valnum = m/$valmatch/ && $1;
222 $uniq{$valnum}++ and next;
223 push @values, $valnum;
227 s/\A\h*// unless $opt{unmodified};
228 $valnum = s/$valmatch/\n/ && $1;
229 push @values, $valnum;
230 push @order, $valnum if length $valnum;
233 if (defined $opt{trim} and defined $valnum) {
234 my $trimpos = abs $opt{trim};
235 $trimpos -= length $valnum if $opt{unmodified};
237 $_ = substr $_, 0, 2;
239 elsif (length > $trimpos) {
240 # cut and replace (intentional lvalue for speed, contrary to PBP)
241 substr($_, $trimpos - 1) = $opt{ascii} ? '>' : '…';
247 show_lines() if defined $opt{interval} and $opt{interval} < 0
248 and $. % $opt{interval} == 0;
251 $SIG{INT} = 'DEFAULT';
254 $opt{color} and defined $_[0] or return '';
255 return "\e[$_[0]m" if defined wantarray;
256 $_ = color(@_) . $_ . color(0) if defined;
261 state $nr = $opt{hidemin} ? $opt{hidemin}->($#lines) : 0;
262 @lines > $nr or return;
264 my $limit = $opt{hidemax} ? $opt{hidemax}->($#lines, $nr) : $#lines;
267 $_ = $uniq{$_} for @values[$nr .. $limit];
271 @order = sort { $b <=> $a } @order unless tied @order;
272 my $maxval = $opt{maxval} // (
273 $opt{hidemax} ? max grep { length } @values[$nr .. $limit] :
276 my $minval = $opt{minval} // min $order[-1] // (), 0;
277 my $range = $maxval - $minval;
278 $range &&= log $range if $opt{log};
279 my $lenval = $opt{'value-length'} // max map { length } @order;
280 my $len = defined $opt{trim} && $opt{trim} <= 0 ? -$opt{trim} + 1 :
281 max(map { length $values[$_] && length $lines[$_] } $nr .. $limit)
283 my $size = defined $opt{width} && $range &&
284 ($opt{width} - $lenval - $len - !!$opt{indicators}); # bar multiplication
287 if ($opt{markers} and $size > 0) {
288 for my $markspec (split /\h/, $opt{markers}) {
289 my ($char, $func) = split //, $markspec, 2;
290 my $increment = $func =~ s/[+]\z//;
292 if ($func =~ /\A\/($float)\z/) {
293 my @range = my $multiple = my $next = $1;
294 while ($next < $maxval) {
295 $multiple *= 10 if $opt{log};
296 push @range, $next += $multiple;
302 warn "Invalid marker $char: $@" if $@;
307 $pos &&= log $pos if $opt{log};
309 $increment ||= $minval && !$pos;
310 color(36) for $barmark[$pos / $range * $size + $increment + .5] = $char;
314 state $lastmax = $maxval;
315 if ($maxval > $lastmax) {
316 print ' ' x ($lenval + $len);
319 ($lastmax - $minval) * $size / $range + .5,
320 '-' x (($values[$nr - 1] - $minval) * $size / $range);
322 say '+' x (($range - $lastmax) * $size / $range + .5);
329 color(31), sprintf('%*s', $lenval, $minval),
330 color(90), '-', color(36), '+',
331 color(32), sprintf('%*s', $size - 3, $maxval),
332 color(90), '-', color(36), '+',
336 while ($nr <= $limit) {
337 my $val = $values[$nr];
340 $rel = $val - $minval;
341 $rel &&= log $rel if $opt{log};
342 $rel = min(1, $rel / $range) if $range; # 0..1
344 my $color = !length $val || !$opt{palette} ? undef :
345 $val == $order[0] ? $opt{palette}->[-1] : # max
346 $val == $order[-1] ? $opt{palette}->[0] : # min
347 $opt{palette}->[ $rel * ($#{$opt{palette}} - 1) + 1 ];
348 my $indicator = $opt{indicators} && $opt{indicators}->[
349 !length($val) || !$#{$opt{indicators}} ? 0 : # blank
350 $#{$opt{indicators}} < 2 ? 1 :
351 $val >= $order[0] ? -1 :
352 $rel * ($#{$opt{indicators}} - 1e-14) + 1
356 say '' if $opt{width} and $nr and $nr % $opt{width} == 0;
357 print color($color), $_ for $indicator;
360 print $indicator if defined $indicator;
363 $val = sprintf("%*s", $lenval,
364 $opt{reformat} ? $opt{'value-format'}->($val) : $val
366 color($color) for $val;
368 my $line = $lines[$nr] =~ s/\n/$val/r;
369 if (not length $val) {
373 printf '%-*s', $len + length($val), $line;
374 if ($rel and $size) {
375 print $barmark[$_] // $opt{'graph-format'}
376 for 1 .. $rel * $size + .5;
383 say $opt{palette} ? color(0) : '' if $opt{spark};
384 %uniq = () if $opt{interval} and $opt{count};
395 my $linemin = !$opt{hidemin} ? 0 :
396 ($vars{start} = $opt{hidemin}->($#lines));
397 my $linemax = !$opt{hidemax} ? $#lines :
398 ($vars{end} = $opt{hidemax}->($#lines, $vars{start}));
400 $vars{partsum} = sum(0, grep {length} @values[$linemin .. $linemax])
401 if $linemin <= $linemax and ($opt{hidemin} or $opt{hidemax});
407 say varfmt($opt{report}, \%vars);
413 if ($func eq 'avg') {
414 return calc('sum') / @order;
416 elsif ($func eq 'sum') {
417 state $cache; # avoid recount
418 state $cachednr = 0; # if unchanged
419 unless (@order == $cachednr) {
420 $cache = sum(@order);
425 elsif ($func =~ /\A([0-9.]+)v\z/) {
427 "percentile $1 out of bounds\n"
429 my $index = $#order * $1 / 100;
430 my $f = $index - int $index;
431 my $val = $order[$index];
433 my $next = $order[$index + 1];
434 $val -= $f * ($val - $next);
438 elsif ($func =~ /\A-?[0-9.]+\z/) {
442 die "$func unknown\n";
447 my ($fmt, $vars) = @_;
448 $fmt =~ s[\$\{ \h*+ ((?: [^{}]++ | \{(?1)\} )+) \}]{
449 my ($name, $op, $cmd) = split /\s*([;:])/, $1, 2;
450 my $format = $name =~ s/\+// || $name !~ s/\#// && $opt{reformat};
451 local $_ = exists $vars->{$name} ? $vars->{$name} : calc($name);
453 $_ = $opt{'value-format'}->($_) if $format;
454 if ($cmd and $op eq ':') {
455 $_ = !!$_ && varfmt($cmd, $vars);
459 warn "Error in \$$name report: $@" if $@;
469 show_stat() if $opt{stat};
470 exit 130 if @_; # 0x80+signo
478 barcat [OPTIONS] [FILES|NUMBERS] (=•.•=)
481 -a, --[no-]ascii Restrict user interface to ASCII characters
482 -C, --[no-]color Force colored output of values and bar markers
483 -c, --count Omit repetitions and count the number of
485 -f, --field=([+]N|REGEXP)
486 Compare values after a given number of whitespace
488 --header Prepend a chart axis with minimum and maximum
490 -H, --human-readable Format values using SI unit prefixes
491 --sexagesimal Convert seconds to HH:MM:SS time format
492 -t, --interval[=(N|-LINES)]
493 Output partial progress every given number of
494 seconds or input lines
495 -l, --length=[-]SIZE[%] Trim line contents (between number and bars)
496 -L, --limit=[N|[-]START(-[END]|+N)]
497 Select a range of lines to display
498 -e, --log Logarithmic (exponential) scale instead of linear
499 --graph-format=CHAR Glyph to repeat for the graph line
500 -m, --markers=FORMAT Statistical positions to indicate on bars
501 --min=N, --max=N Bars extend from 0 or the minimum value if lower
502 --palette=(PRESET|COLORS)
503 Override colors of parsed numbers
504 -_, --spark Replace lines by sparklines
505 --indicators[=CHARS] Prefix a unicode character corresponding to each
507 -s, --stat Total statistics after all data
508 -u, --unmodified Do not reformat values, keeping leading whitespace
509 --value-length=SIZE Reserved space for numbers
510 -w, --width=COLUMNS Override the maximum number of columns to use
511 -h, --usage Overview of available options
512 --help Full pod documentation
513 -V, --version Version information
519 barcat - concatenate texts with graph to visualize values
523 B<barcat> [I<options>] [I<file>... | I<numbers>]
527 Visualizes relative sizes of values read from input
528 (parameters, file(s) or STDIN).
529 Contents are concatenated similar to I<cat>,
530 but numbers are reformatted and a bar graph is appended to each line.
532 It can has various options for input and output (re)formatting,
533 but remains limited to one-dimensional charts.
534 For more complex graphing needs
535 you'll need a larger animal like I<gnuplot>.
541 =item B<-a>, B<-->[B<no->]B<ascii>
543 Restrict user interface to ASCII characters,
544 replacing default UTF-8 by their closest approximation.
545 Input is always interpreted as UTF-8 and shown as is.
547 =item B<-C>, B<-->[B<no->]B<color>
549 Force colored output of values and bar markers.
550 Defaults on if output is a tty,
551 disabled otherwise such as when piped or redirected.
552 Can also be disabled by setting B<-M>
553 or the I<NO_COLOR> environment variable.
555 =item B<-c>, B<--count>
557 Omit repetitions and count the number of occurrences.
558 Similar to piping input through C<sort | uniq -c>
559 but keeping the order of first appearances.
561 Lines are omitted if they (or a specified field) are identical,
562 and the amount of matches is prepended and used as values
563 for bars and subsequent statistics.
565 =item B<-f>, B<--field>=([B<+>]I<number> | I<regexp>)
567 Compare values after a given number of whitespace separators,
568 or matching a regular expression.
570 Unspecified or B<-f0> means values are at the start of each line.
571 With B<-f1> the second word is taken instead.
572 A string can indicate the starting position of a value
573 (such as B<-f:> if preceded by colons),
574 or capture the numbers itself,
575 for example B<-f'(\d+)'> for the first digits anywhere.
576 A shorthand for this is C<+0>, or C<+N> to find the Nth number.
580 Prepend a chart axis with minimum and maximum values labeled.
582 =item B<-H>, B<--human-readable>
584 Format values using SI unit prefixes,
585 turning long numbers like C<12356789> into C<12.4M>.
586 Also changes an exponent C<1.602176634e-19> to C<160.2z>.
587 Short integers are aligned but kept without decimal point.
589 =item B<--sexagesimal>
591 Convert seconds to HH:MM:SS time format.
593 =item B<-t>, B<--interval>[=(I<seconds> | B<->I<lines>)]
595 Output partial progress every given number of seconds or input lines.
596 An update can also be forced by sending a I<SIGALRM> alarm signal.
598 =item B<-l>, B<--length>=[B<->]I<size>[B<%>]
600 Trim line contents (between number and bars)
601 to a maximum number of characters.
602 The exceeding part is replaced by an abbreviation sign,
603 unless B<--length=0>.
605 Prepend a dash (i.e. make negative) to enforce padding
606 regardless of encountered contents.
608 =item B<-L>, B<--limit>=[I<count> | [B<->]I<start>(B<->[I<end>] | B<+>I<count>)]
610 Select a range of lines to display.
611 A single integer indicates the last line number (like I<head>),
612 or first line counting from the bottom if negative (like I<tail>).
614 A range consists of a starting line number followed by either
615 a dash C<-> to an optional end, or plus sign C<+> with count.
617 All hidden input is still counted and analyzed for statistics,
618 but disregarded for padding and bar size.
620 =item B<-e>, B<--log>
622 Logarithmic (B<e>xponential) scale instead of linear
623 to compare orders of magnitude.
625 =item B<--graph-format>=I<character>
627 Glyph to repeat for the graph line.
628 Defaults to a dash C<->.
630 =item B<-m>, B<--markers>=I<format>
632 Statistical positions to indicate on bars.
633 A single indicator glyph precedes each position:
639 Exact value to match on the axis.
640 A vertical bar at the zero crossing is displayed by C<|0>
642 For example C<π3.14> would locate pi.
644 =item B</>I<interval>
646 Repeated at every multiple of a number.
647 For example C<:/1> for a grid at every integer.
649 =item I<percentage>B<v>
651 Ranked value at the given percentile,
652 or score at or below which a percentage falls
653 in its frequency distribution (inclusive).
655 The default shows C<+> at C<50v> for the mean or median:
656 the middle value or interpolation between two values.
657 One standard deviation below the median is at about C<68v>.
658 The default includes C<< >31.73v <68.27v >>
659 to encompass all I<normal> results, or 68% of all entries, by I<< <--> >>.
663 Matches the average (arithmetic mean);
664 the sum of all values divided by the number of counted lines.
665 Indicated by default as C<=>.
669 =item B<--min>=I<number>, B<--max>=I<number>
671 Bars extend from 0 or the minimum value if lower,
672 to the largest value encountered.
673 These options can be set to customize this range.
675 =item B<--palette>=(I<preset> | I<color>...)
677 Override colors of parsed numbers.
678 Can be any CSI escape, such as C<90> for default dark gray,
679 or alternatively C<1;30> for bright black.
681 In case of additional colors,
682 the last is used for values equal to the maximum, the first for minima.
683 If unspecified, these are green and red respectively (C<31 90 32>).
684 Multiple intermediate colors will be distributed
685 relative to the size of values.
687 A non-numeric name can refer to a predefined color scheme:
693 Minimal set of monochrome brightnesses.
697 Utilize the 24 grayscale ramp in 256-color terminals.
701 Gradient red to white in 7 out of 16 colors.
705 Extended to 17 colors out of 256.
709 Saturated red to green to blue to red.
713 All 215 extended colors in unrelated orders.
717 =item B<-_>, B<--spark>
719 Replace lines by I<sparklines>,
720 single characters (configured by B<--indicators>)
721 corresponding to input values.
723 =item B<--indicators>[=I<characters>]
725 Prefix a unicode character corresponding to each value.
726 The first specified character will be used for non-values,
727 the remaining sequence will be distributed over the range of values.
728 Unspecified, block fill glyphs U+2581-2588 will be used.
730 =item B<-s>, B<--stat>
732 Total statistics after all data.
734 While processing (possibly a neverending pipe),
735 intermediate results are also shown on signal I<SIGINFO> if available (control+t on BSDs)
736 or I<SIGQUIT> otherwise (ctrl+\ on linux).
738 =item B<-u>, B<--unmodified>
740 Do not reformat values, keeping leading whitespace.
741 Keep original value alignment, which may be significant in some programs.
743 =item B<--value-length>=I<size>
745 Reserved space for numbers.
747 =item B<-w>, B<--width>=I<columns>
749 Override the maximum number of columns to use.
750 Appended graphics will extend to fill up the entire screen,
751 otherwise determined by the environment variable I<COLUMNS>
752 or by running the I<tput> command.
754 =item B<-h>, B<--usage>
756 Overview of available options.
760 Full pod documentation
761 as rendered by perldoc.
763 =item B<-V>, B<--version>
773 seq 30 | awk '{print sin($1/10)}' | barcat
775 Compare file sizes (with human-readable numbers):
777 du -d0 -b * | barcat -H
779 Same from formatted results, selecting the first numeric value:
781 tree -s --noreport | barcat -H -f+
783 Compare media metadata, like image size or play time:
785 exiftool -T -p '$megapixels ($imagesize) $filename' * | barcat
787 exiftool -T -p '$duration# $avgbitrate# $filename' * | barcat --sexagesimal
789 find -type f -print0 | xargs -0 -L1 \
790 ffprobe -show_format -of json -v error |
791 jq -r '.format|.duration+" "+.bit_rate+" "+.filename' | barcat --sex
793 Memory usage of user processes with long names truncated:
795 ps xo rss,pid,cmd | barcat -l40
797 Monitor network latency from prefixed results:
799 ping google.com | barcat -f'time=\K' -t
801 Commonly used after counting, eg letter frequencies in text files:
803 cat /usr/share/games/fortunes/*.u8 |
804 perl -CS -nE 'say for grep length, split /\PL*/, uc' |
805 sort | uniq -c | barcat
807 Users on the current server while preserving order:
809 users | tr ' ' '\n' | barcat -c
811 Number of HTTP requests per day:
813 barcat -cf'\[([^:]+)' httpd/access.log
815 Any kind of database query results, preserving returned alignment:
817 echo 'SELECT sin(value * .1) FROM generate_series(0, 30) value' |
820 In PostgreSQL from within the client; a fancy C<\dt+> perhaps:
822 > SELECT schemaname, relname, pg_total_relation_size(relid)
823 FROM pg_statio_user_tables ORDER BY idx_blks_hit
826 Same thing in SQLite (requires the sqlite3 client):
829 > SELECT name, sum(pgsize) FROM dbstat GROUP BY 1;
831 Earthquakes worldwide magnitude 1+ in the last 24 hours:
833 curl https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/1.0_day.csv |
834 column -ts, -n | barcat -f4 -u -l80%
836 External datasets, like movies per year:
838 curl https://github.com/prust/wikipedia-movie-data/raw/master/movies.json -L |
839 jq .[].year | uniq -c | barcat
841 Pokémon height comparison:
843 curl https://github.com/Biuni/PokemonGO-Pokedex/raw/master/pokedex.json -L |
844 jq -r '.pokemon[] | [.height,.num,.name] | join(" ")' | barcat
846 USD/EUR exchange rate from CSV provided by the ECB:
848 curl https://sdw.ecb.europa.eu/export.do \
849 -Gd 'node=SEARCHRESULTS&q=EXR.D.USD.EUR.SP00.A&exportType=csv' |
850 barcat -f',\K' --value-length=7
852 Total population history in XML from the World Bank:
854 curl http://api.worldbank.org/v2/country/1W/indicator/SP.POP.TOTL |
855 xmlstarlet sel -t -m '*/*' -v wb:date -o ' ' -v wb:value -n |
856 barcat -f1 -H --markers=+/1e9
858 Population and other information for all countries:
860 curl http://download.geonames.org/export/dump/countryInfo.txt |
861 grep -v '^#\s' | column -ts$'\t' -n | barcat -f+2 -e -u -l150 -s
863 And of course various Git statistics, such commit count by year:
865 git log --pretty=%ci | cut -b-4 | uniq -c | barcat
867 Or the top 3 most frequent authors with statistics over all:
869 git shortlog -sn | barcat -L3 -s
871 Activity graph of the last days (substitute date C<-v-{}d> on BSD):
873 ( git log --pretty=%ci --since=30day | cut -b-10
874 seq 0 30 | xargs -i date +%F -d-{}day ) |
875 sort | uniq -c | awk '$1--' | barcat --spark
877 Sparkline graphics of simple input given as inline parameters:
879 barcat -_ 3 1 4 1 5 0 9 2 4
881 Misusing the spark functionality to draw a lolcat line:
883 seq $(tput cols) | barcat --spark --indicator=- --palette=rainbow
887 Mischa POSLAWSKY <perl@shiar.org>