diff --git a/api/src/engine/connectors/exareme/handlers/algorithms/pearson.handler.spec.ts b/api/src/engine/connectors/exareme/handlers/algorithms/pearson.handler.spec.ts index 1ec54c8b8c69ebae7d7b00262e6b772ff28054d6..1fe22eb459b05e20e97085b69271330bf2431428 100644 --- a/api/src/engine/connectors/exareme/handlers/algorithms/pearson.handler.spec.ts +++ b/api/src/engine/connectors/exareme/handlers/algorithms/pearson.handler.spec.ts @@ -1,4 +1,4 @@ -import { HeatMapResult } from 'src/engine/models/result/heat-map-result.model'; +import { Domain } from '../../../../models/domain.model'; import handlers from '..'; import { Experiment } from '../../../../models/experiment/experiment.model'; import PearsonHandler from './pearson.handler'; @@ -42,8 +42,21 @@ const createExperiment = (): Experiment => ({ results: [], }); -describe('Pearson result handler', () => { - const data = { +const domain: Domain = { + id: 'dummy-id', + groups: [], + rootGroup: { + id: 'dummy-id', + }, + datasets: [{ id: 'desd-synthdata', label: 'Dead Synthdata' }], + variables: [ + { id: 'rightcerebralwhitematter', label: 'Example label' }, + { id: 'ppmicategory', label: 'Example label 2' }, + ], +}; + +const data = [ + { n_obs: 1840, correlations: { variables: [ @@ -413,24 +426,16 @@ describe('Pearson result handler', () => { 0.5096526209667468, 0.5533006654400224, ], }, - }; + }, +]; +describe('Pearson result handler', () => { it('Test pearson handler with regular data', () => { const exp = createExperiment(); - const names = [ - 'correlations', - 'p_values', - 'low_confidence_intervals', - 'high_confidence_intervals', - ]; - - handlers(exp, data, null); - const results = exp.results as HeatMapResult[]; - const heatmaps = names.map((name) => - results.find((it) => it.name === name), - ); + handlers(exp, data, domain); + const results = exp.results; - expect(heatmaps.length).toBeGreaterThanOrEqual(4); + expect(results.length).toBe(2); }); }); diff --git a/api/src/engine/connectors/exareme/handlers/algorithms/pearson.handler.ts b/api/src/engine/connectors/exareme/handlers/algorithms/pearson.handler.ts index cff25e2cf307aec468a7b050c33af97f646e02f0..efca443c52e7ff129313d416c8f1122e5a1d8ca0 100644 --- a/api/src/engine/connectors/exareme/handlers/algorithms/pearson.handler.ts +++ b/api/src/engine/connectors/exareme/handlers/algorithms/pearson.handler.ts @@ -1,16 +1,24 @@ import * as jsonata from 'jsonata'; // old import style needed due to 'export = jsonata' import { Expression } from 'jsonata'; -import { Domain } from 'src/engine/models/domain.model'; +import { formatNumber } from '../../../../../common/utils/shared.utils'; +import { Domain } from '../../../../models/domain.model'; +import { + TableResult, + TableStyle, +} from '../../../../models/result/table-result.model'; import { Experiment } from '../../../../models/experiment/experiment.model'; import { HeatMapResult } from '../../../../models/result/heat-map-result.model'; import BaseHandler from '../base.handler'; +type Lookup = { + [key: string]: string; +}; export default class PearsonHandler extends BaseHandler { public static readonly ALGO_NAME = 'pearson_correlation'; private static readonly transform: Expression = jsonata(` ( - $params := ['correlations', 'p_values', 'ci_lo', 'ci_hi']; + $params := ['correlations']; $dictName := { "correlations": "Correlations", "p_values": "P values", @@ -22,16 +30,58 @@ export default class PearsonHandler extends BaseHandler { { 'name': $lookup($dictName, $k), 'xAxis': { - 'categories': $v.variables + 'categories': $v.variables.($lookup($$.lookupVars, $)) }, 'yAxis': { - 'categories': $reverse($v.variables) + 'categories': $reverse($keys($v.$sift(function($val, $key) {$key ~> /^(?!variables$)/}))).($lookup($$.lookupVars, $)) }, 'matrix': $v.$sift(function($val, $key) {$key ~> /^(?!variables$)/}).$each(function($val, $key) {$val})[] } - }) + })[] )`); + private getTableResult(data: any, lookup: Lookup): TableResult { + const elements = [...data['correlations']['variables']]; + const keys = [ + ...Object.keys(data['correlations']).filter((k) => k !== 'variables'), + ]; + const tableData = []; + const doneMap = {}; + + while (keys.length > 0) { + const key = keys.shift(); + elements.forEach((elem, i) => { + const token = [key, elem].sort().join(); + if (elem === key || doneMap[token]) return; + doneMap[token] = true; + tableData.push([ + lookup[key] ?? key, + lookup[elem] ?? elem, + formatNumber(data['correlations'][key][i]), + formatNumber(data['p_values'][key][i]), + formatNumber(data['ci_lo'][key][i]), + formatNumber(data['ci_hi'][key][i]), + ]); + }); + } + + const tableResult: TableResult = { + name: 'Pearson summary', + tableStyle: TableStyle.DEFAULT, + headers: [ + { name: 'Variable 1', type: 'string' }, + { name: 'Variable 2', type: 'string' }, + { name: 'Correlation', type: 'string' }, + { name: 'P value', type: 'string' }, + { name: 'Low CI', type: 'string' }, + { name: 'High CI', type: 'string' }, + ], + data: tableData, + }; + + return tableResult; + } + /** * This function returns true if the algorithm is Pearson. * @param {string} algorithm - The name of the algorithm to use. @@ -53,6 +103,22 @@ export default class PearsonHandler extends BaseHandler { const extData = data[0]; + const varIds = [...exp.variables, ...(exp.coVariables ?? [])]; + const lookup: Lookup = varIds.reduce((acc, curr) => { + acc[curr] = curr; + return acc; + }, {}); // fallback to original ids if domain is empty + + domain.variables + .filter((v) => varIds.includes(v.id)) + .forEach((v) => { + lookup[v.id] = v.label ?? v.id; + }); + + extData.lookupVars = lookup; + const tableResult = this.getTableResult(extData, lookup); + if (tableResult.data.length > 0) exp.results.push(tableResult); + const results = PearsonHandler.transform.evaluate( extData, ) as HeatMapResult[];