Calculate CDF in js

Maybe a bit of a hail mary but I want to take an array and calculate the statistical cumulative distribution function from data array of x values.
https://www.npmjs.com/package/cumulative-distribution-function?activeTab=readme

would be perfect for my needs but i’m not sure i can import functions like this to pavlovia.

any advice of a function or how to use the above written function would be super appreciated!

Best,
Levi

Hi Levi,

couldn’t you just copy the .js code that defines the needed function from here and paste it into the code component, where you use it in your experiment? Not sure if it works like that.

Adrian

hey adrian,

i tried adding it as a js component in the beginning of the experiment but i get the following error

* **ReferenceError: module is not defined**

any idea how to handle an error like that?
thanks!

If sufficient for your task, I would suggest to use a simpler approximation (for normal distribution).
Suggested here:

Just use a code component JS only and declare the function in the before experiment tab to use it in other JS Code Components during the experiment

thanks so much luke! that will definitely be a close enough approx for normal distribution.

but what if im looking to approx the cdf relative to an empirical array and not of a particular distribution

Hi levis,

Ive just see that you were looking for the ecdf (have just thought about standard cdf, thinking your sample emerges from a known normal distribution).

Than you can really just remove the exports statement (node.js specific) and use this in a JS Only Before Experiment Code Component:

ecdfArray = function(data) {
    "use strict";
    var f, sorted, xs, ps, i, j, l, xx;
    if (Array.isArray(data) && (data.length > 0)) {
      for (i = 0, l = data.length; i < l; ++i) {
        if (typeof(data[i]) !== 'number') {
          throw new TypeError("cdf data must be an array of finite numbers, got:" + typeof(data[i]) + " at " + i);
        }
        if (!isFinite(data[i])) {
          throw new TypeError("cdf data must be an array of finite numbers, got:" + data[i] + " at " + i);
        }
      }
      sorted = data.slice().sort(function(a, b) {
        return +a - b;
      });
      xs = [];
      ps = [];
      j = 0;
      l = sorted.length;
      xs[0] = sorted[0];
      ps[0] = 1 / l;
      for (i = 1; i < l; ++i) {
        xx = sorted[i];
        if (xx === xs[j]) {
          ps[j] = (1 + i) / l;
        } else {
          j++;
          xs[j] = xx;
          ps[j] = (1 + i) / l;
        }
      }
      f = function(x) {
        if (typeof(x) !== 'number') throw new TypeError('cdf function input must be a number, got:' + typeof(x));
        if (Number.isNaN(x)) return Number.NaN;
        var left = 0,
          right = xs.length - 1,
          mid, midval, iteration;
        if (x < xs[0]) return 0;
        if (x >= xs[xs.length - 1]) return 1;
        iteration = 0;
        while ((right - left) > 1) {
          mid = Math.floor((left + right) / 2);
          midval = xs[mid];
          if (x > midval)
            left = mid;
          else if (x < midval)
            right = mid;
          else if (x === midval) {
            left = mid;
            right = mid;
          }
          ++iteration;
          if (iteration>40) throw new Error("cdf function exceeded 40 bisection iterations, aborting bisection loop");
        }
        return ps[left];
      };
      f.xs = function() {
        return xs;
      };
      f.ps = function() {
        return ps;
      };
    } else {
      // missing or zero length data
      throw new TypeError("cdf data must be an array of finite numbers, got: missing or empty array");
    }
    return f;
  };

This should work in the experiment like this:
test = ecdfArray([1,2,3,4,5,5,6])
test(5)
→ 0.857142857142857

thank you so much luke this works perfectly!!