2016年8月22日月曜日

開発環境

Pythonからはじめる数学入門 (Amit Saha (著)、黒川 利明 (翻訳)、オライリージャパン)の3章(データを統計量で記述する)、3.9(プログラミングチャレンジ)、問題3-2(統計電卓)をJavaScript(とD3.js)で取り組んでみる。(バージョンアップで D3.js にいろいろ変更点があったみたい。)

問題3-2(統計電卓)

コード(Emacs)

HTML5

<div id="graph0"></div>
<br>
値: <span style="color:blue">----------</span> 
平均値: <span style="color:green">----------</span> 
中央値: <span style="color:red">----------</span> 
<div id="output0"></div>
<input id="nums_data" type="file">

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>
<script src="sample2.js"></script>

JavaScript

(function () {
    'use strict';
    var width = 600,
        height = 400,
        padding = 50,
        padding_left = 50,
        div_graph = document.querySelector('#graph0'),
        div_output = document.querySelector('#output0'),
        input_file = document.querySelector('#nums_data'),

        readFile,
        getNumbers,
        display,
        drawGraph;

    Array.prototype.sum = function () {
        var s = 0;

        this.forEach(function (num) {
            s += num;
        });
        return s;
    };
    Array.prototype.mean = function () {
        var s = this.sum(),
            n = this.length;

        return s / n;
    };
    Array.prototype.median = function () {
        var numbers = this.slice(),
            len = numbers.length,
            i1,
            i2,
            median;

        numbers.sort();
        if (len % 2 === 0) {
            i1 = len / 2 - 1;
            i2 = i1 + 1;
            median = (numbers[i1] + numbers[i2]) / 2;
        } else {
            i1 = (len + 1) / 2 - 1;
            median = numbers[i1];
        }
        return median;
    };
    Array.prototype.modes = function () {
        var obj = {},
            count,
            num,
            max = 0,
            modes = [];

        this.forEach(function (num) {
            if (obj[num] === undefined) {
                obj[num] = 1;
                if (max === 0) {
                    max = 1;
                }
            } else {
                count = obj[num] + 1;
                obj[num] = count;
                if (count > max) {
                    max = count;
                }
            }
        });
        for (num in obj) {
            if (obj[num] === max) {
                modes.push(parseInt(num, 10));
            }
        }
        return modes;
    };
    Array.prototype.differences = function () {
        var mean = this.mean(),
            diff;

        diff = this.map(function (num) {
            return num - mean;
        });
        return diff;
    };
    Array.prototype.variance = function () {
        var diff = this.differences(),
            squared_diff,
            len = this.length;

        squared_diff = diff.map(function (x) {
            return Math.pow(x, 2);
        });
        return squared_diff.sum() / len;
    };
    Array.prototype.standard_deviation = function () {
        var variance = this.variance(),
            std_deviation = Math.sqrt(variance);

        return std_deviation;
    };

    getNumbers = function () {
        var file = input_file.files[0],
            reader,
            numbers = [],
            i,
            max = 100;

        if (file === undefined) {
            for (i = 0; i < max; i += 1) {
                numbers[i] = Math.floor(Math.random() * 100) + 1;
            }
            display(numbers);
        }
        reader = new FileReader()
        reader.readAsText(file);
        reader.onload = function () {
            var text = reader.result;
            
            numbers = text.split('\n')
                .map(function (x) {
                    return x.trim();
                })
                .filter(function (x) {
                    return x !== '';
                })
                .map(function (x) {
                    return parseFloat(x);
                });
            display(numbers);
        };
        reader.onerror = function (error) {
            throw error;
        };
    };
    display = function (numbers) {
        var mean = numbers.mean(),
            median = numbers.median(),
            modes = numbers.modes(),
            variance = numbers.variance(),
            std_dev = numbers.standard_deviation();
        
        div_output.innerHTML =
            '平均: ' + mean + '<br>' +
            '中央値: ' + median + '<br>' +
            '最頻値: ' + modes.join(', ') + '<br>' +
            '分散: ' + variance + '<br>' +
            '標準偏差: ' + std_dev + '<br>';
        
        drawGraph(numbers, mean, median, modes, std_dev);
    };
    drawGraph = function (numbers, mean, median, modes, std_dev) {
        var n = numbers.length,
            svg,
            xscale,
            xaxis,
            yscale,
            yaxis;
        
        xscale = d3.scaleLinear()
            .domain([0, n])
            .range([padding_left, width - padding]);
        xaxis = d3.axisBottom().scale(xscale);

        yscale = d3.scaleLinear()
            .domain([d3.min(numbers), d3.max(numbers)])
            .range([height - padding, padding]);
        yaxis = d3.axisLeft().scale(yscale);

        div_graph.innerHTML = '';
        svg = d3.select('#graph0')
            .append('svg')
            .attr('width', width)
            .attr('height', height);

        svg.selectAll('circle')
            .data(numbers)
            .enter()
            .append('circle')
            .attr('cx', function (d, i) {
                return xscale(i);
            })
            .attr('cy', function (d, i) {
                return yscale(d);
            })
            .attr('r', 4)
            .attr('fill', 'blue');
        
        svg.append('g')
            .attr('transform', 'translate(0, ' + (height - padding) + ')')
            .call(xaxis);
        
        svg.append('g')
            .attr('transform', 'translate(' + padding_left + ', 0)')
            .call(yaxis);
        svg.append('text')
            .attr('x', padding_left / 4)
            .attr('y', height / 2)
            .attr('text-anchor', 'middle')
            .text('値');

        svg.append('line')
            .attr('x1', xscale(0))
            .attr('y1', yscale(mean))
            .attr('x2', xscale(n))
            .attr('y2', yscale(mean))
            .attr('stroke', 'green');
        
        svg.append('line')
            .attr('x1', xscale(0))
            .attr('y1', yscale(median))
            .attr('x2', xscale(n))
            .attr('y2', yscale(median))
            .attr('stroke', 'red');
    };

    input_file.onchange = getNumbers;

    getNumbers();
}());
値: ---------- 平均値: ---------- 中央値: ----------

0 コメント:

コメントを投稿