Polar area chart

폴라 에어리어 차트

Circular like a pie chart, but every wedge gets an equal angle — the value is encoded in how far out each wedge reaches instead.

Also known as: Nightingale rose chart나이팅게일 로즈 다이어그램
···
html
<div class="viz">
  <svg id="svg"></svg>
</div>
css
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); }

var CATS = ['1월','2월','3월','4월','5월','6월','7월','8월'];
var n = CATS.length;
var cur = CATS.map(function(){ return 30; });
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 draw(){
  svg.innerHTML = '';
  var cx=W/2, cy=H/2;
  var rMax = Math.max(24, Math.min(W,H)/2-26);
  [0.33,0.66,1].forEach(function(f){
    var c = se('circle');
    sa(c,{ cx:cx, cy:cy, r:rMax*f, fill:'none', stroke:'var(--line)', 'stroke-width':1 });
    svg.appendChild(c);
  });
  var ga = (Math.PI*2)/n;
  var maxV = 100;
  var fs = Math.max(7,Math.min(9,W/60));
  CATS.forEach(function(name,i){
    var a0 = -Math.PI/2+i*ga, a1 = a0+ga;
    var r = rMax*Math.sqrt(cur[i]/maxV);
    var s0 = a0+ga*0.06, s1 = a1-ga*0.06;
    var x0 = cx+Math.cos(s0)*r, y0 = cy+Math.sin(s0)*r;
    var x1 = cx+Math.cos(s1)*r, y1 = cy+Math.sin(s1)*r;
    var large = (s1-s0)>Math.PI?1:0;
    var d = 'M'+cx.toFixed(1)+','+cy.toFixed(1)+' L'+x0.toFixed(1)+','+y0.toFixed(1)+' A'+r.toFixed(1)+','+r.toFixed(1)+' 0 '+large+' 1 '+x1.toFixed(1)+','+y1.toFixed(1)+' Z';
    var p = se('path');
    sa(p,{ d:d, fill:'var(--accent)', 'fill-opacity': 0.35+0.55*(cur[i]/maxV) });
    svg.appendChild(p);
    var lx = cx+Math.cos((a0+a1)/2)*(rMax+9), ly = cy+Math.sin((a0+a1)/2)*(rMax+9);
    var t = se('text');
    sa(t,{ x:lx, y:ly+3, 'text-anchor':'middle', fill:'var(--muted)', 'font-size':fs, 'font-weight':600 });
    t.textContent = name;
    svg.appendChild(t);
  });
}

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();
animate(CATS.map(function(){ return R(15,95); }));
setInterval(function(){ animate(CATS.map(function(){ return R(10,98); })); }, 3600);

Florence Nightingale's "rose diagram," devised to show Crimean War deaths month by month, is the origin of this circular shape. A pie chart turns value into angle; a polar area chart gives every wedge the same angle (30° each for 12 wedges) and lets radius carry the value instead — which keeps a fixed, already-ordered category like months, weekdays, or compass directions in its natural sequence instead of pie's uneven wedge widths.

Scaling radius linearly with value is the single most common — and most damaging — mistake here. We perceive a wedge by its area, and area grows with radius squared, so a linear radius scale makes larger values look disproportionately larger than they really are (the exact same trap as radius scaling in a bubble chart). The correct formula is radius = k × sqrt(value); this mistake has shipped in real, widely used charting libraries, which says something about how easy it is to get wrong.

Past around 12 wedges, the radii pack together tightly enough that telling two neighboring wedges apart gets hard — like a pie chart, keeping the wedge count small matters just as much here.

When to use

Use it to compare values across a category with a fixed cyclical order — months, weekdays, compass directions. Without that inherent order, a pie or bar chart reads more naturally.