Sunburst chart

선버스트

Unrolls a nested hierarchy into concentric rings, where each arc angle shows its share of the parent it sits inside.

Also known as: Ring chartRadial treemap방사형 트리맵
···
html
<div class="viz">
  <svg id="svg"></svg>
</div>
css
:root{--viz-4:#e8a23a}
body{display:block}
.viz{position:relative;width:100%;height:100%}
svg{display:block;width:100%;height:100%;overflow:visible}
js
var svg = document.getElementById('svg');
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); }
function sum(arr){ return arr.reduce(function(a,b){ return a+b; },0); }

var ROOTS = [
  { color: 'var(--accent)' },
  { color: 'var(--viz-4)' },
  { color: 'var(--accent-3)' }
];
var LEAF_ROOT = [0,0,1,1,1,2,2];
var cur = LEAF_ROOT.map(function(){ return 20; });
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 arcPath(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 rMax = Math.max(30, Math.min(W,H)/2 - 8);
  var r0=rMax*0.26, r1=rMax*0.58, r2=rMax*0.98;
  var grand = sum(cur);
  var ga = 0.03;
  var a = -Math.PI/2;
  ROOTS.forEach(function(root,ri){
    var rootTotal = 0;
    cur.forEach(function(v,li){ if (LEAF_ROOT[li]===ri) rootTotal += v; });
    var a1 = a + (rootTotal/grand)*Math.PI*2;
    var s0=a+ga, s1=Math.max(s0,a1-ga);
    var p1 = se('path');
    sa(p1,{ d: arcPath(cx,cy,r0,r1,s0,s1), fill: root.color });
    svg.appendChild(p1);
    var la = a, idx = 0;
    cur.forEach(function(v,li){
      if (LEAF_ROOT[li]!==ri) return;
      var la1 = la + (v/rootTotal)*(a1-a);
      var lg = ga*0.5;
      var ls0=la+lg, ls1=Math.max(ls0,la1-lg);
      var p2 = se('path');
      sa(p2,{ d: arcPath(cx,cy,r1,r2,ls0,ls1), fill: root.color, 'fill-opacity': idx%2===0?1:0.55 });
      svg.appendChild(p2);
      la = la1; idx++;
    });
    a = a1;
  });
  var fs = Math.max(10, Math.min(18, rMax/5));
  var ct = se('text');
  sa(ct,{ x:cx, y:cy-1, 'text-anchor':'middle', fill:'var(--fg)', 'font-size':fs, 'font-weight':800 });
  ct.textContent = Math.round(grand);
  svg.appendChild(ct);
  var cl = se('text');
  sa(cl,{ x:cx, y:cy+fs*0.85, 'text-anchor':'middle', fill:'var(--muted)', 'font-size':fs*0.42, '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)/700);
    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();
animate(LEAF_ROOT.map(function(){ return R(8,45); }));
setInterval(function(){
  animate(LEAF_ROOT.map(function(){ return R(6,48); }));
}, 3600);

It answers the same question as a treemap — "where's the mass in this hierarchy" — but a treemap spends rectangle area while a sunburst spends angle. Inner rings are higher levels, outer rings drill down, and siblings sharing a parent should share that parent's hue (varied by lightness) so the "belongs to" relationship reads at a glance.

Because angle from the center equals proportion, it inherits every pie-chart pitfall — outer-ring wedges get thin fast, and label space disappears with them. In practice, stop at three rings and either show labels on hover or only on the largest wedges.

The common mistake is coloring sibling wedges with unrelated hues — the hierarchy vanishes and it reads as a random-looking donut. Without a zoom-on-click interaction, cramming in a fourth level turns the outer ring into hair-thin slivers; past that depth, a treemap or icicle chart works better.

When to use

Use it for 2-3 level hierarchies where each level’s share of its parent should stand out. For deeper hierarchies or precise comparison, use a treemap instead.