14
\$\begingroup\$

The challenge is simple:

Create a pie-chart based on a number of input values.

The input will be a list of positive numbers, decimal or integers, and the output will be a pie-chart where each of the input values are represented by separate colors, and a percentage value outside each of the areas.

Rules:

  • The colors must be visually distinguishable (the exact colors are optional)
  • There will be at least two, and maximum 10 input values
  • The radius of the circle must be in the range [100 300] pixels
    • Vector graphics are OK as long as the default output gives a radius of [100, 300] pixels
  • The percentage values shall be integers
    • There is no strict rule saying where the percentage value shall be placed, but it must be easily seen which area it belongs to
    • The distance between the closest character and the outer edge of the circle must be in the range [5, 40] pixels
    • The font is optional
  • The plot may or may not have black lines separating each region
  • Functions made for creating pie charts, for instance, MATLAB: pie, Python: matplotlib.pyplot.pie and Mathematica: PieChart are not allowed
  • Normal rounding rules (up if it's (1.00, 0.5], down if it's (0.5, 0.00))
  • If the percentage value of a slice is smaller than 0.5%, output 0%. The slice must still be included in the plot.
  • Please provide plots for examination (or a link to an interpreter). It's enough to show only the plot with 10 input values (to avoid very long answers)

Examples

Please use the example values below. You can convert the lists to an appropriate format using a numeric list converter, for instance this 27 byte one by jimmy23013.

x = [0.3, 1.2] 

enter image description here

x = [3, 6, 2, 10]

enter image description here

x = [0.4387, 0.3816, 0.7655, 0.7952, 0.1869, 0.4898, 0.4456, 0.6463, 0.7094, 0.7547]

enter image description here

\$\endgroup\$
  • \$\begingroup\$ "The radius of the circle must be in the range [100 300] pixels." Are vector graphics allowed too? \$\endgroup\$ – Martin Ender Apr 14 '16 at 10:01
  • \$\begingroup\$ @MartinBüttner, yes. That's OK, as long as the output from the program looks like it's between [100, 300] by default. Is that a sufficient answer? \$\endgroup\$ – Stewie Griffin Apr 14 '16 at 10:04
  • \$\begingroup\$ R rounds 0.5 to 0. Is that a problem? \$\endgroup\$ – Masclins Apr 14 '16 at 12:35
  • \$\begingroup\$ It's ok to round 0.5 to zero if that's default. But 0.50001 must be rounded to 1. \$\endgroup\$ – Stewie Griffin Apr 14 '16 at 12:39
12
\$\begingroup\$

Mathematica, 186 183 164 bytes

Graphics[{Hue@#,Disk[{0,0},{1,1},a=2Pi{##}],Black,Text[ToString@Round[100(#2-#)]<>"%",5Through@{Cos,Sin}@Mean@a/4]}&@@@Partition[Accumulate[#/Tr@#]~Prepend~0,2,1]]&

Could be golfed further. Currently generates a Graphics object. Test cases:



\$\endgroup\$
7
\$\begingroup\$

JavaScript (ES6), 311 310 302 298 bytes

a=>{with(Math)document.write(`<svg height=300>`+a.map(n=>`<path fill=#${(p*4e3|0).toString(16)} d=M135,150L${c(o=100,v=0)}A${[o,o,0,(v=n/=s)+.5|0,0,c(o)]}Z /><text x=${(z=c(135,v/=2))[0]} y=${z[p+=n,1]}>${n*o+.5|0}%</text>`,c=r=>[sin(d=PI*2*(v+p))*r+135,cos(d)*r+150],p=s=0,a.map(n=>s+=n)).join``)}

Saved a byte with help from @Neil!

Explanation

Writes some SVG to the HTML of the current page. Builds the chart with centre point 135 x 150 of radius 100px and text at a radius of 135px from the centre.

var solution =

a=>{
  with(Math)
  document.write(       // write to HTML body
    `<svg height=300>`+ // create 300px x 300px SVG canvas (width defaults to 300px)
    a.map(n=>           // for each number
      
      // Get the hex colour by multiplying the current position by (roughly) 0xfff
      `<path fill=#${(p*4e3|0).toString(16)
      
      // Calculate the path of the pie slice
      } d=M135,150L${c(o=100,v=0)}A${[o,o,0,(v=n/=s)+.5|0,0,c(o)]
      
      // Text
      }Z /><text x=${(z=c(135,v/=2))[0]} y=${z[p+=n,1]}>${n*o+.5|0}%</text>`,
      
      // Returns [ x, y ] for a certain radius at position v around the pie
      c=r=>[sin(d=PI*2*(v+p))*r+135,cos(d)*r+150],
      p=s=0,             // p = current position around pie (0 - 1)
      a.map(n=>s+=n)     // s = sum of all numbers
    ).join``
    
    +`</svg>` // <- this is just here for the test, so multiple charts can be displayed
  )
}

// Test
;[
  [0.3, 1.2],
  [3, 6, 2, 10],
  [0.4387, 0.3816, 0.7655, 0.7952, 0.1869, 0.4898, 0.4456, 0.6463, 0.7094, 0.7547]
].map(c=>solution(c));

\$\endgroup\$
  • \$\begingroup\$ I think you can save a few bytes using with(Math)c=r=>[sin(d=PI*2*(v+p))*r+135,cos(d)*r+150]. \$\endgroup\$ – Neil Apr 14 '16 at 12:21
  • \$\begingroup\$ Hmm, you might have to write with(Math)var solution = a=> etc. \$\endgroup\$ – Neil Apr 14 '16 at 12:26
  • \$\begingroup\$ Hmm, actually I can use with. I think I might have been in strict mode when I tried it last... \$\endgroup\$ – user81655 Apr 14 '16 at 12:26
  • \$\begingroup\$ @Neil Got it in there, thanks. I'm pretty sure there's a fair bit more golfing that can be done on this, since I was rushing a bit when I wrote it. \$\endgroup\$ – user81655 Apr 14 '16 at 12:30
  • \$\begingroup\$ Only saved 1 byte? I guess it's a start... \$\endgroup\$ – Neil Apr 14 '16 at 12:34
6
\$\begingroup\$

Python + PIL, 365 355

from math import*;from random import*
from PIL import Image,ImageDraw
L,a,r=256,0,0.8;l,p,c=L/2,L/6,(L,L,L);I=Image.new('RGB',(L,L),c);D=ImageDraw.Draw(I)
x=input()
for i in x:b=a+ceil(360.0*i/sum(x));D.pieslice((p,p,L-p,L-p),int(a),int(b),tuple(map(randrange,c)));t=(a+b)*0.00872;D.text((l+cos(t)*l*r,l+sin(t)*l*r),str(int((b-a)/3.6))+'%',0);a=b
I.show()

enter image description here

Result for the largest example list :

enter image description here

\$\endgroup\$
  • \$\begingroup\$ In Python 2, isn't eval(raw_input()) equivalent to Python 2's input()? \$\endgroup\$ – cat Apr 15 '16 at 2:31
  • \$\begingroup\$ @cat yes it is ! \$\endgroup\$ – dieter Apr 15 '16 at 7:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.