Include uncertainty in a financial model
Visualisation for http://www.ragscripts.com/2014/02/26/include-uncertainty-in-a-financial-model/
by Simon Raper
HTML
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://worrydream.com/Tangle/TangleKit/mootools.js"></script>
<script src="http://worrydream.com/Tangle/TangleKit/sprintf.js"></script>
<script src="http://worrydream.com/Tangle/TangleKit/BVTouchable.js"></script>
<script src="http://worrydream.com/Tangle/Tangle.js"></script>
<script src="http://worrydream.com/Tangle/TangleKit/TangleKit.js"></script>
<link rel="stylesheet" href="http://worrydream.com/Tangle/TangleKit/TangleKit.css">
<body>
<p id="calorieCalculator">
The business has estimated that the average revenue per customer is £ <span class="TKAdjustableNumber" data-var="arpu"> </span> but it is conceivably <span class="TKAdjustableNumber" data-var="arpuAdd"> </span> higher or lower than that.
They have also estimated that monthly churn is <span class="TKAdjustableNumber" data-var="churn"> </span> % but up to <span class="TKAdjustableNumber" data-var="churnAdd"> </span>% higher or lower and that the monthly acquisition rate is <span class="TKAdjustableNumber" data-var="acq"> </span> % which is similarly up to <span class="TKAdjustableNumber" data-var="acqAdd"> </span> % higher or lower.
</p>
<br>
<br>
<canvas id="myCanvas" width="650" height="400" style="border:none;"></canvas>
</body>
CSS
body {
font: 12px sans-serif;
}
.bar rect {
fill: steelblue;
shape-rendering: crispEdges;
}
.bar text {
fill: #fff;
}
.axis path, .axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
JavaScript
var tangle = new Tangle(document.getElementById("calorieCalculator"), {
initialize: function () {
this.arpu = 7;
this.arpuAdd = 2;
this.churn = 5;
this.churnAdd = 2;
this.acq = 6;
this.acqAdd = 1;
// Initialise the d3 histogram
var arpuVar = this.arpuAdd/1.645;
var churnVar = (this.churnAdd/100)/1.645;
var acqVar = (this.acqAdd/100)/1.645;
var simArpu = d3.range(10000).map(d3.random.normal(this.arpu, arpuVar));
var simAcq = d3.range(10000).map(d3.random.normal(this.acq/100, acqVar));
var simChurn = d3.range(10000).map(d3.random.normal(this.churn/100, churnVar));
function revenueCalc(arpu, acq, churn) {
numCust = 5000;
for (var m = 1; m <= 12; m++) {
numCust = numCust + acq * numCust - churn * numCust;
}
return numCust * arpu;
}
var revSim = new Array();
for (var i = 0; i <= 10000; i++) {
revSim[i] = revenueCalc(simArpu[i], simAcq[i], simChurn[i]);
}
//Data
var freq = [];
for (var i = 1; i <= 12; i++) {
var filtered = revSim.filter(function (x) {
return x > (i - 1) * 10000 & x < (i * 10000)
});
freq = freq.concat([filtered.length]);
}
var data = freq;
var labels = ["100k", "200K", "300K", "400K", "500K", "600K", "700K", "800K", "900k", "1000K", "1100K", "1200K"];
//Get canvas
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
//Draw axes
ctx.moveTo(50, 300);
ctx.lineTo(50, 50);
ctx.moveTo(50, 300);
ctx.lineTo(550, 300);
ctx.stroke();
//Draw ticks
for (var i = 1; i <= 13; i++) //x-axis
{
x = 50 + 35 * i;
ctx.moveTo(x, 300);
ctx.lineTo(x, 310);
}
...