@sjcrh/proteinpaint-server 2.30.4 → 2.31.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.
Files changed (54) hide show
  1. package/genome/hg19.js +3 -3
  2. package/genome/hg38.js +3 -3
  3. package/genome/hg38.test.js +3 -3
  4. package/package.json +2 -2
  5. package/routes/burden.ts +5 -2
  6. package/routes/gdc.maf.ts +39 -26
  7. package/routes/gdc.mafBuild.ts +24 -30
  8. package/routes/gdc.topVariablyExpressedGenes.ts +39 -23
  9. package/routes/hicdata.ts +113 -0
  10. package/routes/hicstat.ts +55 -0
  11. package/routes/termdb.categories.ts +30 -6
  12. package/routes/termdb.getpercentile.ts +117 -0
  13. package/routes/termdb.singlecellSamples.ts +45 -0
  14. package/routes/termdb.termbyid.ts +5 -1
  15. package/server.js +1 -1
  16. package/shared/common.js +10 -12
  17. package/src/serverconfig.js +0 -19
  18. package/cards/2dmaf.json +0 -37
  19. package/cards/README.md +0 -15
  20. package/cards/ai.json +0 -37
  21. package/cards/arc.json +0 -34
  22. package/cards/ase.json +0 -99
  23. package/cards/bam.json +0 -264
  24. package/cards/bampile.json +0 -22
  25. package/cards/bedj.json +0 -304
  26. package/cards/bigwig.json +0 -70
  27. package/cards/citations.json +0 -39
  28. package/cards/civicBtn.json +0 -15
  29. package/cards/databrowser.json +0 -276
  30. package/cards/disco.json +0 -69
  31. package/cards/dnanexusTips.txt +0 -221
  32. package/cards/exprank.json +0 -64
  33. package/cards/featuredDatasets.json +0 -84
  34. package/cards/fusioneditor.json +0 -34
  35. package/cards/gdcbam.json +0 -23
  36. package/cards/genefusion.json +0 -57
  37. package/cards/genomepaint.json +0 -122
  38. package/cards/hic.json +0 -79
  39. package/cards/index.json +0 -327
  40. package/cards/junction.json +0 -98
  41. package/cards/lollipop.json +0 -327
  42. package/cards/maf.timeline.json +0 -19
  43. package/cards/mavb.json +0 -47
  44. package/cards/nciGdcBtn.json +0 -21
  45. package/cards/pcmBtn.json +0 -16
  46. package/cards/ped2Btn.json +0 -16
  47. package/cards/pgv.json +0 -59
  48. package/cards/scatterplot.json +0 -31
  49. package/cards/singlecell.json +0 -25
  50. package/cards/study.json +0 -34
  51. package/cards/survivorBtn.json +0 -18
  52. package/cards/svview.txt +0 -101
  53. package/cards/tkFeatures.json +0 -92
  54. package/cards/tklist.json +0 -27
package/genome/hg19.js CHANGED
@@ -44,9 +44,9 @@ exports.default = {
44
44
  vpad: 4,
45
45
  categories: {
46
46
  coding: { color: '#004D99', label: 'Coding gene' },
47
- nonCoding: { color: '#009933', label: 'Noncoding gene' },
48
- problem: { color: '#FF3300', label: 'Problem' },
49
- pseudo: { color: '#FF00CC', label: 'Pseudogene' }
47
+ nonCoding: { color: '#008833', label: 'Noncoding gene' },
48
+ problem: { color: '#CC3300', label: 'Problem' },
49
+ pseudo: { color: '#CC00CC', label: 'Pseudogene' }
50
50
  }
51
51
  },
