@sjcrh/proteinpaint-server 2.98.0 → 2.98.1

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.98.0",
3
+ "version": "2.98.1",
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",
@@ -61,7 +61,7 @@
61
61
  "@sjcrh/augen": "2.87.0",
62
62
  "@sjcrh/proteinpaint-rust": "2.84.0",
63
63
  "@sjcrh/proteinpaint-shared": "2.98.0",
64
- "@sjcrh/proteinpaint-types": "2.98.0",
64
+ "@sjcrh/proteinpaint-types": "2.98.1",
65
65
  "better-sqlite3": "^9.4.1",
66
66
  "body-parser": "^1.15.2",
67
67
  "canvas": "~2.11.2",
@@ -0,0 +1,128 @@
1
+ import { CorrelationVolcanoPayload } from "#types/checkers";
2
+ import { getData } from "../src/termdb.matrix.js";
3
+ import run_R from "../src/run_R.js";
4
+ import serverconfig from "../src/serverconfig.js";
5
+ import { mayLog } from "#src/helpers.ts";
6
+ import path from "path";
7
+ const api = {
8
+ endpoint: "termdb/correlationVolcano",
9
+ methods: {
10
+ get: {
11
+ ...CorrelationVolcanoPayload,
12
+ init
13
+ },
14
+ post: {
15
+ ...CorrelationVolcanoPayload,
16
+ init
17
+ }
18
+ }
19
+ };
20
+ function init({ genomes }) {
21
+ return async (req, res) => {
22
+ const q = req.query;
23
+ try {
24
+ const genome = genomes[q.genome];
25
+ if (!genome)
26
+ throw "invalid genome name";
27
+ const ds = genome.datasets?.[q.dslabel];
28
+ if (!ds)
29
+ throw "invalid ds";
30
+ const result = await compute(q, ds, genome);
31
+ res.send(result);
32
+ } catch (e) {
33
+ res.send({ error: e?.message || e });
34
+ if (e instanceof Error && e.stack)
35
+ console.error(e);
36
+ }
37
+ };
38
+ }
39
+ async function compute(q, ds, genome) {
40
+ const terms = [q.featureTw, ...q.variableTwLst];
41
+ const data = await getData(
42
+ {
43
+ filter: q.filter,
44
+ filter0: q.filter0,
45
+ terms
46
+ },
47
+ ds,
48
+ genome
49
+ );
50
+ if (data.error)
51
+ throw data.error;
52
+ const vtid2array = /* @__PURE__ */ new Map();
53
+ for (const tw of q.variableTwLst) {
54
+ vtid2array.set(tw.$id, { id: tw.$id, v1: [], v2: [] });
55
+ }
56
+ for (const sid in data.samples) {
57
+ const featureValue = data.samples[sid][q.featureTw.$id]?.value;
58
+ if (!Number.isFinite(featureValue))
59
+ continue;
60
+ for (const tw of q.variableTwLst) {
61
+ const variableValue = data.samples[sid][tw.$id]?.value;
62
+ if (!Number.isFinite(variableValue))
63
+ continue;
64
+ vtid2array.get(tw.$id).v1.push(featureValue);
65
+ vtid2array.get(tw.$id).v2.push(variableValue);
66
+ }
67
+ }
68
+ const input = {
69
+ method: q.correlationMethod || "pearson",
70
+ terms: [...vtid2array.values()]
71
+ };
72
+ const time1 = Date.now();
73
+ const r_output = await run_R(path.join(serverconfig.binpath, "utils", "corr.R"), JSON.stringify(input));
74
+ mayLog("Time taken to run correlation analysis:", Date.now() - time1);
75
+ let json_result;
76
+ for (const line of r_output.split("\n")) {
77
+ if (line.startsWith("adjusted_p_values:")) {
78
+ json_result = JSON.parse(line.replace("adjusted_p_values:", ""));
79
+ } else {
80
+ }
81
+ }
82
+ const output = { terms: json_result };
83
+ const result = { variableItems: [] };
84
+ for (const t of output.terms) {
85
+ const t2 = {
86
+ tw$id: t.id,
87
+ sampleSize: t.sample_size,
88
+ //sampleSize: input.terms.get(t.id).v1.length, // This was not working so passed the length of each array from R
89
+ correlation: t.correlation,
90
+ original_pvalue: t.original_p_value,
91
+ adjusted_pvalue: t.adjusted_p_value
92
+ };
93
+ result.variableItems.push(t2);
94
+ }
95
+ return result;
96
+ }
97
+ function validate_correlationVolcano(ds) {
98
+ const cv = ds.cohort.correlationVolcano;
99
+ if (!cv)
100
+ return;
101
+ if (typeof cv.feature != "object")
102
+ throw "cv.feature not obj";
103
+ if (cv.feature.termType == "geneExpression") {
104
+ if (!ds.queries?.geneExpression)
105
+ throw "cv.feature.termType=geneExpression not supported by ds";
106
+ } else {
107
+ throw "unknown cv.feature.termType";
108
+ }
109
+ if (typeof cv.variables != "object")
110
+ throw "cv.variables not obj";
111
+ if (cv.variables.type == "dictionaryTerm") {
112
+ if (!Array.isArray(cv.variables.termIds))
113
+ throw "cv.variables.termIds not array when type=dictionaryTerm";
114
+ for (const id of cv.variables.termIds) {
115
+ const t = ds.cohort.termdb.q.termjsonByOneid(id);
116
+ if (!t)
117
+ throw "cv.variables.termIds: unknown id: " + id;
118
+ if (t.type != "integer" && t.type != "float")
119
+ throw "cv.variables.termIds: not integer/float: " + id;
120
+ }
121
+ } else {
122
+ throw "unknown cv.variables.type";
123
+ }
124
+ }
125
+ export {
126
+ api,
127
+ validate_correlationVolcano
128
+ };
@@ -27,7 +27,7 @@ function init({ genomes }) {
27
27
  if (!genome)
28
28
  throw "invalid genome";
29
29
  const [ds] = get_ds_tdb(genome, q);
30
- return make(q, res, ds, genome);
30
+ return make(q, req, res, ds, genome);
31
31
  } catch (e) {
32
32
  res.send({ error: e.message || e });
33
33
  if (e.stack)
@@ -37,13 +37,11 @@ function init({ genomes }) {
37
37
  }
38
38
  };
