Skip to content

Instantly share code, notes, and snippets.

@pstuffa
Last active September 12, 2016 01:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pstuffa/b294fbd9a3a180499165 to your computer and use it in GitHub Desktop.
Save pstuffa/b294fbd9a3a180499165 to your computer and use it in GitHub Desktop.
Anscombe Quartet

A D3 rendering of Anscombe Quartet, a classic data visualization example where four data sets have the same summary statistics, showing a reason why visualization is important - to see different distrubitions of data, which summary statistics can't always uncover.

group x y
I 10 8.04
I 8 6.95
I 13 7.58
I 9 8.81
I 11 8.33
I 14 9.96
I 6 7.24
I 4 4.26
I 12 10.84
I 7 4.82
I 5 5.68
II 10 9.14
II 8 8.14
II 13 8.74
II 9 8.77
II 11 9.26
II 14 8.1
II 6 6.13
II 4 3.1
II 12 9.13
II 7 7.26
II 5 4.74
III 10 7.46
III 8 6.77
III 13 12.74
III 9 7.11
III 11 7.81
III 14 8.84
III 6 6.08
III 4 5.39
III 12 8.15
III 7 6.42
III 5 5.73
IV 8 6.58
IV 8 5.76
IV 8 7.71
IV 8 8.84
IV 8 8.47
IV 8 7.04
IV 8 5.25
IV 19 12.5
IV 8 5.56
IV 8 7.91
IV 8 6.89
<!DOCTYPE html>
<meta charset="utf-8">
<html>
<style type="text/css">
.axis path,
.axis line {
fill: none;
stroke: #000;
stroke-opacity: .1;
shape-rendering: crispEdges;
}
.dots {
fill: #66ddff;
fill-opacity: .75;
stroke: steelblue;
stroke-width: 2px;
}
body {
font: 12px sans-serif;
}
.dots:hover{
fill: red;
stroke: #99212c;
}
.line {
stroke: blue;
fill:none;
stroke-width: 3;
}
</style>
<body>
<h2></h2>
<button id="one">I</button>
<button id="two">II</button>
<button id="three">III</button>
<button id="four">IV</button>
<div class="g-chart"></div>
<script src="linearRegression.js" charset="utf-8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js" charset="utf-8"></script>
<script>
var margin = { top: 20, right: 20, bottom: 30, left: 40},
width = 350,
height = 350;
var x = d3.scale.linear()
.domain([0,20])
.range([0, width]);
var y = d3.scale.linear()
.domain([0,20])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.innerTickSize(-height)
.outerTickSize(0)
.tickPadding(10);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.innerTickSize(-width)
.outerTickSize(0)
.tickPadding(10);
var svg = d3.select("body")
.append("svg")
.attr("height", height + margin.top + margin.bottom)
.attr("width", width + margin.left + margin.right)
.append("g")
.attr("transform","translate(" + margin.left + "," + margin.top + ")");
svg.append("rect")
.attr("width",width)
.attr("height", height)
.style("fill-opacity", .05);
svg.append("g")
.attr("class","x axis")
.attr("transform","translate(0," + height + ")")
.call(xAxis)
svg.append("g")
.attr("class","y axis")
.call(yAxis)
d3.tsv("data.tsv", function(error, data) {
if (error) throw error;
dataOne = data.filter(function(d) { return d.group == 'I'; })
dataTwo = data.filter(function(d) { return d.group == 'II'; })
dataThree = data.filter(function(d) { return d.group == 'III'; })
dataFour = data.filter(function(d) { return d.group == 'IV'; })
data.forEach(function(d) {
d.x = +d.x;
d.y = +d.y;
});
lr = linearRegression(data.map(function(d) { return d.y; }), data.map(function(d) { return d.x; }))
d3.select(".summary")
.html(function(d) { return "slope: " + lr.slope + "<br />" +
" intercept: " + lr.intercept + "<br />" +
" r2: " + lr.r2;})
var max = d3.max(data, function (d) { return d.x; });
var myLine = svg.append("line")
.attr("x1", x(0))
.attr("y1", y(lr.intercept))
.attr("x2", x(max))
.attr("y2", y( (max * lr.slope) + lr.intercept ))
.style("stroke", "black");
d3.select("body")
.select("h2")
.text("Group I");
dots = svg.selectAll(".dots")
.data(dataOne, function(d,i) { return i; });
dots.enter()
.append("circle")
.attr("class","dots")
.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); })
.attr("r", 8);
d3.selectAll("#one")
.on("click", function() {
lr = linearRegression(dataOne.map(function(d) { return d.y; }), dataOne.map(function(d) { return d.x; }))
d3.select(".summary")
.html(function(d) { return "slope: " + lr.slope + "<br />" +
" intercept: " + lr.intercept + "<br />" +
" r2: " + lr.r2;})
d3.select("body")
.select("h2")
.text("Group I")
dots.data(dataOne)
.transition()
.duration(2000)
.ease("elastic")
.delay(function(d,i) { return i * 100; })
.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); });
});
d3.selectAll("#two")
.on("click", function() {
lr = linearRegression(dataTwo.map(function(d) { return d.y; }), dataTwo.map(function(d) { return d.x; }))
d3.select(".summary")
.html(function(d) { return "slope: " + lr.slope + "<br />" +
" intercept: " + lr.intercept + "<br />" +
" r2: " + lr.r2;})
var max = d3.max(dataTwo, function (d) { return d.x; });
var myLine = svg.append("line")
.attr("x1", x(0))
.attr("y1", y(lr.intercept))
.attr("x2", x(max))
.attr("y2", y( (max * lr.slope) + lr.intercept ))
.style("stroke", "black");
d3.select("body")
.select("h2")
.text("Group II")
dots.data(dataTwo)
.transition()
.duration(2000)
.ease("elastic")
.delay(function(d,i) { return i * 100; })
.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); });
});
d3.selectAll("#three")
.on("click", function() {
lr = linearRegression(dataThree.map(function(d) { return d.y; }), dataThree.map(function(d) { return d.x; }))
d3.select(".summary")
.html(function(d) { return "slope: " + lr.slope + "<br />" +
" intercept: " + lr.intercept + "<br />" +
" r2: " + lr.r2;})
var max = d3.max(dataThree, function (d) { return d.x; });
var myLine = svg.append("line")
.attr("x1", x(0))
.attr("y1", y(lr.intercept))
.attr("x2", x(max))
.attr("y2", y( (max * lr.slope) + lr.intercept ))
.style("stroke", "black");
d3.select("body")
.select("h2")
.text("Group III")
dots.data(dataThree)
.transition()
.duration(2000)
.ease("elastic")
.delay(function(d,i) { return i * 100; })
.attr("class","dots")
.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); });
});
d3.selectAll("#four")
.on("click", function() {
lr = linearRegression(dataFour.map(function(d) { return d.y; }), dataFour.map(function(d) { return d.x; }))
d3.select(".summary")
.html(function(d) { return "slope: " + lr.slope + "<br />" +
" intercept: " + lr.intercept + "<br />" +
" r2: " + lr.r2;})
var max = d3.max(dataFour, function (d) { return d.x; });
var myLine = svg.append("line")
.attr("x1", x(0))
.attr("y1", y(lr.intercept))
.attr("x2", x(max))
.attr("y2", y( (max * lr.slope) + lr.intercept ))
.style("stroke", "black");
d3.select("body")
.select("h2")
.text("Group IV")
dots.data(dataFour)
.transition()
.duration(2000)
.ease("elastic")
.delay(function(d,i) { return i * 100; })
.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); });
});
});
</script>
<div class="summary"></div>
</body>
</html>
// http://trentrichardson.com/2010/04/06/compute-linear-regressions-in-javascript/
function linearRegression(y,x){
var lr = {};
var n = y.length;
var sum_x = 0;
var sum_y = 0;
var sum_xy = 0;
var sum_xx = 0;
var sum_yy = 0;
for (var i = 0; i < y.length; i++) {
sum_x += x[i];
sum_y += y[i];
sum_xy += (x[i]*y[i]);
sum_xx += (x[i]*x[i]);
sum_yy += (y[i]*y[i]);
}
lr['slope'] = (n * sum_xy - sum_x * sum_y) / (n*sum_xx - sum_x * sum_x);
lr['intercept'] = (sum_y - lr.slope * sum_x)/n;
lr['r2'] = Math.pow((n*sum_xy - sum_x*sum_y)/Math.sqrt((n*sum_xx-sum_x*sum_x)*(n*sum_yy-sum_y*sum_y)),2);
return lr;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment