Make a Discrete Gaussian distribution
for genererating a PDF this package Also, this was helpfull
Make a Discrete Gaussian distribution
for genererating a PDF this package Also, this was helpfull
// Models the normal distribution | |
var Gaussian = function(mean, variance) { | |
if (variance <= 0) { | |
throw new Error('Variance must be > 0 (but was ' + variance + ')'); | |
} | |
var stddev = Math.sqrt(variance); | |
var precision = 1 / variance; | |
var precisionmean = precision * mean; | |
// Complementary error function | |
// From Numerical Recipes in C 2e p221 | |
var erfc = function(x) { | |
var z = Math.abs(x); | |
var t = 1 / (1 + z / 2); | |
var r = t * Math.exp(-z * z - 1.26551223 + t * (1.00002368 + | |
t * (0.37409196 + t * (0.09678418 + t * (-0.18628806 + | |
t * (0.27886807 + t * (-1.13520398 + t * (1.48851587 + | |
t * (-0.82215223 + t * 0.17087277))))))))) | |
return x >= 0 ? r : 2 - r; | |
}; | |
// Inverse complementary error function | |
// From Numerical Recipes 3e p265 | |
var ierfc = function(x) { | |
if (x >= 2) { return -100; } | |
if (x <= 0) { return 100; } | |
var xx = (x < 1) ? x : 2 - x; | |
var t = Math.sqrt(-2 * Math.log(xx / 2)); | |
var r = -0.70711 * ((2.30753 + t * 0.27061) / | |
(1 + t * (0.99229 + t * 0.04481)) - t); | |
for (var j = 0; j < 2; j++) { | |
var err = erfc(r) - xx; | |
r += err / (1.12837916709551257 * Math.exp(-(r * r)) - r * err); | |
} | |
return (x < 1) ? r : -r; | |
}; | |
// Construct a new distribution from the precision and precisionmean | |
var fromPrecisionMean = function(precision, precisionmean) { | |
var mean = precisionmean / precision; | |
var variance = 1 / precision; | |
return new Gaussian(mean, variance); | |
}; | |
return { | |
mean: mean, | |
variance: variance, | |
standardDeviation: stddev, | |
precision: precision, | |
precisionmean: precisionmean, | |
// Probability density function | |
pdf: function(x) { | |
var m = stddev * Math.sqrt(2 * Math.PI); | |
var e = Math.exp(-Math.pow(x - mean, 2) / (2 * variance)); | |
return e / m; | |
}, | |
// Cumulative density function | |
cdf: function(x) { | |
return 0.5 * erfc(-(x - mean) / (stddev * Math.sqrt(2))); | |
}, | |
// Percent point function (inverse of cdf) | |
ppf: function(x) { | |
return mean - stddev * Math.sqrt(2) * ierfc(2 * x); | |
}, | |
// Product distribution of this and d | |
mul: function(d) { | |
return fromPrecisionMean( | |
precision + d.precision, | |
precisionmean + d.precisionmean); | |
}, | |
// Quotient distribution of this and d | |
div: function(d) { | |
return fromPrecisionMean( | |
precision - d.precision, | |
precisionmean - d.precisionmean); | |
} | |
}; | |
}; | |
/*module.exports = function(mean, variance) { | |
return new Gaussian(mean, variance); | |
};*/ | |
/* | |
https://github.com/errcw/gaussian | |
Copyright (c) 2012 Eric Woroshow | |
Permission is hereby granted, free of charge, to any person obtaining a copy of | |
this software and associated documentation files (the "Software"), to deal in | |
the Software without restriction, including without limitation the rights to | |
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | |
of the Software, and to permit persons to whom the Software is furnished to do | |
so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in all | |
copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
SOFTWARE. | |
*/ |
<html> | |
<head> | |
<title>Discrete Gausian</title> | |
<!-- general --> | |
<style type="text/css"> | |
body{ | |
font-family: sans-serif; | |
} | |
</style> | |
<!--bars--> | |
<style type="text/css"> | |
.distribution-bar{ | |
fill:#333; | |
stroke:#fff; | |
} | |
</style> | |
<!--slider--> | |
<style type="text/css"> | |
.axis { | |
font: 10px sans-serif; | |
-webkit-user-select: none; | |
-moz-user-select: none; | |
user-select: none; | |
} | |
.axis .domain { | |
fill: none; | |
stroke: #000; | |
stroke-opacity: .3; | |
stroke-width: 10px; | |
stroke-linecap: round; | |
} | |
.axis .halo { | |
fill: none; | |
stroke: #ddd; | |
stroke-width: 8px; | |
stroke-linecap: round; | |
} | |
.slider .handle { | |
fill: #fff; | |
stroke: #000; | |
stroke-opacity: .5; | |
stroke-width: 1.25px; | |
pointer-events: none; | |
} | |
</style> | |
</head> | |
<body> | |
<div id='distribution-chart'><svg id='gaussian'></svg></div> | |
<p>Set the variance:</p> | |
<div id='distribution-control'><svg id='variance-slider'></svg></div> | |
</body> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script type="text/javascript" src="gaussian.js"></script> | |
<script type="text/javascript"> | |
'use strict' | |
function discreteGausian( mean, variance, resolution ){ | |
var mean = 0, | |
distribution = new Gaussian(mean, variance), | |
discretePDF = 1, | |
oldCDF = distribution.cdf(mean - (resolution/2)), | |
discreteDistribution = [], | |
sliceThreshold = 0.001, | |
jobDone = false, | |
i = (mean + resolution/2); | |
while(!jobDone){ | |
var newCDF = distribution.cdf( i ); | |
var slice = newCDF - oldCDF; | |
discreteDistribution.push( slice ); | |
if(discreteDistribution.length > 1 ){ | |
discreteDistribution.unshift( slice ); | |
} | |
if(slice < sliceThreshold){ | |
jobDone = true; | |
} | |
oldCDF = newCDF; | |
i += resolution; | |
} | |
return discreteDistribution; | |
} | |
var height = 300, | |
sliderHeight = 150, | |
width = 700; | |
var varianceSliderScale = d3.scale.linear() | |
.domain([0.01, 30]) | |
.range([0, width-60]) | |
.clamp(true); | |
d3.selectAll('svg') | |
.attr('width',width) | |
.attr('height',height); | |
drawDistribution('#gaussian', discreteGausian(0, 2, 1)); | |
drawControl('#variance-slider', varianceSliderScale, changeVariance); | |
function changeVariance(v){ | |
if(v>0){ | |
drawDistribution('#gaussian', discreteGausian(0, v, 1)); | |
} | |
} | |
function drawControl(svgSelector, scale, callback){ | |
var margin = {top:10,left:30,bottom:30,right:30}; | |
var brush = d3.svg.brush() | |
.x(scale) | |
.extent([0, 0]) | |
.on("brush", brushed); | |
var svg = d3.select(svgSelector) | |
.attr('width', width) | |
.attr('height', sliderHeight) | |
.append('g').attr('transform', 'translate('+margin.left+','+margin.top+')'); | |
svg.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(0," + height / 2 + ")") | |
.call(d3.svg.axis() | |
.scale(scale) | |
.orient("bottom") | |
// .tickFormat(function(d) { return d; }) | |
.tickSize(0) | |
.tickPadding(12)) | |
.select(".domain") | |
.select(function() { return this.parentNode.appendChild(this.cloneNode(true)); }) | |
.attr("class", "halo"); | |
var slider = svg.append("g") | |
.attr("class", "slider") | |
.call(brush); | |
slider.selectAll(".extent,.resize") | |
.remove(); | |
slider.select(".background") | |
.attr("height", height); | |
var handle = slider.append("circle") | |
.attr("class", "handle") | |
.attr("transform", "translate(0," + sliderHeight / 2 + ")") | |
.attr("r", 9); | |
slider | |
.call(brush.event); | |
function brushed() { | |
var value = brush.extent()[0]; | |
if (d3.event.sourceEvent) { // not a programmatic event | |
value = scale.invert(d3.mouse(this)[0]); | |
brush.extent([value, value]); | |
} | |
handle.attr("cx", scale(value)); | |
callback(value); | |
} | |
} | |
function drawDistribution(svgSelector, distribution){ | |
var x = d3.scale.linear() | |
.domain([0, distribution.length]) | |
.range([0, width]); | |
var y = d3.scale.linear() | |
.domain([0, d3.max(distribution)]) | |
.range([0, height]); | |
var group = d3.select(svgSelector).selectAll('rect') | |
.data(distribution) | |
group.enter().append('rect') | |
.attr('x',function(d,i){ | |
return width; | |
}) | |
.attr('y',function(d){ | |
return height-y(d); | |
}) | |
.attr('height',function(d){ | |
return y(d); | |
}) | |
.attr('width', function(){ | |
return x(1); | |
}) | |
.attr('class','distribution-bar'); | |
group.transition() | |
.attr('x',function(d,i){ | |
console.log('c'); | |
return x(i); | |
}) | |
.attr('y',function(d){ | |
return height-y(d); | |
}) | |
.attr('height',function(d){ | |
return y(d); | |
}) | |
.attr('width', function(){ | |
return x(1); | |
}); | |
group.exit().remove(); | |
} | |
</script> | |
</html> |