@sjcrh/proteinpaint-server 2.39.5 → 2.40.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjcrh/proteinpaint-server",
3
- "version": "2.39.5",
3
+ "version": "2.40.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",
package/routes/gdc.maf.ts CHANGED
@@ -90,15 +90,16 @@ async function listMafFiles(q: GdcMafRequest) {
90
90
  { op: '=', content: { field: 'access', value: 'open' } } // delete if later to support controlled files
91
91
  ]
92
92
  }
93
-
93
+ const case_filters: any = { op: 'and', content: [] }
94
94
  if (q.filter0) {
95
- filters.content.push(q.filter0)
95
+ case_filters.content.push(q.filter0)
96
96
  }
97
97
 
98
98
  const headers = { 'Content-Type': 'application/json', Accept: 'application/json' }
99
99
 
100
100
  const data = {
101
101
  filters,
102
+ case_filters,
102
103
  size: maxFileNumber,
103
104
  fields: [
104
105
  'id',
@@ -1,6 +1,8 @@
1
- import { GdcTopMutatedGeneRequest, GdcTopMutatedGeneResponse } from '#shared/types/routes/gdc.topMutatedGenes.ts'
2
- import path from 'path'
1
+ import { GdcTopMutatedGeneRequest, GdcTopMutatedGeneResponse, Gene } from '#shared/types/routes/gdc.topMutatedGenes.ts'
2
+ import { mclasscnvgain, mclasscnvloss, dtsnvindel } from '#shared/common.js'
3
3
  import got from 'got'
4
+ import serverconfig from '#src/serverconfig.js'
5
+ import { getheaders } from '#src/mds3.gdc.js'
4
6
 
5
7
  // TODO change to /termdb/topMutatedGenes
6
8
 
@@ -41,7 +43,10 @@ function init() {
41
43
  }
42
44
  }
43
45
 
44
- const query = `
46
+ // query string copied from v1, works in v2. but v1 are not "cohort-centric and lacks the case_filters: $caseFilters"
47
+ // delete the v1 after soft launch
48
+ const queryV1: any = {
49
+ query: `
45
50
  query GenesTable_relayQuery(
46
51
  $genesTable_filters: FiltersArgument
47
52
  $genesTable_size: Int
@@ -111,155 +116,377 @@ query GenesTable_relayQuery(
111
116
  }
112
117
  }
113
118
  }
