Skip to content

Instantly share code, notes, and snippets.

@SpaceActuary
Last active December 14, 2015 15:25
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 SpaceActuary/41b50ea8bb206e44fec2 to your computer and use it in GitHub Desktop.
Save SpaceActuary/41b50ea8bb206e44fec2 to your computer and use it in GitHub Desktop.
Non-negative Distributions
var gammaDist = function(){
var gamma = {},
shape,
scale;
var labeler = function(shape, scale){
return "Gamma(α = " + d3.round(shape, 3) + ", " +
"θ = " + d3.round(scale, 3) + ")";
}
gamma.shape = function(_) {
if (!arguments.length) return shape;
shape = _;
gamma.label = labeler(shape, scale);
return gamma;
};
gamma.scale = function(_) {
if (!arguments.length) return scale;
scale = _;
gamma.label = labeler(shape, scale);
return gamma;
};
gamma.mean = function(_) {
if (!arguments.length) return jStat.gamma.mean(shape, scale);
scale = _ / shape;
gamma.label = labeler(shape, scale);
return gamma;
};
gamma.pdf = function(x){ return jStat.gamma.pdf(x, shape, scale); }
gamma.cdf = function(x){ return jStat.gamma.cdf(x, shape, scale); }
gamma.inv = function(p){ return jStat.gamma.inv(p, shape, scale); }
return gamma;
}
var lognormalDist = function(){
var lognormal = {},
mu,
sigma;
var labeler = function(mu, sigma){
return "Lognormal(μ = " + d3.round(mu, 3) + ", " +
"σ = " + d3.round(sigma, 3) + ")";
}
lognormal.mu = function(_) {
if (!arguments.length) return mu;
mu = _;
lognormal.label = labeler(mu, sigma);
return lognormal;
};
lognormal.sigma = function(_) {
if (!arguments.length) return sigma;
sigma = _;
lognormal.label = labeler(mu, sigma);
return lognormal;
};
lognormal.mean = function(_) {
if (!arguments.length) return jStat.lognormal.mean(mu, sigma);
mu = Math.log(_) - (sigma * sigma) / 2;
lognormal.label = labeler(mu, sigma);
return lognormal;
};
lognormal.pdf = function(x){ return jStat.lognormal.pdf(x, mu, sigma); }
lognormal.cdf = function(x){ return jStat.lognormal.cdf(x, mu, sigma); }
lognormal.inv = function(p){ return jStat.lognormal.inv(p, mu, sigma); }
return lognormal;
}
var paretoDist = function(){
var pareto = {},
scale,
shape;
var labeler = function(scale, shape){
return "Pareto(x_m = " + d3.round(scale, 3) + ", " +
"α = " + d3.round(shape, 3) + ")";
}
pareto.shape = function(_) {
if (!arguments.length) return shape;
shape = _;
pareto.label = labeler(scale, shape);
return pareto;
};
pareto.scale = function(_) {
if (!arguments.length) return scale;
scale = _;
pareto.label = labeler(scale, shape);
return pareto;
};
pareto.mean = function(_) {
if (!arguments.length) return jStat.pareto.mean(scale, shape);
scale = _ * (shape - 1) / shape;
pareto.label = labeler(scale, shape);
return pareto;
};
pareto.pdf = function(x){ return jStat.pareto.pdf(x, scale, shape); }
pareto.cdf = function(x){ return jStat.pareto.cdf(x, scale, shape); }
pareto.inv = function(p){ return jStat.pareto.inv(p, scale, shape); }
return pareto;
}
var weibullDist = function(){
var weibull = {},
scale,
shape;
var labeler = function(scale, shape){
return "Weibull(λ = " + d3.round(scale, 3) + ", " +
"k = " + d3.round(shape, 3) + ")";
}
weibull.shape = function(_) {
if (!arguments.length) return shape;
shape = _;
weibull.label = labeler(scale, shape);
return weibull;
};
weibull.scale = function(_) {
if (!arguments.length) return scale;
scale = _;
weibull.label = labeler(scale, shape);
return weibull;
};
weibull.mean = function(_) {
if (!arguments.length) return jStat.weibull.mean(scale, shape);
scale = _ / jStat.gammafn(1 + 1/shape);
weibull.label = labeler(scale, shape);
return weibull;
};
weibull.pdf = function(x){ return jStat.weibull.pdf(x, scale, shape); }
weibull.cdf = function(x){ return jStat.weibull.cdf(x, scale, shape); }
weibull.inv = function(p){ return jStat.weibull.inv(p, scale, shape); }
return weibull;
}
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="https://cdn.jsdelivr.net/jstat/1.5.0/jstat.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/1.6.0/d3-legend.js"></script>
<script src="distributions.js"></script>
<style>
body {
margin: 0;
position: fixed;
top: 0; right: 0; bottom: 0; left: 0;
font-family: Arial, Helvetica, sans-serif
}
svg {
width: 100%;
height: 100%;
}
path {
stroke-width: 1;
fill: none;
}
.axis {
/*stroke: lightgrey;*/
shape-rendering: crispEdges;
}
.x.axis line { stroke: lightgrey; }
.x.axis .minor { stroke-opacity: .5; }
.x.axis path { stroke: lightgrey; }
.y.axis line, .y.axis path {
fill: none;
stroke: lightgrey;
}
.handle path {
fill: silver;
stroke: #000;
}
</style>
</head>
<body>
<script>
var margin = {top: 60, right: 20, bottom: 60, left: 50, inner: 60};
var width = 960 - margin.left - margin.inner - margin.right;
var height = 500 - 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)
var svg1 = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var svg2 = svg.append("g")
.attr("transform", "translate(" + (width/2 + margin.left + margin.inner)
+ "," + margin.top + ")");
var i = 300;
var p = 0.01;
var dists = [
/*gamma(1, 2),
gamma(2, 2),
gamma(3, 2),*/
gammaDist().shape(2.5).scale(2),
//gammaDist().shape(5).scale(1),
//gammaDist().shape(10).scale(0.5),
//gammaDist().shape(20).scale(0.25),
/*gamma(9, 0.5),
gamma(7.5, 1)*/
lognormalDist().mu(Math.log(5)-(0.25^2)/2).sigma(0.25),
//lognormalDist().mu(Math.log(5)-(0.5^2)/2).sigma(0.5),
paretoDist().shape(2.5).scale(2),
weibullDist().shape(1.5).mean(5),
weibullDist().shape(2.5).mean(5)
]
//console.log("pareto mean", jStat.pareto.mean(2.5, 2))
var x = d3.scale.linear()
.range([0, width / 2])
.domain([0, d3.max(dists.map(function(dist){
return dist.inv(1 - p);
}))])
.nice()
.clamp(true);
var points = d3.range(x.domain()[0], x.domain()[1],
(x.domain()[1] - x.domain()[0]) / i);
var y1 = d3.scale.linear()
.range([height, 0])
.domain([0, d3.max(dists.map(function(dist){
return d3.max(points, function(pt){ return dist.pdf(pt); })
}))])
.nice();
var y2 = d3.scale.linear()
.range([height, 0])
.domain([0, 1]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis().scale(x).orient("bottom");
svg1.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg2.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
var y1Axis = d3.svg.axis().scale(y1).orient("left");
var y2Axis = d3.svg.axis().scale(y2).orient("left");
svg1.append("g")
.attr("class", "y y1 axis")
.attr("transform", "translate(0,0)")
.call(y1Axis);
svg2.append("g")
.attr("class", "y y2 axis")
.attr("transform", "translate(0,0)")
.call(y2Axis);
var brush = d3.svg.brush()
.x(x)
.extent([0, 0])
.on("brush", brushed)
.on("brushend", brushended);
var pdf_line = function(dist){
return d3.svg.line()
.x(function(d) { return x(d); })
.y(function(d) { return y1(dist.pdf(d)); })
.interpolate("linear");
}
var cdf_line = function(dist){
return d3.svg.line()
.x(function(d) { return x(d); })
.y(function(d) { return y2(dist.cdf(d)); })
.interpolate("linear");
}
var pdf_lines = dists.map(pdf_line);
var cdf_lines = dists.map(cdf_line);
svg1.selectAll("path.pdf")
.data(pdf_lines)
.enter()
.append("path")
.attr("class", "pdf")
.attr("d", function(dist){ return dist(points); })
.attr("stroke", function(dist, i){ return color(i); });
svg2.selectAll("path.cdf")
.data(cdf_lines)
.enter()
.append("path")
.attr("class", "cdf")
.attr("d", function(dist){ return dist(points); })
.attr("stroke", function(dist, i){ return color(i); });
svg1.append("g")
.attr("class", "legendOrdinal")
.attr("transform", "translate(" + (width / 5) + ",20)");
var legendOrdinal = d3.legend.color()
.shape("circle")
.shapeRadius(7)
.shapePadding(10)
.scale(color)
.labels(dists.map(function(dist){ return dist.label; }));
svg.select(".legendOrdinal")
.call(legendOrdinal);
var slider = svg1.append("g")
.attr("class", "slider")
.call(brush);
slider.selectAll(".extent,.resize")
.remove();
slider.select(".background")
.attr("height", height);
var handle = slider.append("g")
.attr("class", "handle")
handle.append("path")
.attr("d", d3.svg.symbol().type("triangle-up").size(200))
.attr("transform", "translate(0," + (height + margin.bottom * 0.6) + ")")
slider
.call(brush.extent([5, 5]))
.call(brush.event);
function redraw(value, duration){
dists = dists.map(function(d, i){
//console.log(i, d);
d.mean(value);
return d;
})
pdf_lines = dists.map(pdf_line);
cdf_lines = dists.map(cdf_line);
svg1.selectAll("path.pdf")
.data(pdf_lines)
.transition().duration(duration)
.attr("d", function(dist){ return dist(points); });
svg2.selectAll("path.cdf")
.data(cdf_lines)
.transition().duration(duration)
.attr("d", function(dist){ return dist(points); });
svg.select(".legendOrdinal")
.call(legendOrdinal.labels(dists.map(function(dist){
return dist.label;
})));
}
function rescale(value, duration){
handle.transition().duration(duration)
.attr("transform", "translate(" + x(value) + ",0)");
/*
y1.domain([0, d3.max(dists.map(function(dist){
return d3.max(points, function(pt){ return dist.pdf(pt); })
}))]);
y1Axis.scale(y1);
svg.selectAll("g.y1.axis").transition()
.delay(duration)
.duration(duration)
.call(y1Axis);
*/
}
function brushed() {
var value = brush.extent()[0];
//console.log(value)
if (d3.event.sourceEvent) { // not a programmatic event
value = x.invert(d3.mouse(this)[0]);
brush.extent([value, value]);
}
handle
.attr("transform", "translate(" + x(value) + ",0)");
redraw(value, 0)
}
function brushended() {
var value = brush.extent()[0];
if (!d3.event.sourceEvent) return; // only transition after input
x = d3.scale.linear()
.range([0, width / 2])
.domain([0, d3.max(dists.map(function(dist){
return dist.inv(1 - p);
}))])
.nice()
.clamp(true);
points = d3.range(x.domain()[0], x.domain()[1],
(x.domain()[1] - x.domain()[0]) / i);
xAxis.scale(x);
svg.selectAll("g.x.axis").transition().duration(1500).call(xAxis);
rescale(value, 1500)
redraw(value, 1500)
}
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment