1 /* 2 * Copyright (c) 2012 LabKey Corporation 3 * 4 * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 5 */ 6 7 /********** Stats **********/ 8 9 if(!LABKEY.vis.Stat){ 10 /** 11 * @namespace The namespace used for statistics related functions. 12 */ 13 LABKEY.vis.Stat = {}; 14 } 15 16 17 /** 18 * Calculates a statistical summary of an array of data. The summary includes Quartiles 1, 2, 3, minimum, maximum and 19 * the inner quartile range. It is used internally to create box plots. 20 * @param {Array} data An array of data. Can be an array of any type of object. 21 * @param {Function} accessor A function that is used to access the value of each item in the array. 22 * @returns {Object} summary 23 * @example 24 var data = [], 25 accessor, 26 summary; 27 28 // Let's generate some data. 29 for (var i = 0; i < 500; i++){ 30 data.push(parseInt(Math.random() * 50)); 31 } 32 33 // Let's define how we access the data. 34 accessor = function(row){ 35 return row; 36 } 37 38 // Now we'll get a summary. 39 summary = LABKEY.vis.Stat.summary(data, accessor); 40 41 console.log(summary); 42 * 43 */ 44 LABKEY.vis.Stat.summary = function(data, accessor){ 45 /* 46 Returns an object with the min, max, Q1, Q2 (median), Q3, interquartile range, and the sorted array of values. 47 */ 48 var summary = {}; 49 50 summary.sortedValues = LABKEY.vis.Stat.sortNumericAscending(data, accessor); 51 summary.min = summary.sortedValues[0]; 52 summary.max = summary.sortedValues[summary.sortedValues.length -1]; 53 summary.Q1 = LABKEY.vis.Stat.Q1(summary.sortedValues); 54 summary.Q2 = LABKEY.vis.Stat.Q2(summary.sortedValues); 55 summary.Q3 = LABKEY.vis.Stat.Q3(summary.sortedValues); 56 summary.IQR = summary.Q3 - summary.Q1; 57 58 return summary; 59 }; 60 61 /** 62 * Returns the 1st quartile for a sorted (asc) array. 63 * @param numbers An array of numbers. 64 * @returns {Number} 65 */ 66 LABKEY.vis.Stat.Q1 = function(numbers){ 67 return d3.quantile(numbers,0.25); 68 }; 69 70 /** 71 * Returns the 2nd quartile (median) for a sorted (asc) array. 72 * @param numbers An array of numbers. 73 * @returns {Number} 74 */ 75 LABKEY.vis.Stat.Q2 = function(numbers){ 76 return d3.quantile(numbers,0.5); 77 }; 78 79 /** 80 * An alias for {@link LABKEY.vis.Stat.Q2} 81 */ 82 LABKEY.vis.Stat.median = LABKEY.vis.Stat.Q2; 83 84 85 /** 86 * Returns the 3rd quartile for a sorted (asc) array. 87 * @param numbers An array of numbers. 88 * @returns {Number} 89 */ 90 LABKEY.vis.Stat.Q3 = function(numbers){ 91 return d3.quantile(numbers,0.75); 92 }; 93 94 95 /** 96 * Sorts an array of data in ascending order. Removes null/undefined values. 97 * @param {Array} data An array of objects that have numeric values. 98 * @param {Function} accessor A function used to access the numeric value that needs to be sorted. 99 * @returns {Array} 100 */ 101 LABKEY.vis.Stat.sortNumericAscending = function(data, accessor){ 102 var numbers = []; 103 for(var i = 0; i < data.length; i++){ 104 var value = accessor(data[i]); 105 if(value !== null && value !== undefined){ 106 numbers.push(value); 107 } 108 } 109 numbers.sort(function(a, b){return a-b;}); 110 return numbers; 111 }; 112 113 /** 114 * Sorts an array of data in descending order. Removes null/undefined values. 115 * @param {Array} data An array of objects that have numeric values. 116 * @param {Function} accessor A function used to access the numeric value that needs to be sorted. 117 * @returns {Array} 118 */ 119 LABKEY.vis.Stat.sortNumericDescending = function(data, accessor){ 120 var numbers = []; 121 for(var i = 0; i < data.length; i++){ 122 var value = accessor(data[i]); 123 if(value !== null && value !== undefined){ 124 numbers.push(value); 125 } 126 } 127 numbers.sort(function(a, b){return b-a;}); 128 return numbers; 129 }; 130 131 /** 132 * Executes a given function n times passing in values between min and max and returns an array of each result. Could 133 * be used to generate data to plot a curve fit as part of a plot. 134 * @param {Function} fn The function to be executed n times. The function must take one number as a parameter. 135 * @param {Number} n The number of times to execute fn. 136 * @param {Number} min The minimum value to pass to fn. 137 * @param {Number} max The maximum value to pass to fn. 138 */ 139 LABKEY.vis.Stat.fn = function(fn, n, min, max){ 140 if(n === undefined || n === null || n < 2){ 141 // We need at least 2 points to make a line. 142 n = 2; 143 } 144 145 var data = [], 146 stepSize = Math.abs((max - min) / (n-1)), 147 count = min; 148 149 for(var i = 0; i < n; i++){ 150 data.push({x: count, y: fn(count)}); 151 count += stepSize; 152 } 153 154 return data; 155 }; 156