The same example as previous test but in this case interactive. You can add points and view how automatically the chart is upgraded with new calculus of linear regression.
xxxxxxxxxx
<html>
<head>
<title>Linear regression test</title>
<style>
path {
stroke: steelblue; stroke-width: 2; fill: none;
}
.axis path, .axis line {
fill: none;
stroke: grey;
stroke-width: 1; shape-rendering: crispEdges;
}
.dot {
stroke: black;
}
div.tooltip {
position: absolute; text-align: center;
width: 80px;
height: 28px;
padding: 2px;
font: 12px sans-serif; background: lightsteelblue; border: 0px; border-radius: 8px; pointer-events: none;
}
</style>
</head>
<body>
<script src="d3.min.js"></script>
<script src="math.min.js"></script>
<script type="text/javascript">
var math = mathjs();
var linear_regression = function(X, y) {
var m = y.length;
X = math.concat(math.ones(m,1), X);
y = math.matrix(y);
var tr = math.transpose(X);
var tr_X = math.multiply(tr, X);
var tr_y = math.multiply(tr, y);
var theta = math.multiply( math.inv(tr_X), tr_y );
return function() {
var args = Array.prototype.slice.call(arguments);
return math.multiply(math.matrix(math.concat([1], args)), theta);
}
}
var data = [{"age":12,"weight":58},{"age":8,"weight":42},{"age":10,"weight":51},{"age":11,"weight":54},{"age":7,"weight":40},{"age":7,"weight":39},{"age":10,"weight":49},{"age":14,"weight":56}];
var xLabel = "age", yLabel = "weight";
var extent = d3.extent(data, function(d) { return d[xLabel]; }),
range = d3.range(extent[0], extent[1], 1);
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 500 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
var x = d3.scale.linear().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis().scale(x)
.orient("bottom")
.ticks(10);
var yAxis = d3.svg.axis().scale(y)
.orient("left")
.ticks(10);
var line = d3.svg.line()
.x(function(d) { return x(d[xLabel]); })
.y(function(d) { return y(d[yLabel]); })
;
var svg = d3.select("body")
.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 + ")");
var rect = this.svg
.append("rect")
.attr("width", this.width)
.attr("height", this.height)
.attr("transform", "translate(0,0)")
.style("fill", "aliceblue");
var div = d3.select("body")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
rect.on("click", function(d) {
var _x = d3.mouse(this)[0],
_y = d3.mouse(this)[1],
ob = {};
ob[xLabel] = x.invert(_x);
ob[yLabel] = y.invert(_y);
data.push(ob);
draw();
});
function calculate() {
var X = data.map(function(d){ return [+d.age]; }),
y = data.map(function(d){ return [+d.weight]; }),
fn = linear_regression(X , y);
return data.map(function(d) {
var ob = {};
ob[xLabel] = d[xLabel];
ob[yLabel] = fn(d[xLabel]);
return ob;
});
}
function draw() {
d3.select(".line").remove();
var regression = calculate();
x.domain(d3.extent(data, function(d) { return d[xLabel]; }));
y.domain(d3.extent(data, function(d) { return d[yLabel]; }));
d3.select(".x").call(xAxis);
d3.select(".y").call(yAxis);
svg.selectAll(".dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return x(d[xLabel]); })
.attr("cy", function(d) { return y(d[yLabel]); })
.attr("r", 2)
.attr("class", "dot")
.on("mousemove", showTooltip)
.on("mouseout", hideTooltip);
svg.append("path")
.attr("d", line(regression))
.attr("class", "line")
.on("mousemove", showTooltip)
.on("mouseout", hideTooltip);
}
function showTooltip(d) {
var _x = d3.mouse(this)[0],
_y = d3.mouse(this)[1];
div.transition()
.duration(200)
.style({
"opacity": .9,
left: d3.event.pageX + 20 + 'px',
top: d3.event.pageY + 10 + 'px'
});
div.html(xLabel + ": " + d3.round(x.invert(_x), 2) + " " + yLabel + ": " + d3.round(y.invert(_y), 2));
}
function hideTooltip() {
div.transition()
.duration(500)
.style("opacity", 0);
}
draw();
</script>
</body>
</html>