@sjcrh/proteinpaint-server 2.64.0 → 2.66.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 +2 -2
- package/routes/hicdata.js +17 -16
- package/routes/hicgenome.js +22 -15
- package/routes/termdb.categories.js +3 -0
- package/routes/termdb.cluster.js +6 -2
- package/routes/termdb.config.js +6 -1
- package/routes/termdb.singlecellSamples.js +44 -44
- package/routes/termdb.topVariablyExpressedGenes.js +12 -12
- package/src/app.js +488 -359
- package/utils/getGeneFromMatrix.R +40 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sjcrh/proteinpaint-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.66.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "a genomics visualization tool for exploring a cohort's genotype and phenotype data",
|
|
6
6
|
"main": "src/app.js",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"postpack": "./dedupjs.sh",
|
|
28
28
|
"dedup": "./dedupjs.sh",
|
|
29
29
|
"//todo": "refactor or deprecate the scripts below",
|
|
30
|
-
"pretest": "tsc
|
|
30
|
+
"pretest": "tsc && ./test/pretest.js",
|
|
31
31
|
"prepare": "ts-patch install",
|
|
32
32
|
"pretest:type": "npm run checkers",
|
|
33
33
|
"pretest:integration": "tsc --esModuleInterop genome/*.ts dataset/*.ts",
|
package/routes/hicdata.js
CHANGED
|
@@ -12,24 +12,25 @@ const api = {
|
|
|
12
12
|
},
|
|
13
13
|
response: {
|
|
14
14
|
typeId: "HicdataResponse"
|
|
15
|
-
}
|
|
16
|
-
/*
|
|
15
|
+
},
|
|
17
16
|
examples: [
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
17
|
+
{
|
|
18
|
+
request: {
|
|
19
|
+
body: {
|
|
20
|
+
embedder: "localhost",
|
|
21
|
+
url: "https://proteinpaint.stjude.org/ppdemo/hg19/hic/hic_demo.hic",
|
|
22
|
+
matrixType: "observed",
|
|
23
|
+
nmeth: "NONE",
|
|
24
|
+
pos1: "3",
|
|
25
|
+
pos2: "2",
|
|
26
|
+
resolution: 1e6
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
response: {
|
|
30
|
+
header: { status: 200 }
|
|
31
|
+
}
|
|
32
|
+
}
|
|
31
33
|
]
|
|
32
|
-
*/
|
|
33
34
|
},
|
|
34
35
|
post: {
|
|
35
36
|
alternativeFor: "get",
|
package/routes/hicgenome.js
CHANGED
|
@@ -8,11 +8,29 @@ const api = {
|
|
|
8
8
|
get: {
|
|
9
9
|
init,
|
|
10
10
|
request: {
|
|
11
|
-
typeId: "
|
|
11
|
+
typeId: "HicGenomeRequest"
|
|
12
12
|
},
|
|
13
13
|
response: {
|
|
14
|
-
typeId: "
|
|
15
|
-
}
|
|
14
|
+
typeId: "HicGenomeResponse"
|
|
15
|
+
},
|
|
16
|
+
examples: [
|
|
17
|
+
{
|
|
18
|
+
request: {
|
|
19
|
+
body: {
|
|
20
|
+
chrlst: ["chr1", "chr2"],
|
|
21
|
+
embedder: "localhost",
|
|
22
|
+
url: "https://proteinpaint.stjude.org/ppdemo/hg19/hic/hic_demo.hic",
|
|
23
|
+
matrixType: "observed",
|
|
24
|
+
nmeth: "NONE",
|
|
25
|
+
nochr: true,
|
|
26
|
+
resolution: 25e5
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
response: {
|
|
30
|
+
header: { status: 200 }
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
]
|
|
16
34
|
},
|
|
17
35
|
post: {
|
|
18
36
|
alternativeFor: "get",
|
|
@@ -34,15 +52,7 @@ function init() {
|
|
|
34
52
|
return new Promise((resolve, reject) => {
|
|
35
53
|
const pos1 = req.query.nochr ? lead.replace("chr", "") : lead;
|
|
36
54
|
const pos2 = req.query.nochr ? follow.replace("chr", "") : follow;
|
|
37
|
-
const par = [
|
|
38
|
-
matrixType,
|
|
39
|
-
req.query.nmeth || "NONE",
|
|
40
|
-
file,
|
|
41
|
-
pos1,
|
|
42
|
-
pos2,
|
|
43
|
-
req.query.isfrag ? "FRAG" : "BP",
|
|
44
|
-
req.query.resolution
|
|
45
|
-
];
|
|
55
|
+
const par = [matrixType, req.query.nmeth || "NONE", file, pos1, pos2, "BP", req.query.resolution];
|
|
46
56
|
const ps = spawn(serverconfig.hicstraw, par);
|
|
47
57
|
const rl = readline.createInterface({ input: ps.stdout });
|
|
48
58
|
const items = [];
|
|
@@ -61,9 +71,6 @@ function init() {
|
|
|
61
71
|
fieldnotnumerical++;
|
|
62
72
|
return;
|
|
63
73
|
}
|
|
64
|
-
if (req.query.mincutoff != void 0 && v <= req.query.mincutoff) {
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
74
|
items.push([n1, n2, v]);
|
|
68
75
|
});
|
|
69
76
|
data.push({ items, lead, follow });
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getOrderedLabels } from "#src/termdb.barchart.js";
|
|
2
2
|
import { getData } from "#src/termdb.matrix.js";
|
|
3
|
+
import { TermTypes } from "#shared/terms.js";
|
|
3
4
|
const api = {
|
|
4
5
|
endpoint: "termdb/categories",
|
|
5
6
|
methods: {
|
|
@@ -195,6 +196,8 @@ function getDefaultQ(term, q) {
|
|
|
195
196
|
}
|
|
196
197
|
if (term.type == "geneVariant")
|
|
197
198
|
return {};
|
|
199
|
+
if (term.type == TermTypes.SINGLECELL_CELLTYPE)
|
|
200
|
+
return {};
|
|
198
201
|
throw "unknown term type";
|
|
199
202
|
}
|
|
200
203
|
export {
|
package/routes/termdb.cluster.js
CHANGED
|
@@ -53,8 +53,12 @@ function init({ genomes }) {
|
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
async function getResult(q, ds) {
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
let _q = q;
|
|
57
|
+
if (q.dataType == TermTypes.GENE_EXPRESSION) {
|
|
58
|
+
_q = JSON.parse(JSON.stringify(q));
|
|
59
|
+
_q.forClusteringAnalysis = true;
|
|
60
|
+
}
|
|
61
|
+
const { term2sample2value, byTermId, bySampleId } = await ds.queries[q.dataType].get(_q);
|
|
58
62
|
if (term2sample2value.size == 0)
|
|
59
63
|
throw "no data";
|
|
60
64
|
if (term2sample2value.size == 1) {
|
package/routes/termdb.config.js
CHANGED
|
@@ -191,6 +191,10 @@ function addNonDictionaryQueries(c, ds, genome) {
|
|
|
191
191
|
q2.rnaseqGeneCount = true;
|
|
192
192
|
}
|
|
193
193
|
if (q.singleCell) {
|
|
194
|
+
const plots = "plots" in q.singleCell.data ? q.singleCell.data.plots.map((p) => ({
|
|
195
|
+
name: p.name,
|
|
196
|
+
colorColumn: p.colorColumn.name
|
|
197
|
+
})) : [];
|
|
194
198
|
q2.singleCell = {
|
|
195
199
|
samples: {
|
|
196
200
|
firstColumnName: q.singleCell.samples.firstColumnName,
|
|
@@ -199,7 +203,8 @@ function addNonDictionaryQueries(c, ds, genome) {
|
|
|
199
203
|
},
|
|
200
204
|
data: {
|
|
201
205
|
sameLegend: q.singleCell.data.sameLegend,
|
|
202
|
-
refName: q.singleCell.data.refName
|
|
206
|
+
refName: q.singleCell.data.refName,
|
|
207
|
+
plots
|
|
203
208
|
}
|
|
204
209
|
};
|
|
205
210
|
if (q.singleCell.geneExpression) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
3
|
+
import { read_file } from "#src/utils.js";
|
|
4
|
+
import run_R from "#src/run_R.js";
|
|
5
5
|
import serverconfig from "#src/serverconfig.js";
|
|
6
6
|
import { gdc_validate_query_singleCell_samples, gdc_validate_query_singleCell_data } from "#src/mds3.gdc.js";
|
|
7
7
|
const api = {
|
|
@@ -61,7 +61,7 @@ async function validate_query_singleCell(ds, genome) {
|
|
|
61
61
|
if (q.data.src == "gdcapi") {
|
|
62
62
|
gdc_validate_query_singleCell_data(ds, genome);
|
|
63
63
|
} else if (q.data.src == "native") {
|
|
64
|
-
validateDataNative(q.data);
|
|
64
|
+
validateDataNative(q.data, ds);
|
|
65
65
|
} else {
|
|
66
66
|
throw "unknown singleCell.data.src";
|
|
67
67
|
}
|
|
@@ -90,7 +90,7 @@ async function validateSamplesNative(S, ds) {
|
|
|
90
90
|
return { samples: Object.values(samples) };
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
|
-
function validateDataNative(D) {
|
|
93
|
+
function validateDataNative(D, ds) {
|
|
94
94
|
const nameSet = /* @__PURE__ */ new Set();
|
|
95
95
|
for (const plot of D.plots) {
|
|
96
96
|
if (nameSet.has(plot.name))
|
|
@@ -100,29 +100,45 @@ function validateDataNative(D) {
|
|
|
100
100
|
D.get = async (q) => {
|
|
101
101
|
try {
|
|
102
102
|
const plots = [];
|
|
103
|
+
let geneExpMap;
|
|
104
|
+
if (ds.queries.singleCell.geneExpression && q.gene) {
|
|
105
|
+
geneExpMap = await ds.queries.singleCell.geneExpression.get({ sample: q.sample, gene: q.gene });
|
|
106
|
+
}
|
|
107
|
+
const file2Lines = {};
|
|
103
108
|
for (const plot of D.plots) {
|
|
109
|
+
if (!q.plots.includes(plot.name))
|
|
110
|
+
continue;
|
|
104
111
|
const tsvfile = path.join(serverconfig.tpmasterdir, plot.folder, q.sample + plot.fileSuffix);
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
112
|
+
if (!file2Lines[tsvfile]) {
|
|
113
|
+
try {
|
|
114
|
+
await fs.promises.stat(tsvfile);
|
|
115
|
+
} catch (e) {
|
|
116
|
+
if (e.code == "ENOENT") {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (e.code == "EACCES")
|
|
120
|
+
throw "cannot read file, permission denied";
|
|
121
|
+
throw "failed to load sc data file";
|
|
110
122
|
}
|
|
111
|
-
|
|
112
|
-
throw "cannot read file, permission denied";
|
|
113
|
-
throw "failed to load sc data file";
|
|
123
|
+
file2Lines[tsvfile] = (await read_file(tsvfile)).trim().split("\n");
|
|
114
124
|
}
|
|
115
|
-
const lines =
|
|
125
|
+
const lines = file2Lines[tsvfile];
|
|
116
126
|
const cells = [];
|
|
117
127
|
for (let i = 1; i < lines.length; i++) {
|
|
118
128
|
const l = lines[i].split(" ");
|
|
119
|
-
const cellId = l[0], x = Number(l[plot.coordsColumns.x]), y = Number(l[plot.coordsColumns.y]);
|
|
129
|
+
const cellId = lines.length > 3 ? l[0] : void 0, x = Number(l[plot.coordsColumns.x]), y = Number(l[plot.coordsColumns.y]);
|
|
120
130
|
const category = l[plot.colorColumn?.index] || "";
|
|
121
131
|
if (!cellId)
|
|
122
132
|
throw "cell id missing";
|
|
123
133
|
if (!Number.isFinite(x) || !Number.isFinite(y))
|
|
124
134
|
throw "x/y not number";
|
|
125
|
-
|
|
135
|
+
const cell = { cellId, x, y, category };
|
|
136
|
+
if (geneExpMap) {
|
|
137
|
+
if (geneExpMap[cellId] !== void 0) {
|
|
138
|
+
cell.geneExp = geneExpMap[cellId];
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
cells.push(cell);
|
|
126
142
|
}
|
|
127
143
|
plots.push({ name: plot.name, cells, colorBy: plot.colorColumn?.name, colorMap: plot.colorColumn?.colorMap });
|
|
128
144
|
}
|
|
@@ -138,41 +154,25 @@ function validateDataNative(D) {
|
|
|
138
154
|
};
|
|
139
155
|
}
|
|
140
156
|
function validateGeneExpressionNative(G) {
|
|
157
|
+
G.sample2gene2expressionBins = {};
|
|
141
158
|
G.get = async (q) => {
|
|
142
|
-
const
|
|
159
|
+
const rdsfile = path.join(serverconfig.tpmasterdir, G.folder, q.sample + ".rds");
|
|
143
160
|
try {
|
|
144
|
-
await fs.promises.stat(
|
|
161
|
+
await fs.promises.stat(rdsfile);
|
|
145
162
|
} catch (e) {
|
|
146
|
-
|
|
163
|
+
return {};
|
|
147
164
|
}
|
|
148
|
-
|
|
149
|
-
|
|
165
|
+
let out;
|
|
166
|
+
try {
|
|
167
|
+
out = JSON.parse(
|
|
168
|
+
await run_R(path.join(serverconfig.binpath, "utils", "getGeneFromMatrix.R"), null, [rdsfile, q.gene])
|
|
169
|
+
);
|
|
170
|
+
} catch (e) {
|
|
171
|
+
return {};
|
|
172
|
+
}
|
|
173
|
+
return out;
|
|
150
174
|
};
|
|
151
175
|
}
|
|
152
|
-
function grepMatrix4geneExpression(tsvfile, gene, header) {
|
|
153
|
-
return new Promise((resolve, reject) => {
|
|
154
|
-
const cp = spawn("grep", ["-m", "1", gene + " ", tsvfile]);
|
|
155
|
-
const out = [], err = [];
|
|
156
|
-
cp.stdout.on("data", (d) => out.push(d));
|
|
157
|
-
cp.stderr.on("data", (d) => err.push(d));
|
|
158
|
-
cp.on("close", () => {
|
|
159
|
-
const e = err.join("");
|
|
160
|
-
if (e)
|
|
161
|
-
reject(e);
|
|
162
|
-
const l = out.join("").split(" ");
|
|
163
|
-
if (l.length != header.length)
|
|
164
|
-
reject(`number of fields differ between data line and header: ${l.length} ${header.length}`);
|
|
165
|
-
const cell2value = {};
|
|
166
|
-
for (let i = 1; i < l.length; i++) {
|
|
167
|
-
const v = Number(l[i]);
|
|
168
|
-
if (Number.isNaN(v))
|
|
169
|
-
continue;
|
|
170
|
-
cell2value[header[i]] = v;
|
|
171
|
-
}
|
|
172
|
-
resolve(cell2value);
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
176
|
export {
|
|
177
177
|
api,
|
|
178
178
|
validate_query_singleCell
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { gdcGetCasesWithExpressionDataFromCohort } from "../src/mds3.gdc.js";
|
|
2
1
|
import path from "path";
|
|
3
2
|
import { run_rust } from "@sjcrh/proteinpaint-rust";
|
|
4
3
|
import got from "got";
|
|
5
4
|
import serverconfig from "#src/serverconfig.js";
|
|
6
5
|
import { get_samples } from "#src/termdb.sql.js";
|
|
6
|
+
import { makeFilter } from "#src/mds3.gdc.js";
|
|
7
7
|
const api = {
|
|
8
8
|
endpoint: "termdb/topVariablyExpressedGenes",
|
|
9
9
|
methods: {
|
|
@@ -106,21 +106,20 @@ async function computeGenes4nativeDs(q, ds, matrixFile, samples) {
|
|
|
106
106
|
function gdcValidateQuery(ds, genome) {
|
|
107
107
|
ds.queries.topVariablyExpressedGenes.getGenes = async (q) => {
|
|
108
108
|
if (serverconfig.features.gdcGenes) {
|
|
109
|
-
console.log(
|
|
109
|
+
console.log(
|
|
110
|
+
"!!GDC!! using serverconfig.features.gdcGenes[] but not live api query. only use this on DEV and never on PROD!"
|
|
111
|
+
);
|
|
110
112
|
return serverconfig.features.gdcGenes;
|
|
111
113
|
}
|
|
112
|
-
if (!ds.__gdc.doneCaching)
|
|
114
|
+
if (!ds.__gdc.doneCaching) {
|
|
113
115
|
throw "The server has not finished caching the case IDs: try again in about 2 minutes.";
|
|
114
|
-
const caseLst = await gdcGetCasesWithExpressionDataFromCohort(q, ds);
|
|
115
|
-
if (caseLst.length == 0) {
|
|
116
|
-
return [];
|
|
117
116
|
}
|
|
118
117
|
const { host, headers } = ds.getHostHeaders(q);
|
|
119
118
|
const url = path.join(host.geneExp, "/gene_expression/gene_selection");
|
|
120
119
|
try {
|
|
121
120
|
const response = await got.post(url, {
|
|
122
121
|
headers,
|
|
123
|
-
body: JSON.stringify(getGeneSelectionArg(q
|
|
122
|
+
body: JSON.stringify(getGeneSelectionArg(q))
|
|
124
123
|
});
|
|
125
124
|
const re = JSON.parse(response.body);
|
|
126
125
|
const genes = [];
|
|
@@ -143,13 +142,14 @@ function gdcValidateQuery(ds, genome) {
|
|
|
143
142
|
throw e;
|
|
144
143
|
}
|
|
145
144
|
};
|
|
146
|
-
function getGeneSelectionArg(q
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
gene_ids: tempGetCGCgenes(genome),
|
|
145
|
+
function getGeneSelectionArg(q) {
|
|
146
|
+
const arg = {
|
|
147
|
+
// add any to avoid tsc err
|
|
148
|
+
case_filters: makeFilter(q),
|
|
151
149
|
selection_size: Number(q.maxGenes)
|
|
152
150
|
};
|
|
151
|
+
arg.gene_ids = tempGetCGCgenes(genome);
|
|
152
|
+
return arg;
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
155
|
function tempGetCGCgenes(genome) {
|