diff --git a/api/package-lock.json b/api/package-lock.json
index 66ccbcaff3c7f389bb1ad9d1ab1f5c3bd9c7a083..d90121669df7b4e1183555c9723b0d67235faa23 100644
--- a/api/package-lock.json
+++ b/api/package-lock.json
@@ -28320,4 +28320,4 @@
"dev": true
}
}
-}
+}
\ No newline at end of file
diff --git a/api/package.json b/api/package.json
index a7c08d3f706e5f149db11143cd6f2a52942f650d..52fb25d717f17aef9237399bc8f43b3276d7e252 100644
--- a/api/package.json
+++ b/api/package.json
@@ -164,4 +164,4 @@
}
]
}
-}
+}
\ No newline at end of file
diff --git a/api/src/engine/connectors/exareme/handlers/algorithms/anova-two-way.handler.spec.ts b/api/src/engine/connectors/exareme/handlers/algorithms/anova-two-way.handler.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1cf5003f6d41ddfacb271cacda2863a760d230c8
--- /dev/null
+++ b/api/src/engine/connectors/exareme/handlers/algorithms/anova-two-way.handler.spec.ts
@@ -0,0 +1,72 @@
+import { Domain } from '../../../../models/domain.model';
+import handlers from '..';
+import { Experiment } from '../../../../models/experiment/experiment.model';
+import AnovaTwoWayHandler from './anova-two-way.handler';
+
+const createExperiment = (): Experiment => ({
+ id: 'dummy-id',
+ name: 'Testing purpose',
+ algorithm: {
+ name: AnovaTwoWayHandler.ALGO_NAME,
+ },
+ datasets: ['desd-synthdata'],
+ domain: 'dementia',
+ variables: ['parkinsonbroadcategory'],
+ coVariables: ['gender'],
+ results: [],
+});
+
+const domain: Domain = {
+ id: 'dummy-id',
+ groups: [],
+ rootGroup: {
+ id: 'dummy-id',
+ },
+ datasets: [{ id: 'desd-synthdata', label: 'Dead Synthdata' }],
+ variables: [
+ { id: 'parkinsonbroadcategory', label: 'Example label' },
+ { id: 'gender', label: 'Example label 2' },
+ { id: 'parkinsonbroadcategory:gender', label: 'Example label 3' },
+ ],
+};
+
+const data = [
+ {
+ terms: [
+ 'gender',
+ 'parkinsonbroadcategory',
+ 'gender:parkinsonbroadcategory',
+ 'Residuals',
+ ],
+ sum_sq: [
+ 122.2949665988383, 33.327112053403425, 0.8516104180441744,
+ 1801.7985931306575,
+ ],
+ df: [1.0, 2.0, 2.0, 708.0],
+ f_stat: [48.05466975170338, 6.547789365517223, 0.16731619679191115, null],
+ f_pvalue: [
+ 9.343970042152705e-12,
+ 0.0015216347633810745,
+ 0.8459655267774153,
+ null,
+ ],
+ },
+];
+
+describe('Anova 2 way result handler', () => {
+ const anovaHandler = new AnovaTwoWayHandler();
+
+ it('Test anova 2 way handler', () => {
+ const exp = createExperiment();
+ const summaryTable = anovaHandler.getSummaryTable(
+ data[0],
+ domain.variables,
+ );
+
+ handlers(exp, data, domain);
+
+ expect(exp.results.length).toBeGreaterThanOrEqual(1);
+
+ expect(summaryTable.data.length).toEqual(4);
+ });
+});
diff --git a/api/src/engine/connectors/exareme/handlers/algorithms/anova-two-way.handler.ts b/api/src/engine/connectors/exareme/handlers/algorithms/anova-two-way.handler.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cb18d2ed9816bc243eeae7f7c11352b62e0f8be6
--- /dev/null
+++ b/api/src/engine/connectors/exareme/handlers/algorithms/anova-two-way.handler.ts
@@ -0,0 +1,55 @@
+import { Domain } from '../../../../models/domain.model';
+import { Experiment } from '../../../../models/experiment/experiment.model';
+import {
+ TableResult,
+ TableStyle,
+} from '../../../../models/result/table-result.model';
+import { Variable } from '../../../../models/variable.model';
+import BaseHandler from '../base.handler';
+
+const NUMBER_PRECISION = 4;
+
+export default class AnovaTwoWayHandler extends BaseHandler {
+ public static readonly ALGO_NAME = 'anova';
+
+ private canHandle(algorithm: string, data: any): boolean {
+ return (
+ algorithm.toLowerCase() === AnovaTwoWayHandler.ALGO_NAME &&
+ data &&
+ data[0] &&
+ data[0]['terms']
+ );
+ }
+
+ getSummaryTable(data: any, variables: Variable[]): TableResult | undefined {
+ return {
+ name: 'Anova two way Summary',
+ tableStyle: TableStyle.DEFAULT,
+ headers: ['', 'DF', 'Sum Sq', 'F value', 'Pr(>F)'].map((name) => ({
+ name,
+ type: 'string',
+ })),
+ data: data['terms'].map((term: string, index: number) => [
+ variables.find((variable) => variable.id == term)?.label ?? term,
+ data['df'][index]?.toPrecision(NUMBER_PRECISION) ?? '',
+ data['sum_sq'][index]?.toPrecision(NUMBER_PRECISION) ?? '',
+ data['f_stat'][index]?.toPrecision(NUMBER_PRECISION) ?? '',
+ data['f_pvalue'][index]?.toPrecision(NUMBER_PRECISION) ?? '',
+ ]),
+ };
+ }
+
+ handle(exp: Experiment, data: any, domain: Domain): void {
+ if (!this.canHandle(exp.algorithm.name, data))
+ return super.handle(exp, data, domain);
+
+ const result = data[0];
+
+ const varIds = [...exp.variables, ...(exp.coVariables ?? [])];
+ const variables = domain.variables.filter((v) => varIds.includes(v.id));
+
+ const summaryTable = this.getSummaryTable(result, variables);
+
+ if (summaryTable) exp.results.push(summaryTable);
+ }
+}
diff --git a/api/src/engine/connectors/exareme/handlers/algorithms/linear-regression-cv.handler.spec.ts b/api/src/engine/connectors/exareme/handlers/algorithms/linear-regression-cv.handler.spec.ts
index 63595a228d26a23033e7a8fe03943925175f81e9..6fe1967a993e02eed1535c4b3f87607aea57de4f 100644
--- a/api/src/engine/connectors/exareme/handlers/algorithms/linear-regression-cv.handler.spec.ts
+++ b/api/src/engine/connectors/exareme/handlers/algorithms/linear-regression-cv.handler.spec.ts
@@ -83,10 +83,8 @@ describe('Linear regression CV result handler', () => {
const dataPoints = experiment.results[0] as TableResult;
const scoresData = experiment.results[1] as TableResult;
- expect(dataPoints.data).toStrictEqual(expectedDataPoints);
+ expect(dataPoints.data.length).toEqual(4);
expect(scoresData.data).toStrictEqual(expectedScoresData);
-
- expect(json.includes(domain.variables[0].label)).toBeTruthy();
});
it('Should be empty with another algo', () => {
diff --git a/api/src/engine/connectors/exareme/handlers/algorithms/linear-regression-cv.handler.ts b/api/src/engine/connectors/exareme/handlers/algorithms/linear-regression-cv.handler.ts
index df0adfc430fe722d91d88079c1417963a910ae7c..1098f86a871742abf4cb6c3929b6da788679beda 100644
--- a/api/src/engine/connectors/exareme/handlers/algorithms/linear-regression-cv.handler.ts
+++ b/api/src/engine/connectors/exareme/handlers/algorithms/linear-regression-cv.handler.ts
@@ -13,7 +13,7 @@ const ALGO_NAME = 'linear_regression_cv';
const lookupDict = {
dependent_var: 'Dependent variable',
indep_vars: 'Independent variables',
- n_obs: 'Number of observations',
+ n_obs: 'Training set sample sizes',
mean_sq_error: 'Root mean squared error',
r_squared: 'R-squared',
mean_abs_error: 'Mean absolute error',
@@ -22,13 +22,14 @@ const lookupDict = {
export default class LinearRegressionCVHandler extends BaseHandler {
private getModel(data: any): TableResult | undefined {
return {
- name: 'Data points',
+ name: 'Folds',
tableStyle: TableStyle.DEFAULT,
- headers: ['', `${lookupDict['n_obs']} (${data['dependent_var']})`].map(
- (name) => ({ name, type: 'string' }),
- ),
- data: data['indep_vars'].map((name: string, i: number) => [
+ headers: ['', lookupDict['n_obs']].map((name) => ({
name,
+ type: 'string',
+ })),
+ data: data['n_obs'].map((size: string, i: number) => [
+ 'Fold ' + (i + 1),
data['n_obs'][i],
]),
};
diff --git a/api/src/engine/connectors/exareme/handlers/index.ts b/api/src/engine/connectors/exareme/handlers/index.ts
index fd465c382338cc4cdba6315c5341a3a66980e7bd..6863edfd62e4d8a5ee97941e83f15424eb65d178 100644
--- a/api/src/engine/connectors/exareme/handlers/index.ts
+++ b/api/src/engine/connectors/exareme/handlers/index.ts
@@ -1,6 +1,7 @@
import { Domain } from '../../../../engine/models/domain.model';
import { Experiment } from '../../../../engine/models/experiment/experiment.model';
import AnovaOneWayHandler from './algorithms/anova-one-way.handler';
+import AnovaTwoWayHandler from './algorithms/anova-two-way.handler';
import DescriptiveHandler from './algorithms/descriptive.handler';
import HistogramHandler from './algorithms/histogram.handler';
import LinearRegressionCVHandler from './algorithms/linear-regression-cv.handler';
@@ -20,6 +21,7 @@ start
.setNext(new HistogramHandler())
.setNext(new DescriptiveHandler())
.setNext(new AnovaOneWayHandler())
+ .setNext(new AnovaTwoWayHandler())
.setNext(new PCAHandler())
.setNext(new LinearRegressionHandler())
.setNext(new LinearRegressionCVHandler())