/src/data/Numbers.js
http://github.com/mbostock/protovis · JavaScript · 313 lines · 127 code · 18 blank · 168 comment · 41 complexity · eb7510868c02c3915493bcb3b7b21642 MD5 · raw file
- /**
- * Returns an array of numbers, starting at <tt>start</tt>, incrementing by
- * <tt>step</tt>, until <tt>stop</tt> is reached. The stop value is
- * exclusive. If only a single argument is specified, this value is interpeted
- * as the <i>stop</i> value, with the <i>start</i> value as zero. If only two
- * arguments are specified, the step value is implied to be one.
- *
- * <p>The method is modeled after the built-in <tt>range</tt> method from
- * Python. See the Python documentation for more details.
- *
- * @see <a href="http://docs.python.org/library/functions.html#range">Python range</a>
- * @param {number} [start] the start value.
- * @param {number} stop the stop value.
- * @param {number} [step] the step value.
- * @returns {number[]} an array of numbers.
- */
- pv.range = function(start, stop, step) {
- if (arguments.length == 1) {
- stop = start;
- start = 0;
- }
- if (step == undefined) step = 1;
- if ((stop - start) / step == Infinity) throw new Error("range must be finite");
- var array = [], i = 0, j;
- stop -= (stop - start) * 1e-10; // floating point precision!
- if (step < 0) {
- while ((j = start + step * i++) > stop) {
- array.push(j);
- }
- } else {
- while ((j = start + step * i++) < stop) {
- array.push(j);
- }
- }
- return array;
- };
- /**
- * Returns a random number in the range [<tt>start</tt>, <tt>stop</tt>) that is
- * a multiple of <tt>step</tt>. More specifically, the returned number is of the
- * form <tt>start</tt> + <i>n</i> * <tt>step</tt>, where <i>n</i> is a
- * nonnegative integer. If <tt>step</tt> is not specified, it defaults to 1,
- * returning a random integer if <tt>start</tt> is also an integer.
- *
- * @param {number} [start] the start value value.
- * @param {number} stop the stop value.
- * @param {number} [step] the step value.
- * @returns {number} a random number between <i>start</i> and <i>stop</i>.
- */
- pv.random = function(start, stop, step) {
- if (arguments.length == 1) {
- stop = start;
- start = 0;
- }
- if (step == undefined) step = 1;
- return step
- ? (Math.floor(Math.random() * (stop - start) / step) * step + start)
- : (Math.random() * (stop - start) + start);
- };
- /**
- * Returns the sum of the specified array. If the specified array is not an
- * array of numbers, an optional accessor function <tt>f</tt> can be specified
- * to map the elements to numbers. See {@link #normalize} for an example.
- * Accessor functions can refer to <tt>this.index</tt>.
- *
- * @param {array} array an array of objects, or numbers.
- * @param {function} [f] an optional accessor function.
- * @returns {number} the sum of the specified array.
- */
- pv.sum = function(array, f) {
- var o = {};
- return array.reduce(f
- ? function(p, d, i) { o.index = i; return p + f.call(o, d); }
- : function(p, d) { return p + d; }, 0);
- };
- /**
- * Returns the maximum value of the specified array. If the specified array is
- * not an array of numbers, an optional accessor function <tt>f</tt> can be
- * specified to map the elements to numbers. See {@link #normalize} for an
- * example. Accessor functions can refer to <tt>this.index</tt>.
- *
- * @param {array} array an array of objects, or numbers.
- * @param {function} [f] an optional accessor function.
- * @returns {number} the maximum value of the specified array.
- */
- pv.max = function(array, f) {
- if (f == pv.index) return array.length - 1;
- return Math.max.apply(null, f ? pv.map(array, f) : array);
- };
- /**
- * Returns the index of the maximum value of the specified array. If the
- * specified array is not an array of numbers, an optional accessor function
- * <tt>f</tt> can be specified to map the elements to numbers. See
- * {@link #normalize} for an example. Accessor functions can refer to
- * <tt>this.index</tt>.
- *
- * @param {array} array an array of objects, or numbers.
- * @param {function} [f] an optional accessor function.
- * @returns {number} the index of the maximum value of the specified array.
- */
- pv.max.index = function(array, f) {
- if (!array.length) return -1;
- if (f == pv.index) return array.length - 1;
- if (!f) f = pv.identity;
- var maxi = 0, maxx = -Infinity, o = {};
- for (var i = 0; i < array.length; i++) {
- o.index = i;
- var x = f.call(o, array[i]);
- if (x > maxx) {
- maxx = x;
- maxi = i;
- }
- }
- return maxi;
- }
- /**
- * Returns the minimum value of the specified array of numbers. If the specified
- * array is not an array of numbers, an optional accessor function <tt>f</tt>
- * can be specified to map the elements to numbers. See {@link #normalize} for
- * an example. Accessor functions can refer to <tt>this.index</tt>.
- *
- * @param {array} array an array of objects, or numbers.
- * @param {function} [f] an optional accessor function.
- * @returns {number} the minimum value of the specified array.
- */
- pv.min = function(array, f) {
- if (f == pv.index) return 0;
- return Math.min.apply(null, f ? pv.map(array, f) : array);
- };
- /**
- * Returns the index of the minimum value of the specified array. If the
- * specified array is not an array of numbers, an optional accessor function
- * <tt>f</tt> can be specified to map the elements to numbers. See
- * {@link #normalize} for an example. Accessor functions can refer to
- * <tt>this.index</tt>.
- *
- * @param {array} array an array of objects, or numbers.
- * @param {function} [f] an optional accessor function.
- * @returns {number} the index of the minimum value of the specified array.
- */
- pv.min.index = function(array, f) {
- if (!array.length) return -1;
- if (f == pv.index) return 0;
- if (!f) f = pv.identity;
- var mini = 0, minx = Infinity, o = {};
- for (var i = 0; i < array.length; i++) {
- o.index = i;
- var x = f.call(o, array[i]);
- if (x < minx) {
- minx = x;
- mini = i;
- }
- }
- return mini;
- }
- /**
- * Returns the arithmetic mean, or average, of the specified array. If the
- * specified array is not an array of numbers, an optional accessor function
- * <tt>f</tt> can be specified to map the elements to numbers. See
- * {@link #normalize} for an example. Accessor functions can refer to
- * <tt>this.index</tt>.
- *
- * @param {array} array an array of objects, or numbers.
- * @param {function} [f] an optional accessor function.
- * @returns {number} the mean of the specified array.
- */
- pv.mean = function(array, f) {
- return pv.sum(array, f) / array.length;
- };
- /**
- * Returns the median of the specified array. If the specified array is not an
- * array of numbers, an optional accessor function <tt>f</tt> can be specified
- * to map the elements to numbers. See {@link #normalize} for an example.
- * Accessor functions can refer to <tt>this.index</tt>.
- *
- * @param {array} array an array of objects, or numbers.
- * @param {function} [f] an optional accessor function.
- * @returns {number} the median of the specified array.
- */
- pv.median = function(array, f) {
- if (f == pv.index) return (array.length - 1) / 2;
- array = pv.map(array, f).sort(pv.naturalOrder);
- if (array.length % 2) return array[Math.floor(array.length / 2)];
- var i = array.length / 2;
- return (array[i - 1] + array[i]) / 2;
- };
- /**
- * Returns the unweighted variance of the specified array. If the specified
- * array is not an array of numbers, an optional accessor function <tt>f</tt>
- * can be specified to map the elements to numbers. See {@link #normalize} for
- * an example. Accessor functions can refer to <tt>this.index</tt>.
- *
- * @param {array} array an array of objects, or numbers.
- * @param {function} [f] an optional accessor function.
- * @returns {number} the variance of the specified array.
- */
- pv.variance = function(array, f) {
- if (array.length < 1) return NaN;
- if (array.length == 1) return 0;
- var mean = pv.mean(array, f), sum = 0, o = {};
- if (!f) f = pv.identity;
- for (var i = 0; i < array.length; i++) {
- o.index = i;
- var d = f.call(o, array[i]) - mean;
- sum += d * d;
- }
- return sum;
- };
- /**
- * Returns an unbiased estimation of the standard deviation of a population,
- * given the specified random sample. If the specified array is not an array of
- * numbers, an optional accessor function <tt>f</tt> can be specified to map the
- * elements to numbers. See {@link #normalize} for an example. Accessor
- * functions can refer to <tt>this.index</tt>.
- *
- * @param {array} array an array of objects, or numbers.
- * @param {function} [f] an optional accessor function.
- * @returns {number} the standard deviation of the specified array.
- */
- pv.deviation = function(array, f) {
- return Math.sqrt(pv.variance(array, f) / (array.length - 1));
- };
- /**
- * Returns the logarithm with a given base value.
- *
- * @param {number} x the number for which to compute the logarithm.
- * @param {number} b the base of the logarithm.
- * @returns {number} the logarithm value.
- */
- pv.log = function(x, b) {
- return Math.log(x) / Math.log(b);
- };
- /**
- * Computes a zero-symmetric logarithm. Computes the logarithm of the absolute
- * value of the input, and determines the sign of the output according to the
- * sign of the input value.
- *
- * @param {number} x the number for which to compute the logarithm.
- * @param {number} b the base of the logarithm.
- * @returns {number} the symmetric log value.
- */
- pv.logSymmetric = function(x, b) {
- return (x == 0) ? 0 : ((x < 0) ? -pv.log(-x, b) : pv.log(x, b));
- };
- /**
- * Computes a zero-symmetric logarithm, with adjustment to values between zero
- * and the logarithm base. This adjustment introduces distortion for values less
- * than the base number, but enables simultaneous plotting of log-transformed
- * data involving both positive and negative numbers.
- *
- * @param {number} x the number for which to compute the logarithm.
- * @param {number} b the base of the logarithm.
- * @returns {number} the adjusted, symmetric log value.
- */
- pv.logAdjusted = function(x, b) {
- if (!isFinite(x)) return x;
- var negative = x < 0;
- if (x < b) x += (b - x) / b;
- return negative ? -pv.log(x, b) : pv.log(x, b);
- };
- /**
- * Rounds an input value down according to its logarithm. The method takes the
- * floor of the logarithm of the value and then uses the resulting value as an
- * exponent for the base value.
- *
- * @param {number} x the number for which to compute the logarithm floor.
- * @param {number} b the base of the logarithm.
- * @returns {number} the rounded-by-logarithm value.
- */
- pv.logFloor = function(x, b) {
- return (x > 0)
- ? Math.pow(b, Math.floor(pv.log(x, b)))
- : -Math.pow(b, -Math.floor(-pv.log(-x, b)));
- };
- /**
- * Rounds an input value up according to its logarithm. The method takes the
- * ceiling of the logarithm of the value and then uses the resulting value as an
- * exponent for the base value.
- *
- * @param {number} x the number for which to compute the logarithm ceiling.
- * @param {number} b the base of the logarithm.
- * @returns {number} the rounded-by-logarithm value.
- */
- pv.logCeil = function(x, b) {
- return (x > 0)
- ? Math.pow(b, Math.ceil(pv.log(x, b)))
- : -Math.pow(b, -Math.ceil(-pv.log(-x, b)));
- };
- (function() {
- var radians = Math.PI / 180,
- degrees = 180 / Math.PI;
- /** Returns the number of radians corresponding to the specified degrees. */
- pv.radians = function(degrees) { return radians * degrees; };
- /** Returns the number of degrees corresponding to the specified radians. */
- pv.degrees = function(radians) { return degrees * radians; };
- })();