This block displays the value of the cumulative distribution function (CDF) based on the standard score (z-score, x-axis). As you mouse over the probability density function display you will see the value of the CDF change in the center of the plot. The droplines are a modified version of Mike Bostock's - X-Value Mouseover and Micah Stubbs - D3 v4 X-Value Mouseover with Droplines
Last active
March 9, 2017 20:38
-
-
Save ctufts/a90019910166d8378c6462dfd2f6f3ec to your computer and use it in GitHub Desktop.
Normal Distribution CDF value based on standard deviations
This file contains hidden or 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
license: mit | |
border: no |
This file contains hidden or 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 lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>Probability Density: Normal Distribution</title> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script src="https://cdn.jsdelivr.net/jstat/latest/jstat.min.js"></script> | |
<link rel="stylesheet" type="text/css" href="main.css"> | |
<link href="https://fonts.googleapis.com/css?family=Roboto+Slab" rel="stylesheet"> | |
</head> | |
<body> | |
<div id="chartdiv"></div> | |
<script> | |
var bisectX = d3.bisector(function(d) { | |
return d.x; | |
}).left; | |
var pct = d3.format('02.2f'); | |
var numDataPoints = 1000; | |
var interval = 0.05 | |
var upper_bound = 3.1; | |
var lower_bound = -3.0; | |
var mean = 0; | |
var std = 1; | |
var margin = { | |
top: 50, | |
right: 20, | |
bottom: 50, | |
left: 50 | |
}; | |
var width = 960 - margin.left - margin.right, | |
height = 500 - margin.top - margin.bottom; | |
var svg = d3.select("#chartdiv").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 dataset = create_data(interval, upper_bound, lower_bound, mean, std); | |
////// Define Scales ///////////////// | |
var xScale = d3.scaleLinear() | |
.domain([d3.min(dataset, function(d) { | |
return d.x; | |
}), d3.max(dataset, function(d) { | |
return d.x; | |
})]) | |
.range([0, width]); | |
var yScale = d3.scaleLinear() | |
.domain([ | |
d3.min(dataset, function(d) { | |
return (d.y); | |
}), | |
d3.max(dataset, function(d) { | |
return d.y; | |
}) | |
]) | |
.range([height, 0]); | |
var area = d3.area() | |
.x(function(d) { | |
return xScale(d.x); | |
}) | |
.y1(function(d) { | |
return yScale(d.y); | |
}); | |
var xlabels = ['-3\u03C3', '-2\u03C3', '-\u03C3', | |
'0', '\u03C3', '2\u03C3', '3\u03C3' | |
]; | |
/////// Define Axis ////////////////////////////// | |
var xAxis = d3.axisBottom() | |
.scale(xScale) | |
.ticks(xlabels.length) | |
.tickFormat(function(d, i) { | |
return xlabels[i]; | |
}); | |
var yAxis = d3.axisLeft() | |
.scale(yScale) | |
.ticks(8); | |
// append data points | |
svg.append("g") | |
.attr("id", "circles") | |
.selectAll("circle") | |
.data(dataset) | |
.enter() | |
.append("circle") | |
.attr("class", "dot") | |
.attr("cx", function(d) { | |
return xScale(d.x); | |
}) | |
.attr("cy", function(d) { | |
return yScale(d.y); | |
}) | |
.attr("r", 3.0) | |
area.y0(yScale(0)); | |
// cut off datapoints that are outside the axis | |
svg.append("clipPath") | |
.attr("id", "chart-area") | |
.append("rect") | |
.attr("width", width) | |
.attr("height", height); | |
// Set area coverage to x-axis 0 position, i.e. 1/2 dataset | |
svg.append("path") | |
.data([dataset.slice(0, Math.floor(dataset.length / 2))]) | |
.attr("clip-path", "url(#chart-area)") | |
.attr("class", "area") | |
.attr("fill", "steelblue") | |
.attr("d", area); | |
svg.append("text") | |
.attr("id", "pdisplay") | |
.attr("x", xScale(0)) | |
.attr("y", yScale(0.2)) | |
.style("text-anchor", "middle") | |
.text("p(X \u2264 x) = 0.50"); | |
var focus = svg.append("g") | |
.attr("class", "focus") | |
.style("display", "inline"); | |
focus.append("circle") | |
.attr("r", 4.5); | |
// Set up focus (container for vertical guiding line) | |
var center_point = dataset[Math.floor(dataset.length / 2) - 1]; | |
focus.attr("transform", "translate(" + xScale(center_point.x) + | |
"," + yScale(center_point.y) + ")"); | |
focus.append("line") | |
.attr('x1', 0) | |
.attr('x2', 0) | |
.attr('y1', 0) | |
.attr('y2', height - yScale(center_point.y));; | |
// rect for tracking mouse (active over dimensions of svg ) | |
svg.append("rect") | |
.attr("class", "overlay") | |
.attr("width", width) | |
.attr("height", height) | |
.on("mouseover", function() { | |
focus.style("display", null); | |
}) | |
.on("mouseout", function() { | |
focus.style("display", "inline"); | |
}) | |
.on("mousemove", mousemove); | |
// append Axes /////////////////////////// | |
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("x", -10) | |
.attr("dy", "0.71em") | |
.attr("fill", "#000") | |
.text("Probability Density");; | |
function mousemove() { | |
var x0 = xScale.invert(d3.mouse(this)[0]), | |
i = bisectX(dataset, x0, 1), | |
d0 = dataset[i - 1], | |
d1 = dataset[i], | |
d = x0 - d0.x > d1.x - x0 ? d1 : d0; | |
focus.attr("transform", "translate(" + xScale(d.x) + "," + yScale(d.y) + ")"); | |
focus.select('line') | |
.attr('x1', 0) | |
.attr('x2', 0) | |
.attr('y1', 0) | |
.attr('y2', height - yScale(d.y)); | |
// // Update the 'area to go with the line' | |
svg.select("path") | |
.data([dataset.slice(0, dataset.indexOf(d) + 1)]) | |
.attr("d", area); | |
// Update center display | |
svg.select("#pdisplay").text('p(X \u2264 x) = ' + pct(jStat.normal.cdf(d.x, mean, std))); | |
} | |
function create_data(interval, upper_bound, lower_bound, mean, std) { | |
var n = Math.ceil((upper_bound - lower_bound) / interval) | |
var data = []; | |
x_position = lower_bound; | |
for (i = 0; i < n; i++) { | |
data.push({ | |
"y": jStat.normal.pdf(x_position, mean, std), | |
"x": x_position | |
}) | |
x_position += interval | |
} | |
return (data); | |
} | |
</script> | |
</body> | |
</html> |
This file contains hidden or 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
.focus line { | |
stroke: #E4002B; | |
/*fill: none;*/ | |
stroke-width: 3; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: black; | |
shape-rendering: crispEdges; | |
} | |
.axis text { | |
font-size: 14px; | |
font-family: 'Roboto Slab', serif; | |
} | |
.dot { | |
stroke: #293b47; | |
fill: #7A99AC | |
} | |
.overlay { | |
fill: none; | |
pointer-events: all; | |
} | |
.focus circle { | |
fill: none; | |
stroke: steelblue; | |
} | |
.area { | |
opacity: 0.2; | |
} | |
#chartdiv { | |
width:960px; | |
height: 500px; | |
} | |
#pdisplay{ | |
font-size: 26px; | |
font-family: 'Roboto Slab', serif; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment