index.html
<!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="//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 = [[],[]];
realvalues.forEach(function(rd,ri) {
pdata = [[],[]];
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)]);
if (((d.group == "1") && (ri == 0)) || ((d.group == "2") && (ri == 1)))
ct = 1;
else
ct = 0;
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 )
})
.on("mouseout", function() {
d3.select(this)
.classed("active", false)
});
});
for (ct in pdata) {
for (i in pdata[ct]) {
pdata[ct][i] = pdata[ct][i].sort(compareNumbers);
}
}
pends = [[],[]];
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)]];
svg.append("path")
.datum(pends[ct][i])
.attr("class", function() {if (ct == "1") return "vertical bar"; else return "vertical pie"})
.attr("d", line)
.on("mouseover", function() {
d3.select(this)
.classed("active", true )
})
.on("mouseout", function() {
d3.select(this)
.classed("active", false)
});
}
}
});
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>
data.csv
name,group,a1,a2,a3,a4,a5,b1,b2,b3,b4,b5
Person 1,1,0.380952381,0.2857142857,0.1428571429,0.1428571429,0.0476190476,0.35,0.25,0.15,0.2,0.05
Person 2,1,0.3,0.25,0.2,0.2,0.05,0.4,0.3,0.15,0.1,0.05
Person 3,1,0.31,0.23,0.2,0.2,0.06,0.3,0.25,0.18,0.15,0.12
Person 4,1,0.35,0.25,0.15,0.15,0.1,0.3,0.25,0.2,0.15,0.1
Person 5,1,0.4,0.35,0.1,0.1,0.05,0.37,0.25,0.15,0.13,0.1
Person 6,1,0.25,0.2391304348,0.2065217391,0.2065217391,0.097826087,0.2696629213,0.2471910112,0.1685393258,0.1685393258,0.1460674157
Person 7,1,0.375,0.3125,0.125,0.125,0.0625,0.3157894737,0.2631578947,0.1578947368,0.1578947368,0.1052631579
Person 8,1,0.3157894737,0.2631578947,0.1578947368,0.1578947368,0.1052631579,0.2772277228,0.2376237624,0.1782178218,0.1683168317,0.1386138614
Person 9,1,0.4,0.3,0.12,0.12,0.06,0.35,0.25,0.2,0.15,0.05
Person 10,1,0.3076923077,0.2435897436,0.1666666667,0.1666666667,0.1153846154,0.2947368421,0.2736842105,0.1894736842,0.1473684211,0.0947368421
Person 11,1,0.27,0.23,0.2,0.2,0.1,0.29,0.26,0.18,0.15,0.12
Person 12,2,0.2947368421,0.2315789474,0.1789473684,0.2105263158,0.0842105263,0.3,0.25,0.2,0.15,0.1
Person 13,2,0.33,0.22,0.18,0.16,0.11,0.3203883495,0.2330097087,0.1747572816,0.145631068,0.1262135922
Person 14,2,0.2678571429,0.25,0.1696428571,0.1607142857,0.1517857143,0.2857142857,0.2244897959,0.2040816327,0.1530612245,0.1326530612
Person 15,2,0.3296703297,0.3076923077,0.1318681319,0.1648351648,0.0659340659,0.3,0.25,0.2,0.15,0.1
Person 16,2,0.2545454545,0.2363636364,0.1909090909,0.1818181818,0.1363636364,0.3225806452,0.2688172043,0.2150537634,0.1075268817,0.0860215054
Person 17,2,0.35,0.25,0.18,0.1,0.12,0.36,0.3,0.2,0.1,0.04
Person 18,2,0.2967032967,0.2637362637,0.1538461538,0.1758241758,0.1098901099,0.2777777778,0.2333333333,0.1888888889,0.1666666667,0.1333333333
Person 19,2,0.3614457831,0.2048192771,0.1445783133,0.1686746988,0.1204819277,0.2830188679,0.2264150943,0.1886792453,0.1603773585,0.141509434
Person 20,2,0.3333333333,0.2222222222,0.1666666667,0.1666666667,0.1111111111,0.3684210526,0.2631578947,0.2105263158,0.1052631579,0.0526315789
Person 21,2,0.2830188679,0.2358490566,0.1886792453,0.2169811321,0.0754716981,0.4,0.28,0.16,0.1,0.06
Person 22,2,0.3539823009,0.2212389381,0.1769911504,0.1592920354,0.0884955752,0.4838709677,0.3225806452,0.1075268817,0.0537634409,0.0322580645