@sjcrh/proteinpaint-server 2.44.0 → 2.46.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/dataset/clinvar.hg19.js +53 -52
- package/dataset/clinvar.hg38.js +74 -73
- package/dataset/clinvar.js +164 -47
- package/dataset/termdb.test.js +257 -0
- package/genome/CriGri.js +1859 -27
- package/genome/cgc.js +743 -7
- package/genome/danRer10.js +1108 -46
- package/genome/dm3.js +71 -44
- package/genome/dm6.js +1926 -45
- package/genome/galGal5.js +23522 -46
- package/genome/galGal6.js +512 -46
- package/genome/hg19.js +293 -198
- package/genome/hg38.js +472 -105
- package/genome/hg38.test.js +406 -40
- package/genome/hgvirus.js +45 -20
- package/genome/mm10.js +135 -67
- package/genome/mm9.js +116 -79
- package/genome/rn6.js +1002 -47
- package/package.json +31 -35
- package/routes/_template_.js +30 -0
- package/routes/burden.js +149 -0
- package/routes/dataset.js +266 -0
- package/routes/dsdata.js +127 -0
- package/routes/gdc.maf.js +120 -0
- package/routes/gdc.mafBuild.js +106 -0
- package/routes/gdc.topMutatedGenes.js +465 -0
- package/routes/gene2canonicalisoform.js +41 -0
- package/routes/genelookup.js +52 -0
- package/routes/genomes.js +144 -0
- package/routes/healthcheck.js +30 -0
- package/routes/hicdata.js +98 -0
- package/routes/hicstat.js +55 -0
- package/routes/isoformlst.js +57 -0
- package/routes/ntseq.js +43 -0
- package/routes/pdomain.js +61 -0
- package/routes/snp.js +107 -0
- package/routes/termdb.categories.js +209 -0
- package/routes/termdb.cluster.js +228 -0
- package/routes/termdb.cohort.summary.js +38 -0
- package/routes/termdb.cohorts.js +49 -0
- package/routes/termdb.config.js +201 -0
- package/routes/termdb.getdescrstats.js +102 -0
- package/routes/termdb.getnumericcategories.js +92 -0
- package/routes/termdb.getpercentile.js +108 -0
- package/routes/termdb.getrootterm.js +65 -0
- package/routes/termdb.gettermchildren.js +67 -0
- package/routes/termdb.singleSampleMutation.js +80 -0
- package/routes/termdb.singlecellData.js +46 -0
- package/routes/termdb.singlecellSamples.js +160 -0
- package/routes/termdb.termsbyids.js +59 -0
- package/routes/termdb.topVariablyExpressedGenes.js +171 -0
- package/routes/termdb.violin.js +77 -0
- package/src/app.js +41498 -0
- package/src/serverconfig.js +14 -8
- package/start.js +3 -3
- package/routes/README.md +0 -84
- package/routes/burden.ts +0 -143
- package/routes/gdc.maf.ts +0 -195
- package/routes/gdc.mafBuild.ts +0 -114
- package/routes/gdc.topMutatedGenes.ts +0 -586
- package/routes/genelookup.ts +0 -50
- package/routes/healthcheck.ts +0 -29
- package/routes/hicdata.ts +0 -111
- package/routes/hicstat.ts +0 -55
- package/routes/termdb.categories.ts +0 -245
- package/routes/termdb.cluster.ts +0 -248
- package/routes/termdb.getdescrstats.ts +0 -102
- package/routes/termdb.getnumericcategories.ts +0 -99
- package/routes/termdb.getpercentile.ts +0 -118
- package/routes/termdb.getrootterm.ts +0 -73
- package/routes/termdb.gettermchildren.ts +0 -82
- package/routes/termdb.singleSampleMutation.ts +0 -87
- package/routes/termdb.singlecellData.ts +0 -49
- package/routes/termdb.singlecellSamples.ts +0 -175
- package/routes/termdb.termsbyids.ts +0 -63
- package/routes/termdb.topVariablyExpressedGenes.ts +0 -214
- package/routes/termdb.violin.ts +0 -77
- package/server.js +0 -2
- package/server.js.map +0 -1
- package/shared/common.js +0 -1080
- package/shared/termdb.initbinconfig.js +0 -96
- package/shared/vcf.js +0 -629
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import fs from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import { read_file } from '#src/utils.js'
|
|
4
|
-
import serverconfig from '#src/serverconfig.js'
|
|
5
|
-
import { SingleCellQuery, SingleCellSamplesNative, SingleCellDataNative } from '#shared/types/dataset.ts'
|
|
6
|
-
import {
|
|
7
|
-
Sample,
|
|
8
|
-
TermdbSinglecellsamplesRequest,
|
|
9
|
-
TermdbSinglecellsamplesResponse
|
|
10
|
-
} from '#shared/types/routes/termdb.singlecellSamples.ts'
|
|
11
|
-
import { Cell, Plot } from '#shared/types/routes/termdb.singlecellData.ts'
|
|
12
|
-
import { gdc_validate_query_singleCell_samples, gdc_validate_query_singleCell_data } from '#src/mds3.gdc.js'
|
|
13
|
-
|
|
14
|
-
/* route returns list of samples with sc data
|
|
15
|
-
this is due to the fact that sometimes not all samples in a dataset has sc data
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
export const api: any = {
|
|
19
|
-
endpoint: 'termdb/singlecellSamples',
|
|
20
|
-
methods: {
|
|
21
|
-
get: {
|
|
22
|
-
init,
|
|
23
|
-
request: {
|
|
24
|
-
typeId: 'TermdbSinglecellsamplesRequest'
|
|
25
|
-
},
|
|
26
|
-
response: {
|
|
27
|
-
typeId: 'TermdbSinglecellsamplesResponse'
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
post: {
|
|
31
|
-
alternativeFor: 'get',
|
|
32
|
-
init
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function init({ genomes }) {
|
|
38
|
-
return async (req: any, res: any): Promise<void> => {
|
|
39
|
-
const q = req.query as TermdbSinglecellsamplesRequest
|
|
40
|
-
let result
|
|
41
|
-
try {
|
|
42
|
-
const g = genomes[q.genome]
|
|
43
|
-
if (!g) throw 'invalid genome name'
|
|
44
|
-
const ds = g.datasets[q.dslabel]
|
|
45
|
-
if (!ds) throw 'invalid dataset name'
|
|
46
|
-
if (!ds.queries?.singleCell) throw 'no singlecell data on this dataset'
|
|
47
|
-
result = (await ds.queries.singleCell.samples.get(q)) as TermdbSinglecellsamplesResponse
|
|
48
|
-
} catch (e: any) {
|
|
49
|
-
if (e.stack) console.log(e.stack)
|
|
50
|
-
result = {
|
|
51
|
-
status: e.status || 400,
|
|
52
|
-
error: e.message || e
|
|
53
|
-
} as TermdbSinglecellsamplesResponse
|
|
54
|
-
}
|
|
55
|
-
res.send(result)
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/////////////////// ds query validator
|
|
60
|
-
export async function validate_query_singleCell(ds: any, genome: any) {
|
|
61
|
-
const q = ds.queries.singleCell as SingleCellQuery
|
|
62
|
-
if (!q) return
|
|
63
|
-
|
|
64
|
-
if (q.samples.src == 'gdcapi') {
|
|
65
|
-
gdc_validate_query_singleCell_samples(ds, genome)
|
|
66
|
-
} else if (q.samples.src == 'native') {
|
|
67
|
-
getSamplesNative(q.samples as SingleCellSamplesNative, ds)
|
|
68
|
-
} else {
|
|
69
|
-
throw 'unknown singleCell.samples.src'
|
|
70
|
-
}
|
|
71
|
-
// q.samples.get() added
|
|
72
|
-
|
|
73
|
-
if (q.data.src == 'gdcapi') {
|
|
74
|
-
gdc_validate_query_singleCell_data(ds, genome)
|
|
75
|
-
} else if (q.data.src == 'native') {
|
|
76
|
-
getDataNative(q.data as SingleCellDataNative, ds)
|
|
77
|
-
} else {
|
|
78
|
-
throw 'unknown singleCell.data.src'
|
|
79
|
-
}
|
|
80
|
-
// q.data.get() added
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async function getSamplesNative(S: SingleCellSamplesNative, ds: any) {
|
|
84
|
-
// for now use this quick fix method to pull sample ids annotated by this term
|
|
85
|
-
// to support situation where not all samples from a dataset has sc data
|
|
86
|
-
const isSamples = ds.cohort.termdb.q.getAllValues4term(S.isSampleTerm)
|
|
87
|
-
if (isSamples.size == 0) throw 'no samples found that are identified by isSampleTerm'
|
|
88
|
-
const samples = [] as any // array of samples with sc data to be sent to client and list in table; cannot use Sample type for the use of "sampleid" temp property
|
|
89
|
-
for (const sampleid of isSamples.keys()) {
|
|
90
|
-
if (isSamples.get(sampleid) == '1')
|
|
91
|
-
samples.push({
|
|
92
|
-
sample: ds.cohort.termdb.q.id2sampleName(sampleid), // string name for display
|
|
93
|
-
sampleid // temporarily kept to assign term value to each sample
|
|
94
|
-
})
|
|
95
|
-
}
|
|
96
|
-
if (S.sampleColumns) {
|
|
97
|
-
// has optional terms to show as table columns and annotate samples
|
|
98
|
-
for (const term of S.sampleColumns) {
|
|
99
|
-
const s2v = ds.cohort.termdb.q.getAllValues4term(term.termid) // map. k: sampleid, v: term value
|
|
100
|
-
for (const s of samples) {
|
|
101
|
-
if (s2v.has(s.sampleid)) s[term.termid] = s2v.get(s.sampleid)
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
for (const s of samples) delete s.sampleid
|
|
106
|
-
|
|
107
|
-
S.get = () => {
|
|
108
|
-
return { samples: samples as Sample[] }
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function getDataNative(D: SingleCellDataNative, ds: any) {
|
|
113
|
-
const nameSet = new Set() // guard against duplicating plot names
|
|
114
|
-
for (const plot of D.plots) {
|
|
115
|
-
if (nameSet.has(plot.name)) throw 'duplicate plot.name'
|
|
116
|
-
nameSet.add(plot.name)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// scoped and cached for runtime
|
|
120
|
-
const _terms = [] as any
|
|
121
|
-
|
|
122
|
-
for (const tid of D.termIds) {
|
|
123
|
-
const t = ds.cohort.termdb.q.termjsonByOneid(tid)
|
|
124
|
-
if (!t) throw 'invalid term id from queries.singleCell.data.termIds[]'
|
|
125
|
-
_terms.push(t)
|
|
126
|
-
}
|
|
127
|
-
D.get = async q => {
|
|
128
|
-
// if sample is int, may convert to string
|
|
129
|
-
try {
|
|
130
|
-
const tid2cellvalue = {}
|
|
131
|
-
for (const tid of D.termIds) tid2cellvalue[tid] = {} // k: cell id, v: cell value for this term
|
|
132
|
-
const plots = [] as Plot[] // given a sample name, collect every plot data for this sample and return
|
|
133
|
-
for (const plot of D.plots) {
|
|
134
|
-
const tsvfile = path.join(serverconfig.tpmasterdir, plot.folder, q.sample + plot.fileSuffix)
|
|
135
|
-
try {
|
|
136
|
-
await fs.promises.stat(tsvfile)
|
|
137
|
-
} catch (e: any) {
|
|
138
|
-
if (e.code == 'ENOENT') {
|
|
139
|
-
// no file found for this sample; allowed because sampleView tests if that sample has sc data or not
|
|
140
|
-
continue
|
|
141
|
-
}
|
|
142
|
-
if (e.code == 'EACCES') throw 'cannot read file, permission denied'
|
|
143
|
-
throw 'failed to load sc data file'
|
|
144
|
-
}
|
|
145
|
-
const lines = (await read_file(tsvfile)).trim().split('\n')
|
|
146
|
-
// 1st line is header
|
|
147
|
-
const cells = [] as Cell[]
|
|
148
|
-
for (let i = 1; i < lines.length; i++) {
|
|
149
|
-
// each line is a cell
|
|
150
|
-
const l = lines[i].split('\t')
|
|
151
|
-
const cellId = l[0],
|
|
152
|
-
x = Number(l[plot.coordsColumns.x]), // FIXME standardize, or define idx in plot
|
|
153
|
-
y = Number(l[plot.coordsColumns.y])
|
|
154
|
-
const category = l[plot.colorColumn?.index] || ''
|
|
155
|
-
if (!cellId) throw 'cell id missing'
|
|
156
|
-
if (!Number.isFinite(x) || !Number.isFinite(y)) throw 'x/y not number'
|
|
157
|
-
cells.push({ cellId, x, y, category })
|
|
158
|
-
|
|
159
|
-
for (const tid of D.termIds) {
|
|
160
|
-
tid2cellvalue[tid][cellId] = l[1]
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
plots.push({ name: plot.name, cells, colorBy: plot.colorColumn?.name, colorMap: plot.colorMap })
|
|
164
|
-
}
|
|
165
|
-
if (plots.length == 0) {
|
|
166
|
-
// no data available for this sample
|
|
167
|
-
return { nodata: true }
|
|
168
|
-
}
|
|
169
|
-
return { plots, terms: _terms, tid2cellvalue }
|
|
170
|
-
} catch (e: any) {
|
|
171
|
-
if (e.stack) console.log(e.stack)
|
|
172
|
-
return { error: e.message || e }
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { gettermsbyidsRequest, gettermsbyidsResponse } from '#shared/types/routes/termdb.termsbyids.js'
|
|
2
|
-
import { copy_term } from '#src/termdb.js'
|
|
3
|
-
|
|
4
|
-
export const api: any = {
|
|
5
|
-
endpoint: 'termdb/termsbyids',
|
|
6
|
-
methods: {
|
|
7
|
-
get: {
|
|
8
|
-
init,
|
|
9
|
-
request: {
|
|
10
|
-
typeId: 'gettermsbyidsRequest'
|
|
11
|
-
},
|
|
12
|
-
response: {
|
|
13
|
-
typeId: 'gettermsbyidsResponse'
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
post: {
|
|
17
|
-
alternativeFor: 'get',
|
|
18
|
-
init
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function init({ genomes }) {
|
|
24
|
-
return async (req: any, res: any): Promise<void> => {
|
|
25
|
-
const q = req.query // as getcategoriesRequest
|
|
26
|
-
try {
|
|
27
|
-
const g = genomes[req.query.genome]
|
|
28
|
-
if (!g) throw 'invalid genome name'
|
|
29
|
-
const ds = g.datasets[req.query.dslabel]
|
|
30
|
-
if (!ds) throw 'invalid dataset name'
|
|
31
|
-
const tdb = ds.cohort.termdb
|
|
32
|
-
if (!tdb) throw 'invalid termdb object'
|
|
33
|
-
|
|
34
|
-
await trigger_gettermsbyid(q, res, tdb) // as getcategoriesResponse
|
|
35
|
-
} catch (e) {
|
|
36
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
37
|
-
// @ts-ignore
|
|
38
|
-
res.send({ error: e?.message || e })
|
|
39
|
-
if (e instanceof Error && e.stack) console.log(e)
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async function trigger_gettermsbyid(
|
|
45
|
-
q: { ids: any },
|
|
46
|
-
res: { send: (arg0: { terms: any }) => void },
|
|
47
|
-
tdb: { q: { termjsonByOneid: (arg0: any) => any } }
|
|
48
|
-
) {
|
|
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
|
-
}
|
|
60
|
-
res.send({
|
|
61
|
-
terms
|
|
62
|
-
})
|
|
63
|
-
}
|
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
TermdbTopVariablyExpressedGenesRequest,
|
|
3
|
-
TermdbTopVariablyExpressedGenesResponse
|
|
4
|
-
} from '#shared/types/routes/termdb.topVariablyExpressedGenes.ts'
|
|
5
|
-
import { gdcGetCasesWithExressionDataFromCohort } from '../src/mds3.gdc.js'
|
|
6
|
-
import path from 'path'
|
|
7
|
-
import { run_rust } from '@sjcrh/proteinpaint-rust'
|
|
8
|
-
import got from 'got'
|
|
9
|
-
import serverconfig from '#src/serverconfig.js'
|
|
10
|
-
import { get_samples } from '#src/termdb.sql.js'
|
|
11
|
-
|
|
12
|
-
export const api = {
|
|
13
|
-
endpoint: 'termdb/topVariablyExpressedGenes',
|
|
14
|
-
methods: {
|
|
15
|
-
all: {
|
|
16
|
-
init,
|
|
17
|
-
request: {
|
|
18
|
-
typeId: 'TermdbTopVariablyExpressedGenesRequest'
|
|
19
|
-
},
|
|
20
|
-
response: {
|
|
21
|
-
typeId: 'TermdbTopVariablyExpressedGenesResponse'
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function init({ genomes }) {
|
|
28
|
-
return async (req: any, res: any): Promise<void> => {
|
|
29
|
-
try {
|
|
30
|
-
const q = req.query as TermdbTopVariablyExpressedGenesRequest
|
|
31
|
-
const genome = genomes[q.genome]
|
|
32
|
-
if (!genome) throw 'invalid genome'
|
|
33
|
-
const ds = genome.datasets?.[q.dslabel]
|
|
34
|
-
if (!ds) throw 'invalid dslabel'
|
|
35
|
-
if (!ds.queries?.topVariablyExpressedGenes) throw 'not supported on dataset'
|
|
36
|
-
|
|
37
|
-
const t = Date.now()
|
|
38
|
-
const genes = await ds.queries.topVariablyExpressedGenes.getGenes(q)
|
|
39
|
-
if (serverconfig.debugmode) console.log('topVariablyExpressedGenes', Date.now() - t, 'ms')
|
|
40
|
-
|
|
41
|
-
res.send({ genes } as TermdbTopVariablyExpressedGenesResponse)
|
|
42
|
-
} catch (e: any) {
|
|
43
|
-
res.send({ status: 'error', error: e.message || e })
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function validate_query_TopVariablyExpressedGenes(ds: any, genome: any) {
|
|
49
|
-
const q = ds.queries.topVariablyExpressedGenes
|
|
50
|
-
if (!q) return
|
|
51
|
-
if (q.src == 'gdcapi') {
|
|
52
|
-
gdcValidateQuery(ds, genome)
|
|
53
|
-
} else if (q.src == 'native') {
|
|
54
|
-
nativeValidateQuery(ds, genome)
|
|
55
|
-
} else {
|
|
56
|
-
throw 'unknown topVariablyExpressedGenes.src'
|
|
57
|
-
}
|
|
58
|
-
// added getter: q.getGenes()
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function nativeValidateQuery(ds: any, genome: any) {
|
|
62
|
-
const gE = ds.queries.geneExpression // a separate query required to supply data for computing top genes
|
|
63
|
-
if (!gE) throw 'topVariablyExpressedGenes query given but geneExpression missing'
|
|
64
|
-
if (gE.src != 'native') throw 'topVariablyExpressedGenes is native but geneExpression.src is not native'
|
|
65
|
-
|
|
66
|
-
ds.queries.topVariablyExpressedGenes.getGenes = async (q: TermdbTopVariablyExpressedGenesRequest) => {
|
|
67
|
-
// get list of samples that are used in current analysis; gE.samples[] contains all sample integer ids with exp data
|
|
68
|
-
const samples = [] as string[]
|
|
69
|
-
if (q.filter) {
|
|
70
|
-
// get all samples pasing pp filter, may contain those without exp data
|
|
71
|
-
const sidlst = await get_samples(q.filter, ds)
|
|
72
|
-
// [{id:int}]
|
|
73
|
-
// filter for those with exp data from q.samples[]
|
|
74
|
-
for (const i of sidlst) {
|
|
75
|
-
if (gE.samples.includes(i.id)) {
|
|
76
|
-
// this sample passing filter also has exp data; convert to string name
|
|
77
|
-
const n: string = ds.cohort.termdb.q.id2sampleName(i.id)
|
|
78
|
-
if (!n) throw 'sample id cannot convert to string name'
|
|
79
|
-
samples.push(n)
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
} else {
|
|
83
|
-
// no filter, use all samples with exp data
|
|
84
|
-
for (const i of gE.samples) {
|
|
85
|
-
const n: string = ds.cohort.termdb.q.id2sampleName(i.id)
|
|
86
|
-
if (!n) throw 'sample id cannot convert to string name'
|
|
87
|
-
samples.push(n)
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// call rust to compute top genes on these samples
|
|
92
|
-
const genes = await computeGenes4nativeDs(q, ds, gE.file, samples)
|
|
93
|
-
return genes
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
async function computeGenes4nativeDs(
|
|
98
|
-
q: TermdbTopVariablyExpressedGenesRequest,
|
|
99
|
-
ds: any,
|
|
100
|
-
matrixFile: string,
|
|
101
|
-
samples: string[]
|
|
102
|
-
) {
|
|
103
|
-
// The param option in input JSON is very important. It instructs what method will be used to calculate variation in the counts for a particular gene. It supports variance as well as interquartile region. This is based on the recommendation of this article https://www.frontiersin.org/articles/10.3389/fgene.2021.632620/full . This article recommends using interquartile region over variance.
|
|
104
|
-
const input_json = {
|
|
105
|
-
input_file: matrixFile,
|
|
106
|
-
samples: samples.join(','),
|
|
107
|
-
filter_extreme_values: true,
|
|
108
|
-
num_genes: Number(q.maxGenes),
|
|
109
|
-
param: 'var'
|
|
110
|
-
}
|
|
111
|
-
const rust_output = await run_rust('topGeneByExpressionVariance', JSON.stringify(input_json))
|
|
112
|
-
const rust_output_list = rust_output.split('\n')
|
|
113
|
-
|
|
114
|
-
let output_json
|
|
115
|
-
for (const item of rust_output_list) {
|
|
116
|
-
if (item.includes('output_json:')) {
|
|
117
|
-
output_json = JSON.parse(item.replace('output_json:', ''))
|
|
118
|
-
} else {
|
|
119
|
-
console.log(item)
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
const varGenes = output_json.map(i => i.gene_symbol)
|
|
123
|
-
return varGenes
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function gdcValidateQuery(ds: any, genome: any) {
|
|
127
|
-
ds.queries.topVariablyExpressedGenes.getGenes = async (q: TermdbTopVariablyExpressedGenesRequest) => {
|
|
128
|
-
if (serverconfig.features.gdcGenes) {
|
|
129
|
-
// for testing on dev, must not set on prod!! delete to trigger api query
|
|
130
|
-
console.log('!!GDC!! using serverconfig.features.gdcGenes[]')
|
|
131
|
-
return serverconfig.features.gdcGenes as string[]
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// disable when caching is incomplete (particularly cases with gene exp data); to prevent showing wrong data on client
|
|
135
|
-
if (!ds.__gdc.doneCaching) throw 'The server has not finished caching the case IDs: try again in ~2 minutes'
|
|
136
|
-
|
|
137
|
-
// based on current cohort, get list of cases with exp data, as input of next api query
|
|
138
|
-
const caseLst = await gdcGetCasesWithExressionDataFromCohort(q, ds)
|
|
139
|
-
if (caseLst.length == 0) {
|
|
140
|
-
// there are no cases with gene exp data
|
|
141
|
-
return [] as string[]
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// change to this when api is available on prod
|
|
145
|
-
const { host, headers } = ds.getHostHeaders(q)
|
|
146
|
-
const url = path.join(host.geneExp, '/gene_expression/gene_selection')
|
|
147
|
-
try {
|
|
148
|
-
const response = await got.post(url, {
|
|
149
|
-
headers,
|
|
150
|
-
body: JSON.stringify(getGeneSelectionArg(q, caseLst))
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
const re = JSON.parse(response.body)
|
|
154
|
-
// {"gene_selection":[{"gene_id":"ENSG00000141510","log2_uqfpkm_median":3.103430497010492,"log2_uqfpkm_stddev":0.8692021350485105,"symbol":"TP53"}, ... ]}
|
|
155
|
-
|
|
156
|
-
const genes = [] as string[]
|
|
157
|
-
if (!Array.isArray(re.gene_selection)) throw 're.gene_selection[] is not array'
|
|
158
|
-
for (const i of re.gene_selection) {
|
|
159
|
-
if (i.gene_id && typeof i.gene_id == 'string') {
|
|
160
|
-
// is ensg, convert to symbol
|
|
161
|
-
const t = genome.genedb.getNameByAlias.get(i.gene_id)
|
|
162
|
-
if (t) genes.push(t.name) // ensg
|
|
163
|
-
} else if (i.symbol && typeof i.symbol == 'string') {
|
|
164
|
-
genes.push(i.symbol)
|
|
165
|
-
} else {
|
|
166
|
-
throw 'one of re.gene_selection[] is missing both gene_id and symbol'
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
return genes
|
|
170
|
-
} catch (e: any) {
|
|
171
|
-
console.log(e.stack || e)
|
|
172
|
-
throw e
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function getGeneSelectionArg(q: any, caseLst: any) {
|
|
177
|
-
//to hide messy logic during testing phase
|
|
178
|
-
|
|
179
|
-
/* when api performance issue is resolved, return this
|
|
180
|
-
return {
|
|
181
|
-
case_ids: caseLst,
|
|
182
|
-
gene_type:'protein_coding',
|
|
183
|
-
selection_size: Number(q.maxGenes)
|
|
184
|
-
}
|
|
185
|
-
*/
|
|
186
|
-
|
|
187
|
-
//////////////////////////////////////////////////
|
|
188
|
-
//
|
|
189
|
-
// !!!!!!!!!!!!!!!! TEMPORARY !!!!!!!!!!!!!!!!!!!!
|
|
190
|
-
//
|
|
191
|
-
//////////////////////////////////////////////////
|
|
192
|
-
// limit the case_ids length, and restrict pool to CGC genes, otherwise the request times out !!!
|
|
193
|
-
// must revert asap
|
|
194
|
-
return {
|
|
195
|
-
case_ids: caseLst, //.slice(0, 20),
|
|
196
|
-
gene_ids: tempGetCGCgenes(genome),
|
|
197
|
-
selection_size: Number(q.maxGenes)
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
function tempGetCGCgenes(genome: any) {
|
|
203
|
-
const lst = [] as string[] // list of ENSG ids from cgc genes
|
|
204
|
-
// don't think there's need to preparse genome.geneset, as this function is only temporary
|
|
205
|
-
for (const s of genome.geneset[0].lst) {
|
|
206
|
-
const a = genome.genedb.getAliasByName.all(s)
|
|
207
|
-
if (a) {
|
|
208
|
-
for (const b of a) {
|
|
209
|
-
if (b.alias.startsWith('ENSG')) lst.push(b.alias)
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
return lst
|
|
214
|
-
}
|
package/routes/termdb.violin.ts
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { getViolinRequest, getViolinResponse } from '#shared/types/routes/termdb.violin.ts'
|
|
2
|
-
import { trigger_getViolinPlotData } from '#src/termdb.violin.js'
|
|
3
|
-
|
|
4
|
-
export const api: any = {
|
|
5
|
-
endpoint: 'termdb/violin',
|
|
6
|
-
methods: {
|
|
7
|
-
get: {
|
|
8
|
-
init,
|
|
9
|
-
request: {
|
|
10
|
-
typeId: 'getViolinRequest'
|
|
11
|
-
},
|
|
12
|
-
response: {
|
|
13
|
-
typeId: 'getViolinResponse'
|
|
14
|
-
},
|
|
15
|
-
examples: [
|
|
16
|
-
{
|
|
17
|
-
request: {
|
|
18
|
-
body: {
|
|
19
|
-
genome: 'hg38-test',
|
|
20
|
-
dslabel: 'TermdbTest',
|
|
21
|
-
embedder: 'localhost',
|
|
22
|
-
devicePixelRatio: 2.200000047683716,
|
|
23
|
-
maxThickness: 150,
|
|
24
|
-
screenThickness: 1218,
|
|
25
|
-
filter: {
|
|
26
|
-
type: 'tvslst',
|
|
27
|
-
in: true,
|
|
28
|
-
join: '',
|
|
29
|
-
lst: [
|
|
30
|
-
{
|
|
31
|
-
tag: 'cohortFilter',
|
|
32
|
-
type: 'tvs',
|
|
33
|
-
tvs: { term: { id: 'subcohort', type: 'categorical' }, values: [{ key: 'ABC', label: 'ABC' }] }
|
|
34
|
-
}
|
|
35
|
-
]
|
|
36
|
-
},
|
|
37
|
-
svgw: 227.27272234672367,
|
|
38
|
-
orientation: 'horizontal',
|
|
39
|
-
datasymbol: 'bean',
|
|
40
|
-
radius: 5,
|
|
41
|
-
strokeWidth: 0.2,
|
|
42
|
-
axisHeight: 60,
|
|
43
|
-
rightMargin: 50,
|
|
44
|
-
unit: 'abs',
|
|
45
|
-
termid: 'agedx'
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
response: {
|
|
49
|
-
header: { status: 200 }
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
]
|
|
53
|
-
},
|
|
54
|
-
post: {
|
|
55
|
-
alternativeFor: 'get',
|
|
56
|
-
init
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function init({ genomes }) {
|
|
62
|
-
return async (req: any, res: any): Promise<void> => {
|
|
63
|
-
const q = req.query as getViolinRequest
|
|
64
|
-
try {
|
|
65
|
-
const g = genomes[req.query.genome]
|
|
66
|
-
const ds = g.datasets[req.query.dslabel]
|
|
67
|
-
if (!g) throw 'invalid genome name'
|
|
68
|
-
const data = await trigger_getViolinPlotData(req.query, null, ds, g) // as getViolinResponse
|
|
69
|
-
res.send(data as getViolinResponse)
|
|
70
|
-
} catch (e) {
|
|
71
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
72
|
-
// @ts-ignore
|
|
73
|
-
res.send({ error: e?.message || e })
|
|
74
|
-
if (e instanceof Error && e.stack) console.log(e)
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|