qesuite 1.0.49 → 1.0.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1019,6 +1019,9 @@ declare const ANOVA: {
1019
1019
  p: number;
1020
1020
  };
1021
1021
  };
1022
+ Multifactor: {
1023
+ MainEffectsPlot(factors: any, response: any): HTMLCanvasElement;
1024
+ };
1022
1025
  };
1023
1026
  declare function SumSquaredDeviation(data: number[], referenceValue?: any): number;
1024
1027
  declare const Probability: {
package/dist/index.d.ts CHANGED
@@ -1019,6 +1019,9 @@ declare const ANOVA: {
1019
1019
  p: number;
1020
1020
  };
1021
1021
  };
1022
+ Multifactor: {
1023
+ MainEffectsPlot(factors: any, response: any): HTMLCanvasElement;
1024
+ };
1022
1025
  };
1023
1026
  declare function SumSquaredDeviation(data: number[], referenceValue?: any): number;
1024
1027
  declare const Probability: {
package/dist/index.js CHANGED
@@ -2766,15 +2766,17 @@ var ANOVA = {
2766
2766
  let scaleDF = Math.sqrt((rCount - 1) / (rCount * tCount));
2767
2767
  let UDL = grandMean + pooledSTD * hAlpha * scaleDF;
2768
2768
  let LDL = grandMean - pooledSTD * hAlpha * scaleDF;
2769
+ let chartSettings = new ChartSettings();
2769
2770
  returnArray.forEach((t, x) => {
2770
2771
  let canvasDraw = t.Mean < UDL && t.Mean > LDL ? new CanvasDrawSettings("#2183b2", "#2183b2", void 0, 0) : new CanvasDrawSettings("#F00", "#F00", void 0, 1);
2771
2772
  let newDataSet = new DataSet([
2772
2773
  new Point(x + 1, t.Mean, canvasDraw),
2773
2774
  new Point(x + 1, grandMean, new CanvasDrawSettings("#000", "#000", 0, 0, 0))
2774
2775
  ], t.treatment, void 0, new Line("straight", new CanvasDrawSettings("#000", "#000", 1)));
2776
+ chartSettings.axis.x.customGridlines.push(new CustomGridline(x + 1, t.treatment, void 0, void 0, void 0, void 0, true));
2775
2777
  dataSets.push(newDataSet);
2776
2778
  });
2777
- let chartSettings = new ChartSettings();
2779
+ chartSettings.axis.x.showAutoGridlines = false;
2778
2780
  chartSettings.axis.y.customGridlines = [new CustomGridline(grandMean, `x\u0305\u0305=${Math.round(grandMean * 1e3) / 1e3}`, new CanvasDrawSettings(GetThemeColor(2), GetThemeColor(2)), void 0, true), new CustomGridline(LDL, `LDL=${Math.round(LDL * 1e3) / 1e3}`, new CanvasDrawSettings("#F00", "#F00"), void 0, true, void 0, true), new CustomGridline(UDL, `UDL=${Math.round(UDL * 1e3) / 1e3}`, new CanvasDrawSettings("#F00", "#F00"), void 0, true, void 0, true)];
2779
2781
  let chart = CreateScatterPlot(dataSets, name ? `Analysis of Means for ${name}` : "Analysis of Means", chartSettings);
2780
2782
  return {
@@ -2852,8 +2854,8 @@ var ANOVA = {
2852
2854
  mean,
2853
2855
  stdev: StDev.S(data[key]),
2854
2856
  SE: standardError,
2855
- CI_Low: mean - tInv * standardError,
2856
- CI_High: mean + tInv * standardError
2857
+ CI_Low: mean - Math.abs(tInv * standardError),
2858
+ CI_High: mean + Math.abs(tInv * standardError)
2857
2859
  };
2858
2860
  summaryTable.ConfidenceIntervals.push(CI_table);
2859
2861
  }
@@ -3676,6 +3678,44 @@ var ANOVA = {
3676
3678
  p: Distributions.F.TwoTail(F, factor1.length - 1, factor2.length - 1)
3677
3679
  };
3678
3680
  }
3681
+ },
3682
+ Multifactor: {
3683
+ MainEffectsPlot(factors, response) {
3684
+ let responseName = Object.keys(response)[0];
3685
+ let factorKeys = Object.keys(factors);
3686
+ let individualCharts = [];
3687
+ factorKeys.forEach((k) => {
3688
+ let arr = factors[k];
3689
+ let uniqueLevels = arr.filter((value, index, array) => array.indexOf(value) === index);
3690
+ let dataSet = new DataSet([]);
3691
+ dataSet.line = new Line("straight");
3692
+ let chartSettings = new ChartSettings();
3693
+ chartSettings.axis.x.showAutoGridlines = false;
3694
+ chartSettings.axis.x.min = 0.5;
3695
+ chartSettings.axis.x.max = uniqueLevels.length + 0.5;
3696
+ chartSettings.axis.x.autoSize = false;
3697
+ uniqueLevels.forEach((level, levelI) => {
3698
+ let mean = 0;
3699
+ let N = 0;
3700
+ arr.forEach((v, i) => {
3701
+ if (v === level) {
3702
+ mean += response[responseName][i];
3703
+ N += 1;
3704
+ }
3705
+ });
3706
+ mean = mean / N;
3707
+ dataSet.values.push(new Point(levelI + 1, mean, new CanvasDrawSettings("#2183b2", "#000", void 0, void 0, 5)));
3708
+ chartSettings.axis.x.customGridlines.push(new CustomGridline(levelI + 1, level, void 0, void 0, void 0, true, false));
3709
+ });
3710
+ chartSettings.width += 1e3;
3711
+ individualCharts.push(new Chart([dataSet], "scatter", k, chartSettings));
3712
+ });
3713
+ let chartSet = new ChartSettings();
3714
+ chartSet.width += 1e3;
3715
+ chartSet.axis.y.tickOnly = true;
3716
+ let graph = CreateSplitGraph(individualCharts, `Main Effects Plot of ${Object.keys(response)[0]}`, chartSet);
3717
+ return graph;
3718
+ }
3679
3719
  }