52
52
  {
package/genome/hg38.js CHANGED
@@ -48,9 +48,9 @@ exports.default = {
48
48
  translatecoding: true,
49
49
  categories: {
50
50
  coding: { color: '#004D99', label: 'Coding gene' },
51
- nonCoding: { color: '#009933', label: 'Noncoding gene' },
52
- problem: { color: '#FF3300', label: 'Problem' },
53
- pseudo: { color: '#FF00CC', label: 'Pseudogene' }
51
+ nonCoding: { color: '#008833', label: 'Noncoding gene' },
52
+ problem: { color: '#CC3300', label: 'Problem' },
53
+ pseudo: { color: '#CC00CC', label: 'Pseudogene' }
54
54
  },
55
55
  type: 'bedj',
56
56
  stackheight: 16,
@@ -24,9 +24,9 @@ var genome = {
24
24
  translatecoding: true,
25
25
  categories: {
26
26
  coding: { color: '#004D99', label: 'Coding gene' },
27
- nonCoding: { color: '#009933', label: 'Noncoding gene' },
28
- problem: { color: '#FF3300', label: 'Problem' },
29
- pseudo: { color: '#FF00CC', label: 'Pseudogene' }
27
+ nonCoding: { color: '#008833', label: 'Noncoding gene' },
28
+ problem: { color: '#CC3300', label: 'Problem' },
29
+ pseudo: { color: '#CC00CC', label: 'Pseudogene' }
30
30
  },
31
31
  type: 'bedj',
32
32
  name: 'GENCODE v41',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjcrh/proteinpaint-server",
3
- "version": "2.30.4",
3
+ "version": "2.31.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",
@@ -56,7 +56,7 @@
56
56
  },
57
57
  "dependencies": {
58
58
  "@sjcrh/augen": "2.27.0",
59
- "@sjcrh/proteinpaint-rust": "2.30.2",
59
+ "@sjcrh/proteinpaint-rust": "2.31.0",
60
60
  "better-sqlite3": "^7.5.3",
61
61
  "body-parser": "^1.15.2",
62
62
  "canvas": "~2.9.3",
package/routes/burden.ts CHANGED
@@ -69,7 +69,10 @@ export const api = {
69
69
  }
70
70
  }
71
71
 
72
- async function getBurdenEstimates(q, ds) {
72
+ async function getBurdenEstimates(
73
+ q: { query: { [x: string]: any } },
74
+ ds: { cohort: { cumburden: { files: { fit: any; surv: any; sample: any } } } }
75
+ ) {
73
76
  const infile = path.join(serverconfig.cachedir, Math.random().toString() + '.json')
74
77
  for (const k in q.query) {
75
78
  q.query[k] = Number(q.query[k])
@@ -91,7 +94,7 @@ async function getBurdenEstimates(q, ds) {
91
94
  return estimates
92
95
  }
93
96
 
94
- function formatPayload(estimates) {
97
+ function formatPayload(estimates: object[]) {
95
98
  const rawKeys = Object.keys(estimates[0])
96
99
  const outKeys = [] as string[]
97
100
  const keys = [] as string[]
package/routes/gdc.maf.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { GdcMafResponse, File } from '#shared/types/routes/gdc.maf.ts'
1
+ import { GdcMafRequest, GdcMafResponse, File } from '#shared/types/routes/gdc.maf.ts'
2
2
  import path from 'path'
3
3
  import got from 'got'
4
4
  import serverconfig from '#src/serverconfig.js'
@@ -6,36 +6,51 @@ import serverconfig from '#src/serverconfig.js'
6
6
  const apihost = process.env.PP_GDC_HOST || 'https://api.gdc.cancer.gov'
7
7
  const maxFileNumber = 1000
8
8
  const allowedWorkflowType = 'Aliquot Ensemble Somatic Variant Merging and Masking'
9
- const allowedExpStrategy = new Set(['WXS', 'Targeted Sequencing'])
10
9
  const maxTotalSizeCompressed = serverconfig.features.gdcMafMaxFileSize || 50000000 // 50Mb
11
10
 
12
11
  export const api = {
13
12
  endpoint: 'gdc/maf',
14
13
  methods: {
15
14
  get: {
16
- init({ genomes }) {
17
- return async (req: any, res: any): Promise<void> => {
18
- try {
19
- const g = genomes.hg38
20
- if (!g) throw 'hg38 missing'
21
- const ds = g.datasets.GDC
22
- if (!ds) throw 'hg38 GDC missing'
23
- const payload = await listMafFiles(req)
24
- res.send(payload)
25
- } catch (e: any) {
26
- res.send({ status: 'error', error: e.message || e })
27
- }
28
- }
29
- },
15
+ init,
30
16
  request: {
31
- typeId: null
32
- //valid: default to type checker
17
+ typeId: 'GdcMafRequest'
33
18
  },
34
19
  response: {
35
20
  typeId: 'GdcMafResponse'
36
21
  // will combine this with type checker
37
22
  //valid: (t) => {}
38
- }
23
+ },
24
+ examples: [
25
+ {
26
+ request: {
27
+ body: {
28
+ experimentalStrategy: 'WXS',
29
+ embedder: 'localhost'
30
+ }
31
+ },
32
+ response: {
33
+ header: { status: 200 }
34
+ }
35
+ }
36
+ ]
37
+ }
38
+ }
39
+ }
40
+
41
+ function init({ genomes }) {
42
+ return async (req: any, res: any): Promise<void> => {
43
+ try {
44
+ // g and ds are not used right now, but could be later
45
+ const g = genomes.hg38
46
+ if (!g) throw 'hg38 missing'
47
+ const ds = g.datasets.GDC
48
+ if (!ds) throw 'hg38 GDC missing'
49
+
50
+ const payload = await listMafFiles(req.query as GdcMafRequest)
51
+ res.send(payload)
52
+ } catch (e: any) {
53
+ res.send({ status: 'error', error: e.message || e })
39
54
  }
40
55
  }
41
56
  }
@@ -52,21 +67,19 @@ ds {
52
67
  }
53
68
  }
54
69
  */
55
- async function listMafFiles(req: any) {
56
- if (!allowedExpStrategy.has(req.query.experimentalStrategy)) throw 'invalid req.query.experimentalStrategy'
57
-
70
+ async function listMafFiles(q: GdcMafRequest) {
58
71
  const filters = {
59
72
  op: 'and',
60
73
  content: [
61
74
  { op: '=', content: { field: 'data_format', value: 'MAF' } },
62
- { op: '=', content: { field: 'experimental_strategy', value: req.query.experimentalStrategy } },
75
+ { op: '=', content: { field: 'experimental_strategy', value: q.experimentalStrategy } },
63
76
  { op: '=', content: { field: 'analysis.workflow_type', value: allowedWorkflowType } },
64
77
  { op: '=', content: { field: 'access', value: 'open' } } // delete if later to support controlled files
65
78
  ]
66
79
  }
67
80
 
68
- if (req.query.filter0) {
69
- filters.content.push(req.query.filter0)
81
+ if (q.filter0) {
82
+ filters.content.push(q.filter0)
70
83
  }
71
84
 
72
85
  const headers = { 'Content-Type': 'application/json', Accept: 'application/json' }
@@ -152,7 +165,7 @@ async function listMafFiles(req: any) {
152
165
 
153
166
  file.case_submitter_id = c.submitter_id
154
167
  if (c.samples) {
155
- file.sample_types = c.samples.map(i => i.sample_type).sort()
168
+ file.sample_types = c.samples.map((i: { sample_type: any }) => i.sample_type).sort()
156
169
  // sort to show sample type names in consistent alphabetical order
157
170
  // otherwise one file shows 'Blood, Primary' and another shows 'Primary, Blood'
158
171
  // FIXME this includes samples not associated with current maf file
@@ -3,6 +3,8 @@ import path from 'path'
3
3
  import fs from 'fs'
4
4
  import { run_rust } from '@sjcrh/proteinpaint-rust'
5
5
  import serverconfig from '#src/serverconfig.js'
6
+ import Readable from 'stream'
7
+ import { GdcMafBuildRequest } from '#shared/types/routes/gdc.mafBuild.ts'
6
8
 
7
9
  const apihost = process.env.PP_GDC_HOST || 'https://api.gdc.cancer.gov'
8
10
  const maxTotalSizeCompressed = serverconfig.features.gdcMafMaxFileSize || 50000000 // 50Mb
@@ -11,58 +13,50 @@ export const api = {
11
13
  endpoint: 'gdc/mafBuild',
12
14
  methods: {
13
15
  all: {
14
- init({ genomes }) {
15
- return async (req: any, res: any): Promise<void> => {
16
- try {
17
- await buildMaf(req, res)
18
- } catch (e) {
19
- if (e.stack) console.log(e.stack)
20
- res.send({ status: 'error', error: e.message || e })
21
- }
22
- }
23
- },
16
+ init,
24
17
  request: {
25
- typeId: null
26
- //valid: default to type checker
18
+ typeId: 'GdcMafBuildRequest'
27
19
  },
28
20
  response: {
29
- typeId: 'GdcMafBuildResponse'
30
- // will combine this with type checker
31
- //valid: (t) => {}
21
+ typeId: null // 'GdcMafBuildResponse'
32
22
  }
33
23
  }
34
24
  }
35
25
  }
36
26
 
37
- /*
38
- req.query {
39
- fileIdLst [] // list of maf file uuids
27
+ function init({ genomes }) {
28
+ return async (req: any, res: any): Promise<void> => {
29
+ try {
30
+ await buildMaf(req.query as GdcMafBuildRequest, res)
31
+ } catch (e: any) {
32
+ if (e.stack) console.log(e.stack)
33
+ res.send({ status: 'error', error: e.message || e })
34
+ }
35
+ }
40
36
  }
41
37
 
38
+ /*
39
+ q{}
42
40
  res{}
43
41
  */
44
- async function buildMaf(req: any, res: any) {
45
- const t0 = new Date()
46
-
47
- const fileLst2 = (await getFileLstUnderSizeLimit(req.query.fileIdLst)) as string[]
48
- console.log('test gdc maf sizes', new Date() - t0)
42
+ async function buildMaf(q: GdcMafBuildRequest, res: any) {
43
+ const t0 = Date.now()
49
44
 
50
- const outFile = path.join(serverconfig.cachedir, 'gdcMaf.' + Math.random().toString()) // should be a gzipped file. does it need to end with '.gz' or it's auto-added?
45
+ const fileLst2 = (await getFileLstUnderSizeLimit(q.fileIdLst)) as string[]
46
+ console.log('test gdc maf sizes', Date.now() - t0)
51
47
 
52
48
  const arg = {
53
49
  fileIdLst: fileLst2,
54
- host: path.join(apihost, 'data'), // must use the /data/ endpoint from current host
55
- outFile
50
+ host: path.join(apihost, 'data') // must use the /data/ endpoint from current host
56
51
  }
57
52
 
58
- await run_rust('gdcmaf', JSON.stringify(arg))
53
+ const dataGzipped = await run_rust('gdcmaf', JSON.stringify(arg))
59
54
 
60
- console.log('rust gdcmaf', new Date() - t0)
55
+ console.log('rust gdcmaf', Date.now() - t0)
61
56
 
62
- const data = await fs.promises.readFile(outFile)
57
+ const data = JSON.parse(dataGzipped)
63
58
 
64
59
  // by directly returning a blob, it won't tell client how many files are used
65
-
66
60
  res.writeHead(200, {
67
61
  'Content-Type': 'application/octet-stream',
68
62
  'Content-Disposition': 'attachment; filename=cohort.maf.gz',
@@ -1,12 +1,15 @@
1
1
  import { GdcTopVariablyExpressedGenesResponse } from '#shared/types/routes/gdc.topVariablyExpressedGenes.ts'
2
2
  import { getCasesWithExressionDataFromCohort } from '../src/mds3.gdc.js'
3
- //import path from 'path'
3
+ import path from 'path'
4
4
  import got from 'got'
5
5
  import serverconfig from '#src/serverconfig.js'
6
6
 
7
7
  // TODO change when api is released to prod
8
8
  //const apihost = process.env.PP_GDC_HOST || 'https://api.gdc.cancer.gov'
9
9
  const apihost = 'https://uat-portal.gdc.cancer.gov/auth/api/v0/gene_expression/gene_selection'
10
+ // temporarily hardcode to use the direct API URL,
11
+ // previously hardcoded to use 'https://uat-portal.gdc.cancer.gov/auth/api/v0/'
12
+ const geneExpHost = 'https://uat-api.gdc.cancer.gov'
10
13
 
11
14
  const gdcGenome = 'hg38'
12
15
  const gdcDslabel = 'GDC'
@@ -23,7 +26,7 @@ export const api = {
23
26
  if (!genome) throw 'hg38 genome missing'
24
27
  const ds = genome.datasets?.[gdcDslabel]
25
28
  if (!ds) throw 'gdc dataset missing'
26
- const genes = await getGenes(req.query, ds)
29
+ const genes = await getGenes(req.query, ds, genome)
27
30
  const payload = { genes } as GdcTopVariablyExpressedGenesResponse
28
31
  res.send(payload)
29
32
  } catch (e: any) {
@@ -53,12 +56,16 @@ req.query {
53
56
 
54
57
  ds { } // server-side ds object
55
58
 
59
+ genome {}
56
60
  */
57
- async function getGenes(q: any, ds: any) {
61
+ async function getGenes(q: any, ds: any, genome: any) {
58
62
  if (serverconfig.features.gdcGenes) {
59
63
  // for testing only; delete when api issue is resolved
60
64
  return serverconfig.features.gdcGenes as string[]
61
65
  }
66
+ if (!ds.__gdc.doneCaching) {
67
+ throw `The server has not finished caching the case IDs: try again in ~2 minutes`
68
+ }
62
69
 
63
70
  // based on current cohort, get list of cases with exp data, as input of next api query
64
71
  const caseLst = await getCasesWithExressionDataFromCohort(q, ds)
@@ -68,30 +75,39 @@ async function getGenes(q: any, ds: any) {
68
75
  }
69
76
 
70
77
  // change to this when api is available on prod
71
- // const url = path.join(apihost, '/gene_expression/gene_selection')
78
+ const url = path.join(geneExpHost, '/gene_expression/gene_selection')
72
79
 
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
80
+ try {
81
+ const response = await got.post(url, {
82
+ headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
83
+ body: JSON.stringify({
84
+ // !!! temporarily limit the case_ids length, otherwise the request times out !!!
85
+ case_ids: caseLst.slice(0, 20),
86
+ //gene_ids: [] // this should not be a required parameter
87
+ gene_type: 'protein_coding',
88
+ selection_size: Number(q.maxGenes || 100)
89
+ })
79
90
  })
80
- })
81
91
 
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"}, ... ]}
92
+ const re = JSON.parse(response.body)
93
+ // {"gene_selection":[{"gene_id":"ENSG00000141510","log2_uqfpkm_median":3.103430497010492,"log2_uqfpkm_stddev":0.8692021350485105,"symbol":"TP53"}, ... ]}
84
94
 
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'
95
+ const genes = [] as string[]
96
+ if (!Array.isArray(re.gene_selection)) throw 're.gene_selection[] is not array'
97
+ for (const i of re.gene_selection) {
98
+ if (i.gene_id && typeof i.gene_id == 'string') {
99
+ // is ensg, convert to symbol
100
+ const t = genome.genedb.getNameByAlias.get(i.gene_id)
101
+ if (t) genes.push(t.name) // ensg
102
+ } else if (i.symbol && typeof i.symbol == 'string') {
103
+ genes.push(i.symbol)
104
+ } else {
105
+ throw 'one of re.gene_selection[] is missing both gene_id and symbol'
106
+ }
94
107
  }
108
+ return genes
109
+ } catch (e) {
110
+ console.log(e.stack || e)
111
+ throw e
95
112
  }
96
- return genes
97
113
  }
@@ -0,0 +1,113 @@
1
+ import { HicdataRequest, HicdataResponse, Item } from '#shared/types/routes/hicdata.ts'
2
+ import { fileurl } from '#src/utils.js'
3
+ import { spawn } from 'child_process'
4
+ import readline from 'readline'
5
+ import serverconfig from '#src/serverconfig.js'
6
+
7
+ export const api: any = {
8
+ endpoint: 'hicdata',
9
+ methods: {
10
+ get: {
11
+ init,
12
+ request: {
13
+ typeId: 'HicdataRequest'
14
+ },
15
+ response: {
16
+ typeId: 'HicdataResponse'
17
+ }
18
+ /*
19
+ examples: [
20
+ {
21
+ request: {
22
+ body: {
23
+ genome: 'hg38-test',
24
+ dslabel: 'TermdbTest',
25
+ embedder: 'localhost',
26
+ gettermbyid: 'subcohort'
27
+ }
28
+ },
29
+ response: {
30
+ header: { status: 200 }
31
+ }
32
+ }
33
+ ]
34
+ */
35
+ },
36
+ post: {
37
+ alternativeFor: 'get',
38
+ init
39
+ }
40
+ }
41
+ }
42
+
43
+ function init({ genomes }) {
44
+ return async (req: any, res: any): Promise<void> => {
45
+ try {
46
+ const payload = await handle_hicdata(req.query as HicdataRequest)
47
+ res.send(payload)
48
+ } catch (e) {
49
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
50
+ // @ts-ignore
51
+ res.send({ error: e?.message || e })
52
+ if (e instanceof Error && e.stack) console.log(e)
53
+ }
54
+ }
55
+ }
56
+
57
+ function handle_hicdata(q: HicdataRequest) {
58
+ return new Promise((resolve, reject) => {
59
+ const [e, file, isurl] = fileurl({ query: q })
60
+ if (e) reject({ error: 'illegal file name' })
61
+
62
+ const par = [
63
+ // TODO add option for observed/oe
64
+ q.nmeth || 'NONE',
65
+ file,
66
+ q.pos1,
67
+ q.pos2,
68
+ q.isfrag ? 'FRAG' : 'BP',
69
+ q.resolution
70
+ ]
71
+
72
+ const ps = spawn(serverconfig.hicstraw, par)
73
+ const rl = readline.createInterface({ input: ps.stdout })
74
+
75
+ const items = [] as Item[]
76
+ const erroutput = [] as string[]
77
+ let linenot3fields = 0
78
+ let fieldnotnumerical = 0
79
+
80
+ rl.on('line', line => {
81
+ // straw output: pos1 \t pos2 \t value
82
+ const l = line.split('\t')
83
+ if (l.length != 3) {
84
+ linenot3fields++
85
+ return
86
+ }
87
+ const n1 = Number.parseInt(l[0])
88
+ const n2 = Number.parseInt(l[1])
89
+ const v = Number.parseFloat(l[2])
90
+ if (Number.isNaN(n1) || Number.isNaN(n2) || Number.isNaN(v)) {
91
+ fieldnotnumerical++
92
+ return
93
+ }
94
+ if (q.mincutoff != undefined && v <= q.mincutoff) {
95
+ return
96
+ }
97
+ items.push([n1, n2, v] as Item)
98
+ })
99
+
100
+ ps.stderr.on('data', i => erroutput.push(i))
101
+ ps.on('close', () => {
102
+ const err = erroutput.join('')
103
+ if (err) reject({ error: err })
104
+
105
+ if (linenot3fields) reject({ error: linenot3fields + ' lines have other than 3 fields' })
106
+
107
+ if (fieldnotnumerical)
108
+ reject({ error: fieldnotnumerical + ' lines have non-numerical values in any of the 3 fields' })
109
+
110
+ resolve({ items })
111
+ })
112
+ })
113
+ }
@@ -0,0 +1,55 @@
1
+ import { fileurl, file_is_readable } from '#src/utils.js'
2
+ import { do_hicstat } from '#src/hicstat.ts'
3
+ import { HicstatRequestWithValidation } from '#shared/types/routes/hicstat.ts'
4
+
5
+ export const api = {
6
+ endpoint: 'hicstat',
7
+ methods: {
8
+ get: {
9
+ init,
10
+ request: {
11
+ typeId: 'HicstatRequest'
12
+ },
13
+ response: {
14
+ typeId: 'HicstatResponse'
15
+ },
16
+ examples: [
17
+ {
18
+ request: {
19
+ body: {
20
+ genome: 'hg19',
21
+ file: 'proteinpaint_demo/hg19/hic/hic_demo.hic',
22
+ embedder: 'localhost'
23
+ }
24
+ },
25
+ response: {
26
+ header: { status: 200 }
27
+ }
28
+ }
29
+ ]
30
+ },
31
+ post: {
32
+ alternativeFor: 'get',
33
+ init
34
+ }
35
+ }
36
+ }
37
+
38
+ function init() {
39
+ return async (req: HicstatRequestWithValidation, res: any): Promise<void> => {
40
+ try {
41
+ const [e, file, isurl] = fileurl(req)
42
+ if (e) throw 'illegal file name'
43
+ if (!isurl) {
44
+ await file_is_readable(file)
45
+ }
46
+ const out = await do_hicstat(file, isurl)
47
+ res.send({ out })
48
+ } catch (e: any) {
49
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
50
+ // @ts-ignore
51
+ res.send({ error: e?.message || e })
52
+ if (e instanceof Error && e.stack) console.log(e)
53
+ }
54
+ }
55
+ }
@@ -87,7 +87,13 @@ function init({ genomes }) {
87
87
  }
88
88
  }
89
89
 
90
- async function trigger_getcategories(q, res, tdb, ds, genome) {
90
+ async function trigger_getcategories(
91
+ q: { tid: string | number; type: string; filter: any; term1_q: any; currentGeneNames: any },
92
+ res: { send: (arg0: { lst: any[]; orderedLabels: any }) => void },
93
+ tdb: { q: { termjsonByOneid: (arg0: any) => any } },
94
+ ds: { assayAvailability: { byDt: { [s: string]: any } | ArrayLike<any> } },
95
+ genome: any
96
+ ) {
91
97
  // thin wrapper of get_summary
92
98
  // works for all types of terms
93
99
  if (!q.tid) throw '.tid missing'
@@ -105,9 +111,9 @@ async function trigger_getcategories(q, res, tdb, ds, genome) {
105
111
  const data = await getData(arg, ds, genome)
106
112
  if (data.error) throw data.error
107
113
 
108
- const lst = []
114
+ const lst = [] as any[]
109
115
  if (q.type == 'geneVariant') {
110
- const samples = data.samples
116
+ const samples = data.samples as { [sampleId: string]: any }
111
117
  const dtClassMap = new Map()
112
118
  if (ds.assayAvailability?.byDt) {
113
119
  for (const [dtType, dtValue] of Object.entries(ds.assayAvailability.byDt)) {
@@ -116,7 +122,7 @@ async function trigger_getcategories(q, res, tdb, ds, genome) {
116
122
  }
117
123
  }
118
124
  }
119
- const sampleCountedFor = new Set() // if the sample is conunted for the
125
+ const sampleCountedFor = new Set() // if the sample is counted
120
126
  for (const [sampleId, sampleData] of Object.entries(samples)) {
121
127
  const values = sampleData[q.tid].values
122
128
  sampleCountedFor.clear()
@@ -175,7 +181,9 @@ async function trigger_getcategories(q, res, tdb, ds, genome) {
175
181
  samplecount: count,
176
182
  key,
177
183
  label:
178
- data.refs?.byTermId?.[q.tid]?.events?.find(e => e.event === key).label || term?.values?.[key]?.label || key
184
+ data.refs?.byTermId?.[q.tid]?.events?.find((e: { event: any }) => e.event === key).label ||
185
+ term?.values?.[key]?.label ||
186
+ key
179
187
  })
180
188
  }
181
189
  }
@@ -195,7 +203,23 @@ async function trigger_getcategories(q, res, tdb, ds, genome) {
195
203
  })
196
204
  }
197
205
 
198
- function getDefaultQ(term, q) {
206
+ function getDefaultQ(
207
+ term: { type: string; bins: { default: any } },
208
+ q: {
209
+ mode?: any
210
+ breaks?: any
211
+ bar_by_grade?: any
212
+ bar_by_children?: any
213
+ value_by_max_grade?: any
214
+ value_by_most_recent?: any
215
+ value_by_computable_grade?: any
216
+ tid?: string | number
217
+ type?: string
218
+ filter?: any
219
+ term1_q?: any
220
+ currentGeneNames?: any
221
+ }
222
+ ) {
199
223
  if (term.type == 'categorical') return {}
200
224
  if (term.type == 'survival') return {}
201
225
  if (term.type == 'integer' || term.type == 'float') return term.bins.default