Visualization of non-negative distribution plots in d3.
Powered using d3.js, jStat, and d3-legend.
Built with blockbuilder.org.
forked from SpaceActuary's block: Distributions
forked from SpaceActuary's block: Non-negative Distributions
forked from anonymous's block: Non-negative Distributions
forked from anonymous's block: Non-negative Distributions
xxxxxxxxxx
<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>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js
https://cdn.jsdelivr.net/jstat/1.5.0/jstat.min.js
https://cdnjs.cloudflare.com/ajax/libs/d3-legend/1.6.0/d3-legend.js