Skip to content

Instantly share code, notes, and snippets.

@rlbarter
Last active July 20, 2018 18:13
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 rlbarter/0d0d5aaaa5008718002cd942f6e63a00 to your computer and use it in GitHub Desktop.
Save rlbarter/0d0d5aaaa5008718002cd942f6e63a00 to your computer and use it in GitHub Desktop.
Bayesian
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-random.v1.min.js"></script>
<script src="https://peterbeshai.com/d3-interpolate-path/d3-interpolate-path.js"></script>
<style>
text {
font-size: 14px;
font-family: avenir;
}
</style>
</head>
<body>
<script>
var margin = {top: 20, right: 10, bottom: 20, left: 10};
var width = 900 - margin.left - margin.right,
height = 1000 - margin.top - margin.bottom;
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 color = d3.scaleOrdinal(d3.schemeCategory10);
var y_2 = 300;
var y_1 = 150;
var y_3 = 500;
var iteration = 0;
var point_opacity = 0.6;
var newkernelpath = [];
var x = d3.scaleLinear()
.domain([-4, 4])
.range([margin.left + 200, width - margin.right - 200]);
var y = d3.scaleLinear()
.domain([0, 0.05])
.range([y_1, y_1 + 20]);
var y_kernel = d3.scaleLinear()
.domain([0, 0.05])
.range([y_3 + 1, y_3]);
var density_data = [-3, -2.99, -2.98, -2.97, -2.96, -2.95, -2.94, -2.93, -2.92, -2.91, -2.9, -2.89, -2.88, -2.87, -2.86, -2.85, -2.84, -2.83, -2.82, -2.81, -2.8, -2.79, -2.78, -2.77, -2.76, -2.75, -2.74, -2.73, -2.72, -2.71, -2.7, -2.69, -2.68, -2.67, -2.66, -2.65, -2.64, -2.63, -2.62, -2.61, -2.6, -2.59, -2.58, -2.57, -2.56, -2.55, -2.54, -2.53, -2.52, -2.51, -2.5, -2.49, -2.48, -2.47, -2.46, -2.45, -2.44, -2.43, -2.42, -2.41, -2.4, -2.39, -2.38, -2.37, -2.36, -2.35, -2.34, -2.33, -2.32, -2.31, -2.3, -2.29, -2.28, -2.27, -2.26, -2.25, -2.24, -2.23, -2.22, -2.21, -2.2, -2.19, -2.18, -2.17, -2.16, -2.15, -2.14, -2.13, -2.12, -2.11, -2.1, -2.09, -2.08, -2.07, -2.06, -2.05, -2.04, -2.03, -2.02, -2.01, -2, -1.99, -1.98, -1.97, -1.96, -1.95, -1.94, -1.93, -1.92, -1.91, -1.9, -1.89, -1.88, -1.87, -1.86, -1.85, -1.84, -1.83, -1.82, -1.81, -1.8, -1.79, -1.78, -1.77, -1.76, -1.75, -1.74, -1.73, -1.72, -1.71, -1.7, -1.69, -1.68, -1.67, -1.66, -1.65, -1.64, -1.63, -1.62, -1.61, -1.6, -1.59, -1.58, -1.57, -1.56, -1.55, -1.54, -1.53, -1.52, -1.51, -1.5, -1.49, -1.48, -1.47, -1.46, -1.45, -1.44, -1.43, -1.42, -1.41, -1.4, -1.39, -1.38, -1.37, -1.36, -1.35, -1.34, -1.33, -1.32, -1.31, -1.3, -1.29, -1.28, -1.27, -1.26, -1.25, -1.24, -1.23, -1.22, -1.21, -1.2, -1.19, -1.18, -1.17, -1.16, -1.15, -1.14, -1.13, -1.12, -1.11, -1.1, -1.09, -1.08, -1.07, -1.06, -1.05, -1.04, -1.03, -1.02, -1.01, -1, -0.99, -0.98, -0.97, -0.96, -0.95, -0.94, -0.93, -0.92, -0.91, -0.9, -0.89, -0.88, -0.87, -0.86, -0.85, -0.84, -0.83, -0.82, -0.81, -0.8, -0.79, -0.78, -0.77, -0.76, -0.75, -0.74, -0.73, -0.72, -0.71, -0.7, -0.69, -0.68, -0.67, -0.66, -0.65, -0.64, -0.63, -0.62, -0.61, -0.6, -0.59, -0.58, -0.57, -0.56, -0.55, -0.54, -0.53, -0.52, -0.51, -0.5, -0.49, -0.48, -0.47, -0.46, -0.45, -0.44, -0.43, -0.42, -0.41, -0.4, -0.39, -0.38, -0.37, -0.36, -0.35, -0.34, -0.33, -0.32, -0.31, -0.3, -0.29, -0.28, -0.27, -0.26, -0.25, -0.24, -0.23, -0.22, -0.21, -0.2, -0.19, -0.18, -0.17, -0.16, -0.15, -0.14, -0.13, -0.12, -0.11, -0.1, -0.0899999999999999, -0.0800000000000001, -0.0699999999999998, -0.0600000000000001, -0.0499999999999998, -0.04, -0.0299999999999998, -0.02, -0.00999999999999979, 0, 0.0100000000000002, 0.02, 0.0300000000000002, 0.04, 0.0500000000000003, 0.0600000000000001, 0.0700000000000003, 0.0800000000000001, 0.0899999999999999, 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.7, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.8, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.9, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, 1.25, 1.26, 1.27, 1.28, 1.29, 1.3, 1.31, 1.32, 1.33, 1.34, 1.35, 1.36, 1.37, 1.38, 1.39, 1.4, 1.41, 1.42, 1.43, 1.44, 1.45, 1.46, 1.47, 1.48, 1.49, 1.5, 1.51, 1.52, 1.53, 1.54, 1.55, 1.56, 1.57, 1.58, 1.59, 1.6, 1.61, 1.62, 1.63, 1.64, 1.65, 1.66, 1.67, 1.68, 1.69, 1.7, 1.71, 1.72, 1.73, 1.74, 1.75, 1.76, 1.77, 1.78, 1.79, 1.8, 1.81, 1.82, 1.83, 1.84, 1.85, 1.86, 1.87, 1.88, 1.89, 1.9, 1.91, 1.92, 1.93, 1.94, 1.95, 1.96, 1.97, 1.98, 1.99, 2, 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, 2.25, 2.26, 2.27, 2.28, 2.29, 2.3, 2.31, 2.32, 2.33, 2.34, 2.35, 2.36, 2.37, 2.38, 2.39, 2.4, 2.41, 2.42, 2.43, 2.44, 2.45, 2.46, 2.47, 2.48, 2.49, 2.5, 2.51, 2.52, 2.53, 2.54, 2.55, 2.56, 2.57, 2.58, 2.59, 2.6, 2.61, 2.62, 2.63, 2.64, 2.65, 2.66, 2.67, 2.68, 2.69, 2.7, 2.71, 2.72, 2.73, 2.74, 2.75, 2.76, 2.77, 2.78, 2.79, 2.8, 2.81, 2.82, 2.83, 2.84, 2.85, 2.86, 2.87, 2.88, 2.89, 2.9, 2.91, 2.92, 2.93, 2.94, 2.95, 2.96, 2.97, 2.98, 2.99, 3];
// AXES //////////////////////////////////////////////////////////////////
// add horizontal lines for parameter space
svg.selectAll("thetaspace")
.data([0])
.enter()
.append("line")
.attr("x1", margin.left + 200)
.attr("x2", margin.left + width - 200)
.attr("y1", y_1)
.attr("y2", y_1)
.attr("stroke", "grey")
svg.selectAll("paramtext")
.data(["parameter space"])
.enter()
.append("text")
.attr("x", margin.left + width - 180)
.attr("y", y_1 + 5)
.attr("fill", "black")
.attr("text-anchor", "left")
.html(function(d) { return d; })
.style("font-size", "20px");
// add horizontal lines for data space
svg.selectAll("dataspace")
.data([0])
.enter()
.append("line")
.attr("x1", margin.left + 200)
.attr("x2", margin.left + width - 200)
.attr("y1", y_2)
.attr("y2", y_2)
.attr("stroke", "grey")
svg.selectAll("datatext")
.data(["data space"])
.enter()
.append("text")
.attr("x", margin.left + width - 180)
.attr("y", y_2 + 5)
.attr("fill", "black")
.attr("text-anchor", "left")
.html(function(d) { return d; })
.style("font-size", "20px");
// add horizontal lines for estimator space
svg.selectAll("estspace")
.data([0])
.enter()
.append("line")
.attr("x1", margin.left + 200)
.attr("x2", margin.left + width - 200)
.attr("y1", y_3)
.attr("y2", y_3)
.attr("stroke", "grey")
svg.selectAll("esttext")
.data(["estimator space"])
.enter()
.append("text")
.attr("x", margin.left + width - 180)
.attr("y", y_3 + 5)
.attr("fill", "black")
.attr("text-anchor", "left")
.html(function(d) { return d; })
.style("font-size", "20px");
// Place theta ///////////////////////////////////////////////////////////
// Add theta at top
var x_theta = d3.randomNormal(0, 1)(1);
d3.select("body").on("click", function() {
svg.append("path")
.attr("d", axisLineFunction(density_data))
.attr("fill", "none")
.attr("stroke", "grey")
.attr("stroke-linejoin", "round")
.transition()
.duration(1000)
.attrTween('d', function () {
return d3.interpolatePath(axisLineFunction(density_data),
densityLineFunction(density_data));
});
// add normal density
d3.select("body").on("click", function() {
svg.append("text")
.attr("x", x(x_theta))
.attr("y", y_1 - 10)
.attr("fill", "black")
.attr("text-anchor", "middle")
.html("&#952")
.style("font-size", "34px");
svg.append("circle")
.attr("cx", x(x_theta))
.attr("cy", y_1)
.attr("fill", "black")
.attr("r", 4);
// add first set of data points
d3.select("body").on("click", function() {
// define the random data
var data = d3.range(10).map(function() {
return d3.randomNormal(x_theta, 1)(1);
});
var lines = svg.selectAll("firstline")
.data(data)
.enter()
.append("line")
.attr("x1", x(x_theta))
.attr("y1", y_1 + 10)
.attr("x2", x(x_theta))
.attr("y2", y_1 + 10)
.attr("stroke", color(iteration))
.transition()
.duration(1000)
.delay(function(d, i) { return i * 100})
.attr("x2", function(d) { return x(d); })
.attr("y2", y_2)
.attr("stroke-width", 2)
.attr("opacity", 1);
var circleborder = svg.selectAll("datacircle")
.data(data)
.enter()
.append("circle")
.attr("r", 0)
.attr("cx", function(d) { return x(d); })
.attr("cy", y_2)
.attr("fill", "white")
.transition()
.delay(function(d, i) { return i * 100 + 800; })
.duration(200)
.attr("r", 13);
var circles = svg.selectAll("datacircle")
.data(data)
.enter()
.append("circle")
.attr("r", 0)
.attr("cx", function(d) { return x(d); })
.attr("cy", y_2)
.attr("fill", color(iteration))
.transition()
.delay(function(d, i) { return i * 100 + 800; })
.duration(200)
.attr("r", 10)
.attr("opacity", 1);
var meancircles = svg.selectAll("datacircle")
.data(data)
.enter()
.append("circle")
.attr("r", 0)
.attr("cx", function(d) { return x(d); })
.attr("cy", y_2)
.attr("fill", color(iteration))
.transition()
.duration(800)
.delay(function(d, i) { return 2000; })
.attr("cx", x(d3.mean(data)))
.attr("cy", y_3)
.attr("fill", color(iteration))
.attr("r", 9);
var mean_data = [d3.mean(data), d3.mean(data)];
var kernel = kernelDensityEstimator(kernelEpanechnikov(1), x.ticks(20))(mean_data);
var kernelpath = svg.append("path")
.attr("d", y3axisLineFunction(density_data))
.attr("fill", "none")
.attr("stroke", "grey")
.attr("stroke-linejoin", "round")
.transition()
.delay(2000)
.duration(2000)
.attrTween('d', function () {
return d3.interpolatePath(y3axisLineFunction(density_data),
kernelLineFunction(kernel));
});
newkernelpath[0] = kernelpath;
// add first set of data points
d3.select("body").on("click", function() {
iteration = iteration + 1;
var x_theta_new = d3.randomNormal(0, 1)(1);
svg.append("text")
.attr("x", x(x_theta_new))
.attr("y", y_1 - 10)
.attr("fill", color(iteration))
.attr("text-anchor", "middle")
.html("&#952")
.style("font-size", "34px");
svg.append("circle")
.attr("cx", x(x_theta_new))
.attr("cy", y_1)
.attr("fill", color(iteration))
.attr("r", 4);
// define the random data
var datanew = d3.range(10).map(function() {
return d3.randomNormal(x_theta_new, 1)(1);
});
var lines = svg.selectAll("firstline")
.data(datanew)
.enter()
.append("line")
.attr("x1", x(x_theta_new))
.attr("y1", y_1 + 10)
.attr("x2", x(x_theta_new))
.attr("y2", y_1 + 10)
.attr("stroke", color(iteration))
.transition()
.duration(1000)
.delay(function(d, i) { return i * 100})
.attr("x2", function(d) { return x(d); })
.attr("y2", y_2)
.attr("stroke-width", 2)
.attr("opacity", point_opacity)
.transition()
.duration(2000)
.delay(function(d, i) { return 1500 - i * 100; })
.attr("opacity", 0);
var circleborder = svg.selectAll("datacircle")
.data(datanew)
.enter()
.append("circle")
.attr("r", 0)
.attr("cx", function(d) { return x(d); })
.attr("cy", y_2)
.attr("fill", "white")
.transition()
.delay(function(d, i) { return i * 100 + 800; })
.duration(200)
.attr("r", 13)
.attr("opacity", point_opacity)
.transition()
.duration(2000)
.delay(function(d, i) { return 1500 - i * 100; })
.attr("opacity", 0);
var circles = svg.selectAll("datacircle")
.data(datanew)
.enter()
.append("circle")
.attr("r", 0)
.attr("cx", function(d) { return x(d); })
.attr("cy", y_2)
.attr("fill", color(iteration))
.transition()
.delay(function(d, i) { return i * 100 + 800; })
.duration(200)
.attr("r", 10)
.attr("opacity", point_opacity)
.transition()
.duration(2000)
.delay(function(d, i) { return 1500 - i * 100; })
.attr("opacity", 0);
var newmeancircles = svg.selectAll("newmeancircle")
.data(datanew)
.enter()
.append("circle")
.attr("r", 0)
.attr("cx", function(d) { return x(d); })
.attr("cy", y_2)
.attr("fill", color(iteration))
.attr("opacity", 0.3)
.transition()
.duration(800)
.delay(2000)
.attr("cx", x(d3.mean(datanew)))
.attr("cy", y_3)
.attr("r", 7)
.attr("opacity", 0.1);
var old_kernel = kernelDensityEstimator(kernelEpanechnikov(1), x.ticks(20))(mean_data);
mean_data.push(d3.mean(datanew));
var kernel = kernelDensityEstimator(kernelEpanechnikov(1), x.ticks(20))(mean_data);
// hacky way to get the kernel path to update at each iteration
newkernelpath[iteration] = newkernelpath[iteration - 1].transition()
.delay(1500)
.duration(2000)
.attrTween('d', function () {
return d3.interpolatePath(kernelLineFunction(old_kernel),
kernelLineFunction(kernel));
});
});
});
});
});
// Normal distribution function ////////////////////////////////////////////
var densityLineFunction = d3.line()
.curve(d3.curveBasis)
.x(function(d) { return x(d); })
.y(function(d) { return y(normalFun(d)); });
var normalFun = function(x) {
return (-(1 / Math.sqrt(Math.PI * 2)) * Math.exp(- 0.5 * Math.pow(x, 2)));
}
var axisLineFunction = d3.line()
.x(function(d) { return x(d); })
.y(y_1);
var y3axisLineFunction = d3.line()
.x(function(d) { return x(d); })
.y(y_3);
// Density function //////////////////////////////////////////////////////////
function kernelDensityEstimator(kernel, X) {
return function(V) {
return X.map(function(x) {
return [x, 10 * d3.mean(V, function(v) { return kernel(x - v); })];
});
};
}
function kernelEpanechnikov(k) {
return function(v) {
return Math.abs(v /= k) <= 1 ? 0.75 * (1 - v * v) / k : 0;
};
}
var kernelLineFunction = d3.line()
.curve(d3.curveBasis)
.x(function(d) { return x(d[0]); })
.y(function(d) { return y_kernel(d[1]); });
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment