@sjcrh/proteinpaint-server 2.170.0 → 2.171.0-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/grin2.js +8 -16
- package/routes/healthcheck.js +2 -1
- package/routes/termdb.boxplot.js +47 -48
- package/routes/termdb.violin.js +10 -2
- package/src/app.js +402 -180
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sjcrh/proteinpaint-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.171.0-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",
|
|
@@ -62,11 +62,11 @@
|
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
64
|
"@sjcrh/augen": "2.143.0",
|
|
65
|
-
"@sjcrh/proteinpaint-python": "2.
|
|
65
|
+
"@sjcrh/proteinpaint-python": "2.171.0-0",
|
|
66
66
|
"@sjcrh/proteinpaint-r": "2.152.1-0",
|
|
67
|
-
"@sjcrh/proteinpaint-rust": "2.
|
|
68
|
-
"@sjcrh/proteinpaint-shared": "2.
|
|
69
|
-
"@sjcrh/proteinpaint-types": "2.
|
|
67
|
+
"@sjcrh/proteinpaint-rust": "2.171.0-0",
|
|
68
|
+
"@sjcrh/proteinpaint-shared": "2.171.0-0",
|
|
69
|
+
"@sjcrh/proteinpaint-types": "2.171.0-0",
|
|
70
70
|
"@types/express": "^5.0.0",
|
|
71
71
|
"@types/express-session": "^1.18.1",
|
|
72
72
|
"better-sqlite3": "^12.4.1",
|
package/routes/grin2.js
CHANGED
|
@@ -6,16 +6,7 @@ import { run_rust } from "@sjcrh/proteinpaint-rust";
|
|
|
6
6
|
import { mayLog } from "#src/helpers.ts";
|
|
7
7
|
import { get_samples } from "#src/termdb.sql.js";
|
|
8
8
|
import { read_file, file_is_readable } from "#src/utils.js";
|
|
9
|
-
import {
|
|
10
|
-
dtsnvindel,
|
|
11
|
-
dtcnv,
|
|
12
|
-
dtfusionrna,
|
|
13
|
-
dtsv,
|
|
14
|
-
dt2lesion,
|
|
15
|
-
optionToDt,
|
|
16
|
-
formatElapsedTime,
|
|
17
|
-
MANHATTAN_LOG_QVALUE_CUTOFF
|
|
18
|
-
} from "#shared";
|
|
9
|
+
import { dtsnvindel, dtcnv, dtfusionrna, dtsv, dt2lesion, optionToDt, formatElapsedTime } from "#shared";
|
|
19
10
|
import crypto from "crypto";
|
|
20
11
|
const MAX_LESIONS_PER_TYPE = serverconfig.features.grin2maxLesionPerType || 11e4;
|
|
21
12
|
const api = {
|
|
@@ -115,9 +106,6 @@ async function runGrin2(g, ds, request) {
|
|
|
115
106
|
lesionTypeMap: buildLesionTypeMap(availableDataTypes)
|
|
116
107
|
};
|
|
117
108
|
for (const c in g.majorchr) {
|
|
118
|
-
if (ds.queries.singleSampleMutation.discoPlot?.skipChrM) {
|
|
119
|
-
if (c.toLowerCase() == "chrm") continue;
|
|
120
|
-
}
|
|
121
109
|
pyInput.chromosomelist[c] = g.majorchr[c];
|
|
122
110
|
}
|
|
123
111
|
const grin2AnalysisStart = Date.now();
|
|
@@ -141,7 +129,9 @@ async function runGrin2(g, ds, request) {
|
|
|
141
129
|
png_dot_radius: request.pngDotRadius,
|
|
142
130
|
lesion_type_colors: request.lesionTypeColors,
|
|
143
131
|
q_value_threshold: request.qValueThreshold,
|
|
144
|
-
|
|
132
|
+
max_capped_points: request.maxCappedPoints,
|
|
133
|
+
hard_cap: request.hardCap,
|
|
134
|
+
bin_size: request.binSize
|
|
145
135
|
};
|
|
146
136
|
const manhattanPlotStart = Date.now();
|
|
147
137
|
const rsResult = await run_rust("manhattan_plot", JSON.stringify(rustInput));
|
|
@@ -214,12 +204,14 @@ async function processSampleData(samples, ds, request, tracker) {
|
|
|
214
204
|
await file_is_readable(filepath);
|
|
215
205
|
const mlst = JSON.parse(await read_file(filepath));
|
|
216
206
|
const { sampleLesions, contributedTypes } = await processSampleMlst(sample.name, mlst, request, tracker);
|
|
217
|
-
|
|
207
|
+
const skipChrM = ds.queries.singleSampleMutation.discoPlot?.skipChrM;
|
|
208
|
+
const filteredLesions = skipChrM ? sampleLesions.filter((lesion) => lesion[1].toLowerCase() !== "chrm") : sampleLesions;
|
|
209
|
+
lesions.push(...filteredLesions);
|
|
218
210
|
for (const type of contributedTypes) {
|
|
219
211
|
samplesPerType.get(type)?.add(sample.name);
|
|
220
212
|
}
|
|
221
213
|
processingSummary.processedSamples += 1;
|
|
222
|
-
processingSummary.totalLesions +=
|
|
214
|
+
processingSummary.totalLesions += filteredLesions.length;
|
|
223
215
|
if (allTypesCapped(tracker)) {
|
|
224
216
|
const remaining = samples.length - 1 - i;
|
|
225
217
|
if (remaining > 0) processingSummary.unprocessedSamples += remaining;
|
package/routes/healthcheck.js
CHANGED
package/routes/termdb.boxplot.js
CHANGED
|
@@ -5,6 +5,7 @@ import { sortPlot2Values } from "./termdb.violin.ts";
|
|
|
5
5
|
import { getDescrStats, getStdDev, getMean } from "./termdb.descrstats.ts";
|
|
6
6
|
import { run_rust } from "@sjcrh/proteinpaint-rust";
|
|
7
7
|
import { roundValueAuto } from "#shared/roundValue.js";
|
|
8
|
+
import { isNumericTerm } from "@sjcrh/proteinpaint-shared";
|
|
8
9
|
const api = {
|
|
9
10
|
endpoint: "termdb/boxplot",
|
|
10
11
|
methods: {
|
|
@@ -31,13 +32,11 @@ function init({ genomes }) {
|
|
|
31
32
|
try {
|
|
32
33
|
const data = await getData({ filter: q.filter, filter0: q.filter0, terms, __protected__: q.__protected__ }, ds);
|
|
33
34
|
if (data.error) throw new Error(data.error);
|
|
34
|
-
const { absMin, absMax, charts, uncomputableValues, descrStats, outlierMin, outlierMax } = await processData(
|
|
35
|
-
data,
|
|
36
|
-
q
|
|
37
|
-
);
|
|
35
|
+
const { absMin, absMax, bins, charts, uncomputableValues, descrStats, outlierMin, outlierMax } = await processData(data, q);
|
|
38
36
|
const returnData = {
|
|
39
37
|
absMin: q.removeOutliers ? outlierMin : absMin,
|
|
40
38
|
absMax: q.removeOutliers ? outlierMax : absMax,
|
|
39
|
+
bins,
|
|
41
40
|
charts,
|
|
42
41
|
uncomputableValues: setUncomputableValues(uncomputableValues),
|
|
43
42
|
descrStats
|
|
@@ -54,15 +53,15 @@ async function processData(data, q) {
|
|
|
54
53
|
const values = samples.map((s) => s?.[q.tw.$id]?.value).filter((v) => typeof v === "number" && !q.tw.term.values?.[v]?.uncomputable);
|
|
55
54
|
const descrStats = getDescrStats(values, q.removeOutliers);
|
|
56
55
|
const sampleType = `All ${data.sampleType?.plural_name || "samples"}`;
|
|
57
|
-
const
|
|
58
|
-
const
|
|
56
|
+
const overlayTw = q.overlayTw;
|
|
57
|
+
const divideTw = q.divideTw;
|
|
59
58
|
const { absMin, absMax, chart2plot2values, uncomputableValues } = parseValues(
|
|
60
59
|
q,
|
|
61
60
|
data,
|
|
62
61
|
sampleType,
|
|
63
62
|
q.isLogScale,
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
overlayTw,
|
|
64
|
+
divideTw
|
|
66
65
|
);
|
|
67
66
|
if (!absMin && absMin !== 0) throw new Error("absMin is undefined");
|
|
68
67
|
if (!absMax && absMax !== 0) throw new Error("absMax is undefined");
|
|
@@ -70,7 +69,7 @@ async function processData(data, q) {
|
|
|
70
69
|
let outlierMin = Number.POSITIVE_INFINITY, outlierMax = Number.NEGATIVE_INFINITY;
|
|
71
70
|
for (const [chart, plot2values] of chart2plot2values) {
|
|
72
71
|
const plots = [];
|
|
73
|
-
for (const [key, values2] of sortPlot2Values(data, plot2values,
|
|
72
|
+
for (const [key, values2] of sortPlot2Values(data, plot2values, overlayTw)) {
|
|
74
73
|
;
|
|
75
74
|
[outlierMax, outlierMin] = setPlotData(
|
|
76
75
|
plots,
|
|
@@ -79,14 +78,14 @@ async function processData(data, q) {
|
|
|
79
78
|
sampleType,
|
|
80
79
|
descrStats,
|
|
81
80
|
q,
|
|
82
|
-
data,
|
|
83
81
|
outlierMin,
|
|
84
82
|
outlierMax,
|
|
85
|
-
|
|
83
|
+
overlayTw
|
|
86
84
|
);
|
|
87
85
|
}
|
|
88
86
|
if (q.tw.term?.values) setHiddenPlots(q.tw, plots);
|
|
89
|
-
if (
|
|
87
|
+
if (overlayTw && overlayTw.term?.values) setHiddenPlots(overlayTw, plots);
|
|
88
|
+
if (divideTw && divideTw.term?.values) setHiddenPlots(divideTw, plots);
|
|
90
89
|
if (q.orderByMedian == true) {
|
|
91
90
|
plots.sort((a, b) => a.boxplot.p50 - b.boxplot.p50);
|
|
92
91
|
}
|
|
@@ -96,11 +95,16 @@ async function processData(data, q) {
|
|
|
96
95
|
}, 0);
|
|
97
96
|
charts[chart] = { chartId: chart, plots, sampleCount };
|
|
98
97
|
}
|
|
99
|
-
|
|
98
|
+
const bins = {
|
|
99
|
+
term1: numericBins(q.tw, data)
|
|
100
|
+
};
|
|
101
|
+
if (overlayTw) bins.term2 = numericBins(overlayTw, data);
|
|
102
|
+
if (divideTw) bins.term0 = numericBins(divideTw, data);
|
|
103
|
+
if (q.showAssocTests && overlayTw) await getWilcoxonData(charts);
|
|
100
104
|
Object.keys(charts).forEach((c) => charts[c].plots.forEach((p) => delete p.tempValues));
|
|
101
|
-
return { absMin, absMax, charts, uncomputableValues, descrStats, outlierMin, outlierMax };
|
|
105
|
+
return { absMin, absMax, bins, charts, uncomputableValues, descrStats, outlierMin, outlierMax };
|
|
102
106
|
}
|
|
103
|
-
function setPlotData(plots, values, key, sampleType, descrStats, q,
|
|
107
|
+
function setPlotData(plots, values, key, sampleType, descrStats, q, outlierMin, outlierMax, overlayTw) {
|
|
104
108
|
const sortedValues = values.sort((a, b) => a - b);
|
|
105
109
|
const vs = sortedValues.map((v) => {
|
|
106
110
|
const value = { value: v };
|
|
@@ -112,33 +116,24 @@ function setPlotData(plots, values, key, sampleType, descrStats, q, data, outlie
|
|
|
112
116
|
}
|
|
113
117
|
const boxplot = boxplot_getvalue(vs, q.removeOutliers);
|
|
114
118
|
if (!boxplot) throw new Error("boxplot_getvalue failed [termdb.boxplot init()]");
|
|
115
|
-
const
|
|
119
|
+
const plot = {
|
|
116
120
|
boxplot,
|
|
117
121
|
descrStats: setIndividualBoxPlotStats(boxplot, sortedValues),
|
|
118
122
|
//quick fix
|
|
119
123
|
//to delete later
|
|
120
124
|
tempValues: sortedValues
|
|
121
125
|
};
|
|
122
|
-
if (
|
|
123
|
-
const _key =
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
key: _key,
|
|
129
|
-
overlayBins: overlayBins.has(key) ? overlayBins.get(key) : null,
|
|
130
|
-
seriesId: key
|
|
131
|
-
});
|
|
132
|
-
plot.boxplot.label = plotLabel;
|
|
133
|
-
plots.push(plot);
|
|
126
|
+
if (overlayTw) {
|
|
127
|
+
const _key = overlayTw?.term?.values?.[key]?.label || key;
|
|
128
|
+
plot.color = overlayTw?.term?.values?.[key]?.color || null;
|
|
129
|
+
plot.key = _key;
|
|
130
|
+
plot.seriesId = key;
|
|
131
|
+
plot.boxplot.label = `${_key}, n=${values.length}`;
|
|
134
132
|
} else {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
key: sampleType
|
|
138
|
-
});
|
|
139
|
-
plot.boxplot.label = plotLabel;
|
|
140
|
-
plots.push(plot);
|
|
133
|
+
plot.key = sampleType;
|
|
134
|
+
plot.boxplot.label = `${sampleType}, n=${values.length}`;
|
|
141
135
|
}
|
|
136
|
+
plots.push(plot);
|
|
142
137
|
return [outlierMax, outlierMin];
|
|
143
138
|
}
|
|
144
139
|
function setIndividualBoxPlotStats(boxplot, values) {
|
|
@@ -204,7 +199,7 @@ async function getWilcoxonData(charts) {
|
|
|
204
199
|
}
|
|
205
200
|
}
|
|
206
201
|
}
|
|
207
|
-
function parseValues(q, data, sampleType, isLog,
|
|
202
|
+
function parseValues(q, data, sampleType, isLog, overlayTw, divideTw) {
|
|
208
203
|
const chart2plot2values = /* @__PURE__ */ new Map();
|
|
209
204
|
const uncomputableValues = {};
|
|
210
205
|
let absMin = Infinity, absMax = -Infinity;
|
|
@@ -219,20 +214,20 @@ function parseValues(q, data, sampleType, isLog, overlayTerm, divideTerm) {
|
|
|
219
214
|
if (isLog && value.value <= 0) continue;
|
|
220
215
|
let chart = "";
|
|
221
216
|
let plot = sampleType;
|
|
222
|
-
if (
|
|
223
|
-
if (!val[
|
|
224
|
-
const value0 = val[
|
|
225
|
-
if (
|
|
226
|
-
const label =
|
|
217
|
+
if (divideTw) {
|
|
218
|
+
if (!val[divideTw?.$id]) continue;
|
|
219
|
+
const value0 = val[divideTw.$id];
|
|
220
|
+
if (divideTw.term?.values?.[value0.key]?.uncomputable) {
|
|
221
|
+
const label = divideTw.term.values[value0?.key]?.label;
|
|
227
222
|
uncomputableValues[label] = (uncomputableValues[label] || 0) + 1;
|
|
228
223
|
}
|
|
229
224
|
chart = value0.key;
|
|
230
225
|
}
|
|
231
|
-
if (
|
|
232
|
-
if (!val[
|
|
233
|
-
const value2 = val[
|
|
234
|
-
if (
|
|
235
|
-
const label =
|
|
226
|
+
if (overlayTw) {
|
|
227
|
+
if (!val[overlayTw?.$id]) continue;
|
|
228
|
+
const value2 = val[overlayTw.$id];
|
|
229
|
+
if (overlayTw.term?.values?.[value2.key]?.uncomputable) {
|
|
230
|
+
const label = overlayTw.term.values[value2?.key]?.label;
|
|
236
231
|
uncomputableValues[label] = (uncomputableValues[label] || 0) + 1;
|
|
237
232
|
}
|
|
238
233
|
plot = value2.key;
|
|
@@ -247,9 +242,13 @@ function parseValues(q, data, sampleType, isLog, overlayTerm, divideTerm) {
|
|
|
247
242
|
}
|
|
248
243
|
return { absMax, absMin, chart2plot2values, uncomputableValues };
|
|
249
244
|
}
|
|
250
|
-
function numericBins(
|
|
251
|
-
const
|
|
252
|
-
|
|
245
|
+
function numericBins(tw, data) {
|
|
246
|
+
const bins = {};
|
|
247
|
+
if (!isNumericTerm(tw?.term)) return bins;
|
|
248
|
+
for (const bin of data.refs.byTermId[tw?.$id]?.bins || []) {
|
|
249
|
+
bins[bin.label] = bin;
|
|
250
|
+
}
|
|
251
|
+
return bins;
|
|
253
252
|
}
|
|
254
253
|
export {
|
|
255
254
|
api,
|
package/routes/termdb.violin.js
CHANGED
|
@@ -150,6 +150,7 @@ function sortPlot2Values(data, plot2values, overlayTerm) {
|
|
|
150
150
|
function setResponse(valuesObject, data, q) {
|
|
151
151
|
const charts = {};
|
|
152
152
|
const overlayTerm = q.overlayTw;
|
|
153
|
+
const divideTw = q.divideTw;
|
|
153
154
|
for (const [chart, plot2values] of valuesObject.chart2plot2values) {
|
|
154
155
|
const plots = [];
|
|
155
156
|
for (const [plot, values] of sortPlot2Values(data, plot2values, overlayTerm)) {
|
|
@@ -157,16 +158,23 @@ function setResponse(valuesObject, data, q) {
|
|
|
157
158
|
label: overlayTerm?.term?.values?.[plot]?.label || plot,
|
|
158
159
|
values,
|
|
159
160
|
seriesId: plot,
|
|
161
|
+
chartId: chart,
|
|
162
|
+
//quick fix to get list samples working
|
|
160
163
|
plotValueCount: values?.length,
|
|
161
|
-
color: overlayTerm?.term?.values?.[plot]?.color || null
|
|
162
|
-
overlayTwBins: isNumericTerm(overlayTerm?.term) ? numericBins(overlayTerm, data) : null
|
|
164
|
+
color: overlayTerm?.term?.values?.[plot]?.color || null
|
|
163
165
|
});
|
|
164
166
|
}
|
|
165
167
|
charts[chart] = { chartId: chart, plots };
|
|
166
168
|
}
|
|
169
|
+
const bins = {
|
|
170
|
+
term1: numericBins(q.tw, data)
|
|
171
|
+
};
|
|
172
|
+
if (overlayTerm) bins.term2 = numericBins(overlayTerm, data);
|
|
173
|
+
if (divideTw) bins.term0 = numericBins(divideTw, data);
|
|
167
174
|
const result = {
|
|
168
175
|
min: valuesObject.min,
|
|
169
176
|
max: valuesObject.max,
|
|
177
|
+
bins,
|
|
170
178
|
charts,
|
|
171
179
|
uncomputableValues: Object.keys(valuesObject.uncomputableValues).length > 0 ? valuesObject.uncomputableValues : null
|
|
172
180
|
};
|