A perceptually accurate pie chart.
inspired by this photo, whose provenance has been lost in the sands of time
the legend is drawn with the handy d3-legend component from @DataToViz
a descendant of this bl.ock from the prolific currankelleher
| border: no | |
| license: CCO-1.0 |
A perceptually accurate pie chart.
inspired by this photo, whose provenance has been lost in the sands of time
the legend is drawn with the handy d3-legend component from @DataToViz
a descendant of this bl.ock from the prolific currankelleher
| feature | label | proportion | |
|---|---|---|---|
| sky | Sky | 0.75 | |
| shadySide | Shady side of the pyramid | 0.06 | |
| sunnySide | Sunny side of the pyramid | 0.19 |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <title>Pyramid Pie</title> | |
| <script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> | |
| <script src="//cdnjs.cloudflare.com/ajax/libs/d3-legend/1.1.0/d3-legend.js"></script> | |
| <script src='https://npmcdn.com/babel-core@5.8.34/browser.min.js'></script> | |
| <link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'> | |
| <style> | |
| .color-legend text { | |
| font-family: 'Open Sans', sans-serif; | |
| font-size: 12pt; | |
| font-weight: 600 | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <script lang='babel' type='text/babel'> | |
| const outerWidth = 960; | |
| const outerHeight = 500; | |
| const margin = { left: 0, top: 0, right: 0, bottom: 0 }; | |
| const radiusMax = 180; | |
| const xColumn = 'name'; | |
| const sliceSizeColumn = 'proportion'; | |
| const colorColumn = 'feature'; | |
| const skyBlue = '#3a5d8f'; | |
| const sunnySide = '#d8a34d'; | |
| const shadySide = '#633c27'; | |
| const pyramidColors = [ | |
| skyBlue, | |
| shadySide, | |
| sunnySide, | |
| ]; | |
| const legendColors = [ | |
| skyBlue, | |
| sunnySide, | |
| shadySide | |
| ]; | |
| const innerWidth = outerWidth - margin.left - margin.right; | |
| const innerHeight = outerHeight - margin.top - margin.bottom; | |
| const svg = d3.select('body').append('svg') | |
| .attr('width', outerWidth) | |
| .attr('height', outerHeight); | |
| const g = svg.append('g') | |
| .attr('transform', `translate(${margin.left}, ${margin.top})`); | |
| const xAxisG = g.append('g') | |
| .attr('class', 'x axis') | |
| .attr('transform', `translate(0, ${innerHeight})`); | |
| const pieG = g.append('g'); | |
| const colorLegendG = g.append('g') | |
| .attr('class', 'color-legend') | |
| .attr('transform', 'translate(620, 145)'); | |
| const xScale = d3.scale.ordinal().rangePoints([0, innerWidth]); | |
| const colorScale = d3.scale.ordinal() | |
| .range(pyramidColors); | |
| const labels = [ | |
| 'Sky', | |
| 'Sunny side of the pyramid', | |
| 'Shady side of the pyramid' | |
| ]; | |
| // a hack to get the legend elements to appear | |
| // in the desired order | |
| const legendColorScale = d3.scale.ordinal() | |
| .domain(labels) | |
| .range(legendColors); | |
| const pie = d3.layout.pie() | |
| .sort(null); | |
| const arc = d3.svg.arc(); | |
| arc.outerRadius(radiusMax); | |
| arc.innerRadius(0); | |
| const colorLegend = d3.legend.color() | |
| .scale(legendColorScale) | |
| .shape('circle') | |
| .shapePadding(50) | |
| .shapeRadius(25) | |
| .labelOffset(12); | |
| function render(data) { | |
| colorScale.domain(data.map(d => d[colorColumn])); | |
| pie.value(d => d[sliceSizeColumn]); | |
| const pieData = pie(data); | |
| pieG.attr('transform', `translate(${innerWidth / 3}, ${innerHeight / 2})`); | |
| const slices = pieG.selectAll('path').data(pieData); | |
| slices.enter().append('path'); | |
| slices | |
| .attr('d', arc) | |
| .attr('fill', d => colorScale(d.data[colorColumn])); | |
| slices.exit().remove(); | |
| slices | |
| .attr('transform', `rotate(220)`); | |
| colorLegend.labels(labels); | |
| colorLegendG.call(colorLegend); | |
| d3.selectAll('text.label') | |
| .attr('dy', '0em'); | |
| } | |
| function type(d) { | |
| d.name = 'World'; | |
| d.population = +d.population; | |
| return d; | |
| } | |
| d3.csv('data.csv', type, render); | |
| </script> | |
| </body> | |
| </html> |