From 32027f061cb5902a72b6f7350f7da65f621e13da Mon Sep 17 00:00:00 2001 From: dhilipkumars Date: Mon, 27 Apr 2015 20:27:11 -0400 Subject: [PATCH] Add Code to display Y-Axis Scale Center the bar's labes Add a screen shot for multi-graph Update the readme. --- README.md | 5 +++++ example/mbarchart.go | 10 ++++++---- example/mbarchart.png | Bin 0 -> 20075 bytes mbar.go | 45 +++++++++++++++++++++++++++++++++++++----- 4 files changed, 51 insertions(+), 9 deletions(-) create mode 100644 example/mbarchart.png diff --git a/README.md b/README.md index 4d0a34c..01458a4 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,11 @@ The `helloworld` color scheme drops in some colors! barchart +#### Mult-Bar / Stacked-Bar Chart +[demo code](https://github.com/gizak/termui/blob/master/example/mbarchart.go) + +barchart + #### Sparklines [demo code](https://github.com/gizak/termui/blob/master/example/sparklines.go) diff --git a/example/mbarchart.go b/example/mbarchart.go index 7729104..a32a28e 100644 --- a/example/mbarchart.go +++ b/example/mbarchart.go @@ -18,10 +18,10 @@ func main() { termui.UseTheme("helloworld") bc := termui.NewMBarChart() - math := []int{45, 75, 34, 62} - english := []int{50, 45, 25, 57} - science := []int{75, 60, 15, 50} - compsci := []int{90, 95, 100, 100} + math := []int{90, 85, 90, 80} + english := []int{70, 85, 75, 60} + science := []int{75, 60, 80, 85} + compsci := []int{100, 100, 100, 100} bc.Data[0] = math bc.Data[1] = english bc.Data[2] = science @@ -33,6 +33,8 @@ func main() { bc.Y = 10 bc.BarWidth = 10 bc.DataLabels = studentsName + bc.ShowScale = true //Show y_axis scale value (min and max) + bc.SetMax(400) bc.TextColor = termui.ColorGreen //this is color for label (x-axis) bc.BarColor[3] = termui.ColorGreen //BarColor for computerscience diff --git a/example/mbarchart.png b/example/mbarchart.png new file mode 100644 index 0000000000000000000000000000000000000000..9a4252616fb8f753ca79a34bc0bf87d0df17502d GIT binary patch literal 20075 zcmeHvc{tSF`#-9uopxH#?vX5oO3Y9yMTlZDmPsWIN=O)Hh89|so@^mAEzj7-m}u<7 zC`l2@WT-4fOpHv7G0gfs@1f_@=X+hh>-zn!-*SC^*X0jyoH_4v?)yIXea`D%&fGX+ zXSHzNs(A_u3JVV%+~=sEFk=Jw(VwFPTI_=E_k&-GL5@~?74jO_K>y72-ebE*K_NeG zzSwgX_@HMWlk_f8ZavOUE(cA_<$( zR9xIIXp*Jc6}}16qkem1*i<=rvY-x9*Sl-GES$Ve-3lwY=mqYvM>BdoJOj!>F|ex8>+pj97Oc2CR3m%#FsC7}Z_ z&HWC{8gtp;58{(gK9!MJobB2gZy~l`T)+T?IZ2$%upTV;rk1AuCpN*@O-)@|w*n|7 zy@XP!7CUA+LL|1#@YO?Y;Oq_J8~bh7YIliqMjdC&hU4*Y%sH=5UHe4uy+g#9D6*i= z>}ad3Vb&3RKTEX6D^S0DdoMi8-U+^om?`e?6-vY$7BA^*!?pZzC#mwXOKlgW+rwE5 zqTO+6-qUg4x`+`Mw1zu&8}rZrqqYhE0SDs^^NOBdBqYV&H=oZO4!*psc%p}&bfA=8 z&j@$-VD}RCy}vKpu><8{vtbVMjo6HTog!zsmFpldn_Hw(-l2O{cVZMjMge!}}2|L?a z9wa5ROM@jmY$yjYaqoe7Tu7x|{ojbB$O--6;y#(Fpozj^7*jjZ$ycR6NWpw~sVq2v z&pV#Md{xukNEwP7Takrm7nW8tdRVt4qsA^p$NR2bk~;Z|5AS5HFX}tBLcmF%H6AG7 zKVr;iFm!m6+P|~6w6Bov79=rer-j1c{yYBLxGhILdbBEwbX8L9w@bPv zcJleCdHV3?kr2TI*O4c4PhgQ;OQTcHS|Lr5DDm9h0|s>w+Gf#N=D*n!GpJ`6(Gk=|_1HkMX)%ntX%6ZD3beqTsu51h?y(sObt|seI$me?_0}FZQg4nncS&L&F2EIKJ(uJ1h)Wkl~vtGEr48!2P z*@6gkLH2s+qK@!y8>RDb<}LP^;A`c=;E>D(FXomJRJdY3ccc#SHXP9;``%hlNy%v^ zdcD5I*sfb?$6lR5aGlpVg8BEup0d#LQLh!YLfu?iLzMH(vv9xb?13O^KdGBUhb)67vU(AWyhD}es zqUTY);gx2H3QL?fov)dA!>{vBD!zr7T;okK8+*^$N-`$ODnF+;mj#=*Gq|oB*@j!s zjA0{`8PxNM&XRs*xdImh;hW;~4J%9TeUc4?4TvrXCEZjbV1OK4<)5rBfAsCn@8ZAu9eSgB z$wLFYPRIKMuYeI(D;5GSsgx4=n;LFer5xhKw=y|mI&X=orXdP1;(wT(oZ^ccBQsXC znyVkpqqtR**xkbV%#lYNx7Ywo(*Eafo3?8@!%KO$(s)*VDt0oS!{eIyi+C#?Cr+18 z2Ug-c_**NldVdw6GI^Qd`Mdx=t~`h!^x*)>b-^#1n`0#W)(_%+{O<$$DS?`uWdyQd zLc%GLGA#5? z4G#>Ces8V$5q5s!TA1u0{?nclPUzqg<;;y1ClFC%EAiF!W$l+SBi~HpPVzYT!0|XZ zox|53tJ0__ieJOvsfRCV8Ld8s>^I-9ch^ECs=&pOt2i3^IIuCy|5QB6OXW;c^4=YE zsqG>S*r8UA`8UIntg5fIt@>VTaNG1wSSgYUHxy;ApF|IKn;+8b#^&yHn*R*_y}2*dmuvpzcTn$_Q19+rJCrqkeWPW-$|+C@kz_SZ(zKMOb!pn- zruU`kt#bN6nLc*^1Hs8hr!RufpR=W(m$$|*2579Rem(?lhDYZ7@$+g`_IBS@xhOfL z`LbA!gEYe6wRZsCJs^r*CC7z++7M!Tnbg|jMg{F2KMeaYa{*F1VK47LM)zn+w6#Ec ziDFAMAn^8jqa0yn43{KT%t~N&b`#HpN`@$_~PGf63o}A2iPU z3pBqbx}VwruymC7EC~69j;%72CW3Yy{Fs|5gcC>QV>}iZ@5Y}|BqdHf>-hwM#V=>& z%-qqq!ZvrbK&xkSOCcWDmdi)~So>XwnfE7!P}XP*%}Ldhi-f$oMCv^=fn|u%uz{MN z0Ld1by{OwQgblZix2wd3nWRF5H*R`J>+BpVeo;CUQ)@-0Y3$_9fh4snF0$DX+0^mF znqy)fw;3WkA8^}@8B#_dn4s4l1MZ{d37Qy2&W+@ z=+yi_bxHho^*kDZ$2$v+t>$Wh)~2wBE|B;Sh*ol$wkcWLpkW~~Iuy3pOitLV6-SWP zoKjOaG>pxDFJF$LNs_+)KO@Qa99lbeLg&hin0)rZCt&TWf|RUve6G1x&a?FVAcz)y zElqh1@okU;k@i& z%_rW1%>XMq56E}#4!A4E-cpE?0xAaPZ(tF}poLivJrY=1I*|d3 z*S}h4cTUWEl=Zok%ocQw2*(BQ z&smngy>6=M&?(@?ICxtFR1#T*1W-u#l{2ftnj`Z|-8;a0OoMmfWI_=-)p3x=6CJ(8 z=}}2!KAByvnZWw=k<|m>cIG62^dRv=HVizbWt0iWg_WM&imN8KM$>PL(InqlErZ%TCYN{Es9DzGlTqbqbIFF_G6eWrFpwDgN?Vhcu#9k~1 zc5P(Z?!Nby<<0^XX8`HVI9L8!@{69j92$K?r)hWb{d4J86rzHD!?KN~a5ZB^CD%E> z!Ox<9>o${H|M4g6h<-rM>ZLU{ZlY+_u*QjIAfL5AOMYz#!eI|AiO;rqC9k+RyYv^- ztS85u<7Gbq{?!HT-ymrL2J#*$RnJMr_-A!gE?2?BnTFDAWgP9L#D$2R4?~bzmsEHu zn!gLUGHYCrGH<5n^Jn&cG`3PAl}f*uONHag%b@}Qa|LVg?$NRE3wZW59^D}xtummfqTiNsbE zj4m9$vl{6E+iH`GP^rMQjZ}=ZHty4~0v?LPtnEqvzT8}4-e#)CCuTvWm;FDW{laN< zLs$3LE_{n94~}z}>8TXMI|E$hviQv@xU-dVCye%0FBwAo{|4qqaTg%R;C~(S$0f6T z>E$`H)rC7EqLX*EG*BaxON0ycNB(#j-Sl%w=BnTWM!-p#;|E;P7hVl@7+EIuYUCC5 zFSwt~&>})~dYnSkBj8Q6DLOloT7K%9R*TL)oe@n~vG5KM+iKuAUr;;-5$jG*52!x$ zIveu)X&^`D08(865}~wlytm>41D=PU-3sh*eDiKD^V4wVFnvT~FdBir0IjAQaLQ5t zO%W<5%yC=ZQ{rMQ!}=6Rg$Q)Txa8;f#&3%u{};pI`Rx@_&9usGz>#+RmH|TmenA0mxYRy)tH-EMAJ2 zIdRK{)iT0sG6P$ix==o?&LF*oXkjIMuW#vg$6h zJx%DTe1$8YZ<;M#jfwXe60+7#0oE$t2fiwFS9QX-W*yLybn zuhN&@js=R6Cf}H#2Z^>LJtRF=ApOmM+{NhI1RyCdJZqovp))3mXElh6?zzmj8 z@0O%#TlgOyl&7~+;;6-444Fh=Ea4WLFO^W^sCZ30o@m}CVLY+nNF=U3U3c+Vu~789 zsY$9-o6Hii1(KgZbnl=xPEf~)S7E=|x6=@wLag;hOAg-DBo(5LC)D%-Y<+Zzs;x<3 zYilk2yWQN8iOvE&IR34tvTQ>Hz7roSIIWzr-M1`V3>ExDZH|g1IZ^-AL^*jM4o7Bg zp`htq`<>G0cxji0Y;5Avc9Q~{wXNL-{a);j*`yXDlF4;|2;R&LOlGa8G>#2?6^UBe zBEkF&*?^CWTB}cPbxy=_bVUUgmxQ=YeokomI&u5W!lt`^n}bXMwXe6_Eu&?WluR_Y zjn=)NI~JI+^OU6HMfO;+9YT%EZ6UD2KQ@`BTMCLd!asPrWE!ph#RFMLe$F;rgrtK7JRFk5!vW@J&#`i_6-9K(_ICRztB+}GT9a#@zd5r#*%G{; zt8~ML^LSmx@}k@Ve)->~REwD9uZ;50ue&~*IJroL<8w1LiU59(!S|M;Icj z34bGOdrWZgkxZ*iX>Z(=0o*E>_f3~#gui0$r>}LpYPic@XX!OinJKv&oD<{@gt7~y zIj-S*iVL>rc5UbsTsJ=(Jw^jgPbK6QKayt479(t^Kpgt$&b$83v8a zEYiAstjr`Eq=6mBO*@}_AHgpY5@rzan(A|$~m?tQ22_eNHo zg}|tBa5Tap5hO~^33r0@;w8x41+7pjrm+6O;31%yAo-|G$(T%du+B0W!@rFOee~ak zlc!G(q)BhbC`7qW`f|3=Oh2}3g)ae_63BfeXHSAo<4>dhW;5puu9qike4zY^Z?efp zP>N@e3Q=r3ncAVe&%pNpRIMrxlRC#kAC`rNqNPrQZ`sJ}nmN zdZ(~A9y$Z%yejKcvY$yS=2vc^^h=PWvVo9>&rD2U;OGU&dHuD95R-I!jv$WP zXHdh62xEkNdY4+nn%bv+$rr?M21e8KS?NV+TmZz}zt)Vq*#9}C>hpf}g%W5wXO63Y z?EjP+Lkl+_s!Mc+UXv3yl+5bd`L|3oam6-=D#}_ObUOw(Pm^&ZW8)|=M6fC$sLaR* zOqILnH!VLI&0jP*y?h*?GX*Cgw+jTDpgiUwNX3^M=0c-Ee@+=f(yS{$HafrQH|4%3 z>?&vjq6J1Jw}P!|VD*o$`%SrP7I4;qw%<&^>tDPkOltOTtWN3wZ@dESgyuwUtH#U$ z{DVJ#DZh&WWaxW;)9ITlS(c#fmsS97>Mw&j&8X#5%MZ!d`R!AUy&$>%o7%5fFfF2K z5rOEztF(>#((TyWKq{FoTgZJ0&Lk+mVSj5#Y;_cED|;sE_VKcHKq9y? z*|f2FLxGv4AkWcebNM|8*p-5*azxpGx40pg-MeM|9^~9a{y22GWiVKUM)xVQ9L>bs zZ17&MwNYO4QEKCxpP*+=zVq~anya;r16p@zHdW(N`H$+H)xmowL%(`=%V`;{3pvSi z5}hj(jot1Qo1F+S|FDXQEvVPIQTLe~lh*XY?qFn9n-VmfuM=aZFBNeoH}}REZHRmF zQ&0Q0m$ifyw$x7HP0Qko1D z7g=;SmkAvmCT7dZx01EzovQ8SHR@o2t0ED3CNI<#SdRM})DraML+i|3lAQG7^}4&? zTdHTStyT3_x@uZedQy1=IzpjRs))Gp41b#pgJs_JA?0e}Wk%2)hX1+qwyKBZB-{65 zso2AF=Cy#!;SZ(S4~AxU+56U*L5Jo87YnpRtX-qpal*?9%DrE{?)Wb z?W6ci)-iJz7xWJ|B-1{0YoC|ES6GynEI8Cuk$?8&FdK}r_9p_|p@1;@+cm?6nyylc zi$o*CP%Ql-_|dSx@L*PUMP2c0b7AJO6c>3N894ZXe?`0ASU*5}nM52eZnbZ9MkfCV zJ&m>{3drUc&*qT(+iyHyRy0dNFRgZ83;`y_QpMyL_B64v!sPr2D?5Mk!o#PC>WDi|c% z;ctNUgIgccmLxk@T(;Zq&T@A(drxZV_AwdC5*a;l2<+ zlFkI@?&h4X%))V1Z{`+Ltwz1oNam{>&8g2-fb5d~d}FM7pF45_u4NHvVGT+I%W0VN zM`5EwdZa`WEwFuwwzr`w9WJ!~BE%!CM2y3r+PE zl`Ns^z$sw13ZrWPvTD=arUfET6;5l&v@J|;4)QA4>D_YrT$ny6LCkO(IsETqq?e>Z zH5}|S2$svQCcIi%xdOQ+nxHE$H}M5=F_>;R(pKr_Q8XpxBrIAXiV1-_#cQzqOlI=Yk**H|E$N&!cbB9Jgk)TsbBIZks*@`BV@y|ny6NDDK;ey)%iT! z1fh<@MsNHn)t4slXtepq9?XKGBHUQwj&kJc_$?%Z%}Vn*_4^rsghEucQ_w%Ii4=M zZp~>G3^VQYyfYWA6)_Ky+b z#t)AMdq!`9QbStSoF*wtL&sVYGAcu@n7~E(N6u=;1UbRS{( z;*QN0ScX|eeC)~P#`L#*GeW7BX6!^j`JtIg4rp6$Luyw_Av+}OzFv+PNjDmk*lLW0 zz42Qm_$wUA7tvO9H9XoiIC7@&3J`WOmkD|8BaS2KqIJ(7^eq8w-?ag^^lyk=AS^t{Ox?XVIf4~Gl-2~^$D?e`nGQ<3)QXc-7LuzKu z+4y_7H}S-)OLIX|h+yG{99~S_>4P{7IetLiZI<#2T(CSQRP`fo^stvVwXQDIfo?BB z-3HgmuSRLK_L~4&<&9J=c~hB#eHRvoi}^9y;E<`wKZ;`v`GG)qKU=+pYb52JqH`sw zmDdI@iZ_luX4J9EV#}Boo3loiD({BX7-qUhbn4qDiiO0L<+UIe@#V1m_I>VH>WUX5 zLCZ6Pdqtn$QQ=)=_=UhM{D4E-?4Y#DA!>iT2fQ`t!h^BaZ$F!fbxd6Mf(L-i2KmcI z<{w9@9Fa$Ne@Joi4^My*!c_b^-0wu7$bpN&bbja0t1d$+S9`FO)h#VherCS>4x2N| zYJwA*zATyBlZ{ArT*tpzAXK_%_H@wm!~4><_Ef#XLHq~f9ai3+hqgZ!B?lDJoFh8@ zm%pMorocUR?2G@_pN>$WCUv)nWOpo!hAUr6`qzVS!P9K{RXDPKmdCn*h0(5Q3k3*} zstg#PQJ;!rp!;#?7OGk$2A%lTTo{IOK=uZ?a~Erb&iFto95*}fi2V2}d~IPSP?M@X zlS@}QT4U|fnG?)Gxi3T^d4D(s9H;XtaQvrYTqHuJeysTkQD9|59&;NcQz~PK5nr51 z#*CA@x)$`dR0F2()mKABsFx=PTYV|)P42#G+QF@zH;;LU?k_zpB{El;a3yY)&wV=* z*NC#VC)M9Y(jV?%1R60orP5?YD*w)SJz_2=8P35g8mP8WnndZMN4PhBQt-7=Bj0A@ z2I|=rm7h|&2l!np{cU$^?x=On8P+)XBOA len(bc.Data[i]) { @@ -122,7 +124,16 @@ func (bc *MBarChart) layout() { bc.max = dsum } } - bc.scale = float64(bc.max) / float64(bc.innerHeight-1) + + //Finally Calculate max sale + if bc.ShowScale { + s := fmt.Sprintf("%d", bc.max) + bc.maxScale = trimStr2Runes(s, len(s)) + bc.scale = float64(bc.max) / float64(bc.innerHeight-2) + } else { + bc.scale = float64(bc.max) / float64(bc.innerHeight-1) + } + } func (bc *MBarChart) SetMax(max int) { @@ -140,9 +151,9 @@ func (bc *MBarChart) Buffer() []Point { for i := 0; i < bc.numBar && i < bc.minDataLen && i < len(bc.DataLabels); i++ { ph := 0 //Previous Height to stack up + oftX = i * (bc.BarWidth + bc.BarGap) for i1 := 0; i1 < bc.numStack; i1++ { h := int(float64(bc.Data[i1][i]) / bc.scale) - oftX = i * (bc.BarWidth + bc.BarGap) // plot bars for j := 0; j < bc.BarWidth; j++ { for k := 0; k < h; k++ { @@ -167,7 +178,7 @@ func (bc *MBarChart) Buffer() []Point { p.Bg = bc.BgColor p.Fg = bc.TextColor p.Y = bc.innerY + bc.innerHeight - 1 - p.X = bc.innerX + oftX + k + p.X = bc.innerX + oftX + ((bc.BarWidth - len(bc.labels[i])) / 2) + k ps = append(ps, p) k += w } @@ -194,5 +205,29 @@ func (bc *MBarChart) Buffer() []Point { } } + if bc.ShowScale { + //Currently bar graph only supprts data range from 0 to MAX + //Plot 0 + p := Point{} + p.Ch = '0' + p.Bg = bc.BgColor + p.Fg = bc.TextColor + p.Y = bc.innerY + bc.innerHeight - 2 + p.X = bc.X + ps = append(ps, p) + + //Plot the maximum sacle value + for i := 0; i < len(bc.maxScale); i++ { + p := Point{} + p.Ch = bc.maxScale[i] + p.Bg = bc.BgColor + p.Fg = bc.TextColor + p.Y = bc.innerY + p.X = bc.X + i + ps = append(ps, p) + } + + } + return bc.Block.chopOverflow(ps) }