Pie and donut chart

파이 · 도넛 차트

Shows composition as slice angle out of a whole — it does exactly one thing well: part-to-whole at a glance.

Also known as: Pie chartDonut chart원형 차트
···
html
<div class="viz">
  <svg id="svg"></svg>
  <div class="legend" id="lg"></div>
</div>
css
:root{--viz-4:#e8a23a;--viz-5:#4098d7}
body{display:block}
.viz{display:flex;flex-direction:column;width:100%;height:100%}
svg{flex:1;min-height:0;display:block;width:100%;overflow:visible}
.legend{flex:none;display:flex;flex-wrap:wrap;gap:4px 10px;justify-content:center;padding:3px 4px;font:600 9px/1 system-ui,sans-serif;color:var(--muted)}
.legend b{display:inline-flex;align-items:center;gap:3px;font-weight:600}
.legend i{width:7px;height:7px;border-radius:2px;display:inline-block}
js
var svg = document.getElementById('svg');
var lg = document.getElementById('lg');
var NS = 'http://www.w3.org/2000/svg';
function se(t){ return document.createElementNS(NS,t); }
function sa(e,o){ for (var k in o) e.setAttribute(k,o[k]); }
function R(a,b){ return a + Math.random()*(b-a); }

var LABELS = ['A','B','C','D','E'];
var COLORS = ['var(--accent)','var(--viz-4)','var(--accent-3)','var(--viz-5)','var(--accent-2)'];
lg.innerHTML = LABELS.map(function(l,i){ return '<b><i style="background:'+COLORS[i]+'"></i>'+l+'</b>'; }).join('');

var cur = [30,24,20,15,11];
var W=300, H=200;

function measure(){
  var r = svg.getBoundingClientRect();
  W = Math.max(r.width,10); H = Math.max(r.height,10);
  sa(svg,{ viewBox: '0 0 ' + W + ' ' + H });
}

function slicePath(cx,cy,r0,r1,a0,a1){
  var x0o=cx+Math.cos(a0)*r1, y0o=cy+Math.sin(a0)*r1;
  var x1o=cx+Math.cos(a1)*r1, y1o=cy+Math.sin(a1)*r1;
  var x1i=cx+Math.cos(a1)*r0, y1i=cy+Math.sin(a1)*r0;
  var x0i=cx+Math.cos(a0)*r0, y0i=cy+Math.sin(a0)*r0;
  var large = (a1-a0) > Math.PI ? 1 : 0;
  return 'M'+x0o+','+y0o+' A'+r1+','+r1+' 0 '+large+' 1 '+x1o+','+y1o+' L'+x1i+','+y1i+' A'+r0+','+r0+' 0 '+large+' 0 '+x0i+','+y0i+' Z';
}

function draw(){
  svg.innerHTML = '';
  var cx=W/2, cy=H/2;
  var r1 = Math.max(12, Math.min(W,H)/2 - 8);
  var r0 = r1*0.58;
  var fs = Math.max(9, Math.min(16, Math.min(W,H)/13));
  var total = cur.reduce(function(a,b){ return a+b; },0);
  var ga = 0.02;
  var a0 = -Math.PI/2;
  cur.forEach(function(v,i){
    var frac = v/total;
    var a1 = a0 + frac*Math.PI*2;
    var s0 = a0+ga, s1 = Math.max(s0, a1-ga);
    var p = se('path');
    sa(p,{d:slicePath(cx,cy,r0,r1,s0,s1), fill:COLORS[i]});
    svg.appendChild(p);
    if (frac >= 0.08){
      var mid=(a0+a1)/2, lr=(r0+r1)/2;
      var t = se('text');
      sa(t,{x:cx+Math.cos(mid)*lr, y:cy+Math.sin(mid)*lr+fs*0.28,'text-anchor':'middle',fill:'#fff','font-size':fs*0.62,'font-weight':700});
      t.textContent = Math.round(frac*100)+'%';
      svg.appendChild(t);
    }
    a0=a1;
  });
  var ct = se('text');
  sa(ct,{x:cx,y:cy-1,'text-anchor':'middle',fill:'var(--fg)','font-size':fs*1.15,'font-weight':800});
  ct.textContent = Math.round(total);
  svg.appendChild(ct);
  var cl = se('text');
  sa(cl,{x:cx,y:cy+fs*0.95,'text-anchor':'middle',fill:'var(--muted)','font-size':fs*0.5,'font-weight':700});
  cl.textContent='TOTAL';
  svg.appendChild(cl);
}

function animate(target){
  var from = cur.slice();
  var t0 = performance.now();
  function step(t){
    var p = Math.min(1,(t-t0)/750);
    var e = 1-Math.pow(1-p,3);
    cur = from.map(function(v,i){ return v+(target[i]-v)*e; });
    draw();
    if (p<1) requestAnimationFrame(step);
  }
  requestAnimationFrame(step);
}

new ResizeObserver(function(){ measure(); draw(); }).observe(svg);
measure();
draw();
setInterval(function(){
  var raw = LABELS.map(function(){ return R(6,32); });
  animate(raw);
}, 3600);

People compare length far more accurately than angle or area. Once you're past 4-5 slices, or the slices are close in size, telling which is bigger becomes a real squint — at that point a bar chart is the more honest choice. As a rule of thumb: 5-6 slices max, fold the rest into "Other" or switch to bars.

A donut carries the same information as a pie but the punched-out center is real estate — most teams use it to show one key number (the total) that a solid pie can't. Convention: order slices largest to smallest, starting at 12 o'clock and going clockwise.

Never tilt it into fake 3D — perspective distorts the angles so front-facing slices read larger than they are. Separate slices with a surface-colored gap instead of a border.

When to use

Use it with 5-6 slices or fewer, when the only question is "what share of the whole is this."