# Draw my bar graph

You have been chosen to make a program that creates some pretty ASCII bar charts. Here is the input format:

[List of words (they can have spaces)] [an integer >= 0]
Bar 3
This is so cool 4
IDK-Why 6


The input will have multiple lines in this format, each one representing one bar in the graph. The output format of a graph will be like this:

 _ _ _ _
|_|_|_|_|
| | | |
| | | + [name of 4th bar]
| | + [name of 3rd bar]
| + [name of 2nd bar]
+ [name of 1st bar]


Here are some examples:

In:
Cool 4
Kool 6

Out:
_
| |
_| |
| | |
| | |
| | |
|_|_|
| |
| + Kool
+ Cool

In:
Graph 5
Bar 3

Out:
_
| |
| |_
| | |
| | |
|_|_|
| |
| + Bar
+ Graph

In:
Very 4
Large 5
Bar 3
Graph 5

Out:
_   _
_| | | |
| | |_| |
| | | | |
| | | | |
|_|_|_|_|
| | | |
| | | + Graph
| | + Bar
| + Large
+ Very

In:
Bars can be 0 0
Large-bars_are$nice2 6 average)(@#$ 3
neato 5

Out:
_
| |  _
| | | |
| |_| |
| | | |
| | | |
_|_|_|_|
| | | |
| | | + neato
| | + average)(@#$| + Large-bars_are$nice2
+ Bars can be 0


Functions or full programs are allowed.

• Is the integer a single digit or can it be > 9? – edc65 Jan 5 '16 at 22:36
• >9 is allowed, I just didn't put it as an example because it would be so big. – J Atkin Jan 5 '16 at 22:40
• Can there be trailing spaces on each line? I.e. make the output rectangular? – Stewie Griffin Jan 6 '16 at 8:08
• Yes, trailing spaces are allowed – J Atkin Jan 6 '16 at 15:04
• Look in the history, @Doorknob removed it, not sure why... – J Atkin Jan 6 '16 at 22:17

# 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", }; runTest(input0); runTest(input1); runTest(input2); runTest(input3); } private static void runTest(String input[]) { System.out.println("In:"); for (String string : input) { System.out.println(string); } System.out.println("Out:"); BarChartTest b = new BarChartTest(); b.print(input); } void p(String a[]){int h[]=of(a).map(this::s).mapToInt(Integer::parseInt).toArray(),M=IntStream.of(h).max().getAsInt(),C=a.length,r,c,y;Object t[]=of(a).map(this::p).toArray();String s="",p=" + ",w="";char n=10,v='|',i=32,u=95,e;for(r=0;r<=M;r++){e=r==M?'_':' ';y=M-r;for(c=0; c<C; c++){s+=h[c]>y?v:c>0?h[c-1]>y?v:e:r==0?e:i;s+=h[c]==y?u:e;}s+=h[C-1]>y?v:e;s+=n;}for(r=0;r<C;r++){for(c=0;c<C-r;c++){s+=" |";}s+=r>0?p+t[C-r]:w;s+=n;}s+=p+t[0];System.out.println(s);}int b(String s){return s.lastIndexOf(" ");}String p(String s){return s.substring(0,b(s));}String s(String s){return s.substring(b(s)+1,s.length());} }  ## Haskell, 323 bytes f x|(p,q)<-unzip$map((\l->(unwords$init l,(read$last l))).words)$lines x=unlines(reverse$init.(zip((zipWith max=<<tail)$0:q++[0])(q++[0])>>=).(!)<$>[0..maximum q])++v p++'\n':(0#p)
v=(>>" |")
_#[]=""
l#(h:t)=(l+1)#t++v[1..l]++" + "++h++"\n"
0!(0,_)=" _"
0!_="|_"
i!(j,k)|i<j=(i==k)?'|'|1<2=(i==k)?' '
i?c|i=c:"_"|1<2=c:" "


Usage example:

*Main> putStr $f "Bars can be 0 0\nLarge-bars_are$nice2 6\naverage)(@#$3\nneato 5" _ | | _ | | | | | |_| | | | | | | | | | _|_|_|_| | | | | | | | + neato | | + average)(@#$
| + Large-bars_are$nice2 + Bars can be 0  How it works (rough overview, details maybe later): (p,q)<-unzip$map((\l->(unwords$init l,(read$last l))).words)$lines x -- breaks the input into a list of labels (-> p), e.g. -- ["Bars can be 0","Lagerge-basr_asr$niche",...] and a list of heights
-- (-> q), e.g. [0,6,3,5]

unlines(reverse$init.(zip((zipWith max=<<tail)$0:q++[0])(q++[0])>>=).(!)<\$>[0..maximum q])
-- builds the bars
v p++"\n"
-- builds the first row of "|" underneath the zero line
(0#p)
-- build the label section


The parsing part ((p,q)<-unlines...) takes a lot of bytes, maybe I can it golf further down.

## Python 2, 345 bytes

B,H=zip(*[(a,int(b))for a,b in[x.rsplit(' ',1)for x in input().split('\n')]])
h=max(H)
L=len(B)
b=['|'*H[0]]*(L*2+1)
for i in range(L):b[2+i*2]='|'*max(H[i],H[min(i+1,L-1)]);b[1+i*2]=('_'+' '*(H[i]-1)+'_')[:H[i]+1]
b=[x.ljust(h+1)for x in b]
for l in zip(*b)[::-1]:print ''.join(l)
print' |'*L
for i in range(-1,-L-1,-1):print' |'*(L+i),'+',B[i]