@sjcrh/proteinpaint-server 2.28.0 → 2.29.1
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 +1 -1
- package/routes/termdb.categories.ts +212 -0
- package/server.js +1 -1
- package/routes/termdb.getCategories.ts +0 -80
package/package.json
CHANGED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// import { getcategoriesRequest, getcategoriesResponse } from '#shared/types/routes/termdb.categories'
|
|
2
|
+
import { getOrderedLabels } from '#src/termdb.barchart.js'
|
|
3
|
+
import { getData } from '#src/termdb.matrix.js'
|
|
4
|
+
|
|
5
|
+
export const api: any = {
|
|
6
|
+
endpoint: 'termdb/categories',
|
|
7
|
+
methods: {
|
|
8
|
+
get: {
|
|
9
|
+
init,
|
|
10
|
+
request: {
|
|
11
|
+
typeId: 'getcategoriesRequest'
|
|
12
|
+
},
|
|
13
|
+
response: {
|
|
14
|
+
typeId: 'getcategoriesResponse'
|
|
15
|
+
},
|
|
16
|
+
examples: [
|
|
17
|
+
{
|
|
18
|
+
request: {
|
|
19
|
+
body: {
|
|
20
|
+
genome: 'hg38-test',
|
|
21
|
+
dslabel: 'TermdbTest',
|
|
22
|
+
embedder: 'localhost',
|
|
23
|
+
getcategories: 1,
|
|
24
|
+
tid: 'diaggrp',
|
|
25
|
+
filter: {
|
|
26
|
+
type: 'tvslst',
|
|
27
|
+
in: true,
|
|
28
|
+
join: '',
|
|
29
|
+
lst: [
|
|
30
|
+
{
|
|
31
|
+
tag: 'cohortFilter',
|
|
32
|
+
type: 'tvs',
|
|
33
|
+
tvs: {
|
|
34
|
+
term: {
|
|
35
|
+
name: 'Cohort',
|
|
36
|
+
type: 'categorical',
|
|
37
|
+
values: { ABC: { label: 'ABC' }, XYZ: { label: 'XYZ' } },
|
|
38
|
+
id: 'subcohort',
|
|
39
|
+
isleaf: false,
|
|
40
|
+
groupsetting: { disabled: true }
|
|
41
|
+
},
|
|
42
|
+
values: [{ key: 'ABC', label: 'ABC' }]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
response: {
|
|
50
|
+
header: { status: 200 }
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
post: {
|
|
56
|
+
alternativeFor: 'get',
|
|
57
|
+
init
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function init({ genomes }) {
|
|
63
|
+
return async (req: any, res: any): Promise<void> => {
|
|
64
|
+
const q = req.query // as getcategoriesRequest
|
|
65
|
+
try {
|
|
66
|
+
const g = genomes[req.query.genome]
|
|
67
|
+
const ds = g.datasets[req.query.dslabel]
|
|
68
|
+
const tdb = ds.cohort.termdb
|
|
69
|
+
|
|
70
|
+
if (!g) throw 'invalid genome name'
|
|
71
|
+
if (!ds) throw 'invalid dataset name'
|
|
72
|
+
if (!tdb) throw 'invalid termdb object'
|
|
73
|
+
await trigger_getcategories(q, res, tdb, ds, g) // as getcategoriesResponse
|
|
74
|
+
} catch (e) {
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
76
|
+
// @ts-ignore
|
|
77
|
+
res.send({ error: e?.message || e })
|
|
78
|
+
if (e instanceof Error && e.stack) console.log(e)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function trigger_getcategories(q, res, tdb, ds, genome) {
|
|
84
|
+
// thin wrapper of get_summary
|
|
85
|
+
// works for all types of terms
|
|
86
|
+
if (!q.tid) throw '.tid missing'
|
|
87
|
+
const term =
|
|
88
|
+
q.type == 'geneVariant' ? { name: q.tid, type: 'geneVariant', isleaf: true } : tdb.q.termjsonByOneid(q.tid)
|
|
89
|
+
const arg = {
|
|
90
|
+
filter: q.filter,
|
|
91
|
+
terms:
|
|
92
|
+
q.type == 'geneVariant'
|
|
93
|
+
? [{ term: term, q: { isAtomic: true } }]
|
|
94
|
+
: [{ id: q.tid, term, q: q.term1_q || getDefaultQ(term, q) }],
|
|
95
|
+
currentGeneNames: q.currentGeneNames
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const data = await getData(arg, ds, genome)
|
|
99
|
+
if (data.error) throw data.error
|
|
100
|
+
|
|
101
|
+
const lst = []
|
|
102
|
+
if (q.type == 'geneVariant') {
|
|
103
|
+
const samples = data.samples
|
|
104
|
+
const dtClassMap = new Map()
|
|
105
|
+
if (ds.assayAvailability?.byDt) {
|
|
106
|
+
for (const [dtType, dtValue] of Object.entries(ds.assayAvailability.byDt)) {
|
|
107
|
+
if (dtValue.byOrigin) {
|
|
108
|
+
dtClassMap.set(parseInt(dtType), { byOrigin: { germline: {}, somatic: {} } })
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const sampleCountedFor = new Set() // if the sample is conunted for the
|
|
113
|
+
for (const [sampleId, sampleData] of Object.entries(samples)) {
|
|
114
|
+
const values = sampleData[q.tid].values
|
|
115
|
+
sampleCountedFor.clear()
|
|
116
|
+
/* values here is an array of result entires, one or more entries for each dt. e.g.
|
|
117
|
+
[
|
|
118
|
+
{ dt: 1, class: 'Blank', _SAMPLEID_: 1, origin: 'germline' },
|
|
119
|
+
{ dt: 1, class: 'WT', _SAMPLEID_: 1, origin: 'somatic' },
|
|
120
|
+
{ dt: 2, class: 'Blank', _SAMPLEID_: 1 },
|
|
121
|
+
{ dt: 4, class: 'WT', _SAMPLEID_: 1 }
|
|
122
|
+
]
|
|
123
|
+
*/
|
|
124
|
+
for (const value of values) {
|
|
125
|
+
if (!dtClassMap.has(value.dt)) {
|
|
126
|
+
dtClassMap.set(value.dt, {})
|
|
127
|
+
}
|
|
128
|
+
const dtClasses = dtClassMap.get(value.dt)
|
|
129
|
+
if (dtClasses.byOrigin) {
|
|
130
|
+
if (!dtClasses.byOrigin[value.origin][value.class]) {
|
|
131
|
+
dtClasses.byOrigin[value.origin][value.class] = 1
|
|
132
|
+
sampleCountedFor.add(`${value.dt} ${value.origin} ${value.class}`)
|
|
133
|
+
}
|
|
134
|
+
if (!sampleCountedFor.has(`${value.dt} ${value.origin} ${value.class}`)) {
|
|
135
|
+
sampleCountedFor.add(`${value.dt} ${value.origin} ${value.class}`)
|
|
136
|
+
dtClasses.byOrigin[value.origin][value.class] += 1
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
if (!dtClasses[value.class]) {
|
|
140
|
+
sampleCountedFor.add(`${value.dt} ${value.class}`)
|
|
141
|
+
dtClasses[value.class] = 1
|
|
142
|
+
}
|
|
143
|
+
if (!sampleCountedFor.has(`${value.dt} ${value.class}`)) {
|
|
144
|
+
sampleCountedFor.add(`${value.dt} ${value.class}`)
|
|
145
|
+
dtClasses[value.class] += 1
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
for (const [dt, classes] of dtClassMap) {
|
|
151
|
+
lst.push({
|
|
152
|
+
dt,
|
|
153
|
+
classes
|
|
154
|
+
})
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
const key2count = new Map()
|
|
158
|
+
// k: category key
|
|
159
|
+
// v: number of samples
|
|
160
|
+
for (const sid in data.samples) {
|
|
161
|
+
const v = data.samples[sid][q.tid]
|
|
162
|
+
if (!v) continue
|
|
163
|
+
if (!('key' in v)) continue
|
|
164
|
+
key2count.set(v.key, 1 + (key2count.get(v.key) || 0))
|
|
165
|
+
}
|
|
166
|
+
for (const [key, count] of key2count) {
|
|
167
|
+
lst.push({
|
|
168
|
+
samplecount: count,
|
|
169
|
+
key,
|
|
170
|
+
label:
|
|
171
|
+
data.refs?.byTermId?.[q.tid]?.events?.find(e => e.event === key).label || term?.values?.[key]?.label || key
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const orderedLabels = getOrderedLabels(
|
|
177
|
+
term,
|
|
178
|
+
data.refs?.byTermId?.[q.tid]?.bins || [],
|
|
179
|
+
data.refs?.byTermId?.[q.tid]?.events,
|
|
180
|
+
q.term1_q
|
|
181
|
+
)
|
|
182
|
+
if (orderedLabels.length) {
|
|
183
|
+
lst.sort((a, b) => orderedLabels.indexOf(a.label) - orderedLabels.indexOf(b.label))
|
|
184
|
+
}
|
|
185
|
+
res.send({
|
|
186
|
+
lst,
|
|
187
|
+
orderedLabels
|
|
188
|
+
})
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function getDefaultQ(term, q) {
|
|
192
|
+
if (term.type == 'categorical') return {}
|
|
193
|
+
if (term.type == 'survival') return {}
|
|
194
|
+
if (term.type == 'integer' || term.type == 'float') return term.bins.default
|
|
195
|
+
if (term.type == 'condition') {
|
|
196
|
+
return {
|
|
197
|
+
mode: q.mode,
|
|
198
|
+
breaks: q.breaks,
|
|
199
|
+
bar_by_grade: q.bar_by_grade,
|
|
200
|
+
/*Leave this here until bug with term1_q not passing to getCategories is figured out.
|
|
201
|
+
Commented out b/c tvs condition tests fail.*/
|
|
202
|
+
//bar_by_children: term.subconditions || q.bar_by_children,
|
|
203
|
+
bar_by_children: q.bar_by_children,
|
|
204
|
+
value_by_max_grade: q.value_by_max_grade,
|
|
205
|
+
value_by_most_recent: q.value_by_most_recent,
|
|
206
|
+
//value_by_computable_grade: term.subconditions || q.value_by_computable_grade
|
|
207
|
+
value_by_computable_grade: q.value_by_computable_grade
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (term.type == 'geneVariant') return {}
|
|
211
|
+
throw 'unknown term type'
|
|
212
|
+
}
|