<div id="display">
  <div class="row" style="width:60%">
  <div class="col"><a></a></div>
  <div class="col"><a>Westville</a></div>
  <div class="col"><a>East County</a></div>
</div>
<form>
  <div class="row" style="width:60%">
    <div class="col"><a>Avocado Party</a></div>
    <div class="col">
      <input type="number" id="a1" class="form-control" value="250" />
    </div>
    <div class="col">
      <input type="number" id="a2" class="form-control" value="200" />
    </div>
  </div>
  <div class="row" style="width:60%">
    <div class="col"><a>Banana Party</a></div>
    <div class="col">
      <input type="number" id="b1" class="form-control" value="150" />
    </div>
    <div class="col">
      <input type="number" id="b2" class="form-control" value="100" />
    </div>
  </div>
  <br>
  <div class="row" style="width:60%">
    <div class="col"><a>P value threshold:</a></div>
    <div class="col">
      <input type="number" id="alpha" class="form-control" value="0.05" />
    </div>
    <div class="col">
      <a></a>
    </div>

  </div>

  <input type="button" onclick="chiSquared()" value="Calculate" />
</form>
</div>
function chiSquared() {
  
  // get variables from the form
  var a1 = Number(document.getElementById("a1").value);
  var a2 = Number(document.getElementById("a2").value);
  var b1 = Number(document.getElementById("b1").value);
  var b2 = Number(document.getElementById("b2").value);
  var alpha = Number(document.getElementById("alpha").value);

  //find the row totals and column totals
  var sumA = a1 + a2;
  var sumB = b1 + b2;
  var sum1 = a1 + b1;
  var sum2 = a2 + b2;
  
  // find the overall total
  var total = a1 + a2 + b1 + b2;

  // calculate each expected value
  var expectedA1 = (sumA * sum1) / total;
  var expectedA2 = (sumA * sum2) / total;
  var expectedB1 = (sumB * sum1) / total;
  var expectedB2 = (sumB * sum2) / total;

  // (observed - expected)**2 / expected
  var valA1 = (a1 - expectedA1) ** 2 / expectedA1;
  var valA2 = (a2 - expectedA2) ** 2 / expectedA2;
  var valB1 = (b1 - expectedB1) ** 2 / expectedB1;
  var valB2 = (b2 - expectedB2) ** 2 / expectedB2;

  // add these up to find Chi-squared statistic
  var chiSq = Math.round(1000 * (valA1 + valA2 + valB1 + valB2)) / 1000;

  // get the p-value
  var pvalue = Math.round(10000 * compute(chiSq)) / 10000;
  var pval = pvalue.toString();
  if (pvalue < 0.0001) {
    pval = "< 0.0001";
  }

  // uglt hack to update HTML
  var result = "";
  var conclusion = "";
  if (pvalue < alpha) {
    result = "Reject the null hypothesis";
    conclusion =
      "There <b>is a significant relationship</b> between region and party membership";
  } else {
    result = "Accept the null hypothesis";
    conclusion =
      "There <b>is no significant relationship</b> between region and party membership";
  }

  document.getElementById("display").innerHTML =
    "<h3>Results</h3> <ul> <li> Chi-squared: " +
    chiSq.toString() +
    " </li> <li>P value: " +
    pval +
    "</li><li>" +
    result +
    "</li><li>" +
    conclusion +
    "</li></ul>";
}

/* Math functions to calculate inverse CDF of chi squared distribution

adapted from: https://www.math.ucla.edu/~tom/distributions/chisq.html

read more: https://en.wikipedia.org/wiki/Chi-squared_distribution#Computational_methods

*/
function LogGamma(Z) {
  var S =
    1 +
    76.18009173 / Z -
    86.50532033 / (Z + 1) +
    24.01409822 / (Z + 2) -
    1.231739516 / (Z + 3) +
    0.00120858003 / (Z + 4) -
    0.00000536382 / (Z + 5);
  var LG =
    (Z - 0.5) * Math.log(Z + 4.5) - (Z + 4.5) + Math.log(S * 2.50662827465);

  return LG;
}

function Gcf(X, A) {
  // Good for X>A+1
  var A0 = 0;
  var B0 = 1;
  var A1 = 1;
  var B1 = X;
  var AOLD = 0;
  var N = 0;
  while (Math.abs((A1 - AOLD) / A1) > 0.00001) {
    AOLD = A1;
    N = N + 1;
    A0 = A1 + (N - A) * A0;
    B0 = B1 + (N - A) * B0;
    A1 = X * A0 + N * A1;
    B1 = X * B0 + N * B1;
    A0 = A0 / B1;
    B0 = B0 / B1;
    A1 = A1 / B1;
    B1 = 1;
  }
  var Prob = Math.exp(A * Math.log(X) - X - LogGamma(A)) * A1;

  return 1 - Prob;
}

function Gser(X, A) {
  // Good for X<A+1.
  var T9 = 1 / A;
  var G = T9;
  var I = 1;
  while (T9 > G * 0.00001) {
    T9 = (T9 * X) / (A + I);
    G = G + T9;
    I = I + 1;
  }
  G = G * Math.exp(A * Math.log(X) - X - LogGamma(A));
  return G;
}

function Gammacdf(x, a) {
  var GI;
  if (x <= 0) {
    GI = 0;
  } else if (x < a + 1) {
    GI = Gser(x, a);
  } else {
    GI = Gcf(x, a);
  }
  return GI;
}

function compute(chisq) {
  Z = chisq;
  DF = 1;
  Chisqcdf = Gammacdf(Z / 2, DF / 2);
  Chisqcdf = Math.round(Chisqcdf * 100000) / 100000;
  return 1 - Chisqcdf;
}

Run Pen

External CSS

  1. https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css

External JavaScript

This Pen doesn't use any external JavaScript resources.