@sjcrh/proteinpaint-server 2.36.0 → 2.38.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjcrh/proteinpaint-server",
3
- "version": "2.36.0",
3
+ "version": "2.38.0",
4
4
  "description": "a genomics visualization tool for exploring a cohort's genotype and phenotype data",
5
5
  "main": "server.js",
6
6
  "bin": "start.js",
@@ -57,7 +57,7 @@
57
57
  },
58
58
  "dependencies": {
59
59
  "@sjcrh/augen": "2.35.0",
60
- "@sjcrh/proteinpaint-rust": "2.34.0",
60
+ "@sjcrh/proteinpaint-rust": "2.38.0",
61
61
  "better-sqlite3": "^7.5.3",
62
62
  "body-parser": "^1.15.2",
63
63
  "canvas": "~2.9.3",
@@ -0,0 +1,145 @@
1
+ // import { getdescrstatsRequest, getdescrstatsResponse } from '#shared/types/routes/termdb.descrstats'
2
+ import roundValue from '#shared/roundValue.js'
3
+ import computePercentile from '#shared/compute.percentile.js'
4
+ import * as termdbsql from '#src/termdb.sql.js'
5
+
6
+ export const api: any = {
7
+ endpoint: 'termdb/descrstats',
8
+ methods: {
9
+ get: {
10
+ init,
11
+ request: {
12
+ typeId: 'getdescrstatsRequest'
13
+ },
14
+ response: {
15
+ typeId: 'getdescrstatsResponse'
16
+ },
17
+ examples: [
18
+ {
19
+ request: {
20
+ body: {
21
+ genome: 'hg38-test',
22
+ dslabel: 'TermdbTest',
23
+ embedder: 'localhost',
24
+ getdescrstats: 1,
25
+ tid: 'hrtavg',
26
+ filter: {
27
+ type: 'tvslst',
28
+ in: true,
29
+ join: '',
30
+ lst: [
31
+ {
32
+ tag: 'cohortFilter',
33
+ type: 'tvs',
34
+ tvs: {
35
+ term: {
36
+ name: 'Cohort',
37
+ type: 'categorical',
38
+ values: { ABC: { label: 'ABC' }, XYZ: { label: 'XYZ' } },
39
+ id: 'subcohort',
40
+ isleaf: false,
41
+ groupsetting: { disabled: true }
42
+ },
43
+ values: [{ key: 'ABC', label: 'ABC' }]
44
+ }
45
+ }
46
+ ]
47
+ }
48
+ }
49
+ },
50
+ response: {
51
+ header: { status: 200 }
52
+ }
53
+ }
54
+ ]
55
+ },
56
+ post: {
57
+ alternativeFor: 'get',
58
+ init
59
+ }
60
+ }
61
+ }
62
+
63
+ function init({ genomes }) {
64
+ return async (req: any, res: any): Promise<void> => {
65
+ const q = req.query // as getdescrstatsRequest
66
+ try {
67
+ const g = genomes[req.query.genome]
68
+ if (!g) throw 'invalid genome name'
69
+ const ds = g.datasets[req.query.dslabel]
70
+ if (!ds) throw 'invalid dataset name'
71
+ const tdb = ds.cohort.termdb
72
+ if (!tdb) throw 'invalid termdb object'
73
+
74
+ await trigger_getdescrstats(q, res, ds) // as getdescrstatsResponse
75
+ } catch (e) {
76
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
77
+ // @ts-ignore
78
+ res.send({ error: e?.message || e })
79
+ if (e instanceof Error && e.stack) console.log(e)
80
+ }
81
+ }
82
+ }
83
+
84
+ async function trigger_getdescrstats(q: any, res: any, ds: any) {
85
+ const term = ds.cohort.termdb.q.termjsonByOneid(q.tid)
86
+ if (!term) throw 'invalid termid'
87
+ if (term.type != 'float' && term.type != 'integer') throw 'not numerical term'
88
+ const rows = await termdbsql.get_rows_by_one_key({
89
+ ds,
90
+ key: q.tid,
91
+ filter: q.filter ? (typeof q.filter == 'string' ? JSON.parse(q.filter) : q.filter) : null
92
+ })
93
+ const values: number[] = []
94
+ for (const { value } of rows) {
95
+ if (term.values && term.values[value] && term.values[value].uncomputable) {
96
+ // skip uncomputable values
97
+ continue
98
+ }
99
+ //skip computing for zeros if scale is log.
100
+ if (q.settings?.violin?.unit === 'log') {
101
+ if (value === 0) {
102
+ continue
103
+ }
104
+ }
105
+ values.push(value)
106
+ }
107
+
108
+ // compute statistics
109
+ // total
110
+ const total = values.length
111
+
112
+ // mean
113
+ const sum = values.reduce((a, b) => a + b, 0)
114
+ const mean = sum / total
115
+
116
+ // percentiles
117
+ const p25 = computePercentile(values, 25)
118
+ const median = computePercentile(values, 50)
119
+ const p75 = computePercentile(values, 75)
120
+
121
+ // standard deviation
122
+ // get sum of squared differences from mean
123
+ const sumSqDiff = values.map(v => (v - mean) ** 2).reduce((a, b) => a + b, 0)
124
+ // get variance
125
+ const variance = sumSqDiff / (values.length - 1)
126
+ // get standard deviation
127
+ const sd = Math.sqrt(variance)
128
+
129
+ // min/max
130
+ const min = Math.min(...values)
131
+ const max = Math.max(...values)
132
+
133
+ res.send({
134
+ values: [
135
+ { id: 'total', label: 'n', value: total },
136
+ { id: 'min', label: 'Minimum', value: roundValue(min, 2) },
137
+ { id: 'p25', label: '1st quartile', value: roundValue(p25, 2) },
138
+ { id: 'median', label: 'Median', value: roundValue(median, 2) },
139
+ { id: 'mean', label: 'Mean', value: roundValue(mean, 2) },
140
+ { id: 'p75', label: '3rd quartile', value: roundValue(p75, 2) },
141
+ { id: 'max', label: 'Maximum', value: roundValue(max, 2) },
142
+ { id: 'sd', label: 'Standard deviation', value: roundValue(sd, 2) }
143
+ ]
144
+ })
145
+ }
@@ -51,6 +51,7 @@ function init({ genomes }) {
51
51
  if (!ds) throw 'invalid dataset name'
52
52
  if (!ds.queries?.singleCell) throw 'no singlecell data on this dataset'
53
53
  result = (await ds.queries.singleCell.samples.get(q)) as TermdbSinglecellsamplesResponse
54
+ result.sameLegend = ds.queries.singleCell.samples.sameLegend
54
55
  } catch (e: any) {
55
56
  if (e.stack) console.log(e.stack)
56
57
  result = {
@@ -1,32 +1,17 @@
1
- // import { gettermbyidRequest, gettermbyidResponse } from '#shared/types/routes/termdb.termbyid'
1
+ import { gettermsbyidsRequest, gettermsbyidsResponse } from '#shared/types/routes/termdb.termsbyids.js'
2
2
  import { copy_term } from '#src/termdb.js'
3
3
 
4
4
  export const api: any = {
5
- endpoint: 'termdb/termbyid',
5
+ endpoint: 'termdb/termsbyids',
6
6
  methods: {
7
7
  get: {
8
8
  init,
9
9
  request: {
10
- typeId: 'gettermbyidRequest'
10
+ typeId: 'gettermsbyidsRequest'
11
11
  },
12
12
  response: {
13
- typeId: 'gettermbyidResponse'
14
- },
15
- examples: [
16
- {
17
- request: {
18
- body: {
19
- genome: 'hg38-test',
20
- dslabel: 'TermdbTest',
21
- embedder: 'localhost',
22
- gettermbyid: 'subcohort'
23
- }
24
- },
25
- response: {
26
- header: { status: 200 }
27
- }
28
- }
29
- ]
13
+ typeId: 'gettermsbyidsResponse'
14
+ }
30
15
  },
31
16
  post: {
32
17
  alternativeFor: 'get',
@@ -46,7 +31,7 @@ function init({ genomes }) {
46
31
  const tdb = ds.cohort.termdb
47
32
  if (!tdb) throw 'invalid termdb object'
48
33
 
49
- await trigger_gettermbyid(q, res, tdb) // as getcategoriesResponse
34
+ await trigger_gettermsbyid(q, res, tdb) // as getcategoriesResponse
50
35
  } catch (e) {
51
36
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
52
37
  // @ts-ignore
@@ -56,13 +41,23 @@ function init({ genomes }) {
56
41
  }
57
42
  }
58
43
 
59
- async function trigger_gettermbyid(
60
- q: { gettermbyid: any },
61
- res: { send: (arg0: { term: any }) => void },
44
+ async function trigger_gettermsbyid(
45
+ q: { ids: any },
46
+ res: { send: (arg0: { terms: any }) => void },
62
47
  tdb: { q: { termjsonByOneid: (arg0: any) => any } }
63
48
  ) {
64
- const t = tdb.q.termjsonByOneid(q.gettermbyid)
49
+ const terms = {}
50
+ for (const id of q.ids) {
51
+ const term = tdb.q.termjsonByOneid(id)
52
+ if (term) {
53
+ if (term.type == 'categorical' && !term.values && !term.groupsetting?.inuse) {
54
+ term.values = {}
55
+ term.samplecount = {}
56
+ }
57
+ }
58
+ terms[id] = term ? copy_term(term) : undefined
59
+ }
65
60
  res.send({
66
- term: t ? copy_term(t) : undefined
61
+ terms
67
62
  })
68
63
  }