@sjcrh/proteinpaint-server 2.107.0 → 2.108.1-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 +3 -3
- package/routes/correlationVolcano.js +20 -2
- package/routes/gdc.maf.js +2 -0
- package/routes/termdb.DE.js +27 -6
- package/routes/termdb.cluster.js +24 -7
- package/src/app.js +99 -28
- package/utils/edge.R +9 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sjcrh/proteinpaint-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.108.1-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",
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"@sjcrh/augen": "2.87.0",
|
|
62
62
|
"@sjcrh/proteinpaint-rust": "2.99.0",
|
|
63
|
-
"@sjcrh/proteinpaint-shared": "2.
|
|
64
|
-
"@sjcrh/proteinpaint-types": "2.
|
|
63
|
+
"@sjcrh/proteinpaint-shared": "2.108.0",
|
|
64
|
+
"@sjcrh/proteinpaint-types": "2.108.0",
|
|
65
65
|
"@types/express": "^5.0.0",
|
|
66
66
|
"@types/express-session": "^1.18.1",
|
|
67
67
|
"better-sqlite3": "^9.4.1",
|
|
@@ -3,7 +3,10 @@ import { getData } from "../src/termdb.matrix.js";
|
|
|
3
3
|
import run_R from "../src/run_R.js";
|
|
4
4
|
import serverconfig from "../src/serverconfig.js";
|
|
5
5
|
import { mayLog } from "#src/helpers.ts";
|
|
6
|
+
import { stdDev } from "#shared/violin.bins.js";
|
|
6
7
|
import path from "path";
|
|
8
|
+
const minArrayLength = 3;
|
|
9
|
+
const minSD = 0.05;
|
|
7
10
|
const api = {
|
|
8
11
|
endpoint: "termdb/correlationVolcano",
|
|
9
12
|
methods: {
|
|
@@ -65,16 +68,31 @@ async function compute(q, ds, genome) {
|
|
|
65
68
|
vtid2array.get(tw.$id).v2.push(variableValue);
|
|
66
69
|
}
|
|
67
70
|
}
|
|
71
|
+
const [acceptedVariables, skippedVariables] = Array.from(vtid2array.values()).reduce(
|
|
72
|
+
([accepted, skipped], t) => {
|
|
73
|
+
const grterThanOne = t.v1.length > minArrayLength && t.v2.length > minArrayLength;
|
|
74
|
+
const significantSD = stdDev(t.v1) > minSD && stdDev(t.v2) > minSD;
|
|
75
|
+
const v = grterThanOne && significantSD ? accepted : skipped;
|
|
76
|
+
if (v === accepted)
|
|
77
|
+
accepted.push(t);
|
|
78
|
+
if (v === skipped)
|
|
79
|
+
skipped.push({ tw$id: t.id });
|
|
80
|
+
return [accepted, skipped];
|
|
81
|
+
},
|
|
82
|
+
[[], []]
|
|
83
|
+
);
|
|
84
|
+
const result = { skippedVariables, variableItems: [] };
|
|
85
|
+
if (!acceptedVariables.length)
|
|
86
|
+
return result;
|
|
68
87
|
const input = {
|
|
69
88
|
method: q.correlationMethod || "pearson",
|
|
70
|
-
terms:
|
|
89
|
+
terms: acceptedVariables
|
|
71
90
|
};
|
|
72
91
|
const time1 = Date.now();
|
|
73
92
|
const output = {
|
|
74
93
|
terms: JSON.parse(await run_R(path.join(serverconfig.binpath, "utils", "corr.R"), JSON.stringify(input)))
|
|
75
94
|
};
|
|
76
95
|
mayLog("Time taken to run correlation analysis:", Date.now() - time1);
|
|
77
|
-
const result = { variableItems: [] };
|
|
78
96
|
for (const t of output.terms) {
|
|
79
97
|
const t2 = {
|
|
80
98
|
tw$id: t.id,
|
package/routes/gdc.maf.js
CHANGED
|
@@ -101,8 +101,10 @@ async function listMafFiles(q, ds) {
|
|
|
101
101
|
if (normalTypeName)
|
|
102
102
|
file.sample_types.push(normalTypeName);
|
|
103
103
|
}
|
|
104
|
+
file.sample_types = [...new Set(file.sample_types)];
|
|
104
105
|
files.push(file);
|
|
105
106
|
}
|
|
107
|
+
files.sort((a, b) => b.file_size - a.file_size);
|
|
106
108
|
const result = {
|
|
107
109
|
files,
|
|
108
110
|
filesTotal: re.data.pagination.total,
|
package/routes/termdb.DE.js
CHANGED
|
@@ -58,12 +58,14 @@ async function run_DE(param, ds, term_results) {
|
|
|
58
58
|
throw "samplelst.groups[0].values.length<1";
|
|
59
59
|
if (param.samplelst.groups[1].values?.length < 1)
|
|
60
60
|
throw "samplelst.groups[1].values.length<1";
|
|
61
|
-
param.storage_type = ds.queries.rnaseqGeneCount.storage_type;
|
|
62
61
|
const q = ds.queries.rnaseqGeneCount;
|
|
63
62
|
if (!q)
|
|
64
63
|
return;
|
|
65
64
|
if (!q.file)
|
|
66
65
|
throw "unknown data type for rnaseqGeneCount";
|
|
66
|
+
if (!q.storage_type)
|
|
67
|
+
throw "storage_type is not defined";
|
|
68
|
+
param.storage_type = q.storage_type;
|
|
67
69
|
const group1names = [];
|
|
68
70
|
const conf1_group1 = [];
|
|
69
71
|
for (const s of param.samplelst.groups[0].values) {
|
|
@@ -73,9 +75,17 @@ async function run_DE(param, ds, term_results) {
|
|
|
73
75
|
if (!n)
|
|
74
76
|
continue;
|
|
75
77
|
if (q.allSampleSet.has(n)) {
|
|
76
|
-
group1names.push(n);
|
|
77
78
|
if (param.tw) {
|
|
78
|
-
|
|
79
|
+
if (term_results.samples[s.sampleId]) {
|
|
80
|
+
if (param.tw.q.mode == "continuous") {
|
|
81
|
+
conf1_group1.push(term_results.samples[s.sampleId][param.tw.$id]["value"]);
|
|
82
|
+
} else {
|
|
83
|
+
conf1_group1.push(term_results.samples[s.sampleId][param.tw.$id]["key"]);
|
|
84
|
+
}
|
|
85
|
+
group1names.push(n);
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
group1names.push(n);
|
|
79
89
|
}
|
|
80
90
|
} else {
|
|
81
91
|
}
|
|
@@ -89,9 +99,17 @@ async function run_DE(param, ds, term_results) {
|
|
|
89
99
|
if (!n)
|
|
90
100
|
continue;
|
|
91
101
|
if (q.allSampleSet.has(n)) {
|
|
92
|
-
group2names.push(n);
|
|
93
102
|
if (param.tw) {
|
|
94
|
-
|
|
103
|
+
if (term_results.samples[s.sampleId]) {
|
|
104
|
+
if (param.tw.q.mode == "continuous") {
|
|
105
|
+
conf1_group2.push(term_results.samples[s.sampleId][param.tw.$id]["value"]);
|
|
106
|
+
} else {
|
|
107
|
+
conf1_group2.push(term_results.samples[s.sampleId][param.tw.$id]["key"]);
|
|
108
|
+
}
|
|
109
|
+
group2names.push(n);
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
group2names.push(n);
|
|
95
113
|
}
|
|
96
114
|
} else {
|
|
97
115
|
}
|
|
@@ -115,7 +133,10 @@ async function run_DE(param, ds, term_results) {
|
|
|
115
133
|
};
|
|
116
134
|
if (param.tw) {
|
|
117
135
|
expression_input.conf1 = [...conf1_group2, ...conf1_group1];
|
|
118
|
-
expression_input.
|
|
136
|
+
expression_input.conf1_mode = param.tw.q.mode;
|
|
137
|
+
if (new Set(expression_input.conf1).size === 1) {
|
|
138
|
+
throw "Confounding variable has only one value";
|
|
139
|
+
}
|
|
119
140
|
}
|
|
120
141
|
const sample_size_limit = 8;
|
|
121
142
|
let result;
|
package/routes/termdb.cluster.js
CHANGED
|
@@ -9,6 +9,7 @@ import { clusterMethodLst, distanceMethodLst } from "#shared/clustering.js";
|
|
|
9
9
|
import { getResult as getResultGene } from "#src/gene.js";
|
|
10
10
|
import { TermTypes, NUMERIC_DICTIONARY_TERM } from "#shared/terms.js";
|
|
11
11
|
import { getData } from "#src/termdb.matrix.js";
|
|
12
|
+
import { termType2label } from "#shared/terms.js";
|
|
12
13
|
const api = {
|
|
13
14
|
endpoint: "termdb/cluster",
|
|
14
15
|
methods: {
|
|
@@ -73,6 +74,12 @@ async function getResult(q, ds, genome) {
|
|
|
73
74
|
;
|
|
74
75
|
({ term2sample2value, byTermId, bySampleId } = await ds.queries[q.dataType].get(_q));
|
|
75
76
|
}
|
|
77
|
+
for (const [term, obj] of term2sample2value) {
|
|
78
|
+
if (Object.keys(obj).length === 0) {
|
|
79
|
+
term2sample2value.delete(term);
|
|
80
|
+
delete byTermId[term];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
76
83
|
if (term2sample2value.size == 0)
|
|
77
84
|
throw "no data";
|
|
78
85
|
if (term2sample2value.size == 1) {
|
|
@@ -106,14 +113,24 @@ async function getNumericDictTermAnnotation(q, ds, genome) {
|
|
|
106
113
|
}
|
|
107
114
|
async function doClustering(data, q, numCases = 1e3) {
|
|
108
115
|
const sampleSet = /* @__PURE__ */ new Set();
|
|
116
|
+
let firstTerm = true;
|
|
109
117
|
for (const o of data.values()) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
118
|
+
const currentSampleIds = new Set(Object.keys(o));
|
|
119
|
+
if (firstTerm) {
|
|
120
|
+
currentSampleIds.forEach((id) => sampleSet.add(id));
|
|
121
|
+
firstTerm = false;
|
|
122
|
+
} else {
|
|
123
|
+
for (const id of sampleSet) {
|
|
124
|
+
if (!currentSampleIds.has(id)) {
|
|
125
|
+
sampleSet.delete(id);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
114
129
|
}
|
|
115
130
|
if (sampleSet.size == 0)
|
|
116
|
-
throw
|
|
131
|
+
throw `termdb.cluster: There are no overlapping tested samples shared across the selected ${termType2label(
|
|
132
|
+
q.dataType
|
|
133
|
+
)}`;
|
|
117
134
|
if (!clusterMethodLst.find((i) => i.value == q.clusterMethod))
|
|
118
135
|
throw "Invalid cluster method";
|
|
119
136
|
if (!distanceMethodLst.find((i) => i.value == q.distanceMethod))
|
|
@@ -122,7 +139,7 @@ async function doClustering(data, q, numCases = 1e3) {
|
|
|
122
139
|
matrix: [],
|
|
123
140
|
row_names: [],
|
|
124
141
|
// genes
|
|
125
|
-
col_names: [...sampleSet],
|
|
142
|
+
col_names: [...sampleSet].slice(0, numCases),
|
|
126
143
|
// samples
|
|
127
144
|
cluster_method: q.clusterMethod,
|
|
128
145
|
distance_method: q.distanceMethod,
|
|
@@ -133,7 +150,7 @@ async function doClustering(data, q, numCases = 1e3) {
|
|
|
133
150
|
inputData.row_names.push(gene);
|
|
134
151
|
const row = [];
|
|
135
152
|
for (const s of inputData.col_names) {
|
|
136
|
-
row.push(o[s]
|
|
153
|
+
row.push(o[s]);
|
|
137
154
|
}
|
|
138
155
|
inputData.matrix.push(q.zScoreTransformation ? getZscore(row) : row);
|
|
139
156
|
}
|