|
<html> |
|
<head> |
|
|
|
<style> |
|
body { |
|
margin: 0 auto; |
|
display: table; |
|
font-family: "Helvetica Neue", sans-serif; |
|
} |
|
.regression { |
|
stroke-width: 2px; |
|
stroke: steelblue; |
|
stroke-dasharray: 10,5; |
|
} |
|
.equation { |
|
font-size: 12px; |
|
margin-top: 10px; |
|
text-align: center; |
|
} |
|
</style> |
|
|
|
</head> |
|
<body> |
|
|
|
<div><select id="selector"></select></div> |
|
<div class="chart"></div> |
|
<div class="equation"></div> |
|
<div class="equation"></div> |
|
|
|
<script src="https://d3js.org/d3.v4.min.js"></script> |
|
<script> |
|
var margin = {top: 25, right: 5, bottom: 20, left: 20}, |
|
width = 450 - margin.left - margin.right, |
|
height = 450 - margin.top - margin.bottom; |
|
|
|
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 + ")"); |
|
|
|
var x = d3.scaleLinear() |
|
.range([0,width]); |
|
|
|
var y = d3.scaleLinear() |
|
.range([height,0]); |
|
|
|
var xAxis = d3.axisBottom() |
|
.scale(x); |
|
|
|
var yAxis = d3.axisLeft() |
|
.scale(y); |
|
|
|
d3.csv("data.csv", types, function(error, data){ |
|
|
|
|
|
y.domain(d3.extent(data, function(d){ return d.y})); |
|
x.domain(d3.extent(data, function(d){ return d.x})); |
|
|
|
|
|
|
|
|
|
// selector............ |
|
|
|
var players = d3.nest() |
|
.key(function(d){ return d.name;}) // group by player |
|
.rollup(function(a) { return a.length}) // aggregation on array |
|
.entries(data); |
|
|
|
|
|
|
|
//add all |
|
players.unshift({"key": "ALL", |
|
"value": d3.sum(players,function(d) {return d.value;})}) |
|
|
|
|
|
var selector= d3.select("#selector"); |
|
|
|
selector |
|
.selectAll("option") |
|
.data(players) |
|
.enter() |
|
.append("option") |
|
.text(function(d) { return d.key + ": " + d.value;}) |
|
.attr("value", function(d){ return d.key;}) |
|
|
|
|
|
selector |
|
.on("change", function(){ |
|
d3.selectAll(".point") |
|
.attr("opacity", 1); |
|
var value = selector.property("value"); |
|
if(value!="ALL") { |
|
d3.selectAll(".point") |
|
.filter(function(d) { return d.name != value; }) |
|
.attr("opacity",0.1); |
|
} |
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// see below for an explanation of the calcLinear function |
|
var lg = calcLinear(data, "x", "y", d3.min(data, function(d){ return d.x}), d3.min(data, function(d){ return d.x})); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
svg.append("line") |
|
.attr("class", "regression") |
|
.attr("x1", x(lg.ptA.x)) |
|
.attr("y1", y(lg.ptA.y)) |
|
.attr("x2", x(lg.ptB.x)) |
|
.attr("y2", y(lg.ptB.y)); |
|
|
|
svg.append("g") |
|
.attr("class", "x axis") |
|
.attr("transform", "translate(0," + height + ")") |
|
.call(xAxis) |
|
|
|
svg.append("g") |
|
.attr("class", "y axis") |
|
.call(yAxis); |
|
|
|
svg.selectAll(".point") |
|
.data(data) |
|
.enter().append("circle") |
|
.attr("class", "point") |
|
.attr("r", 5) |
|
.attr("cy", function(d){ return y(d.y); }) |
|
.attr("cx", function(d){ return x(d.x); }) |
|
; |
|
|
|
|
|
}); // csv fn end |
|
|
|
function types(d){ |
|
d.x = +d.x; |
|
d.y = +d.y; |
|
|
|
return d; |
|
} |
|
|
|
// Calculate a linear regression from the data |
|
|
|
// Takes 5 parameters: |
|
// (1) Your data |
|
// (2) The column of data plotted on your x-axis |
|
// (3) The column of data plotted on your y-axis |
|
// (4) The minimum value of your x-axis |
|
// (5) The minimum value of your y-axis |
|
|
|
// Returns an object with two points, where each point is an object with an x and y coordinate |
|
|
|
function calcLinear(data, x, y, minX, minY){ |
|
///////// |
|
//SLOPE// |
|
///////// |
|
|
|
// Let n = the number of data points |
|
var n = data.length; |
|
|
|
// Get just the points |
|
var pts = []; |
|
data.forEach(function(d,i){ |
|
var obj = {}; |
|
obj.x = d[x]; |
|
obj.y = d[y]; |
|
obj.mult = obj.x*obj.y; |
|
pts.push(obj); |
|
}); |
|
|
|
// Let a equal n times the summation of all x-values multiplied by their corresponding y-values |
|
// Let b equal the sum of all x-values times the sum of all y-values |
|
// Let c equal n times the sum of all squared x-values |
|
// Let d equal the squared sum of all x-values |
|
var sum = 0; |
|
var xSum = 0; |
|
var ySum = 0; |
|
var sumSq = 0; |
|
pts.forEach(function(pt){ |
|
sum = sum + pt.mult; |
|
xSum = xSum + pt.x; |
|
ySum = ySum + pt.y; |
|
sumSq = sumSq + (pt.x * pt.x); |
|
}); |
|
var a = sum * n; |
|
var b = xSum * ySum; |
|
var c = sumSq * n; |
|
var d = xSum * xSum; |
|
|
|
// Plug the values that you calculated for a, b, c, and d into the following equation to calculate the slope |
|
// slope = m = (a - b) / (c - d) |
|
var m = (a - b) / (c - d); |
|
|
|
///////////// |
|
//INTERCEPT// |
|
///////////// |
|
|
|
// Let e equal the sum of all y-values |
|
var e = ySum; |
|
|
|
// Let f equal the slope times the sum of all x-values |
|
var f = m * xSum; |
|
|
|
// Plug the values you have calculated for e and f into the following equation for the y-intercept |
|
// y-intercept = b = (e - f) / n |
|
var b = (e - f) / n; |
|
|
|
// Print the equation below the chart |
|
document.getElementsByClassName("equation")[0].innerHTML = "y = " + m + "x + " + b; |
|
document.getElementsByClassName("equation")[1].innerHTML = "x = ( y - " + b + " ) / " + m; |
|
|
|
// return an object of two points |
|
// each point is an object with an x and y coordinate |
|
return { |
|
ptA : { |
|
x: minX, |
|
y: m * minX + b |
|
}, |
|
ptB : { |
|
y: minY, |
|
x: (minY - b) / m |
|
} |
|
} |
|
|
|
} |
|
</script> |
|
|
|
</body> |
|
</html> |