Last active
March 31, 2022 19:59
-
-
Save twitched/513ee670ec6b561cef14 to your computer and use it in GitHub Desktop.
Dynamic Normal Distribution in D3
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> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> | |
<title>Normal Plot</title> | |
<meta name="description" content=""> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script> | |
<link rel="stylesheet" href="style.css" type="text/css" charset="utf-8"></link> | |
</head> | |
<body> | |
<p class="input"> | |
<label class="input" for="meanbox">Mean: </label> | |
<input class="input inputbox" type="text" id="meanbox" size="3" value="0"/> | |
<label class="input" for="stdevbox">Standard deviation:</label> | |
<input class="input inputbox" type="text" id="stdevbox" size="3" value="1"/> | |
<input class="input inputbox" type="checkbox" id="axisscalecheck" value="lock" checked>Scale axes</input> | |
</p> | |
<script type="text/javascript" src="main.js"></script> | |
</body> | |
</html> |
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
//based on http://bl.ocks.org/phil-pedruco/88cb8a51cdce45f13c7e | |
var margin = { | |
top: 20, | |
right: 20, | |
bottom: 30, | |
left: 50 | |
}, | |
width = 960 - margin.left - margin.right, | |
height = 450 - margin.top - margin.bottom; | |
base_mean = 0; | |
base_sigma = 1; | |
//z score for determining width of graph | |
z_limit = 4; | |
var x = d3.scale.linear() | |
//.domain([-7,7]) | |
.range([0, width]); | |
var y = d3.scale.linear() | |
//.domain([0,.6]) | |
.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 + ")"); | |
svg.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(0," + height + ")") | |
.call(xAxis); | |
svg.append("g") | |
.attr("class", "y axis") | |
.call(yAxis); | |
svg.append("path") | |
.attr("class", "line") | |
.attr("id", "base_normal_curve") | |
update(x, y); | |
//attach event | |
d3.selectAll(".inputbox").on("input", function(){ | |
update(x, y) | |
}); | |
d3.select("#axislockcheck").on("change", function(){ | |
update(x, y) | |
}); | |
//change the curve | |
function update(x, y){ | |
m = Number(d3.select("#meanbox").property("value")); | |
s = Number(d3.select("#stdevbox").property("value")); | |
if(!isNaN(m) && !isNaN(s) && s != 0){ | |
if(d3.select("#axisscalecheck").property("checked")){ | |
update_x_axis(m, s, x); | |
} | |
data = get_data(m, s, x); | |
if(d3.select("#axisscalecheck").property("checked")){ | |
update_y_axis(data, m, s, y); | |
} | |
var line = d3.svg.line() | |
.x(function(d) { | |
return x(d.q); | |
}) | |
.y(function(d) { | |
return y(d.p); | |
}); | |
d3.select("#base_normal_curve") | |
.datum(data) | |
.transition() | |
.attr("d", line); | |
} | |
} | |
//make the x axis min and max scale with the data | |
//needed before data generation | |
function update_x_axis(m, s, x){ | |
x.domain([m - (z_limit * s), m + (z_limit * s)]); | |
d3.select(".x").transition().call(xAxis); | |
} | |
//make the y axis min and max scale with the data | |
//needed after data generation | |
function update_y_axis(data, m, s, y){ | |
y.domain(d3.extent(data, function(d) { | |
return d.p; | |
})); | |
d3.select(".y").transition().call(yAxis); | |
} | |
//given a mean, sigma, and an x scale, return a an array | |
//representing the y points of a normal distribution | |
function get_data(mean, sigma, x){ | |
data = []; //erase current data | |
//populate the data | |
for (i = 0; i < width; i++) { | |
q = x.invert(i); | |
p = gaussian_pdf(q, mean, sigma); // calc prob of each point | |
el = { | |
"q": q, | |
"p": p | |
} | |
//console.log(el); | |
data.push(el); | |
}; | |
return data | |
} | |
//taken from Jason Davies science library | |
// https://github.com/jasondavies/science.js/blob/master/src/stats/distribution/gaussian.js | |
function gaussian_pdf(x, mean, sigma) { | |
var gaussianConstant = 1 / Math.sqrt(2 * Math.PI), | |
x = (x - mean) / sigma; | |
return gaussianConstant * Math.exp(-.5 * x * x) / sigma; | |
}; |
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
body { | |
font: 10pt sans-serif; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.line { | |
fill: none; | |
stroke: steelblue; | |
stroke-width: 1.5px; | |
} | |
.input { | |
font-size: 14pt; | |
margin: 5px; | |
} | |
p.input { | |
text-align: center; | |
} | |
label { | |
display: inline-block; | |
text-align: right; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment