Criar um gráfico de pizza

14

O desafio é simples:

Crie um gráfico de pizza com base em vários valores de entrada.

A entrada será uma lista de números positivos, decimais ou números inteiros, e a saída será um gráfico de pizza em que cada um dos valores de entrada é representado por cores separadas e um valor percentual fora de cada uma das áreas.

Regras:

  • As cores devem ser visualmente distinguíveis (as cores exatas são opcionais)
  • Haverá pelo menos dois e no máximo 10 valores de entrada
  • O raio do círculo deve estar no intervalo de [100 300]pixels
    • Os gráficos vetoriais são bons, desde que a saída padrão dê um raio de [100, 300]pixels
  • Os valores percentuais devem ser inteiros
    • Não existe uma regra estrita que diga onde o valor percentual deve ser colocado, mas é preciso ver facilmente a qual área pertence.
    • A distância entre o caractere mais próximo e a aresta externa do círculo deve estar no intervalo de [5, 40]pixels
    • A fonte é opcional
  • A plotagem pode ou não ter linhas pretas separando cada região
  • Funções criadas para criar gráficos de pizza, por exemplo, MATLAB:, piePython: matplotlib.pyplot.piee Mathematica: PieChartnão são permitidas
  • Regras de arredondamento normais (para cima, se for (1.00, 0.5], para baixo, se for (0.5, 0.00))
  • Se o valor percentual de uma fatia for menor que 0.5%, a saída 0%. A fatia ainda deve ser incluída na plotagem.
  • Forneça parcelas para exame (ou um link para um intérprete). Basta mostrar apenas o gráfico com 10 valores de entrada (para evitar respostas muito longas)

Exemplos

Por favor, use os valores de exemplo abaixo. Você pode converter as listas em um formato apropriado usando um conversor de lista numérica , por exemplo, este byte de 27 bytes por jimmy23013 .

x = [0.3, 1.2] 

insira a descrição da imagem aqui

x = [3, 6, 2, 10]

insira a descrição da imagem aqui

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

insira a descrição da imagem aqui

Stewie Griffin
fonte
"O raio do círculo deve estar no intervalo [100 300] pixels." Os gráficos vetoriais também são permitidos?
Martin Ender
@ MartinBüttner, sim. Tudo bem, desde que a saída do programa pareça estar entre [100, 300] por padrão. Essa resposta é suficiente?
Stewie Griffin
R arredonda 0,5 para 0. Isso é um problema?
Masclins
Não há problema em arredondar 0.5para zero se for o padrão. Mas 0.50001deve ser arredondado para 1.
Stewie Griffin

Respostas:

12

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]]&

Pode ser jogado ainda mais. Atualmente gera um Graphicsobjeto. Casos de teste:



LegionMammal978
fonte
7

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``)}

Guardou um byte com a ajuda de @Neil!

Explicação

Grava algum SVG no HTML da página atual. Constrói o gráfico com o ponto central 135 x 150do raio 100pxe o texto em um raio a 135pxpartir do centro.

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));

user81655
fonte
Eu acho que você pode salvar alguns bytes usando with(Math)c=r=>[sin(d=PI*2*(v+p))*r+135,cos(d)*r+150].
Neil
Hmm, você pode ter que escrever with(Math)var solution = a=>etc.
Neil
Hmm, na verdade eu posso usar with. Eu acho que poderia ter estado no modo estrito quando tentei pela última vez ...
user81655
@ Neil Entendi lá, obrigado. Tenho certeza de que há um pouco mais de golfe que pode ser feito sobre isso, desde que eu estava correndo um pouco quando escrevi.
user81655
Guardou apenas 1 byte? Eu acho que é um começo ...
Neil
6

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()

insira a descrição da imagem aqui

Resultado para a maior lista de exemplos:

insira a descrição da imagem aqui

dieter
fonte
No Python 2, não é eval(raw_input())equivalente ao Python 2 input()?
gato
@cat sim é!
Dieter