3680
3720
  };
3681
3721
  function SumSquaredDeviation(data, referenceValue) {
@@ -3851,7 +3891,7 @@ function AddAxisGridlines(ctx, chartSettings, axis) {
3851
3891
  }
3852
3892
  let x = ConvertToCanvasPt(unadjustedValue, chartSettings.axis.x.min, chartSettings.axis.x.max, chartSettings.width - chartSettings.margins.left - chartSettings.margins.right - (((_v = chartSettings.axis.x.padding) == null ? void 0 : _v.left) ? (_w = chartSettings.axis.x.padding) == null ? void 0 : _w.left : 0) - (((_x = chartSettings.axis.x.padding) == null ? void 0 : _x.right) ? (_y = chartSettings.axis.x.padding) == null ? void 0 : _y.right : 0), chartSettings.axis.x) + chartSettings.margins.left + (((_z = chartSettings.axis.x.padding) == null ? void 0 : _z.left) ? (_A = chartSettings.axis.x.padding) == null ? void 0 : _A.left : 0);
3853
3893
  ctx.beginPath();
3854
- ctx.moveTo(x, chartSettings.axis.x.tickOnly ? chartSettings.height - chartSettings.margins.bottom : yT);
3894
+ ctx.moveTo(x, chartSettings.axis.x.tickOnly ? chartSettings.height - chartSettings.margins.bottom + 10 : yT);
3855
3895
  ctx.lineTo(x, yB);
3856
3896
  if (((_B = chartSettings.axis.x.labels) == null ? void 0 : _B.length) === void 0) {
3857
3897
  chartSettings.axis.x.labels = [];
@@ -3873,9 +3913,9 @@ function AddAxisGridlines(ctx, chartSettings, axis) {
3873
3913
  if (gridline.dashed) {
3874
3914
  ctx.setLineDash([20, 15]);
3875
3915
  }
3876
- ctx.moveTo(x, gridline.tickOnly ? chartSettings.height - chartSettings.margins.bottom : yT);
3916
+ ctx.moveTo(x, gridline.tickOnly ? chartSettings.height - chartSettings.margins.bottom + 10 : yT);
3877
3917
  ctx.lineTo(x, gridline.opposite && !gridline.tickOnly ? chartSettings.height - chartSettings.margins.bottom : yB);
3878
- ctx.fillText(gridline.label || RoundTO(gridline.value, 3), x, gridline.opposite ? chartSettings.margins.top - 10 : chartSettings.height - chartSettings.margins.bottom + 40);
3918
+ ctx.fillText(gridline.label || RoundTO(gridline.value, 3), x, gridline.opposite ? chartSettings.margins.top - 10 : chartSettings.height - chartSettings.margins.bottom + 32);
3879
3919
  ctx.stroke();
3880
3920
  ctx.setLineDash([]);
3881
3921
  ctx.closePath();
@@ -4603,8 +4643,6 @@ function CreateSplitGraph(charts, title, chartSettings = new ChartSettings()) {
4603
4643
  ctx.fillText(chart.title, chart.chartSettings.margins.left, chart.chartSettings.margins.top - 10);
4604
4644
  ctx == null ? void 0 : ctx.closePath();
4605
4645
  }
4606
- chart.chartSettings.axis.x.min = NaN;
4607
- chart.chartSettings.axis.x.max = NaN;
4608
4646
  AutoAxis(chart.data, chart.chartSettings);
4609
4647
  AddAxisGridlines(ctx, chart.chartSettings, "x");
4610
4648
  PlotData(ctx, chart.data, chart.chartSettings);
@@ -5347,8 +5385,6 @@ function GRRRChart(data) {
5347
5385
  gl.display.strokeColor = "rgb(230,230,230)";
5348
5386
  setSettings.axis.x.customGridlines.push(gl);
5349
5387
  }
5350
- setSettings.axis.x.min = 1;
5351
- setSettings.axis.x.min = Npart;
5352
5388
  setSettings.axis.x.showAutoGridlines = false;
5353
5389
  newDataSet.line.type = "straight";
5354
5390
  newDataSet.line.display.strokeWidth = 2;
@@ -5432,8 +5468,6 @@ function GRRXbarChart(data) {
5432
5468
  gl.display.strokeColor = "rgb(230,230,230)";
5433
5469
  setSettings.axis.x.customGridlines.push(gl);
5434
5470
  }
5435
- setSettings.axis.x.min = 1;
5436
- setSettings.axis.x.min = Npart;
5437
5471
  setSettings.axis.x.showAutoGridlines = false;
5438
5472
  newDataSet.line.type = "straight";
5439
5473
  newDataSet.line.display.strokeWidth = 2;
package/dist/index.mjs CHANGED
@@ -2674,15 +2674,17 @@ var ANOVA = {
2674
2674
  let scaleDF = Math.sqrt((rCount - 1) / (rCount * tCount));
2675
2675
  let UDL = grandMean + pooledSTD * hAlpha * scaleDF;
2676
2676
  let LDL = grandMean - pooledSTD * hAlpha * scaleDF;
2677
+ let chartSettings = new ChartSettings();
2677
2678
  returnArray.forEach((t, x) => {
2678
2679
  let canvasDraw = t.Mean < UDL && t.Mean > LDL ? new CanvasDrawSettings("#2183b2", "#2183b2", void 0, 0) : new CanvasDrawSettings("#F00", "#F00", void 0, 1);
2679
2680
  let newDataSet = new DataSet([
2680
2681
  new Point(x + 1, t.Mean, canvasDraw),
2681
2682
  new Point(x + 1, grandMean, new CanvasDrawSettings("#000", "#000", 0, 0, 0))
2682
2683
  ], t.treatment, void 0, new Line("straight", new CanvasDrawSettings("#000", "#000", 1)));
2684
+ chartSettings.axis.x.customGridlines.push(new CustomGridline(x + 1, t.treatment, void 0, void 0, void 0, void 0, true));
2683
2685
  dataSets.push(newDataSet);
2684
2686
  });
2685
- let chartSettings = new ChartSettings();
2687
+ chartSettings.axis.x.showAutoGridlines = false;
2686
2688
  chartSettings.axis.y.customGridlines = [new CustomGridline(grandMean, `x\u0305\u0305=${Math.round(grandMean * 1e3) / 1e3}`, new CanvasDrawSettings(GetThemeColor(2), GetThemeColor(2)), void 0, true), new CustomGridline(LDL, `LDL=${Math.round(LDL * 1e3) / 1e3}`, new CanvasDrawSettings("#F00", "#F00"), void 0, true, void 0, true), new CustomGridline(UDL, `UDL=${Math.round(UDL * 1e3) / 1e3}`, new CanvasDrawSettings("#F00", "#F00"), void 0, true, void 0, true)];
2687
2689
  let chart = CreateScatterPlot(dataSets, name ? `Analysis of Means for ${name}` : "Analysis of Means", chartSettings);
2688
2690
  return {
@@ -2760,8 +2762,8 @@ var ANOVA = {
2760
2762
  mean,
2761
2763
  stdev: StDev.S(data[key]),
2762
2764
  SE: standardError,
2763
- CI_Low: mean - tInv * standardError,
2764
- CI_High: mean + tInv * standardError
2765
+ CI_Low: mean - Math.abs(tInv * standardError),
2766
+ CI_High: mean + Math.abs(tInv * standardError)
2765
2767
  };
2766
2768
  summaryTable.ConfidenceIntervals.push(CI_table);
2767
2769
  }
@@ -3584,6 +3586,44 @@ var ANOVA = {
3584
3586
  p: Distributions.F.TwoTail(F, factor1.length - 1, factor2.length - 1)
3585
3587
  };
3586
3588
  }
3589
+ },
3590
+ Multifactor: {
3591
+ MainEffectsPlot(factors, response) {
3592
+ let responseName = Object.keys(response)[0];
3593
+ let factorKeys = Object.keys(factors);
3594
+ let individualCharts = [];
3595
+ factorKeys.forEach((k) => {
3596
+ let arr = factors[k];
3597
+ let uniqueLevels = arr.filter((value, index, array) => array.indexOf(value) === index);
3598
+ let dataSet = new DataSet([]);
3599
+ dataSet.line = new Line("straight");
3600
+ let chartSettings = new ChartSettings();
3601
+ chartSettings.axis.x.showAutoGridlines = false;
3602
+ chartSettings.axis.x.min = 0.5;
3603
+ chartSettings.axis.x.max = uniqueLevels.length + 0.5;
3604
+ chartSettings.axis.x.autoSize = false;
3605
+ uniqueLevels.forEach((level, levelI) => {
3606
+ let mean = 0;
3607
+ let N = 0;
3608
+ arr.forEach((v, i) => {
3609
+ if (v === level) {
3610
+ mean += response[responseName][i];
3611
+ N += 1;
3612
+ }
3613
+ });
3614
+ mean = mean / N;
3615
+ dataSet.values.push(new Point(levelI + 1, mean, new CanvasDrawSettings("#2183b2", "#000", void 0, void 0, 5)));
3616
+ chartSettings.axis.x.customGridlines.push(new CustomGridline(levelI + 1, level, void 0, void 0, void 0, true, false));
3617
+ });
3618
+ chartSettings.width += 1e3;
3619
+ individualCharts.push(new Chart([dataSet], "scatter", k, chartSettings));
3620
+ });
3621
+ let chartSet = new ChartSettings();
3622
+ chartSet.width += 1e3;
3623
+ chartSet.axis.y.tickOnly = true;
3624
+ let graph = CreateSplitGraph(individualCharts, `Main Effects Plot of ${Object.keys(response)[0]}`, chartSet);
3625
+ return graph;
3626
+ }
3587
3627
  }
3588
3628
  };
3589
3629
  function SumSquaredDeviation(data, referenceValue) {
@@ -3759,7 +3799,7 @@ function AddAxisGridlines(ctx, chartSettings, axis) {
3759
3799
  }
3760
3800
  let x = ConvertToCanvasPt(unadjustedValue, chartSettings.axis.x.min, chartSettings.axis.x.max, chartSettings.width - chartSettings.margins.left - chartSettings.margins.right - (((_v = chartSettings.axis.x.padding) == null ? void 0 : _v.left) ? (_w = chartSettings.axis.x.padding) == null ? void 0 : _w.left : 0) - (((_x = chartSettings.axis.x.padding) == null ? void 0 : _x.right) ? (_y = chartSettings.axis.x.padding) == null ? void 0 : _y.right : 0), chartSettings.axis.x) + chartSettings.margins.left + (((_z = chartSettings.axis.x.padding) == null ? void 0 : _z.left) ? (_A = chartSettings.axis.x.padding) == null ? void 0 : _A.left : 0);
3761
3801
  ctx.beginPath();
3762
- ctx.moveTo(x, chartSettings.axis.x.tickOnly ? chartSettings.height - chartSettings.margins.bottom : yT);
3802
+ ctx.moveTo(x, chartSettings.axis.x.tickOnly ? chartSettings.height - chartSettings.margins.bottom + 10 : yT);
3763
3803
  ctx.lineTo(x, yB);
3764
3804
  if (((_B = chartSettings.axis.x.labels) == null ? void 0 : _B.length) === void 0) {
3765
3805
  chartSettings.axis.x.labels = [];
@@ -3781,9 +3821,9 @@ function AddAxisGridlines(ctx, chartSettings, axis) {
3781
3821
  if (gridline.dashed) {
3782
3822
  ctx.setLineDash([20, 15]);
3783
3823
  }
3784
- ctx.moveTo(x, gridline.tickOnly ? chartSettings.height - chartSettings.margins.bottom : yT);
3824
+ ctx.moveTo(x, gridline.tickOnly ? chartSettings.height - chartSettings.margins.bottom + 10 : yT);
3785
3825
  ctx.lineTo(x, gridline.opposite && !gridline.tickOnly ? chartSettings.height - chartSettings.margins.bottom : yB);
3786
- ctx.fillText(gridline.label || RoundTO(gridline.value, 3), x, gridline.opposite ? chartSettings.margins.top - 10 : chartSettings.height - chartSettings.margins.bottom + 40);
3826
+ ctx.fillText(gridline.label || RoundTO(gridline.value, 3), x, gridline.opposite ? chartSettings.margins.top - 10 : chartSettings.height - chartSettings.margins.bottom + 32);
3787
3827
  ctx.stroke();
3788
3828
  ctx.setLineDash([]);
3789
3829
  ctx.closePath();
@@ -4511,8 +4551,6 @@ function CreateSplitGraph(charts, title, chartSettings = new ChartSettings()) {
4511
4551
  ctx.fillText(chart.title, chart.chartSettings.margins.left, chart.chartSettings.margins.top - 10);
4512
4552
  ctx == null ? void 0 : ctx.closePath();
4513
4553
  }
4514
- chart.chartSettings.axis.x.min = NaN;
4515
- chart.chartSettings.axis.x.max = NaN;
4516
4554
  AutoAxis(chart.data, chart.chartSettings);
4517
4555
  AddAxisGridlines(ctx, chart.chartSettings, "x");
4518
4556
  PlotData(ctx, chart.data, chart.chartSettings);
@@ -5255,8 +5293,6 @@ function GRRRChart(data) {
5255
5293
  gl.display.strokeColor = "rgb(230,230,230)";
5256
5294
  setSettings.axis.x.customGridlines.push(gl);
5257
5295
  }
5258
- setSettings.axis.x.min = 1;
5259
- setSettings.axis.x.min = Npart;
5260
5296
  setSettings.axis.x.showAutoGridlines = false;
5261
5297
  newDataSet.line.type = "straight";
5262
5298
  newDataSet.line.display.strokeWidth = 2;
@@ -5340,8 +5376,6 @@ function GRRXbarChart(data) {
5340
5376
  gl.display.strokeColor = "rgb(230,230,230)";
5341
5377
  setSettings.axis.x.customGridlines.push(gl);
5342
5378
  }
5343
- setSettings.axis.x.min = 1;
5344
- setSettings.axis.x.min = Npart;
5345
5379
  setSettings.axis.x.showAutoGridlines = false;
5346
5380
  newDataSet.line.type = "straight";
5347
5381
  newDataSet.line.display.strokeWidth = 2;
package/index.ts CHANGED
@@ -977,6 +977,28 @@ export const Gamma = {
977
977
  **/
978
978
  Trigamma(x: number){
979
979
  return 1 / x + 1 / (2 * (x ^ 2)) + 1 / (6 * (x ^ 3)) - 1 / (30 * (x ^ 5)) + 1 / (42 * (x ^ 7)) - 1 / (30 * (x ^ 9)) + 5 / (66 * (x ^ 11)) - 691 / (2730 * (x ^ 13)) + 15 / (6 * (x ^ 15))
980
+ },
981
+ /**
982
+ * Evaluates the lower incomplete gamma function for the specified value.
983
+ * @customfunction
984
+ * @param n
985
+ * @param x
986
+ **/
987
+ LowerIncomplete(n: number, x: number){
988
+ return Gamma.fn(n) - Gamma.UpperIncomplete(n, x);
989
+ },
990
+ /**
991
+ * Evaluates the upper incomplete gamma function for the specified value.
992
+ * @customfunction
993
+ * @param n
994
+ * @param x
995
+ **/
996
+ UpperIncomplete(n: number, x: number){
997
+ let expSum = 0;
998
+ for(let k = 0; k < n; k++){
999
+ expSum += Math.pow(x, k) / Probability.Factorialize(k);
1000
+ }
1001
+ return Probability.Factorialize(n-1) * Math.exp(-x) * expSum
980
1002
  }
981
1003
  }
982
1004
 
@@ -1134,11 +1156,44 @@ export const Distributions = {
1134
1156
  }
1135
1157
  },
1136
1158
  ChiSq: {
1159
+ pdf(x: number, df: number){
1160
+ let num = Math.pow(x, df/2-1) * Math.exp(-x/2)
1161
+ let den = Math.pow(2, df/2) * Gamma.fn(df/2);
1162
+ return num/den
1163
+ },
1137
1164
  cdf(x: number, df: number){
1138
1165
  if(df === 2){
1139
1166
  return 1 - Math.exp(-x/2);
1140
1167
  }
1141
- return NaN
1168
+ if(df%2){
1169
+
1170
+ let test = 0;
1171
+ let stepCount = 10000000;
1172
+ let stepSize = x/stepCount;
1173
+
1174
+ for(let i = 0; i < stepCount + 1; i++){
1175
+ test += stepSize * Distributions.ChiSq.pdf(i*stepSize, df);
1176
+ }
1177
+ return test
1178
+
1179
+ //this approximation is best used when x < df
1180
+ if(x < df){
1181
+ let y = Math.sqrt(df/2)*Math.log(df/x);
1182
+ const aFunc = (c1, c2, c3, c4) => {
1183
+ return c1 + c2 * Math.pow(2/df, .5) + c3 * (2/df) + c4 * Math.pow(2/df,1/5)
1184
+ }
1185
+ let A = aFunc(.5, .1323, .0036, -.0038)
1186
+ let a1 = aFunc(.1968, -.0452, -.0128, -.0168);
1187
+ let a2 = aFunc(0.1152,-0.099,0.0539,-0.0168);
1188
+ let a3 = aFunc(0.0004,0.0442,-0.0866,0.0398);
1189
+ let a4 = aFunc(0.0195,-0.0629,0.0708,0.0269);
1190
+
1191
+ return A/Math.pow(1 + a1*y + a2*Math.pow(y,2) + a3*Math.pow(y,3) + a4*Math.pow(y,4),4)
1192
+ }
1193
+ }
1194
+ let num = Gamma.LowerIncomplete(df/2, x/2)
1195
+ let den = Gamma.fn(df/2)
1196
+ return num/den;
1142
1197
  },
1143
1198
  RightTail(x: number, df: number){
1144
1199
  return 1 - Distributions.ChiSq.cdf(x, df);
@@ -2839,6 +2894,59 @@ export function Sum(data: any[]){
2839
2894
  return sum;
2840
2895
  }
2841
2896
 
2897
+ function SumSquareByGroups(groups: any, response: any) {
2898
+ let groupKeys = Object.keys(groups);
2899
+ let groupSets: any[] = [];
2900
+ let treatmentCount = 0;
2901
+ groupKeys.forEach((group) => {
2902
+ let set = new Set(groups[group]);
2903
+ groupSets.push(set)
2904
+ treatmentCount += set.size;
2905
+ });
2906
+
2907
+ let placeFactors: any[] = [];
2908
+ groupSets.forEach((s, sI) => {
2909
+ if(sI === groupSets.length - 1){
2910
+ placeFactors.push(1);
2911
+ }else{
2912
+ placeFactors.push(groupSets[sI+1].size)
2913
+ }
2914
+ })
2915
+
2916
+ let returnObject = {};
2917
+ let groupNObject = {};
2918
+ response[Object.keys(response)[0]].forEach((value, index) => {
2919
+ let indexer: any[] = [];
2920
+ groupKeys.forEach((k, kI) => {
2921
+ let currentKey = groups[k][index]
2922
+ groupSets[kI].forEach((s,sI) => {
2923
+ if(s === currentKey){
2924
+ indexer.push(sI)
2925
+ }
2926
+ })
2927
+ })
2928
+ returnObject[JSON.stringify(indexer)] = 0;
2929
+ groupNObject[JSON.stringify(indexer)] = 0;
2930
+ })
2931
+ response[Object.keys(response)[0]].forEach((value, index) => {
2932
+ let indexer: any = [];
2933
+ groupKeys.forEach((k, kI) => {
2934
+ let currentKey = groups[k][index]
2935
+ groupSets[kI].forEach((s,sI) => {
2936
+ if(s === currentKey){
2937
+ indexer.push(sI)
2938
+ }
2939
+ })
2940
+ })
2941
+ returnObject[JSON.stringify(indexer)] += value;
2942
+ groupNObject[JSON.stringify(indexer)] += 1;
2943
+ })
2944
+ let sumsq = 0;
2945
+ Object.keys(returnObject).forEach(k => {
2946
+ sumsq += Math.pow(returnObject[k], 2)/groupNObject[k]
2947
+ })
2948
+ return sumsq;
2949
+ }
2842
2950
  /**
2843
2951
  * Calculates the mean of the array supplied.
2844
2952
  * @customfunction
@@ -3018,17 +3126,18 @@ export const ANOVA = {
3018
3126
  let UDL = grandMean + pooledSTD*hAlpha*scaleDF
3019
3127
  let LDL = grandMean - pooledSTD*hAlpha*scaleDF
3020
3128
 
3129
+ let chartSettings = new ChartSettings();
3021
3130
  returnArray.forEach((t,x) => {
3022
3131
  let canvasDraw: CanvasDrawSettings = (t.Mean < UDL && t.Mean > LDL) ? new CanvasDrawSettings('#2183b2', '#2183b2', undefined, 0) : new CanvasDrawSettings('#F00', '#F00',undefined,1)
3023
3132
  let newDataSet = new DataSet([
3024
3133
  new Point(x+1, t.Mean, canvasDraw),
3025
3134
  new Point(x+1, grandMean, new CanvasDrawSettings('#000', '#000', 0, 0, 0))
3026
3135
  ],t.treatment,undefined, new Line("straight",new CanvasDrawSettings('#000','#000',1)));
3027
-
3136
+ chartSettings.axis.x.customGridlines.push(new CustomGridline(x+1, t.treatment, undefined, undefined, undefined, undefined, true))
3028
3137
  dataSets.push(newDataSet);
3029
3138
  })
3030
3139
 
3031
- let chartSettings = new ChartSettings();
3140
+ chartSettings.axis.x.showAutoGridlines = false;
3032
3141
  chartSettings.axis.y.customGridlines = [new CustomGridline(grandMean, `x̅̅=${Math.round(grandMean*1000)/1000}`, new CanvasDrawSettings(GetThemeColor(2), GetThemeColor(2)),undefined, true),new CustomGridline(LDL, `LDL=${Math.round(LDL*1000)/1000}`, new CanvasDrawSettings('#F00', '#F00'),undefined,true,undefined,true), new CustomGridline(UDL, `UDL=${Math.round(UDL*1000)/1000}`, new CanvasDrawSettings('#F00', '#F00'),undefined,true,undefined,true)]
3033
3142
  let chart = CreateScatterPlot(dataSets, name ? `Analysis of Means for ${name}` : "Analysis of Means", chartSettings);
3034
3143
 
@@ -3115,8 +3224,8 @@ export const ANOVA = {
3115
3224
  mean: mean,
3116
3225
  stdev: StDev.S(data[key]),
3117
3226
  SE: standardError,
3118
- CI_Low: mean - tInv*standardError,
3119
- CI_High: mean + tInv*standardError
3227
+ CI_Low: mean - Math.abs(tInv*standardError),
3228
+ CI_High: mean + Math.abs(tInv*standardError)
3120
3229
  }
3121
3230
  summaryTable.ConfidenceIntervals.push(CI_table);
3122
3231
  }
@@ -3977,6 +4086,184 @@ export const ANOVA = {
3977
4086
  p: Distributions.F.TwoTail(F, factor1.length - 1, factor2.length - 1)
3978
4087
  }
3979
4088
  }
4089
+ },
4090
+ Multifactor: {
4091
+ MainEffectsPlot(factors: any, response: any){
4092
+ let responseName = Object.keys(response)[0]
4093
+ let factorKeys = Object.keys(factors)
4094
+ let individualCharts: Chart[] = [];
4095
+ factorKeys.forEach(k => {
4096
+ let arr = factors[k];
4097
+ let uniqueLevels = arr.filter((value, index, array) => array.indexOf(value) === index);
4098
+
4099
+ let dataSet = new DataSet([]);
4100
+ dataSet.line = new Line('straight')
4101
+
4102
+ let chartSettings = new ChartSettings();
4103
+ chartSettings.axis.x.showAutoGridlines = false
4104
+ chartSettings.axis.x.min = .5;
4105
+ chartSettings.axis.x.max = uniqueLevels.length + .5
4106
+ chartSettings.axis.x.autoSize = false
4107
+
4108
+ uniqueLevels.forEach((level, levelI) => {
4109
+ let mean = 0;
4110
+ let N = 0;
4111
+ arr.forEach((v,i) => {
4112
+ if(v === level){
4113
+ mean += response[responseName][i]
4114
+ N += 1
4115
+ }
4116
+ })
4117
+ mean = mean/N;
4118
+ dataSet.values.push(new Point(levelI+1, mean, new CanvasDrawSettings('#2183b2','#000',undefined,undefined,5)));
4119
+ chartSettings.axis.x.customGridlines.push(new CustomGridline(levelI + 1, level,undefined, undefined,undefined, true, false))
4120
+ })
4121
+ chartSettings.width += 1000
4122
+
4123
+ individualCharts.push(new Chart([dataSet], "scatter", k, chartSettings))
4124
+ })
4125
+ let chartSet = new ChartSettings()
4126
+ chartSet.width += 1000
4127
+ chartSet.axis.y.tickOnly = true
4128
+ let graph = CreateSplitGraph(individualCharts, `Main Effects Plot of ${Object.keys(response)[0]}`, chartSet)
4129
+ console.log(graph)
4130
+ return graph
4131
+ },
4132
+ Table(factors: any, response: any){
4133
+ let anovaTable = {};
4134
+ let factorKeys = Object.keys(factors);
4135
+ let responseKey = Object.keys(response)[0];
4136
+ let Ntotal = response[responseKey].length;
4137
+ let DFE = 1;
4138
+ let correctionFactor = Math.pow(Sum(response[responseKey]),2)/Ntotal;
4139
+ // Individual Variance
4140
+ factorKeys.forEach(f => {
4141
+ let fSet = new Set(factors[f])
4142
+ let Nf = fSet.size;
4143
+ let SS_f = 0;
4144
+
4145
+ fSet.forEach(level => {
4146
+ let levelTotal = 0;
4147
+ let levelN = 0;
4148
+ factors[f].forEach((v,j) => {
4149
+ if(v === level){
4150
+ levelTotal += response[responseKey][j];
4151
+ levelN += 1;
4152
+ }
4153
+ })
4154
+ SS_f += Math.pow(levelTotal, 2) / levelN
4155
+ })
4156
+ SS_f = SS_f - correctionFactor;
4157
+
4158
+ anovaTable[f] = {
4159
+ DF: Nf-1,
4160
+ SS: SS_f,
4161
+ MS: SS_f/(Nf-1),
4162
+ F: undefined,
4163
+ p: undefined
4164
+ }
4165
+ DFE = DFE*Nf;
4166
+ })
4167
+ DFE = Ntotal - DFE;
4168
+
4169
+ // Interaction Effects
4170
+ for(let i = 0; i < factorKeys.length - 1; i++){
4171
+ let f_i_Set = new Set(factors[factorKeys[i]])
4172
+ for(let j = i+1; j < factorKeys.length; j++){
4173
+ let f_j_Set = new Set(factors[factorKeys[j]])
4174
+ let SS_subtotal = 0;
4175
+ f_i_Set.forEach(fi => {
4176
+ f_j_Set.forEach(fj => {
4177
+ let groupSum = 0;
4178
+ let groupN = 0;
4179
+ response[responseKey].forEach((val, index) => {
4180
+ if(factors[factorKeys[i]][index] === fi && factors[factorKeys[j]][index] === fj){
4181
+ groupSum += val
4182
+ groupN += 1;
4183
+ }
4184
+ })
4185
+ SS_subtotal += Math.pow(groupSum, 2)/groupN;
4186
+ })
4187
+ })
4188
+ SS_subtotal = SS_subtotal-correctionFactor;
4189
+
4190
+ let iRow = anovaTable[factorKeys[i]]
4191
+ let jRow = anovaTable[factorKeys[j]]
4192
+ let fi_fj_DF = iRow.DF*jRow.DF
4193
+ let fi_fj_SS = SS_subtotal - iRow.SS - jRow.SS;
4194
+ anovaTable[`${factorKeys[i]}*${factorKeys[j]}`] = {DF: fi_fj_DF, SS: fi_fj_SS, MS: fi_fj_SS/fi_fj_DF, F: undefined, p: undefined}
4195
+ }
4196
+ }
4197
+
4198
+ // Total Interaction Effects
4199
+ let interactionSS_subtotal = SumSquareByGroups(factors, response) - correctionFactor;
4200
+ let fullInteractionDF = 1;
4201
+ let SSE = 0;
4202
+
4203
+ factorKeys.forEach(source => {
4204
+ fullInteractionDF = fullInteractionDF * anovaTable[source].DF;
4205
+ })
4206
+ Object.keys(anovaTable).forEach((source) => {
4207
+ interactionSS_subtotal = interactionSS_subtotal - anovaTable[source].SS;
4208
+ SSE += anovaTable[source].SS;
4209
+ });
4210
+ let fullInteractionName = factorKeys.join("*");
4211
+ anovaTable[fullInteractionName] = {DF: fullInteractionDF, SS: interactionSS_subtotal, MS: interactionSS_subtotal/fullInteractionDF, F: undefined, p: undefined}
4212
+
4213
+ SSE += interactionSS_subtotal;
4214
+ let SStotal = SumSquaredDeviation(response[responseKey], 0) - correctionFactor;
4215
+ SSE = SStotal - SSE;
4216
+ let MSE = SSE/DFE;
4217
+
4218
+ Object.keys(anovaTable).forEach(source => {
4219
+ let sourceF = anovaTable[source].MS/MSE;
4220
+ anovaTable[source].F = sourceF;
4221
+ anovaTable[source].p = Distributions.F.RightTail(sourceF, anovaTable[source].DF, DFE);
4222
+ })
4223
+
4224
+ anovaTable["Error"] = {DF: DFE, SS: SSE, MS: MSE}
4225
+ anovaTable["Total"] = {DF: Ntotal - 1, SS: SStotal}
4226
+
4227
+ return anovaTable;
4228
+ },
4229
+ GLM(factors: any, response: any){
4230
+ let factorKeys = Object.keys(factors);
4231
+ let anovaTable = {}
4232
+ let responseKey = Object.keys(response)[0];
4233
+ let Ntotal = response[responseKey].length;
4234
+ let DFE = 1;
4235
+ let responseData = response[responseKey];
4236
+
4237
+ factorKeys.forEach(k => {
4238
+ let SS = 0;
4239
+ let levels = new Set(factors[k]);
4240
+ let groupedData = GroupData(factors[k], responseData);
4241
+
4242
+ let descriptiveStats = {};
4243
+ let mean_0;
4244
+ Object.keys(groupedData).forEach((k, k_i) => {
4245
+ let mean = Mean(groupedData[k]);
4246
+ descriptiveStats[k].mean = mean;
4247
+ descriptiveStats[k].std = StDev.S(groupedData[k]);
4248
+ descriptiveStats[k].N = groupedData[k].length;
4249
+ if(k_i === 0){
4250
+ mean_0 = mean;
4251
+ groupedData[k].forEach(d => {
4252
+ SS += mean;
4253
+ })
4254
+ }else{
4255
+ groupedData[k].forEach(d => {
4256
+ SS += mean - Math.pow(mean - d, 2)
4257
+ })
4258
+ }
4259
+ })
4260
+ console.log(k, SS);
4261
+ })
4262
+
4263
+
4264
+
4265
+ return anovaTable;
4266
+ }
3980
4267
  }
3981
4268
  }
3982
4269
 
@@ -4003,6 +4290,22 @@ export const Probability = {
4003
4290
  }
4004
4291
  }
4005
4292
  }
4293
+
4294
+ function GroupData(groupingArray, responseArray){
4295
+ if(groupingArray.length != responseArray.length){return {forEachGroup(){}}}
4296
+ let returnObj = {}
4297
+
4298
+ let levels = new Set(groupingArray);
4299
+
4300
+ levels.forEach((l: any) => {
4301
+ returnObj[l] = [];
4302
+ })
4303
+
4304
+ for(let i = 0; i < groupingArray.length; i++){
4305
+ returnObj[groupingArray[i]].push(responseArray[i])
4306
+ }
4307
+ return returnObj;
4308
+ }
4006
4309
  // End General Statistics
4007
4310
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4008
4311
  /** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -4209,7 +4512,7 @@ function AddAxisGridlines(ctx: any, chartSettings: ChartSettings, axis: string)
4209
4512
  let x = ConvertToCanvasPt(unadjustedValue, chartSettings.axis.x.min, chartSettings.axis.x.max, chartSettings.width - chartSettings.margins.left - chartSettings.margins.right - (chartSettings.axis.x.padding?.left ? chartSettings.axis.x.padding?.left : 0) - (chartSettings.axis.x.padding?.right ? chartSettings.axis.x.padding?.right : 0), chartSettings.axis.x) + chartSettings.margins.left + (chartSettings.axis.x.padding?.left ? chartSettings.axis.x.padding?.left : 0);
4210
4513
 
4211
4514
  ctx.beginPath();
4212
- ctx.moveTo(x, chartSettings.axis.x.tickOnly ? chartSettings.height - chartSettings.margins.bottom : yT);
4515
+ ctx.moveTo(x, chartSettings.axis.x.tickOnly ? chartSettings.height - chartSettings.margins.bottom + 10 : yT);
4213
4516
  ctx.lineTo(x, yB);
4214
4517
  if(chartSettings.axis.x.labels?.length === undefined){
4215
4518
  chartSettings.axis.x.labels = []
@@ -4233,10 +4536,10 @@ function AddAxisGridlines(ctx: any, chartSettings: ChartSettings, axis: string)
4233
4536
 
4234
4537
  ctx.beginPath();
4235
4538
  if(gridline.dashed){ctx.setLineDash([20, 15])}
4236
- ctx.moveTo(x, gridline.tickOnly ? chartSettings.height - chartSettings.margins.bottom : yT);
4539
+ ctx.moveTo(x, gridline.tickOnly ? chartSettings.height - chartSettings.margins.bottom + 10 : yT);
4237
4540
  ctx.lineTo(x, gridline.opposite && !gridline.tickOnly ? chartSettings.height - chartSettings.margins.bottom : yB);
4238
4541
 
4239
- ctx.fillText(gridline.label || RoundTO(gridline.value, 3), x, gridline.opposite ? chartSettings.margins.top - 10 : chartSettings.height - chartSettings.margins.bottom + 40);
4542
+ ctx.fillText(gridline.label || RoundTO(gridline.value, 3), x, gridline.opposite ? chartSettings.margins.top - 10 : chartSettings.height - chartSettings.margins.bottom + 32);
4240
4543
  ctx.stroke();
4241
4544
  ctx.setLineDash([])
4242
4545
  ctx.closePath();
@@ -5110,8 +5413,8 @@ export function CreateSplitGraph(charts: Chart[], title: string, chartSettings:
5110
5413
  }
5111
5414
 
5112
5415
  // Automate X-axis
5113
- chart.chartSettings.axis.x.min = NaN;
5114
- chart.chartSettings.axis.x.max = NaN;
5416
+ // chart.chartSettings.axis.x.min = NaN;
5417
+ // chart.chartSettings.axis.x.max = NaN;
5115
5418
  AutoAxis(chart.data, chart.chartSettings);
5116
5419
  AddAxisGridlines(ctx, chart.chartSettings, 'x');
5117
5420
 
@@ -6029,8 +6332,6 @@ function GRRRChart(data: GRRData){
6029
6332
  gl.display.strokeColor = 'rgb(230,230,230)'
6030
6333
  setSettings.axis.x.customGridlines.push(gl)
6031
6334
  }
6032
- setSettings.axis.x.min = 1
6033
- setSettings.axis.x.min = Npart;
6034
6335
  setSettings.axis.x.showAutoGridlines = false;
6035
6336
  newDataSet.line.type = 'straight';
6036
6337
  newDataSet.line.display.strokeWidth = 2;
@@ -6123,8 +6424,6 @@ function GRRXbarChart(data: GRRData){
6123
6424
  gl.display.strokeColor = 'rgb(230,230,230)'
6124
6425
  setSettings.axis.x.customGridlines.push(gl)
6125
6426
  }
6126
- setSettings.axis.x.min = 1
6127
- setSettings.axis.x.min = Npart;
6128
6427
  setSettings.axis.x.showAutoGridlines = false;
6129
6428
  newDataSet.line.type = 'straight';
6130
6429
  newDataSet.line.display.strokeWidth = 2;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qesuite",
3
- "version": "1.0.49",
3
+ "version": "1.0.51",
4
4
  "description": "Performs advanced statistical analysis of data. Specifically designed for engineering statistical analysis",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -0,0 +1,14 @@
1
+ Added Features:
2
+ - ANOVA
3
+ - Multifactor
4
+ - MainEffectsPlot
5
+
6
+ Modified Features
7
+ - Split graph
8
+ - removed lines that set x.min and x.max to NaN to fix custom gridline bug
9
+ - GRRRChart & GGRXBarChart
10
+ - removed lines of code that set x.min and x.max to fix NaN custom gridlining bug (see previous note^)
11
+ - AnalysisOfMeans.OneWay() Chart
12
+ - changed x-axis to match categorical treatment groupings
13
+ - ANOVA.OneWay.Table
14
+ - fixed CI_Low/CI_High flipped bug in Confidence Intervals by using absolute value of Tcrit
@@ -0,0 +1 @@
1
+ - Added approximations for ChiSq Distribution CDF