@sjcrh/proteinpaint-server 2.39.1 → 2.39.4

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.1",
3
+ "version": "2.39.4",
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",
@@ -1,11 +1,18 @@
1
- import { TermdbClusterRequest, TermdbClusterResponse } from '#shared/types/routes/termdb.cluster.ts'
2
1
  import path from 'path'
2
+ import fs from 'fs'
3
+ import lines2R from '#src/lines2R.js'
4
+ import {
5
+ TermdbClusterRequest,
6
+ TermdbClusterResponse,
7
+ Clustering,
8
+ ValidResponse,
9
+ SinglegeneResponse
10
+ } from '#shared/types/routes/termdb.cluster.ts'
3
11
  import * as utils from '#src/utils.js'
4
12
  import serverconfig from '#src/serverconfig.js'
5
13
  import { GeneExpressionQuery, GeneExpressionQueryNative } from '#shared/types/dataset.ts'
6
14
  import { gdc_validate_query_geneExpression } from '#src/mds3.gdc.js'
7
15
  import { mayLimitSamples } from '#src/mds3.filter.js'
8
- import { doClustering } from '#src/doClustering.js' // unable to convert this to ts yet, when converted, move all code here
9
16
  import { dtgeneexpression } from '#shared/common.js'
10
17
 
11
18
  export const api = {
@@ -57,14 +64,87 @@ async function getResult(q: TermdbClusterRequest, ds: any) {
57
64
  if (gene2sample2value.size == 1) {
58
65
  // get data for only 1 gene; still return data, may create violin plot later
59
66
  const g = Array.from(gene2sample2value.keys())[0]
60
- return { gene: g, data: gene2sample2value.get(g) }
67
+ return { gene: g, data: gene2sample2value.get(g) } as SinglegeneResponse
61
68
  }
62
69
 
63
70
  // have data for multiple genes, run clustering
64
71
  const t = Date.now() // use "t=new Date()" will lead to tsc error
65
- const clustering = await doClustering(gene2sample2value, q, ds)
72
+ const clustering: Clustering = await doClustering(gene2sample2value, q)
66
73
  if (serverconfig.debugmode) console.log('clustering done:', Date.now() - t, 'ms')
67
- return { clustering, byTermId, bySampleId }
74
+ return { clustering, byTermId, bySampleId } as ValidResponse
75
+ }
76
+
77
+ async function doClustering(data: any, q: TermdbClusterRequest) {
78
+ // get set of unique sample names, to generate col_names dimension
79
+ const sampleSet = new Set()
80
+ for (const o of data.values()) {
81
+ // {sampleId: value}
82
+ for (const s in o) sampleSet.add(s)
83
+ break
84
+ }
85
+
86
+ const inputData = {
87
+ matrix: [] as number[][],
88
+ row_names: [] as string[], // genes
89
+ col_names: [...sampleSet] as string[], // samples
90
+ cluster_method: q.clusterMethod as string,
91
+ plot_image: false // When true causes cluster.rs to plot the image into a png file (EXPERIMENTAL)
92
+ }
93
+
94
+ // compose "data{}" into a matrix
95
+ for (const [gene, o] of data) {
96
+ inputData.row_names.push(gene)
97
+ const row: number[] = []
98
+ for (const s of inputData.col_names) {
99
+ row.push(o[s] || 0)
100
+ }
101
+ inputData.matrix.push(getZscore(row))
102
+ }
103
+
104
+ const Rinputfile = path.join(serverconfig.cachedir, Math.random().toString() + '.json')
105
+ await utils.write_file(Rinputfile, JSON.stringify(inputData))
106
+ const Routput = JSON.parse(await lines2R(path.join(serverconfig.binpath, 'utils/hclust.R'), [], [Rinputfile]))
107
+ fs.unlink(Rinputfile, (arg: any) => {
108
+ return
109
+ })
110
+
111
+ const row_names_index: number[] = Routput.RowOrder.map(row => inputData.row_names.indexOf(row.name)) // sorted rows. value is array index in input data
112
+ const col_names_index: number[] = Routput.ColOrder.map(col => inputData.col_names.indexOf(col.name)) // sorted columns, value is array index from input array
113
+
114
+ // generated sorted matrix based on row/col clustering order
115
+ const output_matrix: number[][] = []
116
+ for (const rowI of row_names_index) {
117
+ const newRow: number[] = []
118
+ for (const colI of col_names_index) {
119
+ newRow.push(inputData.matrix[rowI][colI])
120
+ }
121
+ output_matrix.push(newRow)
122
+ }
123
+
124
+ return {
125
+ row: {
126
+ merge: Routput.RowMerge,
127
+ height: Routput.RowHeight,
128
+ order: Routput.RowOrder,
129
+ inputOrder: inputData.row_names
130
+ },
131
+ col: {
132
+ merge: Routput.ColumnMerge,
133
+ height: Routput.ColumnHeight,
134
+ order: Routput.ColOrder,
135
+ inputOrder: inputData.col_names
136
+ },
137
+ matrix: output_matrix
138
+ }
139
+ }
140
+ function getZscore(l: number[]) {
141
+ const mean: number = l.reduce((sum, v) => sum + v, 0) / l.length
142
+ const sd: number = Math.sqrt(l.reduce((sum, v) => sum + Math.pow(v - mean, 2), 0) / l.length)
143
+
144
+ if (sd == 0) {
145
+ return l
146
+ }
147
+ return l.map(v => (v - mean) / sd)
68
148
  }
69
149
 
70
150
  export async function validate_query_geneExpression(ds: any, genome: any) {
@@ -1,4 +1,6 @@
1
1
  import { getroottermRequest, getroottermResponse } from '#shared/types/routes/termdb.getrootterm.ts'
2
+ import { get_ds_tdb } from '#src/termdb.js'
3
+
2
4
 
3
5
  export const api: any = {
4
6
  endpoint: 'termdb/rootterm',
@@ -38,12 +40,16 @@ export const api: any = {
38
40
  function init({ genomes }) {
39
41
  return async (req: any, res: any): Promise<void> => {
40
42
  const q = req.query as getroottermRequest
43
+ const cohortValues = q.cohortValues ? q.cohortValues : ''
44
+ const treeFilter = q.treeFilter ? q.treeFilter : ''
45
+ //res.send({ lst: await tdb.q.getRootTerms(cohortValues, treeFilter) })
46
+
41
47
  try {
42
48
  const g = genomes[req.query.genome]
43
49
  if (!g) throw 'invalid genome name'
44
- const ds = g.datasets[req.query.dslabel]
50
+
51
+ const [ds, tdb] = get_ds_tdb(g, q)
45
52
  if (!ds) throw 'invalid dataset name'
46
- const tdb = ds.cohort.termdb
47
53
  if (!tdb) throw 'invalid termdb object'
48
54
 
49
55
  await trigger_rootterm(q, res, tdb) // as getroottermResponse
@@ -1,5 +1,5 @@
1
1
  import { gettermchildrenRequest, gettermchildrenResponse } from '#shared/types/routes/termdb.gettermchildren.ts'
2
- import { copy_term } from '#src/termdb.js'
2
+ import { copy_term, get_ds_tdb } from '#src/termdb.js'
3
3
 
4
4
  export const api: any = {
5
5
  endpoint: 'termdb/termchildren',
@@ -43,11 +43,11 @@ function init({ genomes }) {
43
43
  try {
44
44
  const g = genomes[req.query.genome]
45
45
  if (!g) throw 'invalid genome name'
46
- const ds = g.datasets[req.query.dslabel]
46
+ const [ds, tdb] =await get_ds_tdb(g, q)
47
47
  if (!ds) throw 'invalid dataset name'
48
- const tdb = ds.cohort.termdb
49
48
  if (!tdb) throw 'invalid termdb object'
50
49
 
50
+
51
51
  await trigger_children(q, res, tdb)
52
52
  } catch (e) {
53
53
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment