D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
michalskop
Full window
Github gist
Pie chart vs. Bar chart fight
<!DOCTYPE html> <meta charset="utf-8"> <style> g { font: 10px sans-serif; } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .x.axis path { display: none; } .line { fill: none; stroke: #bbb; stroke-width: 1px; opacity: .5; } .line.active { stroke-width: 5px; stroke: #444 } .group-2 { fill: none; stroke: #bb0; stroke-width: 1px; } .group-2.active { stroke-width: 5px; stroke: #880; } .zeroline { fill: none; stroke: red; stroke-width: 3px; } .pie { fill: green; stroke: #222; opacity: .5; } .pie.active { fill: #222; opacity: 1; } .bar { fill: blue; stroke: #222; opacity: .5; } .bar.active { fill: #222; opacity: 1; } .vertical { stroke-width: 3px; opacity: 1; } .vertical.bar { stroke: blue; } .vertical.pie { stroke: green; } .vertical.active { stroke-width: 5px; } .group { font-size: 2em; } .g1 { border:1px solid #bbb; } .g2 { border:1px solid #bb0; } .e.pie { border:3px solid green; padding: 2px; opacity: 1; } .e.bar { border:3px solid blue; padding: 2px; opacity: 1; } p { font: 1em sans-serif; } </style> <body> <h1>Pie chart vs. Bar chart figth</h1> <div id="chart"></div> <p> Experiment conducted on 22 university students divided into 2 groups (11 each). Each group was shown 1 pie chart and 1 bar chart showing election results. The students were asked to estimate the percentage won by each party (later rescaled to sum 100%). </p> <p> The chart above summarizes the experiment's results: <ul> <li>Every point is one error of estimate (by one student)</li> <li>Green circles are error of estimates based on a pie chart</li> <li>Blue squares are error of estimates based on a bar chart</li> <li>Horizontal lines connect estimates by one person, colored by the election</li> <li>Vertical lines show variance, the 2 extreme error of estimates in each groups are taken away</li> <li>Green lines are for error of estimates from pie chart, blue lines are for bar chart</li> <li>The values on x-axis are slightly randomly moved, so the overlapped points may be visible.</li> </ul> </p> <p> There is no clear evidence that any of the charts performs better, the results are slightly better for pie charts. But the sample is not big enough for better conclusions. </p> <p>The actual file used for the experiment is <a href="https://docs.google.com/document/d/1YqkQzXvi79k_Uoe_MFKD5uWy2oLxvnQkKU7TWc5y4qo/pub">here</a>. The table below shows the experimental design:</p> <table> <tr><th></th><th><span class="group g1">Election 1</span></th><th><span class="group g2">Election 2</span></th></th> <tr><td><span class="group">Group 1:</span></td><td class="e pie"><image src="volby1998_2.png" title="Election 1, pie" /></td><td class="e bar"><image src="volby2002.png" title="Election 2, bar" /></td></tr> <tr><td><span class="group">Group 2:</span></td><td class="e bar"><image src="volby1998.png" title="Election 1, bar" /></td><td class="e pie"><image src="volby2002_2.png" title="Election 2, pie" /></td></tr> </table> <p>The real values were:<br/> Election 1: 0.2910, 0.2499, 0.1804, 0.1793, 0.0994<br/> Election 2: 0.3024, 0.2450, 0.1853, 0.1429, 0.1244 </p> <script src="https://d3js.org/d3.v3.js"></script> <script> var realvalues = [ [0.2910,0.2499,0.1804,0.1793,0.09935], [0.3024,0.2450,0.1853,0.1429,0.1244] ]; var margin = {top: 20, right: 20, bottom: 30, left: 50}, width = 960 - margin.left - margin.right, height = 400 - margin.top - margin.bottom; var x = d3.scale.linear() .range([0, width]) .domain([0.05,0.35]); var y = d3.scale.linear() .range([height, 0]) .domain([-0.15,0.2]); var xAxis = d3.svg.axis() .scale(x) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .orient("left"); var svg = d3.select("#chart").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .append("text") .attr("x", x(.35)) .attr("dx", ".71em") .style("text-anchor", "end") .text("Real values of percentage"); svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Errors of Estimates"); var line = d3.svg.line() .x( function(d) { return d[0]; }) .y(function(d) { return d[1]; }); zeroline = Array([x(0.05),y(0)],[x(0.35),y(0)]); var r = 3; svg.append("path") .datum(zeroline) .attr("class", "zeroline") .attr("d", line); d3.csv("data.csv", function(error, data) { points = [[],[]]; // 2 groups realvalues.forEach(function(rd,ri) { pdata = [[],[]]; // 2 chart types for (i in realvalues[ri]) { pdata[0][i] = []; pdata[1][i] = []; } data.forEach(function(d) { rdata = Array(); for (i in realvalues[ri]) { xx = realvalues[ri][i] + Math.random()/200-0.0025; if (ri == 0) letter = "a"; else letter = "b"; k = parseInt(i) + 1; yy = +d[letter+k]-realvalues[ri][i]; rdata.push([x(xx),y(yy)]); //type of chart: if (((d.group == "1") && (ri == 0)) || ((d.group == "2") && (ri == 1))) ct = 1; //bar else ct = 0; //pie points[ct].push([xx,yy]); pdata[ct][parseInt(i)].push(yy); } svg.append("path") .datum(rdata) .attr("class", function() {if (ri == 1) return "line group-2"; else return "line"}) .attr("d", line) .attr("title",d.name) .on("mouseover", function() { d3.select(this) .classed("active", true ) // should then accept fill from CSS }) .on("mouseout", function() { d3.select(this) .classed("active", false) }); }); //vertical lines for (ct in pdata) { for (i in pdata[ct]) { pdata[ct][i] = pdata[ct][i].sort(compareNumbers); } } //prepare ends (eliminate extremes) pends = [[],[]]; //2 charts pmid = [[],[]]; for (ct in pdata) { for (i in pdata[ct]) { pends[ct][i] = []; pends[ct][i].push([x(realvalues[ri][parseInt(i)])+3*parseInt(ct),y(pdata[ct][i][1])]); pends[ct][i].push([x(realvalues[ri][parseInt(i)])+3*parseInt(ct),y(pdata[ct][i][pdata[ct][i].length-2])]); pmid[ct][i] = [realvalues[ri], pdata[ct][i][Math.round(pdata[ct][i].length/2-1)]]; //approx, ok for odd numbers svg.append("path") .datum(pends[ct][i]) .attr("class", function() {if (ct == "1") return "vertical bar"; else return "vertical pie"}) .attr("d", line) //.attr("title",d.name) .on("mouseover", function() { d3.select(this) .classed("active", true ) // should then accept fill from CSS }) .on("mouseout", function() { d3.select(this) .classed("active", false) }); } } }); //points svg.selectAll('circle') .data(points[0]) .enter().append('circle') .attr("cx", function(d) {return x(d[0]) }) .attr("cy", function(d) {return y(d[1]) }) .attr("r", 3) .attr("class", "pie") .attr("title",function(d) {return "Error of colour estimate: " + Math.round(d[1]*1000)/10 + "% (percentage points)"}) .on("mouseover", function() { d3.select(this) .classed("active", true ) }) .on("mouseout", function() { d3.select(this) .classed("active", false) }); svg.selectAll('rect') .data(points[1]) .enter().append('rect') .attr("x", function(d) {return x(d[0]) - r }) .attr("y", function(d) {return y(d[1]) - r}) .attr("height", 2*r) .attr("width", 2*r) .attr("class", "bar") .attr("title",function(d) {return "Error of colour estimate: " + Math.round(d[1]*1000)/10 + "% (percentage points)"}) .on("mouseover", function() { d3.select(this) .classed("active", true ) }) .on("mouseout", function() { d3.select(this) .classed("active", false) }); }); function compareNumbers(a, b) { return a - b; } </script> <script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-8592359-13', 'ocks.org'); ga('send', 'pageview'); </script> </body>
Modified
http://d3js.org/d3.v3.js
to a secure url
https://d3js.org/d3.v3.js