@sjcrh/proteinpaint-server 2.138.0 → 2.138.2
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/dataset/termdb.test.js +5 -1
- package/package.json +2 -2
- package/routes/brainImaging.js +1 -1
- package/routes/correlationVolcano.js +5 -5
- package/routes/filterTermValues.js +26 -25
- package/routes/profileFormScores.js +3 -4
- package/routes/profileScores.js +3 -4
- package/routes/termdb.DE.js +2 -4
- package/routes/termdb.boxplot.js +1 -9
- package/routes/termdb.categories.js +3 -3
- package/routes/termdb.cluster.js +8 -6
- package/routes/termdb.descrstats.js +6 -3
- package/routes/termdb.violin.js +10 -5
- package/src/app.js +92 -97
package/dataset/termdb.test.js
CHANGED
|
@@ -4,7 +4,8 @@ function termdb_test_default() {
|
|
|
4
4
|
isSupportedChartOverride: {
|
|
5
5
|
runChart: () => true,
|
|
6
6
|
frequencyChart: () => true,
|
|
7
|
-
report: () => true
|
|
7
|
+
report: () => true,
|
|
8
|
+
summarizeMutationDiagnosis: () => true
|
|
8
9
|
},
|
|
9
10
|
cohort: {
|
|
10
11
|
massNav: {
|
|
@@ -175,6 +176,9 @@ function termdb_test_default() {
|
|
|
175
176
|
]
|
|
176
177
|
}
|
|
177
178
|
}
|
|
179
|
+
},
|
|
180
|
+
defaultTw4correlationPlot: {
|
|
181
|
+
disease: { id: "diaggrp", q: {} }
|
|
178
182
|
}
|
|
179
183
|
},
|
|
180
184
|
scatterplots: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sjcrh/proteinpaint-server",
|
|
3
|
-
"version": "2.138.
|
|
3
|
+
"version": "2.138.2",
|
|
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",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"@sjcrh/proteinpaint-r": "2.137.2-0",
|
|
65
65
|
"@sjcrh/proteinpaint-rust": "2.137.2-0",
|
|
66
66
|
"@sjcrh/proteinpaint-shared": "2.137.3",
|
|
67
|
-
"@sjcrh/proteinpaint-types": "2.138.
|
|
67
|
+
"@sjcrh/proteinpaint-types": "2.138.1",
|
|
68
68
|
"@types/express": "^5.0.0",
|
|
69
69
|
"@types/express-session": "^1.18.1",
|
|
70
70
|
"better-sqlite3": "^9.4.1",
|
package/routes/brainImaging.js
CHANGED
|
@@ -62,7 +62,7 @@ async function getBrainImage(query, genomes, plane, index) {
|
|
|
62
62
|
if (overlayTW)
|
|
63
63
|
terms.push(overlayTW);
|
|
64
64
|
const selectedSampleNames = query.selectedSampleFileNames.map((s) => s.split(".nii")[0]);
|
|
65
|
-
const data = await getData({ terms }, ds
|
|
65
|
+
const data = await getData({ terms }, ds);
|
|
66
66
|
const divideByCat = {};
|
|
67
67
|
const uniqueOverlayTwCats = /* @__PURE__ */ new Set();
|
|
68
68
|
for (const sampleName of selectedSampleNames) {
|
|
@@ -29,7 +29,7 @@ function init({ genomes }) {
|
|
|
29
29
|
const ds = genome.datasets?.[q.dslabel];
|
|
30
30
|
if (!ds)
|
|
31
31
|
throw "invalid ds";
|
|
32
|
-
const result = await compute(q, ds
|
|
32
|
+
const result = await compute(q, ds);
|
|
33
33
|
res.send(result);
|
|
34
34
|
} catch (e) {
|
|
35
35
|
res.send({ error: e?.message || e });
|
|
@@ -38,16 +38,16 @@ function init({ genomes }) {
|
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
-
async function compute(q, ds
|
|
41
|
+
async function compute(q, ds) {
|
|
42
42
|
const terms = [q.featureTw, ...q.variableTwLst];
|
|
43
43
|
const data = await getData(
|
|
44
44
|
{
|
|
45
45
|
filter: q.filter,
|
|
46
46
|
filter0: q.filter0,
|
|
47
|
-
terms
|
|
47
|
+
terms,
|
|
48
|
+
__protected__: q.__protected__
|
|
48
49
|
},
|
|
49
|
-
ds
|
|
50
|
-
genome
|
|
50
|
+
ds
|
|
51
51
|
);
|
|
52
52
|
if (data.error)
|
|
53
53
|
throw data.error;
|
|
@@ -21,34 +21,14 @@ function init({ genomes }) {
|
|
|
21
21
|
if (!g)
|
|
22
22
|
throw "invalid genome name";
|
|
23
23
|
const ds = g.datasets?.[req.query.dslabel];
|
|
24
|
-
getFilters(req.query, ds,
|
|
24
|
+
getFilters(req.query, ds, res);
|
|
25
25
|
} catch (e) {
|
|
26
26
|
console.log(e);
|
|
27
27
|
res.send({ status: "error", error: e.message || e });
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
-
function
|
|
32
|
-
const values = Object.values(tw.term.values);
|
|
33
|
-
values.sort((v1, v2) => v1.label.localeCompare(v2.label));
|
|
34
|
-
const twSamples = samplesPerFilter[tw.term.id];
|
|
35
|
-
const data = [];
|
|
36
|
-
for (const sample of twSamples) {
|
|
37
|
-
data.push(filtersData.samples[sample]);
|
|
38
|
-
}
|
|
39
|
-
const annotations = data.filter((s) => s != void 0).map((sample) => sample[tw.$id]?.value);
|
|
40
|
-
const sampleValues = Array.from(new Set(annotations));
|
|
41
|
-
const filteredValues = [];
|
|
42
|
-
for (const value of values) {
|
|
43
|
-
const label = value.label.replace(/["']/g, "");
|
|
44
|
-
const disabled = !sampleValues.includes(value.key || value.label);
|
|
45
|
-
filteredValues.push({ value: value.key || value.label, label, disabled });
|
|
46
|
-
}
|
|
47
|
-
filteredValues.unshift({ label: "", value: "" });
|
|
48
|
-
filteredValues.sort((a, b) => a.label.localeCompare(b.label));
|
|
49
|
-
return filteredValues;
|
|
50
|
-
}
|
|
51
|
-
async function getFilters(query, ds, genome, res) {
|
|
31
|
+
async function getFilters(query, ds, res) {
|
|
52
32
|
if (!query.filterByUserSites)
|
|
53
33
|
authApi.mayAdjustFilter(query, ds, query.terms);
|
|
54
34
|
try {
|
|
@@ -58,12 +38,11 @@ async function getFilters(query, ds, genome, res) {
|
|
|
58
38
|
terms: query.terms,
|
|
59
39
|
__protected__: query.__protected__
|
|
60
40
|
},
|
|
61
|
-
ds
|
|
62
|
-
genome
|
|
41
|
+
ds
|
|
63
42
|
);
|
|
64
43
|
const tw2List = {};
|
|
65
44
|
for (const tw of query.terms) {
|
|
66
|
-
tw2List[tw.term.id] = getList(samplesPerFilter, filtersData, tw);
|
|
45
|
+
tw2List[tw.term.id] = getList(samplesPerFilter, filtersData, tw, query.showAll);
|
|
67
46
|
}
|
|
68
47
|
res.send({ ...tw2List });
|
|
69
48
|
} catch (e) {
|
|
@@ -71,6 +50,28 @@ async function getFilters(query, ds, genome, res) {
|
|
|
71
50
|
res.send({ error: e.message || e });
|
|
72
51
|
}
|
|
73
52
|
}
|
|
53
|
+
function getList(samplesPerFilter, filtersData, tw, showAll) {
|
|
54
|
+
const values = Object.values(tw.term.values);
|
|
55
|
+
values.sort((v1, v2) => v1.label.localeCompare(v2.label));
|
|
56
|
+
const twSamples = samplesPerFilter[tw.term.id];
|
|
57
|
+
const data = [];
|
|
58
|
+
for (const sample of twSamples) {
|
|
59
|
+
data.push(filtersData.samples[sample]);
|
|
60
|
+
}
|
|
61
|
+
const annotations = data.filter((s) => s != void 0).map((sample) => sample[tw.$id]?.value);
|
|
62
|
+
const sampleValues = Array.from(new Set(annotations));
|
|
63
|
+
const filteredValues = [];
|
|
64
|
+
for (const value of values) {
|
|
65
|
+
const label = value.label.replace(/["']/g, "");
|
|
66
|
+
const disabled = !sampleValues.includes(value.key || value.label);
|
|
67
|
+
if (!showAll && disabled)
|
|
68
|
+
continue;
|
|
69
|
+
filteredValues.push({ value: value.key || value.label, label, disabled });
|
|
70
|
+
}
|
|
71
|
+
filteredValues.unshift({ label: "", value: "" });
|
|
72
|
+
filteredValues.sort((a, b) => a.label.localeCompare(b.label));
|
|
73
|
+
return filteredValues;
|
|
74
|
+
}
|
|
74
75
|
export {
|
|
75
76
|
api
|
|
76
77
|
};
|
|
@@ -20,7 +20,7 @@ function init({ genomes }) {
|
|
|
20
20
|
if (!g)
|
|
21
21
|
throw "invalid genome name";
|
|
22
22
|
const ds = g.datasets?.[req.query.dslabel];
|
|
23
|
-
const result = await getScoresDict(req.query, ds
|
|
23
|
+
const result = await getScoresDict(req.query, ds);
|
|
24
24
|
res.send(result);
|
|
25
25
|
} catch (e) {
|
|
26
26
|
console.log(e);
|
|
@@ -28,7 +28,7 @@ function init({ genomes }) {
|
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
-
async function getScoresDict(query, ds
|
|
31
|
+
async function getScoresDict(query, ds) {
|
|
32
32
|
if (!query.filterByUserSites)
|
|
33
33
|
query.__protected__.ignoredTermIds.push(query.facilityTW.term.id);
|
|
34
34
|
const terms = [...query.scoreTerms, query.facilityTW];
|
|
@@ -41,8 +41,7 @@ async function getScoresDict(query, ds, genome) {
|
|
|
41
41
|
//if isRadarFacility and site is specified, do not apply the filter
|
|
42
42
|
__protected__: query.__protected__
|
|
43
43
|
},
|
|
44
|
-
ds
|
|
45
|
-
genome
|
|
44
|
+
ds
|
|
46
45
|
);
|
|
47
46
|
const lst = Object.values(data.samples);
|
|
48
47
|
let sites = lst.map((s) => {
|
package/routes/profileScores.js
CHANGED
|
@@ -20,7 +20,7 @@ function init({ genomes }) {
|
|
|
20
20
|
if (!g)
|
|
21
21
|
throw "invalid genome name";
|
|
22
22
|
const ds = g.datasets?.[req.query.dslabel];
|
|
23
|
-
const result = await getScores(req.query, ds
|
|
23
|
+
const result = await getScores(req.query, ds);
|
|
24
24
|
res.send(result);
|
|
25
25
|
} catch (e) {
|
|
26
26
|
console.log(e);
|
|
@@ -28,7 +28,7 @@ function init({ genomes }) {
|
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
-
async function getScores(query, ds
|
|
31
|
+
async function getScores(query, ds) {
|
|
32
32
|
if (!query.filterByUserSites)
|
|
33
33
|
query.__protected__.ignoredTermIds.push(query.facilityTW.term.id);
|
|
34
34
|
const terms = [query.facilityTW];
|
|
@@ -45,8 +45,7 @@ async function getScores(query, ds, genome) {
|
|
|
45
45
|
//if site is specified, do not apply the filter that is for the aggregation
|
|
46
46
|
__protected__: query.__protected__
|
|
47
47
|
},
|
|
48
|
-
ds
|
|
49
|
-
genome
|
|
48
|
+
ds
|
|
50
49
|
);
|
|
51
50
|
const lst = Object.values(data.samples);
|
|
52
51
|
let sites = lst.map((s) => {
|
package/routes/termdb.DE.js
CHANGED
|
@@ -40,8 +40,7 @@ function init({ genomes }) {
|
|
|
40
40
|
filter0: q.filter0,
|
|
41
41
|
terms
|
|
42
42
|
},
|
|
43
|
-
ds
|
|
44
|
-
genome
|
|
43
|
+
ds
|
|
45
44
|
);
|
|
46
45
|
if (term_results.error)
|
|
47
46
|
throw term_results.error;
|
|
@@ -55,8 +54,7 @@ function init({ genomes }) {
|
|
|
55
54
|
filter0: q.filter0,
|
|
56
55
|
terms: terms2
|
|
57
56
|
},
|
|
58
|
-
ds
|
|
59
|
-
genome
|
|
57
|
+
ds
|
|
60
58
|
);
|
|
61
59
|
if (term_results2.error)
|
|
62
60
|
throw term_results2.error;
|
package/routes/termdb.boxplot.js
CHANGED
|
@@ -31,15 +31,7 @@ function init({ genomes }) {
|
|
|
31
31
|
const terms = [q.tw];
|
|
32
32
|
if (q.overlayTw)
|
|
33
33
|
terms.push(q.overlayTw);
|
|
34
|
-
const data = await getData(
|
|
35
|
-
{
|
|
36
|
-
filter: q.filter,
|
|
37
|
-
filter0: q.filter0,
|
|
38
|
-
terms
|
|
39
|
-
},
|
|
40
|
-
ds,
|
|
41
|
-
genome
|
|
42
|
-
);
|
|
34
|
+
const data = await getData({ filter: q.filter, filter0: q.filter0, terms, __protected__: q.__protected__ }, ds);
|
|
43
35
|
if (data.error)
|
|
44
36
|
throw data.error;
|
|
45
37
|
const sampleType = `All ${data.sampleType?.plural_name || "samples"}`;
|
|
@@ -27,7 +27,7 @@ function init({ genomes }) {
|
|
|
27
27
|
const tdb = ds.cohort.termdb;
|
|
28
28
|
if (!tdb)
|
|
29
29
|
throw "invalid termdb object";
|
|
30
|
-
await trigger_getcategories(q, res, tdb, ds
|
|
30
|
+
await trigger_getcategories(q, res, tdb, ds);
|
|
31
31
|
} catch (e) {
|
|
32
32
|
res.send({ error: e?.message || e });
|
|
33
33
|
if (e instanceof Error && e.stack)
|
|
@@ -35,7 +35,7 @@ function init({ genomes }) {
|
|
|
35
35
|
}
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
|
-
async function trigger_getcategories(q, res, tdb, ds
|
|
38
|
+
async function trigger_getcategories(q, res, tdb, ds) {
|
|
39
39
|
if (!q.tw.$id)
|
|
40
40
|
q.tw.$id = "_";
|
|
41
41
|
const $id = q.tw.$id;
|
|
@@ -49,7 +49,7 @@ async function trigger_getcategories(q, res, tdb, ds, genome) {
|
|
|
49
49
|
// optional, from mds3 mayAddGetCategoryArgs()
|
|
50
50
|
__protected__: q.__protected__
|
|
51
51
|
};
|
|
52
|
-
const data = await getData(arg, ds
|
|
52
|
+
const data = await getData(arg, ds);
|
|
53
53
|
if (data.error)
|
|
54
54
|
throw data.error;
|
|
55
55
|
const [lst, orderedLabels] = getCategories(data, q, ds, $id);
|
package/routes/termdb.cluster.js
CHANGED
|
@@ -47,7 +47,7 @@ function init({ genomes }) {
|
|
|
47
47
|
throw `gene list is not an array`;
|
|
48
48
|
if (q.terms.length < 3)
|
|
49
49
|
throw `A minimum of three genes is required for clustering. Please refresh this page to clear this error.`;
|
|
50
|
-
result = await getResult(q, ds
|
|
50
|
+
result = await getResult(q, ds);
|
|
51
51
|
} else {
|
|
52
52
|
throw "unknown q.dataType " + q.dataType;
|
|
53
53
|
}
|
|
@@ -62,7 +62,7 @@ function init({ genomes }) {
|
|
|
62
62
|
res.send(result);
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
|
-
async function getResult(q, ds
|
|
65
|
+
async function getResult(q, ds) {
|
|
66
66
|
let _q = q;
|
|
67
67
|
if (q.dataType == TermTypes.GENE_EXPRESSION) {
|
|
68
68
|
_q = JSON.parse(JSON.stringify(q));
|
|
@@ -71,7 +71,7 @@ async function getResult(q, ds, genome) {
|
|
|
71
71
|
let term2sample2value, byTermId, bySampleId, skippedSexChrGenes;
|
|
72
72
|
if (q.dataType == NUMERIC_DICTIONARY_TERM) {
|
|
73
73
|
;
|
|
74
|
-
({ term2sample2value, byTermId, bySampleId } = await getNumericDictTermAnnotation(q, ds
|
|
74
|
+
({ term2sample2value, byTermId, bySampleId } = await getNumericDictTermAnnotation(q, ds));
|
|
75
75
|
} else {
|
|
76
76
|
;
|
|
77
77
|
({ term2sample2value, byTermId, bySampleId, skippedSexChrGenes } = await ds.queries[q.dataType].get(_q));
|
|
@@ -108,12 +108,14 @@ async function getResult(q, ds, genome) {
|
|
|
108
108
|
result.removedHierClusterTerms = removedHierClusterTerms;
|
|
109
109
|
return result;
|
|
110
110
|
}
|
|
111
|
-
async function getNumericDictTermAnnotation(q, ds
|
|
111
|
+
async function getNumericDictTermAnnotation(q, ds) {
|
|
112
112
|
const getDataArgs = {
|
|
113
|
+
terms: q.terms.map((term) => ({ term, q: { mode: "continuous" } })),
|
|
113
114
|
filter: q.filter,
|
|
114
|
-
|
|
115
|
+
filter0: q.filter0,
|
|
116
|
+
__protected__: q.__protected__
|
|
115
117
|
};
|
|
116
|
-
const data = await getData(getDataArgs, ds
|
|
118
|
+
const data = await getData(getDataArgs, ds);
|
|
117
119
|
const term2sample2value = /* @__PURE__ */ new Map();
|
|
118
120
|
for (const [key, sampleData] of Object.entries(data.samples)) {
|
|
119
121
|
for (const [term, value] of Object.entries(sampleData)) {
|
|
@@ -32,15 +32,18 @@ function init({ genomes }) {
|
|
|
32
32
|
q.tw.$id = "_";
|
|
33
33
|
const data = await getData(
|
|
34
34
|
{ filter: q.filter, filter0: q.filter0, terms: [q.tw], __protected__: q.__protected__ },
|
|
35
|
-
ds
|
|
36
|
-
genome
|
|
35
|
+
ds
|
|
37
36
|
);
|
|
38
37
|
if (data.error)
|
|
39
38
|
throw data.error;
|
|
40
39
|
const values = [];
|
|
41
40
|
for (const key in data.samples) {
|
|
42
41
|
const sample = data.samples[key];
|
|
43
|
-
const
|
|
42
|
+
const v = sample[q.tw.$id];
|
|
43
|
+
if (!v && v !== 0) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const value = v.value;
|
|
44
47
|
if (q.tw.q.hiddenValues?.[value]) {
|
|
45
48
|
continue;
|
|
46
49
|
}
|
package/routes/termdb.violin.js
CHANGED
|
@@ -32,7 +32,7 @@ function init({ genomes }) {
|
|
|
32
32
|
const ds = g.datasets?.[q.dslabel];
|
|
33
33
|
if (!ds)
|
|
34
34
|
throw "invalid ds";
|
|
35
|
-
data = await trigger_getViolinPlotData(q, ds
|
|
35
|
+
data = await trigger_getViolinPlotData(q, ds);
|
|
36
36
|
} catch (e) {
|
|
37
37
|
data = { error: e?.message || e };
|
|
38
38
|
if (e instanceof Error && e.stack)
|
|
@@ -41,7 +41,7 @@ function init({ genomes }) {
|
|
|
41
41
|
res.send(data);
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
|
-
async function trigger_getViolinPlotData(q, ds
|
|
44
|
+
async function trigger_getViolinPlotData(q, ds) {
|
|
45
45
|
if (typeof q.tw?.term != "object" || typeof q.tw?.q != "object")
|
|
46
46
|
throw "q.tw not of {term,q}";
|
|
47
47
|
const term = q.tw.term;
|
|
@@ -53,9 +53,14 @@ async function trigger_getViolinPlotData(q, ds, genome) {
|
|
|
53
53
|
if (q.divideTw)
|
|
54
54
|
terms.push(q.divideTw);
|
|
55
55
|
const data = await getData(
|
|
56
|
-
{
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
{
|
|
57
|
+
terms,
|
|
58
|
+
filter: q.filter,
|
|
59
|
+
filter0: q.filter0,
|
|
60
|
+
currentGeneNames: q.currentGeneNames,
|
|
61
|
+
__protected__: q.__protected__
|
|
62
|
+
},
|
|
63
|
+
ds
|
|
59
64
|
);
|
|
60
65
|
const sampleType = `All ${data.sampleType?.plural_name || "samples"}`;
|
|
61
66
|
if (data.error)
|