114
- `
115
-
116
- async function getGenesGraphql(q: GdcTopMutatedGeneRequest) {
117
- // set type "any" to avoid complains
118
- const variables: any = {
119
- genesTable_filters: {
120
- op: 'and',
121
- content: []
122
- },
123
- genesTable_size: q.maxGenes || 50,
124
- genesTable_offset: 0,
125
- score: 'case.project.project_id',
126
- ssmCase: {
127
- op: 'and',
128
- content: [
129
- {
130
- op: 'in',
131
- content: {
132
- field: 'cases.available_variation_data',
133
- value: ['ssm']
119
+ `,
120
+ getVariables: (q: any) => {
121
+ // set type "any" to avoid complains
122
+ const variables: any = {
123
+ genesTable_filters: { op: 'and', content: [] },
124
+ genesTable_size: q.maxGenes || 50,
125
+ genesTable_offset: 0,
126
+ score: 'case.project.project_id',
127
+ ssmCase: {
128
+ op: 'and',
129
+ content: [
130
+ {
131
+ op: 'in',
132
+ content: {
133
+ field: 'cases.available_variation_data',
134
+ value: ['ssm']
135
+ }
136
+ },
137
+ {
138
+ op: 'NOT',
139
+ content: {
140
+ field: 'genes.case.ssm.observation.observation_id',
141
+ value: 'MISSING'
142
+ }
134
143
  }
135
- },
136
- {
137
- op: 'NOT',
138
- content: {
139
- field: 'genes.case.ssm.observation.observation_id',
140
- value: 'MISSING'
144
+ ]
145
+ },
146
+ geneCaseFilter: {
147
+ content: [
148
+ {
149
+ content: {
150
+ field: 'cases.available_variation_data',
151
+ value: ['ssm']
152
+ },
153
+ op: 'in'
141
154
  }
142
- }
143
- ]
144
- },
145
- geneCaseFilter: {
146
- content: [
147
- {
148
- content: {
149
- field: 'cases.available_variation_data',
150
- value: ['ssm']
151
- },
152
- op: 'in'
153
- }
154
- ],
155
- op: 'and'
156
- },
157
- ssmTested: {
158
- content: [
159
- {
160
- content: {
161
- field: 'cases.available_variation_data',
162
- value: ['ssm']
163
- },
164
- op: 'in'
165
- }
166
- ],
167
- op: 'and'
168
- },
169
- cnvTested: {
170
- op: 'and',
171
- content: [
172
- {
173
- content: {
174
- field: 'cases.available_variation_data',
175
- value: ['cnv']
155
+ ],
156
+ op: 'and'
157
+ },
158
+ ssmTested: {
159
+ content: [
160
+ {
161
+ content: {
162
+ field: 'cases.available_variation_data',
163
+ value: ['ssm']
164
+ },
165
+ op: 'in'
166
+ }
167
+ ],
168
+ op: 'and'
169
+ },
170
+ cnvTested: {
171
+ op: 'and',
172
+ content: [
173
+ {
174
+ content: {
175
+ field: 'cases.available_variation_data',
176
+ value: ['cnv']
177
+ },
178
+ op: 'in'
179
+ }
180
+ ]
181
+ },
182
+ cnvGainFilters: {
183
+ op: 'and',
184
+ content: [
185
+ {
186
+ content: {
187
+ field: 'cases.available_variation_data',
188
+ value: ['cnv']
189
+ },
190
+ op: 'in'
176
191
  },
177
- op: 'in'
178
- }
179
- ]
180
- },
181
- cnvGainFilters: {
182
- op: 'and',
183
- content: [
184
- {
185
- content: {
186
- field: 'cases.available_variation_data',
187
- value: ['cnv']
192
+ {
193
+ content: {
194
+ field: 'cnvs.cnv_change',
195
+ value: ['Gain']
196
+ },
197
+ op: 'in'
198
+ }
199
+ ]
200
+ },
201
+ cnvLossFilters: {
202
+ op: 'and',
203
+ content: [
204
+ {
205
+ content: {
206
+ field: 'cases.available_variation_data',
207
+ value: ['cnv']
208
+ },
209
+ op: 'in'
188
210
  },
189
- op: 'in'
190
- },
191
- {
192
- content: {
193
- field: 'cnvs.cnv_change',
194
- value: ['Gain']
211
+ {
212
+ content: {
213
+ field: 'cnvs.cnv_change',
214
+ value: ['Loss']
215
+ },
216
+ op: 'in'
217
+ }
218
+ ]
219
+ }
220
+ }
221
+
222
+ if (q.filter0) {
223
+ variables.genesTable_filters.content.push(JSON.parse(JSON.stringify(q.filter0)))
224
+ variables.geneCaseFilter.content.push(JSON.parse(JSON.stringify(q.filter0)))
225
+ variables.cnvTested.content.push(JSON.parse(JSON.stringify(q.filter0)))
226
+ variables.cnvGainFilters.content.push(JSON.parse(JSON.stringify(q.filter0)))
227
+ variables.cnvLossFilters.content.push(JSON.parse(JSON.stringify(q.filter0)))
228
+ }
229
+
230
+ if (q.geneFilter == 'CGC') {
231
+ variables.genesTable_filters.content.push(geneCGC())
232
+ variables.geneCaseFilter.content.push(geneCGC())
233
+ variables.cnvTested.content.push(geneCGC())
234
+ variables.cnvGainFilters.content.push(geneCGC())
235
+ variables.cnvLossFilters.content.push(geneCGC())
236
+ }
237
+ return variables
238
+ }
239
+ }
240
+
241
+ const queryV2: any = {
242
+ query: `
243
+ query GenesTable(
244
+ $caseFilters: FiltersArgument
245
+ $genesTable_filters: FiltersArgument
246
+ $genesTable_size: Int
247
+ $genesTable_offset: Int
248
+ $score: String
249
+ $ssmCase: FiltersArgument
250
+ $geneCaseFilter: FiltersArgument
251
+ $ssmTested: FiltersArgument
252
+ $cnvTested: FiltersArgument
253
+ $cnvGainFilters: FiltersArgument
254
+ $cnvLossFilters: FiltersArgument
255
+ $sort: [Sort]
256
+ ) {
257
+ genesTableViewer: viewer {
258
+ explore {
259
+ cases {
260
+ hits(first: 0, case_filters: $ssmTested) {
261
+ total
262
+ }
263
+ }
264
+ filteredCases: cases {
265
+ hits(first: 0, case_filters: $geneCaseFilter) {
266
+ total
267
+ }
268
+ }
269
+ cnvCases: cases {
270
+ hits(first: 0, case_filters: $cnvTested) {
271
+ total
272
+ }
273
+ }
274
+ genes {
275
+ hits(
276
+ first: $genesTable_size
277
+ offset: $genesTable_offset
278
+ filters: $genesTable_filters
279
+ case_filters: $caseFilters
280
+ score: $score
281
+ sort: $sort
282
+ ) {
283
+ total
284
+ edges {
285
+ node {
286
+ id
287
+ numCases: score
288
+ symbol
289
+ name
290
+ cytoband
291
+ biotype
292
+ gene_id
293
+ is_cancer_gene_census
294
+ ssm_case: case {
295
+ hits(first: 0, filters: $ssmCase) {
296
+ total
297
+ }
298
+ }
299
+ cnv_case: case {
300
+ hits(first: 0, filters: $cnvTested) {
301
+ total
302
+ }
303
+ }
304
+ case_cnv_gain: case {
305
+ hits(first: 0, filters: $cnvGainFilters) {
306
+ total
307
+ }
308
+ }
309
+ case_cnv_loss: case {
310
+ hits(first: 0, filters: $cnvLossFilters) {
311
+ total
312
+ }
313
+ }
314
+ }
315
+ }
316
+ }
317
+ }
318
+ }
319
+ }
320
+ }`,
321
+ getVariables: (q: any) => {
322
+ const variables: any = {
323
+ caseFilters: { op: 'and', content: [] },
324
+ genesTable_filters: { op: 'and', content: [] },
325
+ genesTable_size: q.maxGenes || 50,
326
+ genesTable_offset: 0,
327
+ score: 'case.project.project_id',
328
+ ssmCase: {
329
+ op: 'and',
330
+ content: [
331
+ {
332
+ op: 'in',
333
+ content: {
334
+ field: 'cases.available_variation_data',
335
+ value: ['ssm']
336
+ }
195
337
  },
196
- op: 'in'
197
- }
198
- ]
199
- },
200
- cnvLossFilters: {
201
- op: 'and',
202
- content: [
203
- {
204
- content: {
205
- field: 'cases.available_variation_data',
206
- value: ['cnv']
338
+ {
339
+ op: 'NOT',
340
+ content: {
341
+ field: 'genes.case.ssm.observation.observation_id',
342
+ value: 'MISSING'
343
+ }
344
+ }
345
+ ]
346
+ },
347
+ geneCaseFilter: {
348
+ content: [
349
+ {
350
+ content: {
351
+ field: 'cases.available_variation_data',
352
+ value: ['ssm']
353
+ },
354
+ op: 'in'
355
+ }
356
+ ],
357
+ op: 'and'
358
+ },
359
+ ssmTested: {
360
+ content: [
361
+ {
362
+ content: {
363
+ field: 'cases.available_variation_data',
364
+ value: ['ssm']
365
+ },
366
+ op: 'in'
367
+ }
368
+ ],
369
+ op: 'and'
370
+ },
371
+ cnvTested: {
372
+ op: 'and',
373
+ content: [
374
+ {
375
+ content: {
376
+ field: 'cases.available_variation_data',
377
+ value: ['cnv']
378
+ },
379
+ op: 'in'
380
+ }
381
+ ]
382
+ },
383
+ cnvGainFilters: {
384
+ op: 'and',
385
+ content: [
386
+ {
387
+ content: {
388
+ field: 'cases.available_variation_data',
389
+ value: ['cnv']
390
+ },
391
+ op: 'in'
207
392
  },
208
- op: 'in'
209
- },
210
- {
211
- content: {
212
- field: 'cnvs.cnv_change',
213
- value: ['Loss']
393
+ {
394
+ content: {
395
+ field: 'cnvs.cnv_change',
396
+ value: ['Gain']
397
+ },
398
+ op: 'in'
399
+ }
400
+ ]
401
+ },
402
+ cnvLossFilters: {
403
+ op: 'and',
404
+ content: [
405
+ {
406
+ content: {
407
+ field: 'cases.available_variation_data',
408
+ value: ['cnv']
409
+ },
410
+ op: 'in'
214
411
  },
215
- op: 'in'
216
- }
217
- ]
412
+ {
413
+ content: {
414
+ field: 'cnvs.cnv_change',
415
+ value: ['Loss']
416
+ },
417
+ op: 'in'
418
+ }
419
+ ]
420
+ }
421
+ }
422
+
423
+ if (q.filter0) {
424
+ variables.caseFilters.content.push(JSON.parse(JSON.stringify(q.filter0)))
425
+ variables.geneCaseFilter.content.push(JSON.parse(JSON.stringify(q.filter0)))
426
+ variables.cnvLossFilters.content.push(JSON.parse(JSON.stringify(q.filter0)))
427
+ variables.cnvGainFilters.content.push(JSON.parse(JSON.stringify(q.filter0)))
428
+ variables.cnvTested.content.push(JSON.parse(JSON.stringify(q.filter0)))
218
429
  }
219
- }
220
430
 
221
- if (q.filter0) {
222
- variables.genesTable_filters.content.push(JSON.parse(JSON.stringify(q.filter0)))
223
- variables.geneCaseFilter.content.push(JSON.parse(JSON.stringify(q.filter0)))
224
- variables.cnvTested.content.push(JSON.parse(JSON.stringify(q.filter0)))
225
- variables.cnvGainFilters.content.push(JSON.parse(JSON.stringify(q.filter0)))
226
- variables.cnvLossFilters.content.push(JSON.parse(JSON.stringify(q.filter0)))
431
+ if (q.geneFilter == 'CGC') {
432
+ variables.genesTable_filters.content.push(geneCGC())
433
+ variables.cnvLossFilters.content.push(geneCGC())
434
+ variables.cnvGainFilters.content.push(geneCGC())
435
+ }
436
+ return variables
227
437
  }
438
+ }
439
+
440
+ async function getGenesGraphql(q: GdcTopMutatedGeneRequest) {
441
+ let query: string, variables: object
228
442
 
229
- if (q.geneFilter == 'CGC') {
230
- variables.genesTable_filters.content.push(geneCGC())
231
- variables.geneCaseFilter.content.push(geneCGC())
232
- variables.cnvTested.content.push(geneCGC())
233
- variables.cnvGainFilters.content.push(geneCGC())
234
- variables.cnvLossFilters.content.push(geneCGC())
443
+ if (serverconfig.features?.geneExpHost) {
444
+ // quick fix! this is only set on local dev machines, meaning it's using v1 api; delete this after soft launch!!
445
+ query = queryV1.query
446
+ variables = queryV1.getVariables(q)
447
+ } else {
448
+ // this is not set and should be in qa-orange. it should be like this after softlaunch
449
+ query = queryV2.query
450
+ variables = queryV2.getVariables(q)
235
451
  }
236
452
 
237
453
  const response = await got.post(apihostGraphql, {
238
- headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
454
+ headers: getheaders(q),
239
455
  body: JSON.stringify({ query, variables })
240
456
  })
241
457
 
242
458
  const re: any = JSON.parse(response.body)
243
- const genes: string[] = []
459
+ const genes: Gene[] = []
244
460
  for (const g of re.data.genesTableViewer.explore.genes.hits.edges) {
245
- /*
461
+ /* g.node is:
246
462
  {
247
- node: {
248
- biotype: 'protein_coding',
249
- case_cnv_gain: { hits: [Object] },
250
- case_cnv_loss: { hits: [Object] },
251
- cnv_case: { hits: [Object] },
252
- cytoband: [ '17q11.2' ],
253
- gene_id: 'ENSG00000196712',
254
- is_cancer_gene_census: true,
255
- name: 'neurofibromin 1',
256
- numCases: 93,
257
- ssm_case: { hits: [Object] },
258
- symbol: 'NF1'
259
- }
463
+ "biotype": "protein_coding",
464
+ "case_cnv_gain": { "hits": { "total": 65 } },
465
+ "case_cnv_loss": { "hits": { "total": 93 } },
466
+ "cnv_case": { "hits": { "total": 173 } },
467
+ "cytoband": [
468
+ "12q15"
469
+ ],
470
+ "gene_id": "ENSG00000127329",
471
+ "is_cancer_gene_census": true,
472
+ "name": "protein tyrosine phosphatase receptor type B",
473
+ "numCases": 18,
474
+ "ssm_case": { "hits": { "total": 630 } },
475
+ "symbol": "PTPRB"
260
476
  }
261
477
  */
262
- genes.push(g.node.symbol)
478
+ if (typeof g.node != 'object') throw 'node missing from re.data.genesTableViewer.explore.genes.hits.edges[]'
479
+ const mutationStat: any = []
480
+ if (Number.isInteger(g.node.case_cnv_gain?.hits?.total) && g.node.case_cnv_gain.hits.total > 0)
481
+ mutationStat.push({ class: mclasscnvgain, count: g.node.case_cnv_gain.hits.total })
482
+ if (Number.isInteger(g.node.case_cnv_loss?.hits?.total) && g.node.case_cnv_loss.hits.total > 0)
483
+ mutationStat.push({ class: mclasscnvloss, count: g.node.case_cnv_loss.hits.total })
484
+ if (Number.isInteger(g.node.ssm_case?.hits?.total) && g.node.ssm_case.hits.total > 0)
485
+ mutationStat.push({ dt: dtsnvindel, count: g.node.ssm_case.hits.total })
486
+ genes.push({
487
+ gene: g.node.symbol,
488
+ mutationStat
489
+ })
263
490
  }
264
491
  return genes
265
492
  }
@@ -276,11 +503,11 @@ function geneCGC() {
276
503
  }
277
504
 
278
505
  /*************************************
506
+ below are old code
279
507
  old method to use rest api
280
508
  **************************************
281
509
  this api only gets ssm-cases and does not account for cnv cases, will not return any gene for ssm-less cohort e.g. APOLLO-LUAD
282
510
  thus is replaced by getGenesGraphql
283
- */
284
511
  async function getGenes(q: GdcTopMutatedGeneRequest) {
285
512
  const _f = q.filter0 || { op: 'and', content: [] } // allow blank filter to test geneset edit ui (without filter)
286
513
  const response = await got.post(path.join(apihost, '/analysis/top_mutated_genes_by_project'), {
@@ -299,6 +526,7 @@ async function getGenes(q: GdcTopMutatedGeneRequest) {
299
526
  }
300
527
  return genes
301
528
  }
529
+ */
302
530
 
303
531
  /*
304
532
  str:
@@ -315,7 +543,6 @@ geneFilter: str
315
543
  }
316
544
  ]
317
545
  }
318
- */
319
546
  function mayAddCGC2filter(f: any, geneFilter?: string) {
320
547
  // reformulate f into f2
321
548
  // f may be "in" or "and". f2 is always "and", in order to join in additional filters
@@ -354,3 +581,4 @@ function mayAddCGC2filter(f: any, geneFilter?: string) {
354
581
 
355
582
  return f2
356
583
  }
584
+ */
package/routes/hicdata.ts CHANGED
@@ -86,7 +86,7 @@ function handle_hicdata(q: HicdataRequest) {
86
86
  }
87
87
  const n1 = Number.parseInt(l[0])
88
88
  const n2 = Number.parseInt(l[1])
89
- const v = Number.parseFloat(l[2])
89
+ const v = q.matrixType == 'oe' ? Math.log(Number.parseFloat(l[2])) : Number.parseFloat(l[2])
90
90
  if (Number.isNaN(n1) || Number.isNaN(n2) || Number.isNaN(v)) {
91
91
  fieldnotnumerical++
92
92
  return
@@ -25,7 +25,7 @@ export const api: any = {
25
25
 
26
26
  function init({ genomes }) {
27
27
  return async (req: any, res: any): Promise<void> => {
28
- const q = req.query as TermdbSingleSampleMutationRequest
28
+ const q: TermdbSingleSampleMutationRequest = req.query
29
29
  let result
30
30
  try {
31
31
  const g = genomes[q.genome]
@@ -42,7 +42,6 @@ export const api: any = {
42
42
  axisHeight: 60,
43
43
  rightMargin: 50,
44
44
  unit: 'abs',
45
- plotThickness: 150,
46
45
  termid: 'agedx'
47
46
  }
48
47
  },