@sjcrh/proteinpaint-server 2.26.1 → 2.27.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/cards/databrowser.json +1 -1
- package/cards/disco.json +69 -0
- package/cards/hic.json +1 -0
- package/cards/index.json +12 -2
- package/genome/hg19.js +0 -6
- package/genome/hg38.js +0 -6
- package/package.json +13 -10
- package/routes/README.md +84 -0
- package/routes/burden.ts +140 -0
- package/routes/gdc.maf.ts +106 -0
- package/routes/gdc.topMutatedGenes.ts +130 -0
- package/routes/gdc.topVariablyExpressedGenes.ts +97 -0
- package/routes/genelookup.ts +4 -12
- package/routes/healthcheck.ts +3 -46
- package/routes/termdb.violin.ts +78 -0
- package/server.js +1 -1
- package/utils/burden.R +334 -0
- package/utils/fastclust.R +8 -1
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { GdcTopVariablyExpressedGenesResponse } from '#shared/types/routes/gdc.topVariablyExpressedGenes.ts'
|
|
2
|
+
import { getCasesWithExressionDataFromCohort } from '../src/mds3.gdc.js'
|
|
3
|
+
//import path from 'path'
|
|
4
|
+
import got from 'got'
|
|
5
|
+
import serverconfig from '../src/serverconfig.js'
|
|
6
|
+
|
|
7
|
+
// TODO change when api is released to prod
|
|
8
|
+
//const apihost = process.env.PP_GDC_HOST || 'https://api.gdc.cancer.gov'
|
|
9
|
+
const apihost = 'https://uat-portal.gdc.cancer.gov/auth/api/v0/gene_expression/gene_selection'
|
|
10
|
+
|
|
11
|
+
const gdcGenome = 'hg38'
|
|
12
|
+
const gdcDslabel = 'GDC'
|
|
13
|
+
|
|
14
|
+
export const api = {
|
|
15
|
+
endpoint: 'gdc/topVariablyExpressedGenes',
|
|
16
|
+
methods: {
|
|
17
|
+
get: {
|
|
18
|
+
init({ genomes }) {
|
|
19
|
+
return async (req: any, res: any): Promise<void> => {
|
|
20
|
+
try {
|
|
21
|
+
// following logic requires hg38 gdc dataset
|
|
22
|
+
const genome = genomes[gdcGenome]
|
|
23
|
+
if (!genome) throw 'hg38 genome missing'
|
|
24
|
+
const ds = genome.datasets?.[gdcDslabel]
|
|
25
|
+
if (!ds) throw 'gdc dataset missing'
|
|
26
|
+
const genes = await getGenes(req.query, ds)
|
|
27
|
+
const payload = { genes } as GdcTopVariablyExpressedGenesResponse
|
|
28
|
+
res.send(payload)
|
|
29
|
+
} catch (e: any) {
|
|
30
|
+
res.send({ status: 'error', error: e.message || e })
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
request: {
|
|
35
|
+
typeId: null
|
|
36
|
+
//valid: default to type checker
|
|
37
|
+
},
|
|
38
|
+
response: {
|
|
39
|
+
typeId: 'GdcTopVariablyExpressedGenesResponse'
|
|
40
|
+
// will combine this with type checker
|
|
41
|
+
//valid: (t) => {}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/*
|
|
48
|
+
req.query {
|
|
49
|
+
filter0 // optional gdc GFF cohort filter, invisible and read only
|
|
50
|
+
FIXME should there be pp filter too?
|
|
51
|
+
maxGenes: int
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
ds { } // server-side ds object
|
|
55
|
+
|
|
56
|
+
*/
|
|
57
|
+
async function getGenes(q: any, ds: any) {
|
|
58
|
+
if (serverconfig.features.gdcGenes) {
|
|
59
|
+
// for testing only; delete when api issue is resolved
|
|
60
|
+
return serverconfig.features.gdcGenes as string[]
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// based on current cohort, get list of cases with exp data, as input of next api query
|
|
64
|
+
const caseLst = await getCasesWithExressionDataFromCohort(q, ds)
|
|
65
|
+
if (caseLst.length == 0) {
|
|
66
|
+
// there are no cases with gene exp data
|
|
67
|
+
return [] as string[]
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// change to this when api is available on prod
|
|
71
|
+
// const url = path.join(apihost, '/gene_expression/gene_selection')
|
|
72
|
+
|
|
73
|
+
const response = await got.post(apihost, {
|
|
74
|
+
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
|
|
75
|
+
body: JSON.stringify({
|
|
76
|
+
case_ids: caseLst,
|
|
77
|
+
//gene_ids: [] // this should not be a required parameter
|
|
78
|
+
size: q.maxGenes || 100
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
const re = JSON.parse(response.body)
|
|
83
|
+
// {"gene_selection":[{"gene_id":"ENSG00000141510","log2_uqfpkm_median":3.103430497010492,"log2_uqfpkm_stddev":0.8692021350485105,"symbol":"TP53"}, ... ]}
|
|
84
|
+
|
|
85
|
+
const genes = [] as string[]
|
|
86
|
+
if (!Array.isArray(re.gene_selection)) throw 're.gene_selection[] is not array'
|
|
87
|
+
for (const i of re.gene_selection) {
|
|
88
|
+
if (i.gene_id && typeof i.gene_id == 'string') {
|
|
89
|
+
genes.push(i.gene_id) // ensg
|
|
90
|
+
} else if (i.symbol && typeof i.symbol == 'string') {
|
|
91
|
+
genes.push(i.symbol)
|
|
92
|
+
} else {
|
|
93
|
+
throw 'one of re.gene_selection[] is missing both gene_id and symbol'
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return genes
|
|
97
|
+
}
|
package/routes/genelookup.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { getResult } from '#src/gene.js'
|
|
2
|
+
import { GeneLookupRequest, GeneLookupResponse } from '#shared/types/routes/genelookup.ts'
|
|
2
3
|
|
|
3
4
|
function init({ genomes }) {
|
|
4
5
|
return (req: any, res: any): void => {
|
|
5
6
|
try {
|
|
7
|
+
const q = req.query as GeneLookupRequest
|
|
6
8
|
const g = genomes[req.query.genome]
|
|
7
9
|
if (!g) throw 'invalid genome name'
|
|
8
|
-
|
|
10
|
+
const result = getResult(g, req.query) as GeneLookupResponse
|
|
11
|
+
res.send(result)
|
|
9
12
|
} catch (e: any) {
|
|
10
13
|
res.send({ error: e.message || e })
|
|
11
14
|
if (e.stack) console.log(e.stack)
|
|
@@ -45,14 +48,3 @@ export const api: any = {
|
|
|
45
48
|
}
|
|
46
49
|
}
|
|
47
50
|
}
|
|
48
|
-
|
|
49
|
-
export type GeneLookupRequest = {
|
|
50
|
-
input: string
|
|
51
|
-
genome: string
|
|
52
|
-
deep: boolean
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export type GeneLookupResponse = {
|
|
56
|
-
error?: string
|
|
57
|
-
hits: string[]
|
|
58
|
-
}
|
package/routes/healthcheck.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { getStat } from '#src/health.ts'
|
|
2
|
+
import { HealthCheckResponse } from '#shared/types/routes/healthcheck.ts'
|
|
2
3
|
|
|
3
4
|
export const api = {
|
|
4
5
|
endpoint: 'healthcheck',
|
|
5
6
|
methods: {
|
|
6
7
|
get: {
|
|
7
8
|
init({ genomes }) {
|
|
8
|
-
return async (req:
|
|
9
|
+
return async (req: undefined, res: any): Promise<void> => {
|
|
9
10
|
try {
|
|
10
|
-
const health = await getStat(genomes)
|
|
11
|
+
const health = (await getStat(genomes)) as HealthCheckResponse
|
|
11
12
|
res.send(health)
|
|
12
13
|
} catch (e: any) {
|
|
13
14
|
res.send({ status: 'error', error: e.message || e })
|
|
@@ -26,47 +27,3 @@ export const api = {
|
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* for documentation only, to signify integer: not type-checked statically
|
|
32
|
-
*/
|
|
33
|
-
type int = number
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Information aboute the server build version and dates,
|
|
37
|
-
* including the date when the server was last launched
|
|
38
|
-
*/
|
|
39
|
-
export type VersionInfo = {
|
|
40
|
-
pkgver: string
|
|
41
|
-
codedate: string
|
|
42
|
-
launchdate: string
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
type BuildByGenome = {
|
|
46
|
-
[index: string]: GenomeBuildInfo
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export type GenomeBuildInfo = {
|
|
50
|
-
genedb: DbInfo
|
|
51
|
-
termdbs?: {
|
|
52
|
-
[index: string]: DbInfo
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
type DbInfo = {
|
|
57
|
-
buildDate: string // "unknown" or a Date-convertible string
|
|
58
|
-
tables?: {
|
|
59
|
-
[index: string]: int
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Server sttus and data related to it's health
|
|
65
|
-
*/
|
|
66
|
-
export type HealthCheckResponse = {
|
|
67
|
-
status: 'ok' | 'error'
|
|
68
|
-
genomes: BuildByGenome
|
|
69
|
-
versionInfo: VersionInfo
|
|
70
|
-
w?: number[]
|
|
71
|
-
rs?: number
|
|
72
|
-
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { trigger_getViolinPlotData } from '#src/termdb.violin.js'
|
|
2
|
+
// import { getViolinRequest, getViolinResponse } from '#shared/types/routes/termdb.violin'
|
|
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
|
+
plotThickness: 150,
|
|
46
|
+
termid: 'agedx'
|
|
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 getViolinRequest
|
|
65
|
+
try {
|
|
66
|
+
const g = genomes[req.query.genome]
|
|
67
|
+
const ds = g.datasets[req.query.dslabel]
|
|
68
|
+
if (!g) throw 'invalid genome name'
|
|
69
|
+
const data = await trigger_getViolinPlotData(req.query, null, ds, g) // as getViolinResponse
|
|
70
|
+
res.send(data)
|
|
71
|
+
} catch (e) {
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
73
|
+
// @ts-ignore
|
|
74
|
+
res.send({ error: e?.message || e })
|
|
75
|
+
if (e instanceof Error && e.stack) console.log(e)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|