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);
        }

       ...