@sjcrh/proteinpaint-server 2.145.1-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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjcrh/proteinpaint-server",
3
- "version": "2.145.1-1",
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.1-0",
67
- "@sjcrh/proteinpaint-shared": "2.145.1-0",
68
- "@sjcrh/proteinpaint-types": "2.145.1-1",
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",
@@ -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 { roundValueAuto } from "#shared/roundValue.js";
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, values] of sortPlot2Values(data, plot2values, overlayTerm)) {
51
- const sortedValues = values.sort((a, b) => a - b);
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 boxplot = boxplot_getvalue(vs);
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=${values.length}`;
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=${values.length}`;
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 }));