39
39
  }
40
- function make(q, res, ds, genome) {
40
+ function make(q, req, res, ds, genome) {
41
41
  const tdb = ds.cohort.termdb;
42
- const auth = { embedder: q.embedder };
43
42
  const c = {
44
- selectCohort: tdb.selectCohort,
45
- // optional
46
- supportedChartTypes: tdb.q?.getSupportedChartTypes(auth),
43
+ selectCohort: getSelectCohort(ds, req),
44
+ supportedChartTypes: tdb.q?.getSupportedChartTypes(req),
47
45
  renamedChartTypes: ds.cohort.renamedChartTypes,
48
46
  allowedTermTypes: getAllowedTermTypes(ds),
49
47
  termMatch2geneSet: tdb.termMatch2geneSet,
@@ -68,8 +66,6 @@ function make(q, res, ds, genome) {
68
66
  c.plotConfigByCohort = tdb.plotConfigByCohort;
69
67
  if (tdb.multipleTestingCorrection)
70
68
  c.multipleTestingCorrection = tdb.multipleTestingCorrection;
71
- if (tdb.neuroOncRegression)
72
- c.neuroOncRegression = tdb.neuroOncRegression;
73
69
  if (tdb.helpPages)
74
70
  c.helpPages = tdb.helpPages;
75
71
  if (tdb.minTimeSinceDx)
@@ -90,15 +86,22 @@ function make(q, res, ds, genome) {
90
86
  c.excludedTermtypeByTarget = tdb.excludedTermtypeByTarget;
91
87
  if (tdb.survival)
92
88
  c.survival = tdb.survival;
89
+ if (tdb.regression)
90
+ c.regression = tdb.regression;
93
91
  if (ds.assayAvailability)
94
92
  c.assayAvailability = ds.assayAvailability;
95
93
  if (ds.customTwQByType)
96
94
  c.customTwQByType = ds.customTwQByType;
95
+ if (ds.cohort.correlationVolcano)
96
+ c.correlationVolcano = ds.cohort.correlationVolcano;
97
97
  c.requiredAuth = authApi.getRequiredCredForDsEmbedder(q.dslabel, q.embedder);
98
98
  addRestrictAncestries(c, tdb);
99
99
  addScatterplots(c, ds);
100
100
  addMatrixplots(c, ds);
101
101
  addNonDictionaryQueries(c, ds, genome);
102
+ c.requiredAuth = authApi.getRequiredCredForDsEmbedder(q.dslabel, q.embedder);
103
+ const info = authApi.getNonsensitiveInfo(req);
104
+ c.clientAuthResult = info.clientAuthResult || {};
102
105
  res.send({ termdbConfig: c });
103
106
  }
104
107
  function addRestrictAncestries(c, tdb) {
@@ -256,6 +259,16 @@ function getAllowedTermTypes(ds) {
256
259
  typeSet.add(TermTypes.METABOLITE_INTENSITY);
257
260
  return [...typeSet];
258
261
  }
262
+ function getSelectCohort(ds, req) {
263
+ if (!ds.cohort.termdb.selectCohort)
264
+ return;
265
+ const copy = Object.assign({}, ds.cohort.termdb.selectCohort);
266
+ if (ds.cohort.termdb.selectCohort.descriptionByUser) {
267
+ copy.description = ds.cohort.termdb.selectCohort.descriptionByUser(authApi.getNonsensitiveInfo(req));
268
+ delete copy.descriptionByUser;
269
+ }
270
+ return copy;
271
+ }
259
272
  export {
260
273
  api
261
274
  };
@@ -122,7 +122,7 @@ function divideValues(q, data, sampleType) {
122
122
  key2values,
123
123
  min: absMin,
124
124
  max: absMax,
125
- uncomputableValueObj: sortObj(uncomputableValues)
125
+ uncomputableValues: sortObj(uncomputableValues)
126
126
  };
127
127
  }
128
128
  function sortObj(object) {
@@ -148,16 +148,14 @@ function setResponse(valuesObject, data, q, sampleType) {
148
148
  seriesId: key,
149
149
  plotValueCount: values?.length,
150
150
  color: overlayTerm?.term?.values?.[key]?.color || null,
151
- divideTwBins: isNumericTerm(overlayTerm.term) ? numericBins(overlayTerm, data) : null,
152
- uncomputableValueObj: Object.keys(valuesObject.uncomputableValueObj).length > 0 ? valuesObject.uncomputableValueObj : null
151
+ divideTwBins: isNumericTerm(overlayTerm.term) ? numericBins(overlayTerm, data) : null
153
152
  });
154
153
  } else {
155
- const plot = {
154
+ plots.push({
156
155
  label: sampleType,
157
156
  values,
158
157
  plotValueCount: values.length
159
- };
160
- plots.push(plot);
158
+ });
161
159
  }
162
160
  }
163
161
  const result = {
@@ -165,7 +163,7 @@ function setResponse(valuesObject, data, q, sampleType) {
165
163
  max: valuesObject.max,
166
164
  plots,
167
165
  pvalues: [],
168
- uncomputableValueObj: Object.keys(valuesObject.uncomputableValueObj).length > 0 ? valuesObject.uncomputableValueObj : null
166
+ uncomputableValues: Object.keys(valuesObject.uncomputableValues).length > 0 ? valuesObject.uncomputableValues : null
169
167
  };
170
168
  return result;
171
169
  }
@@ -222,9 +220,8 @@ function createCanvasImg(q, result, ds) {
222
220
  ctx.stroke();
223
221
  });
224
222
  plot.src = canvas.toDataURL();
225
- const isKDE = q.isKDE;
226
- plot.density = getBinsDensity(axisScale, plot, isKDE, q.ticks);
227
- plot.summaryStats = summaryStats(plot.values);
223
+ plot.density = getBinsDensity(axisScale, plot, q.isKDE, q.ticks);
224
+ plot.summaryStats = summaryStats(plot.values).values;
228
225
  delete plot.values;
229
226
  }
230
227
  }