@sjcrh/proteinpaint-server 2.145.1 → 2.145.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/package.json +4 -4
- package/routes/termdb.boxplot.js +20 -30
- package/src/app.js +42 -55
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sjcrh/proteinpaint-server",
|
|
3
|
-
"version": "2.145.
|
|
3
|
+
"version": "2.145.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",
|
|
@@ -63,9 +63,9 @@
|
|
|
63
63
|
"@sjcrh/augen": "2.143.0",
|
|
64
64
|
"@sjcrh/proteinpaint-python": "2.144.0",
|
|
65
65
|
"@sjcrh/proteinpaint-r": "2.145.1-0",
|
|
66
|
-
"@sjcrh/proteinpaint-rust": "2.145.
|
|
67
|
-
"@sjcrh/proteinpaint-shared": "2.145.
|
|
68
|
-
"@sjcrh/proteinpaint-types": "2.145.
|
|
66
|
+
"@sjcrh/proteinpaint-rust": "2.145.2",
|
|
67
|
+
"@sjcrh/proteinpaint-shared": "2.145.2",
|
|
68
|
+
"@sjcrh/proteinpaint-types": "2.145.2",
|
|
69
69
|
"@types/express": "^5.0.0",
|
|
70
70
|
"@types/express-session": "^1.18.1",
|
|
71
71
|
"better-sqlite3": "^9.4.1",
|
package/routes/termdb.boxplot.js
CHANGED
|
@@ -2,9 +2,7 @@ import { boxplotPayload } from "#types/checkers";
|
|
|
2
2
|
import { getData } from "../src/termdb.matrix.js";
|
|
3
3
|
import { boxplot_getvalue } from "../src/utils.js";
|
|
4
4
|
import { sortPlot2Values } from "./termdb.violin.ts";
|
|
5
|
-
import {
|
|
6
|
-
import { getMean, getVariance } from "#shared/descriptive.stats.js";
|
|
7
|
-
const minSampleSize = 5;
|
|
5
|
+
import { summaryStats, getDescriptiveStats, summaryStatsFromStats } from "#shared/descriptive.stats.js";
|
|
8
6
|
const api = {
|
|
9
7
|
endpoint: "termdb/boxplot",
|
|
10
8
|
methods: {
|
|
@@ -31,6 +29,9 @@ function init({ genomes }) {
|
|
|
31
29
|
if (q.divideTw) terms.push(q.divideTw);
|
|
32
30
|
const data = await getData({ filter: q.filter, filter0: q.filter0, terms, __protected__: q.__protected__ }, ds);
|
|
33
31
|
if (data.error) throw data.error;
|
|
32
|
+
const samples = Object.values(data.samples);
|
|
33
|
+
const values = samples.map((s) => s?.[q.tw.$id]?.value).filter((v) => typeof v === "number");
|
|
34
|
+
const statsAllSummary = summaryStats(values).values;
|
|
34
35
|
const sampleType = `All ${data.sampleType?.plural_name || "samples"}`;
|
|
35
36
|
const overlayTerm = q.overlayTw;
|
|
36
37
|
const divideTerm = q.divideTw;
|
|
@@ -45,24 +46,30 @@ function init({ genomes }) {
|
|
|
45
46
|
if (!absMin && absMin !== 0) throw "absMin is undefined [termdb.boxplot init()]";
|
|
46
47
|
if (!absMax && absMax !== 0) throw "absMax is undefined [termdb.boxplot init()]";
|
|
47
48
|
const charts = {};
|
|
49
|
+
let outlierMin = Number.POSITIVE_INFINITY, outlierMax = Number.NEGATIVE_INFINITY;
|
|
48
50
|
for (const [chart, plot2values] of chart2plot2values) {
|
|
49
51
|
const plots = [];
|
|
50
|
-
for (const [key,
|
|
51
|
-
const sortedValues =
|
|
52
|
+
for (const [key, values2] of sortPlot2Values(data, plot2values, overlayTerm)) {
|
|
53
|
+
const sortedValues = values2.sort((a, b) => a - b);
|
|
52
54
|
const vs = sortedValues.map((v) => {
|
|
53
55
|
const value = { value: v };
|
|
54
56
|
return value;
|
|
55
57
|
});
|
|
56
|
-
const
|
|
58
|
+
const stats = getDescriptiveStats(sortedValues);
|
|
59
|
+
if (q.removeOutliers) {
|
|
60
|
+
outlierMin = Math.min(outlierMin, stats.outlierMin);
|
|
61
|
+
outlierMax = Math.max(outlierMax, stats.outlierMax);
|
|
62
|
+
}
|
|
63
|
+
const descrStats = summaryStatsFromStats(stats, true).values;
|
|
64
|
+
const boxplot = boxplot_getvalue(vs, q.removeOutliers);
|
|
57
65
|
if (!boxplot) throw "boxplot_getvalue failed [termdb.boxplot init()]";
|
|
58
|
-
const descrStats = setDescrStats(boxplot, sortedValues);
|
|
59
66
|
const _plot = {
|
|
60
67
|
boxplot,
|
|
61
68
|
descrStats
|
|
62
69
|
};
|
|
63
70
|
if (overlayTerm) {
|
|
64
71
|
const _key = overlayTerm?.term?.values?.[key]?.label || key;
|
|
65
|
-
const plotLabel = `${_key}, n=${
|
|
72
|
+
const plotLabel = `${_key}, n=${values2.length}`;
|
|
66
73
|
const overlayBins = numericBins(overlayTerm, data);
|
|
67
74
|
const plot = Object.assign(_plot, {
|
|
68
75
|
color: overlayTerm?.term?.values?.[key]?.color || null,
|
|
@@ -73,7 +80,7 @@ function init({ genomes }) {
|
|
|
73
80
|
plot.boxplot.label = plotLabel;
|
|
74
81
|
plots.push(plot);
|
|
75
82
|
} else {
|
|
76
|
-
const plotLabel = `${sampleType}, n=${
|
|
83
|
+
const plotLabel = `${sampleType}, n=${values2.length}`;
|
|
77
84
|
const plot = Object.assign(_plot, {
|
|
78
85
|
key: sampleType
|
|
79
86
|
});
|
|
@@ -89,10 +96,11 @@ function init({ genomes }) {
|
|
|
89
96
|
charts[chart] = { chartId: chart, plots };
|
|
90
97
|
}
|
|
91
98
|
const returnData = {
|
|
92
|
-
absMin,
|
|
93
|
-
absMax,
|
|
99
|
+
absMin: q.removeOutliers ? outlierMin : absMin,
|
|
100
|
+
absMax: q.removeOutliers ? outlierMax : absMax,
|
|
94
101
|
charts,
|
|
95
|
-
uncomputableValues: setUncomputableValues(uncomputableValues)
|
|
102
|
+
uncomputableValues: setUncomputableValues(uncomputableValues),
|
|
103
|
+
descrStats: statsAllSummary
|
|
96
104
|
};
|
|
97
105
|
res.send(returnData);
|
|
98
106
|
} catch (e) {
|
|
@@ -114,24 +122,6 @@ function setHiddenPlots(term, plots) {
|
|
|
114
122
|
}
|
|
115
123
|
return plots;
|
|
116
124
|
}
|
|
117
|
-
function setDescrStats(boxplot, sortedValues) {
|
|
118
|
-
if (sortedValues.length < minSampleSize) return [{ id: "total", label: "Total", value: sortedValues.length }];
|
|
119
|
-
const mean = getMean(sortedValues);
|
|
120
|
-
const variance = getVariance(sortedValues);
|
|
121
|
-
const sd = Math.sqrt(variance);
|
|
122
|
-
return [
|
|
123
|
-
{ id: "total", label: "Total", value: sortedValues.length },
|
|
124
|
-
{ id: "min", label: "Minimum", value: roundValueAuto(sortedValues[0], true) },
|
|
125
|
-
{ id: "p25", label: "1st quartile", value: roundValueAuto(boxplot.p25, true) },
|
|
126
|
-
{ id: "median", label: "Median", value: roundValueAuto(boxplot.p50, true) },
|
|
127
|
-
{ id: "mean", label: "Mean", value: roundValueAuto(mean, true) },
|
|
128
|
-
{ id: "p75", label: "3rd quartile", value: roundValueAuto(boxplot.p75, true) },
|
|
129
|
-
{ id: "max", label: "Maximum", value: roundValueAuto(sortedValues[sortedValues.length - 1], true) },
|
|
130
|
-
{ id: "sd", label: "Standard deviation", value: isNaN(sd) ? null : roundValueAuto(sd, true) },
|
|
131
|
-
{ id: "variance", label: "Variance", value: roundValueAuto(variance, true) },
|
|
132
|
-
{ id: "iqr", label: "Inter-quartile range", value: roundValueAuto(boxplot.iqr, true) }
|
|
133
|
-
];
|
|
134
|
-
}
|
|
135
125
|
function setUncomputableValues(values) {
|
|
136
126
|
if (Object.entries(values)?.length) {
|
|
137
127
|
return Object.entries(values).map(([label, v]) => ({ label, value: v }));
|