@sjcrh/proteinpaint-server 2.37.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 +2 -2
- package/routes/termdb.getdescrstats.ts +145 -0
- package/routes/termdb.singlecellSamples.ts +1 -0
- package/server.js +1 -1
- package/server.js.map +1 -1
- package/utils/cuminc.R +3 -4
- package/utils/{fastclust.R → hclust.R} +64 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sjcrh/proteinpaint-server",
|
|
3
|
-
"version": "2.
|
|
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.
|
|
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 = {
|