Last active
August 26, 2020 12:20
-
-
Save johnwalley/8287941 to your computer and use it in GitHub Desktop.
Weight
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
body { | |
font: 16px sans-serif; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.x.axis path { | |
display: none; | |
} | |
.line { | |
fill: none; | |
stroke: steelblue; | |
stroke-width: 5px; | |
} | |
div.tooltip { | |
position: absolute; | |
text-align: center; | |
width: 140px; | |
height: 40px; | |
padding: 2px; | |
font: 16px sans-serif; | |
background: lightsteelblue; | |
border: 0px; | |
border-radius: 8px; | |
pointer-events: none; | |
} | |
</style> | |
<body> | |
<script src="https://d3js.org/d3.v3.js"></script> | |
<script> | |
function loess(xval, yval, bandwidth) | |
{ | |
function tricube(x) { | |
var tmp = 1 - x * x * x; | |
return tmp * tmp * tmp; | |
} | |
var res = []; | |
var left = 0; | |
var right = Math.floor(bandwidth * xval.length) - 1; | |
for(var i in xval) | |
{ | |
var x = xval[i]; | |
if (i > 0) { | |
if (right < xval.length - 1 && | |
xval[right+1] - xval[i] < xval[i] - xval[left]) { | |
left++; | |
right++; | |
} | |
} | |
var edge; | |
if (xval[i] - xval[left] > xval[right] - xval[i]) | |
edge = left; | |
else | |
edge = right; | |
var denom = Math.abs(1.0 / (xval[edge] - x)); | |
var sumWeights = 0; | |
var sumX = 0, sumXSquared = 0, sumY = 0, sumXY = 0; | |
var k = left; | |
while(k <= right) | |
{ | |
var xk = xval[k]; | |
var yk = yval[k]; | |
var dist; | |
if (k < i) { | |
dist = (x - xk); | |
} else { | |
dist = (xk - x); | |
} | |
var w = tricube(dist * denom); | |
var xkw = xk * w; | |
sumWeights += w; | |
sumX += xkw; | |
sumXSquared += xk * xkw; | |
sumY += yk * w; | |
sumXY += yk * xkw; | |
k++; | |
} | |
var meanX = sumX / sumWeights; | |
var meanY = sumY / sumWeights; | |
var meanXY = sumXY / sumWeights; | |
var meanXSquared = sumXSquared / sumWeights; | |
var beta; | |
if (meanXSquared == meanX * meanX) | |
beta = 0; | |
else | |
beta = (meanXY - meanX * meanY) / (meanXSquared - meanX * meanX); | |
var alpha = meanY - beta * meanX; | |
res[i] = beta * x + alpha; | |
} | |
return res; | |
} | |
var margin = {top: 20, right: 20, bottom: 30, left: 50}, | |
width = 960 - margin.left - margin.right, | |
height = 500 - margin.top - margin.bottom; | |
var parseDate = d3.time.format("%d/%m/%Y").parse; | |
var formatTime = d3.time.format("%e %B %Y"); | |
var x = d3.time.scale() | |
.range([0, width]); | |
var y = d3.scale.linear() | |
.range([height, 0]); | |
var xAxis = d3.svg.axis() | |
.scale(x) | |
.orient("bottom"); | |
var yAxis = d3.svg.axis() | |
.scale(y) | |
.orient("left"); | |
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 line = d3.svg.line() | |
.interpolate("basis") | |
.x(function(d) { return x(d.Date); }) | |
.y(function(d) { return y(d.Weight); }); | |
var div = d3.select("body").append("div") | |
.attr("class", "tooltip") | |
.style("opacity", 0); | |
d3.csv("https://docs.google.com/spreadsheets/d/e/2PACX-1vSAJC6Bj_1ij2nPZarqpBmHL0xqd3W7iwKi3aqP-rR-Chf0o1QdqqZwBELTd-YaV7_bg4tTO8DXy0C-/pub?gid=1&single=true&output=csv", function(error, data) { | |
data.forEach(function(d) { | |
d.Date = parseDate(d.Date); | |
d.Weight = +d.Weight; | |
}); | |
x.domain(d3.extent(data, function(d) { return d.Date; })); | |
y.domain(d3.extent(data, function(d) { return d.Weight; })); | |
svg.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(0," + height + ")") | |
.call(xAxis); | |
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("Weight (kg)"); | |
var lx = []; | |
var ly = []; | |
for (var i = 0; i < data.length; i++) { lx[i] = data[i].Date / 1e12; ly[i] = data[i].Weight; } | |
var yOut = loess(lx, ly, 0.2); | |
var data2 = []; | |
for (var i = 0; i < data.length; i++) { data2[i] = {}, data2[i].Date = data[i].Date, data2[i].Weight = yOut[i]; } | |
svg.append("path") | |
.datum(data2) | |
.attr("class", "line") | |
.attr("d", line); | |
svg.selectAll("dot") | |
.data(data) | |
.enter().append("circle") | |
.attr("r", 5) | |
.attr("cx", function(d) { return x(d.Date); }) | |
.attr("cy", function(d) { return y(d.Weight); }) | |
.on("mouseover", function(d) { | |
div.transition() | |
.duration(200) | |
.style("opacity", .9); | |
div .html(formatTime(d.Date) + "<br/>" + d.Weight + "kg") | |
.style("left", (d3.event.pageX) + "px") | |
.style("top", (d3.event.pageY - 28) + "px"); | |
}) | |
.on("mouseout", function(d) { | |
div.transition() | |
.duration(500) | |
.style("opacity", 0); | |
}); | |
}); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment