diff --git a/api/src/engine/connectors/datashield/assets/SOPHIA_logo.png b/api/src/engine/connectors/datashield/assets/SOPHIA_logo.png deleted file mode 100644 index f6eb8e35ce3cb90fe7588eb7ee73d8321360f449..0000000000000000000000000000000000000000 Binary files a/api/src/engine/connectors/datashield/assets/SOPHIA_logo.png and /dev/null differ diff --git a/api/src/engine/connectors/datashield/main.connector.ts b/api/src/engine/connectors/datashield/main.connector.ts index 4451989fa7dbf3220832d9f5cab8bddcf1a0c29e..81f7bf6bb6ecba86cba15b2350d460e57dadf933 100644 --- a/api/src/engine/connectors/datashield/main.connector.ts +++ b/api/src/engine/connectors/datashield/main.connector.ts @@ -20,7 +20,10 @@ import { ExperimentCreateInput } from 'src/engine/models/experiment/input/experi import { ExperimentEditInput } from 'src/engine/models/experiment/input/experiment-edit.input'; import { ListExperiments } from 'src/engine/models/experiment/list-experiments.model'; import { RawResult } from 'src/engine/models/result/raw-result.model'; -import { TableResult } from 'src/engine/models/result/table-result.model'; +import { + TableResult, + ThemeType, +} from 'src/engine/models/result/table-result.model'; import { transformToDomains, transformToHisto, @@ -60,12 +63,12 @@ export default class DataShieldService implements IEngineService { }), ); - if (response.data['breaks'] === undefined) { + if (response.data['global'] === undefined) { DataShieldService.logger.warn('Inconsistency on histogram result'); DataShieldService.logger.verbose(path); return { rawdata: { - data: response.data[0], + data: 'Engine result are inconsitent', type: MIME_TYPES.ERROR, }, }; @@ -73,6 +76,7 @@ export default class DataShieldService implements IEngineService { const title = variable.replace(/\./g, ' ').trim(); const data = { ...response.data, title }; + const chart = transformToHisto.evaluate(data); return { @@ -96,7 +100,11 @@ export default class DataShieldService implements IEngineService { const title = variable.replace(/\./g, ' ').trim(); const data = { ...response.data, title }; - return transformToTable.evaluate(data); + const table = transformToTable.evaluate(data); + return { + ...table, + theme: ThemeType.NORMAL, + }; } async createExperiment( @@ -164,16 +172,16 @@ export default class DataShieldService implements IEngineService { } async getDomains(): Promise<Domain[]> { - const path = this.options.baseurl + 'start'; + const loginPath = this.options.baseurl + 'login'; - const response = await firstValueFrom( - this.httpService.get(path, { + const loginData = await firstValueFrom( + this.httpService.get(loginPath, { auth: { username: 'guest', password: 'guest123' }, }), ); - if (response.headers && response.headers['set-cookie']) { - const cookies = response.headers['set-cookie'] as string[]; + const cookies = (loginData.headers['set-cookie'] as string[]) ?? []; + if (loginData.headers && loginData.headers['set-cookie']) { cookies.forEach((cookie) => { const [key, value] = cookie.split(/={1}/); this.req.res.cookie(key, value, { @@ -183,6 +191,16 @@ export default class DataShieldService implements IEngineService { }); } + const path = this.options.baseurl + 'getvars'; + + const response = await firstValueFrom( + this.httpService.get(path, { + headers: { + cookie: cookies.join(';'), + }, + }), + ); + return [transformToDomains.evaluate(response.data)]; } diff --git a/api/src/engine/connectors/datashield/tests/histograms.spec.ts b/api/src/engine/connectors/datashield/tests/histograms.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..32761b5dd37b39813e41e46cecb24dd3ac700246 --- /dev/null +++ b/api/src/engine/connectors/datashield/tests/histograms.spec.ts @@ -0,0 +1,25 @@ +// query /histogram?var=Alanine.aminotransferase..Enzymatic.activity.volume..in.Serum.or.Plasma&type=combine + +export {}; + +const data = { + global: { + breaks: [ + 1.9766, 15.083, 28.1893, 41.2957, 54.4021, 67.5085, 80.6149, 93.7212, + 106.8276, 119.934, 133.0404, + ], + counts: [69, 388, 74, 17, 10, 0, 0, 0, 0, 0], + density: [0.0093, 0.0526, 0.0104, 0.0023, 0.0014, 0, 0, 0, 0, 0], + mids: [ + 8.5298, 21.6361, 34.7425, 47.8489, 60.9553, 74.0617, 87.168, 100.2744, + 113.3808, 126.4872, + ], + xname: 'xvect', + equidist: true, + intensities: [0.0093, 0.0526, 0.0104, 0.0023, 0.0014, 0, 0, 0, 0, 0], + }, +}; + +describe('Histograms', () => { + test.todo('TODO'); +}); diff --git a/api/src/engine/connectors/datashield/tests/quantiles.spec.ts b/api/src/engine/connectors/datashield/tests/quantiles.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..b2e3eea2b0a731b216135e5d2e4ad537c304fb41 --- /dev/null +++ b/api/src/engine/connectors/datashield/tests/quantiles.spec.ts @@ -0,0 +1,41 @@ +// query : quantiles?var=Alanine.aminotransferase..Enzymatic.activity.volume..in.Serum.or.Plasma&type=split + +export {}; + +const data = { + 'omop_test.db': { + '5%': 14.175, + '10%': 16, + '25%': 17.3, + '50%': 20.8, + '75%': 23.85, + '90%': 36.75, + '95%': 42.775, + Mean: 22.5667, + }, + 'test.db': { + '5%': 14.305, + '10%': 14.9, + '25%': 16.7, + '50%': 21.05, + '75%': 24.15, + '90%': 35.4, + '95%': 40.76, + Mean: 22.9203, + }, + 'sophia.db': { + '5%': 17.05, + '10%': 20.5, + '25%': 21, + '50%': 22.4, + '75%': 24.775, + '90%': 36.37, + '95%': 43.79, + Mean: 25.5347, + }, + title: 'test', +}; + +describe('Quantiles', () => { + test.todo('TODO'); +}); diff --git a/api/src/engine/connectors/datashield/transformations.ts b/api/src/engine/connectors/datashield/transformations.ts index 2f31ab278d897eb7bab1106a6b84a2f49290ff4c..0a664d3809e96135fb5a7b711f874a4cef9bd31a 100644 --- a/api/src/engine/connectors/datashield/transformations.ts +++ b/api/src/engine/connectors/datashield/transformations.ts @@ -31,83 +31,50 @@ export const transformToDomains = jsonata(` export const transformToHisto = jsonata(` ( - $nbBreaks := $count(breaks); + $nbBreaks := $count(global.breaks); + $params := ["counts"]; - { - "chart": { - "type": 'column' - }, - "legend": { - "enabled": false - }, - "series": [ - { - "data": counts, - "dataLabels": { - "enabled": true - } - } - ], - "title": { - "text": title ? title : '' - }, - "tooltip": { - "enabled": true - }, - "xAxis": { - "categories": breaks#$i[$i < $nbBreaks-1].[$ & ' - ' & %.*[$i+1]] - }, - "yAxis": { - "min": 0, - "minRange": 0.1, - "allowDecimals": true - } + { + "chart": { + "type": 'column' + }, + "legend": { + "enabled": false + }, + "series": global.$each(function ($v, $k) { + $k in $params ? { + "name": $k, + "data": $v + } : undefined + })[], + "title": { + "text": title ? title : '' + }, + "tooltip": { + "enabled": true + }, + "xAxis": { + "categories": global.breaks#$i[$i < $nbBreaks-1].[$ & ' - ' & %.*[$i+1]] + }, + "yAxis": { + "min": 0, + "minRange": 0.1, + "allowDecimals": true + } }) `); export const transformToTable = jsonata(` -{ - "name": "Descriptive Statistics", - "headers": $append(title, ['5%','10%','25%','50%','75%','90%','95%','Mean']).{ - "name": $, - "type": "string" - }, - "data": $.message.$each(function($v, $k) { - $append($k,$v) - }) -} -`); - -/*export const transformToTable = jsonata(` -( - $params := ["xname", "equidist", "breaks"]; - $concat := function($i, $j) { - $append($i, $j) - }; - - { - "name": "test", - "headers": $append('', $.*[0].breaks).{ - "name": $, - "type": "string" - }, - "data": $.$each(function($v, $k) { - [[$k],$v.$each(function($v, $k) {$not($k in $params) ? $append($k, $v) : undefined})] - }) ~> $reduce($concat, []) - } -) -`);*/ - -/* export const transformToTable = jsonata(` ( - $params := ["xname", "equidist", "breaks"]; - - $.$each(function($v, $k) { - { - "name": $k, - "headers": $v.breaks, - "data": $v.$each(function($v, $k) {$not($k in $params) ? $append($k, $v) : undefined}) - } - }) -) -`); */ + $params := ["title"]; + { + "name": "Descriptive Statistics", + "headers": $append(title, ['5%','10%','25%','50%','75%','90%','95%','Mean']).{ + "name": $, + "type": "string" + }, + "data": $.$each(function($v, $k) { + $not($k in $params) ? $append($k,$v.*) : undefined + }) +}) +`); diff --git a/api/src/engine/models/result/table-result.model.ts b/api/src/engine/models/result/table-result.model.ts index 002d59c5b15ce974e56bc9a9b0d9272212961c31..664d64c2e823aa2c37b9d98fd345af6cced24d66 100644 --- a/api/src/engine/models/result/table-result.model.ts +++ b/api/src/engine/models/result/table-result.model.ts @@ -1,7 +1,16 @@ -import { Field, ObjectType } from '@nestjs/graphql'; +import { Field, ObjectType, registerEnumType } from '@nestjs/graphql'; import { Header } from './common/header.model'; import { Result } from './common/result.model'; +export enum ThemeType { + DEFAULT, + NORMAL, +} + +registerEnumType(ThemeType, { + name: 'ThemeType', +}); + @ObjectType() export class TableResult extends Result { @Field() @@ -12,4 +21,7 @@ export class TableResult extends Result { @Field(() => [Header]) headers: Header[]; + + @Field(() => ThemeType, { defaultValue: ThemeType.DEFAULT }) + theme?: ThemeType; } diff --git a/api/src/schema.gql b/api/src/schema.gql index b8935c5dc2eb1b36888b27187445faca6f9912c1..9fb8aadc4ad75433fbaa7215ecde5afe71110e58 100644 --- a/api/src/schema.gql +++ b/api/src/schema.gql @@ -82,6 +82,12 @@ type TableResult { name: String! data: [[String!]!]! headers: [Header!]! + theme: ThemeType! +} + +enum ThemeType { + DEFAULT + NORMAL } type RawResult {