@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 +1 -1
- package/routes/termdb.cluster.ts +85 -5
- package/routes/termdb.getrootterm.ts +8 -2
- package/routes/termdb.gettermchildren.ts +3 -3
- package/server.js +1 -1
- package/server.js.map +1 -1
- package/utils/hclust.R +29 -47
package/package.json
CHANGED
package/routes/termdb.cluster.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
|
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
|