Better graph

This commit is contained in:
2016-03-29 11:33:34 +08:00
parent 79db852b26
commit 3c38b06da7
5 changed files with 296 additions and 515 deletions
+140
View File
@@ -0,0 +1,140 @@
/** List of distributions, arguments, and defaults **/
var distributions = {
"arcsine": {
"argDefaults": [0, 1],
"argNames": ["min", "max"]
},
"beta": {
"argDefaults": [1, 1, 0, 1],
"argNames": ["v", "w", "min", "max"]
},
"cauchy": {
"argDefaults": [1, 1],
"argNames": ["a", "b"]
},
"chiSquare": {
"argDefaults": [1],
"argNames": ["df"]
},
"cosine": {
"argDefaults": [0, 1],
"argNames": ["min", "max"]
},
"doubleLog": {
"argDefaults": [0, 1],
"argNames": ["min", "max"]
},
"erlang": {
"argDefaults": [1, 1],
"argNames": ["b", "c"]
},
"exponential": {
"argDefaults": [1, 1],
"argNames": ["a", "b"]
},
"extremeValue": {
"argDefaults": [0.5, 5, 0, 1],
"argNames": ["a", "b"]
},
"fRatio": {
"argDefaults": [1, 1],
"argNames": ["v", "w"]
},
"gamma": {
"argDefaults": [1, 1, 1],
"argNames": ["a", "b", "c"]
},
"laplace": {
"argDefaults": [1, 1],
"argNames": ["a", "b"]
},
"logarithmic": {
"argDefaults": [0, 1],
"argNames": ["min", "max"]
},
"logistic": {
"argDefaults": [1, 1],
"argNames": ["a", "b"]
},
"lognormal": {
"argDefaults": [1, 1, 1],
"argNames": ["a", "mu", "sigma"]
},
"normal": {
"argDefaults": [1, 1],
"argNames": ["mu", "sigma"]
},
"parabolic": {
"argDefaults": [0, 1],
"argNames": ["min", "max"]
},
"pareto": {
"argDefaults": [1],
"argNames": ["c"]
},
"pearson5": {
"argDefaults": [1, 1],
"argNames": ["b", "c"]
},
"pearson6": {
"argDefaults": [1, 1, 1],
"argNames": ["b", "v", "w"]
},
"power": {
"argDefaults": [1],
"argNames": ["c"]
},
"rayleigh": {
"argDefaults": [1, 1],
"argNames": ["a", "b"]
},
"studentT": {
"argDefaults": [1],
"argNames": ["df"]
},
"triangular": {
"argDefaults": [0, 1, 1],
"argNames": ["min", "max", "c"]
},
"uniform": {
"argDefaults": [0, 1],
"argNames": ["min", "max"]
},
"weibull": {
"argDefaults": [1, 1, 1],
"argNames": ["a", "b", "c"]
},
"bernoulli": {
"argDefaults": [0.5],
"argNames": ["p"]
},
"binomial": {
"argDefaults": [10, 0.5],
"argNames": ["n", "p"]
},
"geometric": {
"argDefaults": [0.5],
"argNames": ["p"]
},
"hypergeometric": {
"argDefaults": [6, 10, 4],
"argNames": ["n", "N", "K"]
},
"negativeBinomial": {
"argDefaults": [5, 0.5],
"argNames": ["s", "p"]
},
"pascal": {
"argDefaults": [5, 0.5],
"argNames": ["s", "p"]
},
"poisson": {
"argDefaults": [5],
"argNames": ["mu"]
},
"uniformDiscrete": {
"argDefaults": [1, 10],
"argNames": ["i", "j"]
}
}
+42
View File
@@ -0,0 +1,42 @@
/** Graph to visualize normal dists **/
/** bin and normalise data so it can be plotted on a line graph **/
function bin_data(values, nbins) {
nbins=nbins||100
var flatVals = _(values).values().flatten().value()
var max = _.max(flatVals)
var min = _.min(flatVals)
var steps = (max - min) / nbins
var bins = d3.range(min, max, steps)
var binner = d3.layout.histogram()
.bins(bins)
.frequency(false) // use probability
// I want to remove start and end bins with few values in to improve display
var cuttofProb = 0.002
var allBinned = binner(flatVals).map(v=>v.y/v.dx).map(v=>v<cuttofProb?0:v)
i0=_.findIndex(allBinned,v=>v!=0)
i1=_.findLastIndex(allBinned,v=>v!=0)
bins2=bins.slice(i0,i1-i0)
var binner = d3.layout.histogram()
.bins(bins2)
.frequency(false) // use probability
// format for c3
c3data = {x:'x'}
c3data.columns=[
_.concat(['x'],bins)
]
// bin and adjust for bin width
for (var name in values) {
var vals = values[name]
normalisedData = binner(vals).map(v=>v.y/v.dx)
var column = _.concat([name],normalisedData)
c3data.columns.push(column)
}
return c3data
}
+93
View File
@@ -0,0 +1,93 @@
var gui = new dat.GUI();
var distGuiConfig = {};
var chart;
$(window).ready(function () {
function genVals(sd, total) {
var intval = $('#intval').val()
var f = random[sd]
var argDefaults = distributions[sd].argDefaults
var vals = []
for (var i = 0; i < total; i++) {
vals.push(f.apply(random, argDefaults))
}
return vals
}
/** make/update chart for selected values **/
function genSelected() {
var allVals = {}
for (var name in distGuiConfig) {
if (distributions.hasOwnProperty(name) && (distGuiConfig[name].on)) {
allVals[name] = genVals(name, distGuiConfig.npoints)
}
}
var c3data = bin_data(allVals, distGuiConfig.bins)
chart.load({
columns: c3data.columns,
unload: true
})
}
function loadDistGui() {
// make config
initialOn = ['gamma', 'normal', 'cosine']
distGuiConfig = {
npoints: 50000,
bins: 80
}
var npoints = gui.add(distGuiConfig, 'npoints').onChange(genSelected.bind(this))
var bins = gui.add(distGuiConfig, 'bins').onChange(genSelected.bind(this))
for (var name in distributions) {
if (distributions.hasOwnProperty(name)) {
var folder = gui.addFolder(name);
distGuiConfig[name] = {
on: initialOn.indexOf(name) > -1
}
var button = folder.add(distGuiConfig[name], 'on');
var args = distributions[name].argNames
var argDefaults = distributions[name].argDefaults
for (var i = 0; i < args.length; i++) {
var arg = args[i]
var defV = argDefaults[i]
distGuiConfig[name][arg] = defV
var controller = folder.add(distGuiConfig[name], arg, defV)
controller.onChange(genSelected.bind(this));
}
button.onChange(genSelected.bind(this));
if (distGuiConfig[name].on) folder.open()
}
}
// init chart
chart = c3.generate({
axis: {
x: {
tick: {
format: d3.format(".2g")
},
label: 'outputs'
},
y:{
label: 'probability'
}
},
data: {
x: 'x',
columns: [],
type: 'spline',
}
});
}
loadDistGui()
genSelected()
});
View File
+21 -515
View File
@@ -7,52 +7,9 @@
<title>Statistical Distributions</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.2/css/bootstrap.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.2/css/bootstrap-responsive.css" rel="stylesheet">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/sugar/1.4.1/sugar-full.development.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.6.1/lodash.js"></script>
<script type="text/javascript" src="./src/random.js"></script>
<!-- <script type="text/javascript" src="/web/20140418143337js_/http://blog.codinglabs.org/demo/s/js/v/distributions.js"></script> -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highcharts/3.0.10/highcharts.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/1.9.0/d3-legend.js"></script>
<style>
body {
font: 10px sans-serif;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.css" rel="stylesheet">
<link href="gh-pages/style.css" rel="stylesheet">
.bar rect {
fill: steelblue;
shape-rendering: crispEdges;
}
.bar text {
fill: #fff;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.plotLab {
font-size: 28px;
font-family: "Helvetica";
}
.grid line {
stroke: #C8D5DA;
stroke-dasharray: 1 1;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
</style>
</head>
<body>
@@ -61,487 +18,36 @@
<h2 id="diName"></h2>
<div class="row-fluid">
<div class="span8">
<h4>Density Histogram</h4>
<!-- <div id="density" style="width:100%;height:400px"></div> -->
<h4>Distribution Histogram</h4>
<h4>Distribution</h4>
<!-- <div id="distribution" style="width:100%;height:400px"></div> -->
</div>
<div class="span4">
<form>
<fieldset>
<legend>Parameters</legend>
<div class="control-group">
<label class="control-label" for="sd">statistical distributions</label>
<div class="controls">
<select id="sd"></select>
</div>
</div>
<div class="control-group">
<label class="control-label" for="total">number of points</label>
<div class="controls">
<input type="number" value="10000" min="1" max="10000000" id="total" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="intval">intval</label>
<div class="controls">
<input type="number" value="0.1" min="0.1" step="0.1" id="intval" />
</div>
</div>
<div id="diParams"></div>
<div class="control-group">
<div class="controls">
<button id="gen" type="button" class="btn btn-success"><i class="icon-play icon-white"></i> Generate</button>
</div>
</div>
</fieldset>
</form>
</div>
</div>
</div>
<script type="text/javascript">
var distributions = {
"arcsine": {
"argDefaults": [0, 1],
"argNames": ["min", "max"]
},
"beta": {
"argDefaults": [1, 1, 0, 1],
"argNames": ["v", "w", "min", "max"]
},
"cauchy": {
"argDefaults": [1, 1],
"argNames": ["a", "b"]
},
"chiSquare": {
"argDefaults": [1],
"argNames": ["df"]
},
"cosine": {
"argDefaults": [0, 1],
"argNames": ["min", "max"]
},
"doubleLog": {
"argDefaults": [0, 1],
"argNames": ["min", "max"]
},
"erlang": {
"argDefaults": [1, 1],
"argNames": ["b", "c"]
},
"exponential": {
"argDefaults": [1, 1],
"argNames": ["a", "b"]
},
"extremeValue": {
"argDefaults": [0.5, 5, 0, 1],
"argNames": ["a", "b"]
},
"fRatio": {
"argDefaults": [1, 1],
"argNames": ["v", "w"]
},
"gamma": {
"argDefaults": [1, 1, 1],
"argNames": ["a", "b", "c"]
},
"laplace": {
"argDefaults": [1, 1],
"argNames": ["a", "b"]
},
"logarithmic": {
"argDefaults": [0, 1],
"argNames": ["min", "max"]
},
"logistic": {
"argDefaults": [1, 1],
"argNames": ["a", "b"]
},
"lognormal": {
"argDefaults": [1, 1, 1],
"argNames": ["a", "mu", "sigma"]
},
"normal": {
"argDefaults": [1, 1],
"argNames": ["mu", "sigma"]
},
"parabolic": {
"argDefaults": [0, 1],
"argNames": ["min", "max"]
},
"pareto": {
"argDefaults": [1],
"argNames": ["c"]
},
"pearson5": {
"argDefaults": [1, 1],
"argNames": ["b", "c"]
},
"pearson6": {
"argDefaults": [1, 1, 1],
"argNames": ["b", "v", "w"]
},
"power": {
"argDefaults": [1],
"argNames": ["c"]
},
"rayleigh": {
"argDefaults": [1, 1],
"argNames": ["a", "b"]
},
"studentT": {
"argDefaults": [1],
"argNames": ["df"]
},
"triangular": {
"argDefaults": [0, 1, 1],
"argNames": ["min", "max", "c"]
},
"uniform": {
"argDefaults": [0, 1],
"argNames": ["min", "max"]
},
"weibull": {
"argDefaults": [1, 1, 1],
"argNames": ["a", "b", "c"]
},
"bernoulli": {
"argDefaults": [0.5],
"argNames": ["p"]
},
"binomial": {
"argDefaults": [10, 0.5],
"argNames": ["n", "p"]
},
"geometric": {
"argDefaults": [0.5],
"argNames": ["p"]
},
"hypergeometric": {
"argDefaults": [6, 10, 4],
"argNames": ["n", "N", "K"]
},
"negativeBinomial": {
"argDefaults": [5, 0.5],
"argNames": ["s", "p"]
},
"pascal": {
"argDefaults": [5, 0.5],
"argNames": ["s", "p"]
},
"poisson": {
"argDefaults": [5],
"argNames": ["mu"]
},
"uniformDiscrete": {
"argDefaults": [1, 10],
"argNames": ["i", "j"]
}
}
<div class="container">
<div class="row-fluid">
<div class="span8">
<div id="chart"></div>
</div>
</div>
</div>
var bins = 40
var numPoints = 5500
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.6.1/lodash.js"></script>
function line(values, name) {
// http://bl.ocks.org/phil-pedruco/88cb8a51cdce45f13c7e
// line chart based on http://bl.ocks.org/mbostock/3883245
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var flatVals = _(values).values().flatten().value()
var max = _.max(flatVals)
var min = _.min(flatVals)
max=_.clamp(max,0,40)
min=_.clamp(min,-40,0)
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.js"></script>
var x = d3.scale.linear()
.domain([min, max])
.range([0, width]);
var y = d3.scale.linear()
.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 + ")");
x.domain(d3.extent([min,max]));
y.domain([0, 1]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
// legend
var colors = d3.scale.category10()
var names = Object.keys(values)
var ordinal = d3.scale.category10()
.domain(names)
svg.append("g")
.attr("class", "legendOrdinal")
.attr("transform", "translate(" + width * 0.8 + ",20)");
var legendOrdinal = d3.legend.color()
.shape("path", d3.svg.symbol().type("triangle-up").size(150)())
.shapePadding(10)
.scale(ordinal);
svg.select(".legendOrdinal")
.call(legendOrdinal);
var allData = {}
for (var name in values) {
var nameInd = Object.keys(values).indexOf(name)
var vals = values[name]
var dmin = _.min(vals)
var dmax = _.max(vals)
dmax=_.clamp(dmax,min,max)
dmin=_.clamp(dmin,min,max)
var nbins = vals.length / 100
var dsteps = (dmax - dmin) / nbins
var dbins = d3.range(dmin, dmax, dsteps)
allData[name] = d3.layout.histogram()
.bins(dbins)
(vals);
// normalise counts
// scale by bin width and total count
allData[name] = allData[name]
.map(v => {
v.y = v.y / values[name].length * ((dmax - dmin) / v.dx);
return v;
})
// scale by max y
var maxy = _(allData[name]).map(v => v.y).max()
allData[name] = allData[name]
.map(v => {
v.y = v.y / maxy;
return v;
})
var line = d3.svg.line()
.x(function(d) {
return x(d.x);
})
.y(function(d) {
return y(d.y);
})
.interpolate('basis')
svg.append("path")
.datum(allData[name])
.attr("class", "line")
.attr("d", line)
.style("stroke", colors(nameInd));
console.log(
name,
_(allData[name]).map(r => r.x).min(),
_(allData[name]).map(r => r.x).max(),
_(allData[name]).map(r => r.y).min(),
_(allData[name]).map(r => r.y).max()
)
}
}
/* graph from http://bl.ocks.org/mbostock/3048450*/
function hist(values, nbins, name) {
if (!nbins) nbins = bins || 20
// A formatter for counts.
var formatCount = d3.format(",.0f");
var min = Math.min.apply(null, values);
var max = Math.max.apply(null, values);
var margin = {
top: 10,
right: 30,
bottom: 30,
left: 30
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear()
.domain([min, max])
.range([0, width]);
// Generate a histogram using N uniformly-spaced bins.
var data = d3.layout.histogram()
.bins(x.ticks(bins))
(values);
var y = d3.scale.linear()
.domain([d3.min(data, function(d) {
return d.y;
}), d3.max(data, function(d) {
return d.y;
})])
.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 + ")");
var bar = svg.selectAll(".bar")
.data(data)
.enter().append("g")
.attr("class", "bar")
.attr("transform", function(d) {
return "translate(" + x(d.x) + "," + y(d.y) + ")";
});
bar.append("rect")
.attr("x", 1)
.attr("width", x(data[0].dx) - 1)
.attr("height", function(d) {
return height - y(d.y);
});
// bind labels
bar.append("text")
.attr("dy", ".75em")
.attr("y", 6)
.attr("x", x(data[0].dx) / 2)
.attr("text-anchor", "middle")
.text(function(d) {
return formatCount(d.y);
});
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
var g = svg.append("g")
//.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var gridX = g.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(xAxis
.tickSize(-height, 0, 0)
.tickFormat("")
);
var gridY = g.append("g")
.attr("class", "grid")
.call(yAxis
.tickSize(-width, 0, 0)
.tickFormat("")
);
var label = g.append("svg:text")
.attr("class", "plotLab")
.attr("text-anchor", "middle")
.attr("x", width / 2)
.attr("y", height / 20)
.text(name);
}
$(function() {
/** generate random numbers **/
function gen() {
// get values from buttons
var sd = $('#sd').val()
var total = $('#total').val()
// var intval = $('#intval').val()
var f = random[sd]
var argDefaults = distributions[sd].argDefaults
var vals = genVals(sd,total)
hist(vals,20,sd)
// var o={}
// o[sd]=vals
// line(o)
}
function genVals(sd,total){
var intval = $('#intval').val()
var f = random[sd]
var argDefaults = distributions[sd].argDefaults
var vals = []
for (var i = 0; i < total; i++) {
vals.push(f.apply(random, argDefaults))
}
return vals
}
var total = $('#total').val()
var allVals={}
for (var sd in distributions) {
if (distributions.hasOwnProperty(sd)) {
allVals[sd]=genVals(sd,total)
}
}
line(allVals)
/** change Distribution **/
function changeDi(event) {
var dist = $('#sd').val()
}
var diMeta = Object.keys(random)
$.each(diMeta, function(i, e) {
$('#sd').append('<option value="' + e + '">' + e + '</option>');
});
$('#sd').on('change', changeDi);
$('#gen').on('click', gen);
changeDi();
});
</script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5.1/dat.gui.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jstat/1.5.2/jstat.min.js"></script>
<script type="text/javascript" src="./src/random.js"></script>
<script type="text/javascript" src="gh-pages/distributions.js"></script>
<script type="text/javascript" src="gh-pages/graphs.js"></script>
<script type="text/javascript" src="gh-pages/main.js"></script>
</body>
</html>