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 728ecb5da4bc104ddfa5987d180d6118077df58e..22413dfd17017d6c90fe8c26315cf6269b2afe00 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 @@ -93,7 +93,7 @@ describe('Linear regression CV result handler', () => { experiment.algorithm.name = 'dummy_algo'; linearHandler.handle(experiment, data, domain); - expect(experiment.results.length === 0); + expect(experiment.results.length).toBe(0); }); }); }); diff --git a/api/src/engine/connectors/exareme/handlers/algorithms/linear-regression.handler.spec.ts b/api/src/engine/connectors/exareme/handlers/algorithms/linear-regression.handler.spec.ts index b4dee3ed2cc6b8b67d5ad4aea07effe2439e7f08..5fe1ecb65824d585e9f3b6a1ef2d84c4755e6cdf 100644 --- a/api/src/engine/connectors/exareme/handlers/algorithms/linear-regression.handler.spec.ts +++ b/api/src/engine/connectors/exareme/handlers/algorithms/linear-regression.handler.spec.ts @@ -68,13 +68,13 @@ describe('Linear regression result handler', () => { const json = JSON.stringify(experiment.results); expect(json.includes(domain.variables[0].label)).toBeTruthy(); - expect(experiment.results.length === 2); + expect(experiment.results.length).toBe(2); }); it('Should be empty with another algo', () => { experiment.algorithm.name = 'dummy_algo'; linearHandler.handle(experiment, data, domain); - expect(experiment.results.length === 0); + expect(experiment.results.length).toBe(0); }); }); }); diff --git a/api/src/engine/connectors/exareme/handlers/algorithms/ttest-onesample.handler.spec.ts b/api/src/engine/connectors/exareme/handlers/algorithms/ttest-onesample.handler.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..258f8106788321276cbdce6aa785190d44a307fc --- /dev/null +++ b/api/src/engine/connectors/exareme/handlers/algorithms/ttest-onesample.handler.spec.ts @@ -0,0 +1,56 @@ +import { TableResult } from '../../../../models/result/table-result.model'; +import { Experiment } from '../../../../models/experiment/experiment.model'; +import TtestOnesampleHandler from './ttest-onesample.handler'; + +const data = { + n_obs: 1991, + t_value: 304.98272738655413, + p_value: 0.0, + df: 1990.0, + mean_diff: 220.17867654445, + se_diff: 0.7464781919192859, + ci_upper: 221.64263732187715, + ci_lower: 218.71471576702288, + cohens_d: 6.835017232945105, +}; + +const createExperiment = (): Experiment => ({ + id: 'dummy-id', + name: 'Testing purpose', + algorithm: { + name: TtestOnesampleHandler.ALGO_NAME.toUpperCase(), + }, + datasets: ['desd-synthdata'], + domain: 'dementia', + variables: ['lefthippocampus'], + coVariables: ['righthippocampus', 'leftamygdala'], + results: [], +}); + +describe('T-Test Paired handler', () => { + let tTestOnesampleHandler: TtestOnesampleHandler; + let experiment: Experiment; + + beforeEach(() => { + tTestOnesampleHandler = new TtestOnesampleHandler(); + experiment = createExperiment(); + }); + + describe('Handle', () => { + it('with standard t-test algo data', () => { + tTestOnesampleHandler.handle(experiment, data); + + const table = experiment.results[0] as TableResult; + + expect(experiment.results.length).toBe(1); + expect(table.data.length).toBe(9); + }); + + it('Should be empty with another algo', () => { + experiment.algorithm.name = 'dummy_algo'; + tTestOnesampleHandler.handle(experiment, data); + + expect(experiment.results.length).toBe(0); + }); + }); +}); diff --git a/api/src/engine/connectors/exareme/handlers/algorithms/ttest-onesample.handler.ts b/api/src/engine/connectors/exareme/handlers/algorithms/ttest-onesample.handler.ts new file mode 100644 index 0000000000000000000000000000000000000000..0cb7bb1903e8e49f68820f5fe337c5353175cc4f --- /dev/null +++ b/api/src/engine/connectors/exareme/handlers/algorithms/ttest-onesample.handler.ts @@ -0,0 +1,72 @@ +import { isNumber } from '../../../../../common/utils/shared.utils'; +import { Domain } from '../../../../models/domain.model'; +import { Experiment } from '../../../../models/experiment/experiment.model'; +import { + TableResult, + TableStyle, +} from '../../../../models/result/table-result.model'; +import BaseHandler from '../base.handler'; + +const lookupDict = { + t_value: 'T-value', + n_obs: 'Number of observations', + p: 'P-value', + df: 'Degrees of freedom', + mean_diff: 'Mean difference', + se_diff: 'Standard error of difference', + ci_lower: 'Lower 95% confidence interval', + ci_upper: 'Upper 95% confidence interval', + cohens_d: "Cohen's d", +}; +const NUMBER_PRECISION = 4; +const EXCLUDE_PRECISION = ['n_obs', 'ci_lower', 'ci_upper']; + +const isNumberPrecision = (value: any, name: string) => { + if (!EXCLUDE_PRECISION.includes(name) && isNumber(value)) + return value.toPrecision(NUMBER_PRECISION); + + return value; +}; + +export default class TtestOnesampleHandler extends BaseHandler { + public static readonly ALGO_NAME = 'ttest_onesample'; + + private canHandle(algoId: string) { + return algoId.toLocaleLowerCase() === TtestOnesampleHandler.ALGO_NAME; + } + + private getTable(data: any): TableResult { + const tableModel: TableResult = { + name: 'T-test', + tableStyle: TableStyle.NORMAL, + headers: ['name', 'value'].map((name) => ({ name, type: 'string' })), + data: [ + 'n_obs', + 't_value', + 'p', + 'df', + 'mean_diff', + 'se_diff', + 'ci_lower', + 'ci_upper', + 'cohens_d', + ].map((name) => [ + lookupDict[name], + isNumberPrecision(data[name], name) + ? data[name].toPrecision(NUMBER_PRECISION) + : data[name], + ]), + }; + + return tableModel; + } + + handle(experiment: Experiment, data: any, domain?: Domain): void { + if (!this.canHandle(experiment.algorithm.name)) + return super.handle(experiment, data, domain); + + const tableModel = this.getTable(data); + + if (tableModel) experiment.results.push(tableModel); + } +} diff --git a/api/src/engine/connectors/exareme/handlers/algorithms/ttest-paired.handler.spec.ts b/api/src/engine/connectors/exareme/handlers/algorithms/ttest-paired.handler.spec.ts index d0267143776d0dee332e5c7b7b5655d6c655390e..b1e0629051c6a34941173ec2d56eb04b47560045 100644 --- a/api/src/engine/connectors/exareme/handlers/algorithms/ttest-paired.handler.spec.ts +++ b/api/src/engine/connectors/exareme/handlers/algorithms/ttest-paired.handler.spec.ts @@ -41,15 +41,15 @@ describe('T-Test Paired handler', () => { const table = experiment.results[0] as TableResult; - expect(experiment.results.length === 1); - expect(table.data.length === 7); + expect(experiment.results.length).toBe(1); + expect(table.data.length).toBe(8); }); it('Should be empty with another algo', () => { experiment.algorithm.name = 'dummy_algo'; tTestPairedHandler.handle(experiment, data); - expect(experiment.results.length === 0); + expect(experiment.results.length).toBe(0); }); }); }); diff --git a/api/src/engine/connectors/exareme/handlers/algorithms/ttest-paired.handler.ts b/api/src/engine/connectors/exareme/handlers/algorithms/ttest-paired.handler.ts index e04ccb7cfb847cd9f77e81b1c2c32930be64304f..f7196ee295154f399f64c888d5228424f9403f54 100644 --- a/api/src/engine/connectors/exareme/handlers/algorithms/ttest-paired.handler.ts +++ b/api/src/engine/connectors/exareme/handlers/algorithms/ttest-paired.handler.ts @@ -50,7 +50,8 @@ export default class TTestPairedHandler extends BaseHandler { } handle(experiment: Experiment, data: any, domain?: Domain): void { - if (!this.canHandle) return super.handle(experiment, data, domain); + if (!this.canHandle(experiment.algorithm.name)) + return super.handle(experiment, data, domain); const tableModel = this.getTable(data);