Draw my bar graph
sh + awk + tac, 173
Mostly an awk
script that prints the graph bottom up which is then reversed by tac
.
awk '{n[NR]=$NF;$NF="";$0=p" + "$0;p=" |"p}1;END{for(print p;p~/\|/;print p (k>($0=0)?"|":""))for(i=k=p="";i<NR;p=p (j>0||k>0?"|":" ")(!k||$0?"_":" ")){j=k;k=n[++i]--}}'|tac
Description
awk, first part, executed for each input line
{
n[NR]=$NF; # store the value, here n[1]=0, n[2]=6, n[3]=3, n[4]=5
$NF=""; # remove the value from the label
$0=p" + "$0; # add a prefix (initially empty) and a " + " in the front
p=" |"p # grow the prefix for the next string
}1; # implicitly print $0
Output
+ Bars can be 0
| + Large-bars_are$nice2
| | + average)(@#$
| | | + neato
awk, second part, executed once in the end
END{
for(print p;p~/\|/;print p (k>($0=0)?"|":""))
for(i=k=p="";i<NR;p=p (j>0||k>0?"|":" ")(!k||$0?"_":" "))
{j=k;k=n[++i]--}}
ungolfed:
END{
print p; # print the prefix again
for(;p~/\|/;) # for each line, bottom up. no more "|" -> we're done
{
p=""; # string to be built
i=k=0; # i: bar index, k: heigth of the previous bar
for(;i<NR;) # for each bar, left to right
{
j=k; # store the previous bars heigth in j
k=n[++i]--; # get the current bars remaining height and decrement it
p=p (j>0||k>0?"|":" ")(!k||$0?"_":" ");
# if the bar to the left or this one have some height
remaining, draw a border in between them, else a space
# if this bars remaining heigth is exactly 0, draw a top
# if $0 is set, draw the bottom
}
print p (k>0?"|":"");
# draw (or not) the rightmost border, finally print
$0=0; # unset $0, only to detect first run
}
}
Output
| | | | # the prefix
_|_|_|_| # the strings built by the nested loops
| | | | |
| | | | v
| |_| |
| | | |
| | _
_ # no more "|" in the string, we're done
tac reverses the lines
_
| | _
| | | |
| |_| |
| | | |
| | | |
_|_|_|_|
| | | |
| | | + neato
| | + average)(@#$
| + Large-bars_are$nice2
+ Bars can be 0
JavaScript (ES6), 270 262 270 287
Bug fix added a missing row of '|' under the bars
l=>{t=p=o='';l=l.split`
`.map(r=>([,b,c]=r.match(/(.*) (\d+)/),[' + '+b,+c>t?t=c:c]));for(++t;t--;o+=`
`)l.map(x=>o+=x[1]<t?'y y':x[1]>t?t?'x x':'x_x':'y_y');return o.replace(/(yx)|(xy)|(xx?)/g,'|').replace(/y+/g,' ')+[...l,' '].map(x=>p+x[p+=' |',0]).reverse().join`
`}
Test Test in Firefox, as Chrome does not support ES6 Destructuring assignment
F=l=>{
t=p=o='';l=l.split`\n`.map(r=>([,b,c]=r.match(/(.*) (\d+)/),[' + '+b,+c>t?t=c:c]));
for(++t;t--;o+=`\n`)l.map(x=>o+=x[1]<t?'y y':x[1]>t?t?'x x':'x_x':'y_y');
return o.replace(/(yx)|(xy)|(xx?)/g,'|').replace(/y+/g,' ')
+[...l,' '].map(x=>p+x[p+=' |',0]).reverse().join`\n`
}
function test()
{
var i=I.value
O.textContent=F(i)
}
test()
textarea { display:block; width:50%; height:5em}
Input
<textarea id=I>Bars can be 0 0
Large-bars_are$nice2 6
average)(@#$ 3
neato 5</textarea>
<button onclick='test()'>go</button><br>
Output
<pre id=O></pre>
421 bytes - Python 2
import sys
l=sys.stdin.read().split('\n')
b=[(' '.join(x[:-1]),int(x[-1])) for x in map(str.split,l[:-1])]
a=len(b)
e=enumerate
m=[' '*(a+1)+'|'*x[1] for i,x in e(b)]+[' '*(len(b)+1)+'|'*b[-1][1]]
h=[' '*i+'+'+'|'*(a-i)+'_'+' '*(x[1]-1)+'_' for i,x in e(b)]
c=m+h
c[::2]=m
c[1::2]=h
c=[''.join(' ' if not x else x for x in l) for l in map(None,*c)]
for i,(n,_) in e(b):
c[a-i-1]+='\b'*i*2+n
c='\n'.join(c[::-1])
print(c)
Tests
a 1
b 2
c 3
_
_| |
_| | |
|_|_|_|
| | |
| | + c
| + b
+ a