Source: sigplot.statistics.js

/**
 * @license
 * File: sigplot.playback.js
 *
 * Copyright (c) 2012-2014, Michael Ihde, All rights reserved.
 * Copyright (c) 2012-2014, Axios Inc., All rights reserved.
 *
 * This file is part of SigPlot.
 *
 * SigPlot is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser
 * General Public License as published by the Free Software Foundation; either version 3.0 of the License, or
 * (at your option) any later version. This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the
 * GNU Lesser General Public License along with SigPlot.
 */

/* global mx */
/* global m */
(function(sigplot, mx, m, undefined) {

    function calculate_stats(xpoint, ypoint, npts, xmin, xmax, ymin, ymax) {

        var stats = {
            npts: 0,
            mean: 0,
            m2: 0,
            variance: 0,
            stddev: 0,
            max: {
                x: null,
                y: null,
                idx: null
            },
            min: {
                x: null,
                y: null,
                idx: null
            }
        };

        // Use Knuth Online Algorithm
        var delta;
        for (var i = 0; i < npts; i++) {
            if (xmin && xpoint[i] < xmin) {
                continue;
            }
            if (xmax && xpoint[i] > xmax) {
                continue;
            }
            if (ymin && ypoint[i] < ymin) {
                continue;
            }
            if (ymax && ypoint[i] > ymax) {
                continue;
            }

            stats.npts += 1;
            delta = ypoint[i] - stats.mean;
            stats.mean = stats.mean + (delta / stats.npts);
            stats.m2 = stats.m2 + delta * (ypoint[i] - stats.mean);

            if ((stats.max.x === null) || (ypoint[i] > stats.max.y)) {
                stats.max = {
                    x: xpoint[i],
                    y: ypoint[i],
                    idx: i
                };
            }

            if ((stats.min.x === null) || (ypoint[i] < stats.min.y)) {
                stats.min = {
                    x: xpoint[i],
                    y: ypoint[i],
                    idx: i
                };
            }
        }
        if (stats.npts < 2) {
            stats.variance = 0;
            stats.stddev = 0;
        } else {
            stats.variance = stats.m2 / (stats.npts - 1);
            stats.stddev = Math.sqrt(stats.variance);
        }

        return stats;
    }

    /**
     * @constructor
     * @param options
     * @returns {sigplot.Statistics1DPlugin}
     */
    sigplot.Statistics1DPlugin = function(options) {
        this.options = (options === undefined) ? {} : options;
        this.enabled = this.options.enabled || false;
        this.font = this.options.font;
        // Features off by default
        this.show_max = this.options.show_max || false;
        this.show_min = this.options.show_min || false;
        // Features on by default
        this.show_mean = this.options.show_mean || true;
        this.show_stddev = this.options.show_stddev || true;
    };

    sigplot.Statistics1DPlugin.prototype = {
        init: function(plot) {
            this.plot = plot;
            this.statistics = {};

            this.color = this.options.color || this.plot._Mx.xwfg;
            this.symbol = this.options.symbol || mx.L_CircleSymbol;
            this.radius = this.options.radius || 3;

            // Create event handlers
            var self = this;
            this.onlayeradd = function(evt) {
                self.statistics[evt.index] = {
                    npts: null,
                    mean: null,
                    m2: null,
                    variance: null,
                    stddev: null,
                    max: {
                        x: null,
                        y: null,
                        idx: null
                    },
                    min: {
                        x: null,
                        y: null,
                        idx: null
                    }
                };
            };
            this.plot.addListener("lyradd", this.onlayeradd);

            this.onlayerdel = function(evt) {
                delete self.statistics[evt.index];
            };
            this.plot.addListener("lyrdel", this.onlayerdel);

            this.onlayerdraw = function(evt) {
                var Mx = self.plot._Mx;
                if (evt.layer.xpoint && evt.layer.ypoint) {
                    self.statistics[evt.index] = calculate_stats(evt.layer.xpoint, evt.layer.ypoint, evt.layer.npts, Mx.stk[Mx.level].xmin, Mx.stk[Mx.level].xmax, Mx.stk[Mx.level].ymin, Mx.stk[Mx.level].ymax);
                }
            };
            this.plot.addListener("lyrdraw", this.onlayerdraw);

            this.onkeypress = function(evt) {
                if (evt.keyCode === 83 && evt.shiftKey) { // 'shift-s'
                    self.enabled = !self.enabled;
                    self.plot.refresh();
                }
            };
            this.plot.addListener("plotkeypress", this.onkeypress);

            this.onmtag = function(evt) {
                // No layers mean nothing to do
                if (self.plot._Gx.lyr.length === 0) {
                    return;
                }
                // Only do statistics if the mtag is a box
                if (evt.w && evt.h) {
                    var stats_text = "";
                    for (var layer_n = 0; layer_n < self.plot._Gx.lyr.length; layer_n++) {
                        var xpoint = self.plot._Gx.lyr[layer_n].xpoint;
                        var ypoint = self.plot._Gx.lyr[layer_n].ypoint;
                        var npts = self.plot._Gx.lyr[layer_n].npts;
                        if (xpoint && ypoint) {
                            var stats = calculate_stats(xpoint, ypoint, npts, evt.x, evt.x + evt.w, evt.y - evt.h, evt.y);

                            stats_text = stats_text + "\n" +
                                "N: " + mx.format_g(stats.npts, 10, 3, true) + "\n" +
                                "Min X: " + mx.format_g(evt.x, 10, 3, true) + "\n" +
                                "Max X: " + mx.format_g(evt.x + evt.w, 10, 3, true) + "\n" +
                                "Min Y: " + mx.format_g(stats.min.y, 10, 3, true) + "\n" +
                                "Max Y: " + mx.format_g(stats.max.y, 10, 3, true) + "\n" +
                                "\u03BC Y: " + mx.format_g(stats.mean, 10, 3, true) + "\n" +
                                "\u03C3 Y: " + mx.format_g(stats.stddev, 10, 3, true);
                        }
                    }
                    mx.message(self.plot._Mx, stats_text, null, evt.xpos, evt.ypos);
                }
            };
            this.plot.addListener("mtag", this.onmtag);
        },

        menu: function() {
            var self = this;
            return {
                text: "Statistics",
                menu: {
                    title: "STATISTICS OPTIONS",
                    items: [{
                        text: "Enable",
                        style: "checkbox",
                        checked: this.enabled,
                        handler: function() {
                            self.enabled = !self.enabled;
                        }
                    }, {
                        text: "Features",
                        style: "separator"
                    }, {
                        text: "Show Max",
                        style: "checkbox",
                        checked: this.show_max,
                        handler: function() {
                            self.show_max = !self.show_max;
                        }
                    }, {
                        text: "Show Min",
                        style: "checkbox",
                        checked: this.show_min,
                        handler: function() {
                            self.show_min = !self.show_min;
                        }
                    }, {
                        text: "Show Mean",
                        style: "checkbox",
                        checked: this.show_mean,
                        handler: function() {
                            self.show_mean = !self.show_mean;
                        }
                    }, {
                        text: "Show Std. Dev.",
                        style: "checkbox",
                        checked: this.show_stddev,
                        handler: function() {
                            self.show_stddev = !self.show_stddev;
                        }
                    }]
                }
            };
        },

        refresh: function(canvas) {
            var Mx = this.plot._Mx;
            var self = this;
            var ctx = canvas.getContext("2d");

            if (!this.enabled) {
                return;
            }

            mx.onCanvas(Mx, canvas, function() {
                for (var layer_n in self.statistics) {
                    var stats = self.statistics[layer_n];

                    if (self.show_max) {
                        if (stats.max.x !== null && stats.max.y !== null) {
                            var pix = mx.real_to_pixel(Mx, stats.max.x, stats.max.y, false);
                            if (!pix.clipped) {
                                mx.draw_symbol(Mx, self.color, pix.x, pix.y, self.symbol, self.radius);
                            }
                        }
                    }

                    if (self.show_min) {
                        if (stats.min.x !== null && stats.min.y !== null) {
                            var pix = mx.real_to_pixel(Mx, stats.min.x, stats.min.y, false);
                            if (!pix.clipped) {
                                mx.draw_symbol(Mx, self.color, pix.x, pix.y, self.symbol, self.radius);
                            }
                        }
                    }

                    if (self.show_mean) {
                        if (stats.mean !== null) {
                            var pix = mx.real_to_pixel(Mx, null, stats.mean, false);
                            if (!pix.clipped_y) {
                                mx.draw_line(Mx, self.color, Mx.l, pix.y, Mx.r, pix.y);

                                ctx.font = self.font || Mx.font.font;
                                ctx.globalAlpha = 1;
                                ctx.textBaseline = "alphabetic";
                                ctx.textAlign = "left";
                                ctx.fillStyle = self.color;
                                var height = ctx.measureText("M").width; // approximation of height
                                var text = mx.format_g(stats.mean, 6, 3, true);
                                ctx.fillText("\u03BC=" + text, Mx.l + 5, pix.y - 5);
                            }
                        }
                    }

                    if (self.show_stddev) {
                        if (stats.sqrt !== null) {
                            var pix = mx.real_to_pixel(Mx, null, stats.mean + stats.stddev, false);
                            if (!pix.clipped_y) {
                                mx.draw_line(Mx, self.color, Mx.l, pix.y, Mx.r, pix.y, 1, {
                                    mode: "dashed",
                                    on: 3,
                                    off: 3
                                });

                                ctx.font = self.font || Mx.font.font;
                                ctx.globalAlpha = 1;
                                ctx.textBaseline = "alphabetic";
                                ctx.textAlign = "left";
                                ctx.fillStyle = self.color;
                                var height = ctx.measureText("M").width; // approximation of height
                                var text = mx.format_g(stats.stddev, 6, 3, true);
                                ctx.fillText("\u03C3=+" + text, Mx.l + 5, pix.y + 5 + height);
                            }

                            var pix = mx.real_to_pixel(Mx, null, stats.mean - stats.stddev, false);
                            if (!pix.clipped_y) {
                                mx.draw_line(Mx, self.color, Mx.l, pix.y, Mx.r, pix.y, 1, {
                                    mode: "dashed",
                                    on: 3,
                                    off: 3
                                });

                                ctx.font = self.font || Mx.font.font;
                                ctx.globalAlpha = 1;
                                ctx.textBaseline = "alphabetic";
                                ctx.textAlign = "left";
                                ctx.fillStyle = self.color;
                                var height = ctx.measureText("M").width; // approximation of height
                                var text = mx.format_g(stats.stddev, 6, 3, true);
                                ctx.fillText("\u03C3=-" + text, Mx.l + 5, pix.y - 5);
                            }
                        }
                    }
                }
            });
        },

        dispose: function() {
            this.plot.addListener("lyradd", this.onlayerdraw);
            this.plot.addListener("lyrdel", this.onlayerdraw);
            this.plot.removeListener("lyrdraw", this.onlayerdraw);
            this.plot = undefined;
            this.boxes = undefined;
            this.statistics = {};
        }
    };

}(window.sigplot = window.sigplot || {}, mx, m));
DocStrap Copyright © 2012-2013 The contributors to the JSDoc3 and DocStrap projects.
Documentation generated by JSDoc 3.2.2 on Wed Mar 11 2015 20:53:17 GMT-0000 (GMT) using the DocStrap template.