@sjcrh/proteinpaint-server 2.185.0 → 2.187.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 +5 -5
- package/routes/genesetEnrichment.js +21 -5
- package/routes/profile.forms2.js +107 -0
- package/routes/termdb.DE.js +11 -13
- package/routes/termdb.cluster.js +7 -1
- package/routes/termdb.config.js +32 -18
- package/routes/termdb.diffMeth.js +26 -164
- package/routes/termdb.proteome.js +97 -66
- package/routes/termdb.singlecellSamples.js +13 -16
- package/routes/termdb.violinBox.js +0 -1
- package/src/app.js +1311 -873
|
@@ -26,42 +26,47 @@ function init({ genomes }) {
|
|
|
26
26
|
const term = q.term?.term || q.term;
|
|
27
27
|
if (!term?.name) throw "term.name missing";
|
|
28
28
|
const cohorts = [];
|
|
29
|
-
for (const
|
|
30
|
-
const
|
|
31
|
-
for (const
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
29
|
+
for (const organismName in ds.queries.proteome.organisms) {
|
|
30
|
+
const organism = ds.queries.proteome.organisms[organismName];
|
|
31
|
+
for (const assayName in organism.assays) {
|
|
32
|
+
const assay = organism.assays[assayName];
|
|
33
|
+
for (const cohortName in assay.cohorts || {}) {
|
|
34
|
+
const details = {
|
|
35
|
+
dbfile: ds.queries.proteome.dbfile,
|
|
36
|
+
organism: organismName,
|
|
37
|
+
assay: assayName,
|
|
38
|
+
cohort: cohortName
|
|
39
|
+
};
|
|
40
|
+
const tw = {
|
|
41
|
+
$id: "_",
|
|
42
|
+
term: {
|
|
43
|
+
name: term.name,
|
|
44
|
+
type: "proteomeAbundance",
|
|
45
|
+
proteomeDetails: details
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const cohortData = await ds.queries.proteome.get({
|
|
49
|
+
terms: [tw],
|
|
50
|
+
proteomeDetails: details,
|
|
51
|
+
filter: q.filter,
|
|
52
|
+
filter0: q.filter0,
|
|
53
|
+
for: "proteinView",
|
|
54
|
+
__abortSignal: q.__abortSignal
|
|
55
|
+
});
|
|
56
|
+
const controlSampleIds = cohortData.controlSampleIds || /* @__PURE__ */ new Set();
|
|
57
|
+
const prior = assay.cohorts[cohortName].prior;
|
|
58
|
+
for (const entry of cohortData.allEntries || []) {
|
|
59
|
+
const s2v = entry.s2v;
|
|
60
|
+
const stats = getCohortStats(s2v, controlSampleIds, prior);
|
|
61
|
+
delete entry.s2v;
|
|
62
|
+
entry.foldChange = stats.foldChange;
|
|
63
|
+
entry.pValue = stats.pValue;
|
|
64
|
+
entry.testedN = stats.testedN;
|
|
65
|
+
entry.controlN = stats.controlN;
|
|
66
|
+
if (assay.mclassOverride) entry.mclassOverride = assay.mclassOverride;
|
|
67
|
+
if (organism.genomeName) entry.genomeName = organism.genomeName;
|
|
68
|
+
cohorts.push(entry);
|
|
43
69
|
}
|
|
44
|
-
};
|
|
45
|
-
const cohortData = await ds.queries.proteome.get({
|
|
46
|
-
terms: [tw],
|
|
47
|
-
proteomeDetails: details,
|
|
48
|
-
filter: q.filter,
|
|
49
|
-
filter0: q.filter0,
|
|
50
|
-
for: "proteinView",
|
|
51
|
-
__abortSignal: q.__abortSignal
|
|
52
|
-
});
|
|
53
|
-
const controlSampleIds = cohortData.controlSampleIds || /* @__PURE__ */ new Set();
|
|
54
|
-
const prior = assay.cohorts[cohortName].prior;
|
|
55
|
-
for (const entry of cohortData.allEntries || []) {
|
|
56
|
-
const s2v = entry.s2v;
|
|
57
|
-
const stats = getCohortStats(s2v, controlSampleIds, prior);
|
|
58
|
-
delete entry.s2v;
|
|
59
|
-
entry.foldChange = stats.foldChange;
|
|
60
|
-
entry.pValue = stats.pValue;
|
|
61
|
-
entry.testedN = stats.testedN;
|
|
62
|
-
entry.controlN = stats.controlN;
|
|
63
|
-
if (assay.mclassOverride) entry.mclassOverride = assay.mclassOverride;
|
|
64
|
-
cohorts.push(entry);
|
|
65
70
|
}
|
|
66
71
|
}
|
|
67
72
|
}
|
|
@@ -202,8 +207,8 @@ function lnGamma(z) {
|
|
|
202
207
|
async function validate_query_proteome(ds) {
|
|
203
208
|
const q = ds.queries.proteome;
|
|
204
209
|
if (!q) return;
|
|
205
|
-
if (!q.
|
|
206
|
-
throw "queries.proteome.
|
|
210
|
+
if (!q.organisms) {
|
|
211
|
+
throw "queries.proteome.organisms is missing";
|
|
207
212
|
}
|
|
208
213
|
if (!q.dbfile) {
|
|
209
214
|
throw "queries.proteome.dbfile is missing";
|
|
@@ -213,21 +218,31 @@ async function validate_query_proteome(ds) {
|
|
|
213
218
|
} catch (e) {
|
|
214
219
|
throw `Cannot connect to proteome db ${q.dbfile}: ${e.message || e}`;
|
|
215
220
|
}
|
|
216
|
-
for (const
|
|
217
|
-
const
|
|
218
|
-
if (
|
|
219
|
-
if (
|
|
220
|
-
if (
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
221
|
+
for (const organismName in q.organisms) {
|
|
222
|
+
const organism = q.organisms[organismName];
|
|
223
|
+
if (organism.columnIdx == null) throw `queries.proteome.organisms.${organismName}.columnIdx missing`;
|
|
224
|
+
if (organism.columnValue == null) throw `queries.proteome.organisms.${organismName}.columnValue missing`;
|
|
225
|
+
if (!organism.assays || typeof organism.assays != "object")
|
|
226
|
+
throw `queries.proteome.organisms.${organismName}.assays missing or invalid`;
|
|
227
|
+
for (const assayName in organism.assays) {
|
|
228
|
+
const assay = organism.assays[assayName];
|
|
229
|
+
if (assay.columnIdx == null)
|
|
230
|
+
throw `queries.proteome.organisms.${organismName}.assays.${assayName}.columnIdx missing`;
|
|
231
|
+
if (assay.columnValue == null)
|
|
232
|
+
throw `queries.proteome.organisms.${organismName}.assays.${assayName}.columnValue missing`;
|
|
233
|
+
if (assay.cohorts) {
|
|
234
|
+
for (const cohortName in assay.cohorts) {
|
|
235
|
+
const cohort = assay.cohorts[cohortName];
|
|
236
|
+
if (!cohort.controlFilter)
|
|
237
|
+
throw `Missing controlFilter in queries.proteome.organisms.${organismName}.assays.${assayName}.cohorts.${cohortName}`;
|
|
238
|
+
if (!cohort.caseFilter)
|
|
239
|
+
throw `Missing caseFilter in queries.proteome.organisms.${organismName}.assays.${assayName}.cohorts.${cohortName}`;
|
|
240
|
+
if (!cohort.prior?.d0 || !cohort.prior?.s0sq)
|
|
241
|
+
throw `Missing prior.d0 and prior.s0sq in queries.proteome.organisms.${organismName}.assays.${assayName}.cohorts.${cohortName}`;
|
|
242
|
+
}
|
|
243
|
+
} else {
|
|
244
|
+
throw `Invalid assay structure for "${assayName}". Must have .cohorts`;
|
|
228
245
|
}
|
|
229
|
-
} else {
|
|
230
|
-
throw `Invalid assay structure for "${assayName}". Must have .cohorts`;
|
|
231
246
|
}
|
|
232
247
|
}
|
|
233
248
|
q.find = async (arg) => {
|
|
@@ -235,22 +250,27 @@ async function validate_query_proteome(ds) {
|
|
|
235
250
|
if (!Array.isArray(proteins) || proteins.length == 0) throw "queries.proteome.find arg.proteins[] missing";
|
|
236
251
|
const matches = /* @__PURE__ */ new Set();
|
|
237
252
|
const details = arg?.proteomeDetails || {};
|
|
253
|
+
const organism = details.organism;
|
|
238
254
|
const assay = details.assay;
|
|
239
255
|
const cohort = details.cohort;
|
|
240
256
|
const MAX_FIND_RESULTS = 500;
|
|
241
257
|
const filters = [];
|
|
242
258
|
if (Object.keys(details).length) {
|
|
243
|
-
if (!assay || !cohort)
|
|
244
|
-
|
|
259
|
+
if (!organism || !assay || !cohort)
|
|
260
|
+
throw "queries.proteome.find arg.proteomeDetails.{organism,assay,cohort} missing";
|
|
261
|
+
const organismConfig = q.organisms?.[organism];
|
|
262
|
+
if (!organismConfig) throw `queries.proteome.find invalid organism: ${organism}`;
|
|
263
|
+
const assayConfig = organismConfig.assays?.[assay];
|
|
245
264
|
if (!assayConfig) throw `queries.proteome.find invalid assay: ${assay}`;
|
|
246
265
|
const cohortConfig = assayConfig?.cohorts?.[cohort];
|
|
247
266
|
if (!cohortConfig) throw `queries.proteome.find invalid cohort: ${cohort}`;
|
|
267
|
+
const organismFilter = [{ columnIdx: organismConfig.columnIdx, columnValue: organismConfig.columnValue }];
|
|
248
268
|
const assayFilter = [{ columnIdx: assayConfig.columnIdx, columnValue: assayConfig.columnValue }];
|
|
249
269
|
const cohortFilter = (Array.isArray(cohortConfig.caseFilter) ? cohortConfig.caseFilter : []).filter(
|
|
250
270
|
(filter) => !!filter
|
|
251
271
|
);
|
|
252
272
|
if (!cohortFilter.length) throw `queries.proteome.find invalid cohort caseFilter: ${cohort}`;
|
|
253
|
-
filters.push(...assayFilter, ...cohortFilter);
|
|
273
|
+
filters.push(...organismFilter, ...assayFilter, ...cohortFilter);
|
|
254
274
|
}
|
|
255
275
|
for (const p of proteins) {
|
|
256
276
|
if (!p) continue;
|
|
@@ -280,8 +300,8 @@ async function validate_query_proteome(ds) {
|
|
|
280
300
|
};
|
|
281
301
|
q.get = async (param) => {
|
|
282
302
|
if (!param?.terms?.length) throw "queries.proteome.get param.terms[] missing";
|
|
283
|
-
if (!param.proteomeDetails?.assay || !param.proteomeDetails?.cohort)
|
|
284
|
-
throw "queries.proteome.get param.proteomeDetails.{assay,cohort} missing";
|
|
303
|
+
if (!param.proteomeDetails?.assay || !param.proteomeDetails?.cohort || !param.proteomeDetails?.organism)
|
|
304
|
+
throw "queries.proteome.get param.proteomeDetails.{assay,cohort,organism} missing";
|
|
285
305
|
return await getProteomeValuesFromCohort(ds, param, q);
|
|
286
306
|
};
|
|
287
307
|
}
|
|
@@ -312,23 +332,28 @@ function buildFilterClause(filters) {
|
|
|
312
332
|
function queryDbRows(db, matchColumn, matchValue, filters) {
|
|
313
333
|
const { conditions, params } = buildFilterClause(filters);
|
|
314
334
|
const allConditions = [`${matchColumn} = ? COLLATE NOCASE`, ...conditions];
|
|
315
|
-
const sql = `SELECT identifier, protein_accession, isoform, modsite, gene, sample, value
|
|
335
|
+
const sql = `SELECT organism, disease, identifier, protein_accession, isoform, modsite, gene, sample, value
|
|
316
336
|
FROM proteome_abundance
|
|
317
337
|
WHERE ${allConditions.join(" AND ")}`;
|
|
318
338
|
return db.prepare(sql).all(matchValue, ...params);
|
|
319
339
|
}
|
|
320
340
|
async function getProteomeValuesFromCohort(ds, param, q) {
|
|
321
341
|
const db = ds.queries.proteome.db;
|
|
322
|
-
const { assay, cohort } = param.proteomeDetails;
|
|
323
|
-
const
|
|
342
|
+
const { assay, cohort, organism } = param.proteomeDetails;
|
|
343
|
+
const organismConfig = q.organisms?.[organism];
|
|
344
|
+
if (!organismConfig) throw `queries.proteome invalid organism: ${organism}`;
|
|
345
|
+
const organismColumnIdx = organismConfig.columnIdx;
|
|
346
|
+
const organismColumnValue = organismConfig.columnValue;
|
|
347
|
+
const assayConfig = organismConfig.assays?.[assay];
|
|
324
348
|
if (!assayConfig) throw `queries.proteome.get invalid assay: ${assay}`;
|
|
325
|
-
const PTMType =
|
|
349
|
+
const PTMType = assayConfig.PTMType;
|
|
326
350
|
const assayColumnIdx = assayConfig.columnIdx;
|
|
327
351
|
const assayColumnValue = assayConfig.columnValue;
|
|
328
352
|
const cohortConfig = assayConfig?.cohorts?.[cohort];
|
|
329
353
|
if (!cohortConfig) throw `queries.proteome.get invalid cohort: ${cohort}`;
|
|
330
354
|
const cohortControlFilter = cohortConfig.controlFilter;
|
|
331
355
|
const cohortCaseFilter = cohortConfig.caseFilter;
|
|
356
|
+
const organismFilter = [{ columnIdx: organismColumnIdx, columnValue: organismColumnValue }];
|
|
332
357
|
const assayFilter = [{ columnIdx: assayColumnIdx, columnValue: assayColumnValue }];
|
|
333
358
|
const term2sample2value = /* @__PURE__ */ new Map();
|
|
334
359
|
const allEntries = [];
|
|
@@ -346,8 +371,12 @@ async function getProteomeValuesFromCohort(ds, param, q) {
|
|
|
346
371
|
}
|
|
347
372
|
const matchColumn = param.for === "proteinView" ? "gene" : "identifier";
|
|
348
373
|
const matchValue = param.for === "proteinView" ? geneName : identifier;
|
|
349
|
-
const caseRows = queryDbRows(db, matchColumn, matchValue, [...assayFilter, ...cohortCaseFilter]);
|
|
350
|
-
const controlRows = queryDbRows(db, matchColumn, matchValue, [
|
|
374
|
+
const caseRows = queryDbRows(db, matchColumn, matchValue, [...organismFilter, ...assayFilter, ...cohortCaseFilter]);
|
|
375
|
+
const controlRows = queryDbRows(db, matchColumn, matchValue, [
|
|
376
|
+
...organismFilter,
|
|
377
|
+
...assayFilter,
|
|
378
|
+
...cohortControlFilter
|
|
379
|
+
]);
|
|
351
380
|
for (const row of controlRows) {
|
|
352
381
|
const sid = ds.cohort.termdb.q.sampleName2id(row.sample);
|
|
353
382
|
if (sid !== void 0) controlSampleIds.add(String(sid));
|
|
@@ -359,8 +388,8 @@ async function getProteomeValuesFromCohort(ds, param, q) {
|
|
|
359
388
|
if (sid !== void 0) allSampleIds.push(sid);
|
|
360
389
|
}
|
|
361
390
|
const uniqueSampleIds = [...new Set(allSampleIds)];
|
|
362
|
-
const
|
|
363
|
-
if (
|
|
391
|
+
const allowedSampleIds = await mayLimitSamples(param, uniqueSampleIds, ds);
|
|
392
|
+
if (allowedSampleIds?.size == 0) {
|
|
364
393
|
return { term2sample2value: /* @__PURE__ */ new Map(), byTermId: {}, bySampleId: {} };
|
|
365
394
|
}
|
|
366
395
|
if (param.for === "proteinView") {
|
|
@@ -368,9 +397,11 @@ async function getProteomeValuesFromCohort(ds, param, q) {
|
|
|
368
397
|
for (const row of allRows) {
|
|
369
398
|
const sid = ds.cohort.termdb.q.sampleName2id(row.sample);
|
|
370
399
|
if (sid === void 0) continue;
|
|
371
|
-
if (
|
|
400
|
+
if (allowedSampleIds && !allowedSampleIds.has(sid)) continue;
|
|
372
401
|
if (!entryMap.has(row.identifier)) {
|
|
373
402
|
entryMap.set(row.identifier, {
|
|
403
|
+
organism: row.organism,
|
|
404
|
+
disease: row.disease,
|
|
374
405
|
uniqueIdentifier: row.identifier,
|
|
375
406
|
assayName: assay,
|
|
376
407
|
cohortName: cohort,
|
|
@@ -391,7 +422,7 @@ async function getProteomeValuesFromCohort(ds, param, q) {
|
|
|
391
422
|
for (const row of allRows) {
|
|
392
423
|
const sid = ds.cohort.termdb.q.sampleName2id(row.sample);
|
|
393
424
|
if (sid === void 0) continue;
|
|
394
|
-
if (
|
|
425
|
+
if (allowedSampleIds && !allowedSampleIds.has(sid)) continue;
|
|
395
426
|
s2v[sid] = row.value;
|
|
396
427
|
}
|
|
397
428
|
if (Object.keys(s2v).length) {
|
|
@@ -135,23 +135,24 @@ function validateDataNative(D, ds) {
|
|
|
135
135
|
}
|
|
136
136
|
const file2Lines = {};
|
|
137
137
|
D.get = async (q) => {
|
|
138
|
+
const sampleId = q.sample?.eID || q.sample?.sID;
|
|
138
139
|
if (q.checkPlotAvailability) {
|
|
139
140
|
const plots2 = [];
|
|
140
141
|
for (const plot of D.plots) {
|
|
141
142
|
if (!q.plots.includes(plot.name)) continue;
|
|
142
|
-
const tsvfile = path.join(
|
|
143
|
-
serverconfig.tpmasterdir,
|
|
144
|
-
plot.folder,
|
|
145
|
-
(q.sample?.eID || q.sample?.sID) + (plot.fileSuffix || "")
|
|
146
|
-
);
|
|
143
|
+
const tsvfile = path.join(serverconfig.tpmasterdir, plot.folder, sampleId + (plot.fileSuffix || ""));
|
|
147
144
|
try {
|
|
148
145
|
await file_is_readable(tsvfile);
|
|
149
|
-
plots2.push({
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
146
|
+
plots2.push({ name: plot.name });
|
|
147
|
+
} catch (_) {
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const imgs = ds.queries.singleCell?.images;
|
|
151
|
+
if (imgs) {
|
|
152
|
+
const imgFile = path.join(serverconfig.tpmasterdir, imgs.folder, sampleId, imgs.fileName);
|
|
153
|
+
try {
|
|
154
|
+
await file_is_readable(imgFile);
|
|
155
|
+
plots2.push({ name: imgs?.label || "Image" });
|
|
155
156
|
} catch (_) {
|
|
156
157
|
}
|
|
157
158
|
}
|
|
@@ -166,11 +167,7 @@ function validateDataNative(D, ds) {
|
|
|
166
167
|
}
|
|
167
168
|
for (const plot of D.plots) {
|
|
168
169
|
if (!q.plots.includes(plot.name)) continue;
|
|
169
|
-
const tsvfile = path.join(
|
|
170
|
-
serverconfig.tpmasterdir,
|
|
171
|
-
plot.folder,
|
|
172
|
-
(q.sample?.eID || q.sample?.sID) + (plot.fileSuffix || "")
|
|
173
|
-
);
|
|
170
|
+
const tsvfile = path.join(serverconfig.tpmasterdir, plot.folder, sampleId + (plot.fileSuffix || ""));
|
|
174
171
|
if (!file2Lines[tsvfile]) {
|
|
175
172
|
await file_is_readable(tsvfile);
|
|
176
173
|
const text = await read_file(tsvfile);
|
|
@@ -71,7 +71,6 @@ function expandNumericTermCollection(q, data) {
|
|
|
71
71
|
throw new Error("overlayTw is not supported with numeric termCollection; member terms are used as the overlay");
|
|
72
72
|
if (q.divideTw) throw new Error("divideTw is not supported with numeric termCollection");
|
|
73
73
|
const termlst = term.termlst || [];
|
|
74
|
-
mayLog("termlst", termlst);
|
|
75
74
|
mayLog(
|
|
76
75
|
`Expanding numeric termCollection with ${termlst.length} member terms and ${Object.keys(data.samples).length} samples`
|
|
77
76
|
);
|