@sjcrh/proteinpaint-server 2.142.0 → 2.143.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.
Files changed (65) hide show
  1. package/dataset/protected.test.js +1 -2
  2. package/dataset/termdb.test.js +3 -2
  3. package/package.json +9 -8
  4. package/routes/aiProjectAdmin.js +46 -60
  5. package/routes/aiProjectSelectedWSImages.js +161 -0
  6. package/routes/brainImaging.js +9 -18
  7. package/routes/brainImagingSamples.js +2 -4
  8. package/routes/burden.js +13 -26
  9. package/routes/correlationVolcano.js +18 -36
  10. package/routes/dataset.js +6 -12
  11. package/routes/deleteWSIAnnotation.js +75 -0
  12. package/routes/dsdata.js +7 -14
  13. package/routes/dzimages.js +4 -8
  14. package/routes/gdc.grin2.list.js +13 -26
  15. package/routes/gdc.grin2.run.js +3 -6
  16. package/routes/gdc.maf.js +8 -16
  17. package/routes/gdc.mafBuild.js +14 -28
  18. package/routes/gene2canonicalisoform.js +4 -8
  19. package/routes/genelookup.js +2 -4
  20. package/routes/genesetEnrichment.js +6 -12
  21. package/routes/genesetOverrepresentation.js +1 -2
  22. package/routes/genomes.js +1 -2
  23. package/routes/grin2.js +13 -17
  24. package/routes/healthcheck.js +3 -6
  25. package/routes/hicdata.js +4 -8
  26. package/routes/hicgenome.js +4 -8
  27. package/routes/hicstat.js +2 -4
  28. package/routes/img.js +1 -2
  29. package/routes/isoformlst.js +6 -12
  30. package/routes/ntseq.js +4 -8
  31. package/routes/pdomain.js +5 -10
  32. package/routes/sampledzimages.js +2 -4
  33. package/routes/samplewsimages.js +3 -67
  34. package/routes/saveWSIAnnotation.js +100 -0
  35. package/routes/snp.js +9 -18
  36. package/routes/termdb.DE.js +23 -46
  37. package/routes/termdb.boxplot.js +84 -84
  38. package/routes/termdb.categories.js +9 -18
  39. package/routes/termdb.cluster.js +23 -46
  40. package/routes/termdb.cohort.summary.js +3 -6
  41. package/routes/termdb.cohorts.js +4 -8
  42. package/routes/termdb.config.js +32 -64
  43. package/routes/termdb.descrstats.js +6 -12
  44. package/routes/termdb.filterTermValues.js +4 -8
  45. package/routes/termdb.numericcategories.js +5 -10
  46. package/routes/termdb.percentile.js +6 -12
  47. package/routes/termdb.profileFormScores.js +12 -24
  48. package/routes/termdb.profileScores.js +7 -14
  49. package/routes/termdb.rootterm.js +4 -8
  50. package/routes/termdb.sampleImages.js +4 -8
  51. package/routes/termdb.singleSampleMutation.js +9 -18
  52. package/routes/termdb.singlecellDEgenes.js +4 -8
  53. package/routes/termdb.singlecellData.js +4 -8
  54. package/routes/termdb.singlecellSamples.js +28 -56
  55. package/routes/termdb.termchildren.js +5 -10
  56. package/routes/termdb.termsbyids.js +4 -8
  57. package/routes/termdb.topMutatedGenes.js +15 -30
  58. package/routes/termdb.topTermsByType.js +9 -18
  59. package/routes/termdb.topVariablyExpressedGenes.js +13 -26
  60. package/routes/termdb.violin.js +124 -135
  61. package/routes/tileserver.js +14 -15
  62. package/routes/wsimages.js +42 -46
  63. package/routes/wsisamples.js +3 -6
  64. package/src/app.js +4345 -6708
  65. package/routes/sampleWsiAiApi.js +0 -33
@@ -28,8 +28,7 @@ function init({ genomes }) {
28
28
  try {
29
29
  const q = req.query;
30
30
  const genome = genomes[q.genome];
31
- if (!genome)
32
- throw "invalid genome";
31
+ if (!genome) throw "invalid genome";
33
32
  const [ds] = get_ds_tdb(genome, q);
34
33
  let term_results = [];
35
34
  if (q.tw) {
@@ -42,8 +41,7 @@ function init({ genomes }) {
42
41
  },
43
42
  ds
44
43
  );
45
- if (term_results.error)
46
- throw term_results.error;
44
+ if (term_results.error) throw term_results.error;
47
45
  }
48
46
  let term_results2 = [];
49
47
  if (q.tw2) {
@@ -56,44 +54,33 @@ function init({ genomes }) {
56
54
  },
57
55
  ds
58
56
  );
59
- if (term_results2.error)
60
- throw term_results2.error;
57
+ if (term_results2.error) throw term_results2.error;
61
58
  }
62
59
  const results = await run_DE(req.query, ds, term_results, term_results2);
63
- if (!results || !results.data)
64
- throw "No data [termdb.DE.ts init()]";
60
+ if (!results || !results.data) throw "No data [termdb.DE.ts init()]";
65
61
  res.send(results);
66
62
  } catch (e) {
67
63
  res.send({ status: "error", error: e.message || e });
68
- if (e instanceof Error && e.stack)
69
- console.log(e);
64
+ if (e instanceof Error && e.stack) console.log(e);
70
65
  }
71
66
  };
72
67
  }
73
68
  async function run_DE(param, ds, term_results, term_results2) {
74
- if (param.samplelst?.groups?.length != 2)
75
- throw ".samplelst.groups.length!=2";
76
- if (param.samplelst.groups[0].values?.length < 1)
77
- throw "samplelst.groups[0].values.length<1";
78
- if (param.samplelst.groups[1].values?.length < 1)
79
- throw "samplelst.groups[1].values.length<1";
69
+ if (param.samplelst?.groups?.length != 2) throw ".samplelst.groups.length!=2";
70
+ if (param.samplelst.groups[0].values?.length < 1) throw "samplelst.groups[0].values.length<1";
71
+ if (param.samplelst.groups[1].values?.length < 1) throw "samplelst.groups[1].values.length<1";
80
72
  const q = ds.queries.rnaseqGeneCount;
81
- if (!q)
82
- return;
83
- if (!q.file)
84
- throw "unknown data type for rnaseqGeneCount";
85
- if (!q.storage_type)
86
- throw "storage_type is not defined";
73
+ if (!q) return;
74
+ if (!q.file) throw "unknown data type for rnaseqGeneCount";
75
+ if (!q.storage_type) throw "storage_type is not defined";
87
76
  param.storage_type = q.storage_type;
88
77
  const group1names = [];
89
78
  const conf1_group1 = [];
90
79
  const conf2_group1 = [];
91
80
  for (const s of param.samplelst.groups[0].values) {
92
- if (!Number.isInteger(s.sampleId))
93
- continue;
81
+ if (!Number.isInteger(s.sampleId)) continue;
94
82
  const n = ds.cohort.termdb.q.id2sampleName(s.sampleId);
95
- if (!n)
96
- continue;
83
+ if (!n) continue;
97
84
  if (q.allSampleSet.has(n)) {
98
85
  if (param.tw && !param.tw2) {
99
86
  if (term_results.samples[s.sampleId]) {
@@ -136,11 +123,9 @@ async function run_DE(param, ds, term_results, term_results2) {
136
123
  const conf1_group2 = [];
137
124
  const conf2_group2 = [];
138
125
  for (const s of param.samplelst.groups[1].values) {
139
- if (!Number.isInteger(s.sampleId))
140
- continue;
126
+ if (!Number.isInteger(s.sampleId)) continue;
141
127
  const n = ds.cohort.termdb.q.id2sampleName(s.sampleId);
142
- if (!n)
143
- continue;
128
+ if (!n) continue;
144
129
  if (q.allSampleSet.has(n)) {
145
130
  if (param.tw && !param.tw2) {
146
131
  if (term_results.samples[s.sampleId]) {
@@ -181,10 +166,8 @@ async function run_DE(param, ds, term_results, term_results2) {
181
166
  }
182
167
  const sample_size1 = group1names.length;
183
168
  const sample_size2 = group2names.length;
184
- if (sample_size1 < 1)
185
- throw "sample size of group1 < 1";
186
- if (sample_size2 < 1)
187
- throw "sample size of group2 < 1";
169
+ if (sample_size1 < 1) throw "sample size of group1 < 1";
170
+ if (sample_size2 < 1) throw "sample size of group2 < 1";
188
171
  const commonnames = group1names.filter((element) => group2names.includes(element));
189
172
  if (commonnames.length > 0) {
190
173
  throw "Common elements found between both groups:" + commonnames.map((i) => i).join(",");
@@ -233,8 +216,7 @@ async function run_DE(param, ds, term_results, term_results2) {
233
216
  await readFileAndDelete(mds_imagePath, "mds_image", result2);
234
217
  }
235
218
  const images = [result2.ql_image];
236
- if (result2.mds_image)
237
- images.push(result2.mds_image);
219
+ if (result2.mds_image) images.push(result2.mds_image);
238
220
  return {
239
221
  data: result2.gene_data,
240
222
  sample_size1,
@@ -259,16 +241,13 @@ async function readFileAndDelete(file, key, response) {
259
241
  };
260
242
  response[key] = obj;
261
243
  fs.unlink(file, (err) => {
262
- if (err)
263
- throw err;
244
+ if (err) throw err;
264
245
  });
265
246
  }
266
247
  async function validate_query_rnaseqGeneCount(ds) {
267
248
  const q = ds.queries.rnaseqGeneCount;
268
- if (!q)
269
- return;
270
- if (!q.file)
271
- throw "unknown data type for rnaseqGeneCount";
249
+ if (!q) return;
250
+ if (!q.file) throw "unknown data type for rnaseqGeneCount";
272
251
  q.file = path.join(serverconfig.tpmasterdir, q.file);
273
252
  {
274
253
  let samples = [];
@@ -284,13 +263,11 @@ async function validate_query_rnaseqGeneCount(ds) {
284
263
  const time2 = (/* @__PURE__ */ new Date()).valueOf();
285
264
  mayLog("Time taken to query gene expression:", time2 - time1, "ms");
286
265
  samples = result.split(",");
287
- } else
288
- throw "unknown storage type:" + ds.queries.rnaseqGeneCount.storage_type;
266
+ } else throw "unknown storage type:" + ds.queries.rnaseqGeneCount.storage_type;
289
267
  q.allSampleSet = new Set(samples);
290
268
  const unknownSamples = [];
291
269
  for (const n of q.allSampleSet) {
292
- if (!ds.cohort.termdb.q.sampleName2id(n))
293
- unknownSamples.push(n);
270
+ if (!ds.cohort.termdb.q.sampleName2id(n)) unknownSamples.push(n);
294
271
  }
295
272
  console.log(q.allSampleSet.size, `rnaseqGeneCount samples from ${ds.label}`);
296
273
  }
@@ -1,7 +1,7 @@
1
1
  import { boxplotPayload } from "#types/checkers";
2
2
  import { getData } from "../src/termdb.matrix.js";
3
3
  import { boxplot_getvalue } from "../src/utils.js";
4
- import { sortKey2values } from "./termdb.violin.ts";
4
+ import { sortPlot2Values } from "./termdb.violin.ts";
5
5
  import { roundValueAuto } from "#shared/roundValue.js";
6
6
  import { getMean, getVariance } from "#shared/descriptive.stats.js";
7
7
  const minSampleSize = 5;
@@ -23,103 +23,99 @@ function init({ genomes }) {
23
23
  const q = req.query;
24
24
  try {
25
25
  const genome = genomes[q.genome];
26
- if (!genome)
27
- throw "invalid genome name";
26
+ if (!genome) throw "invalid genome name";
28
27
  const ds = genome.datasets?.[q.dslabel];
29
- if (!ds)
30
- throw "invalid ds";
28
+ if (!ds) throw "invalid ds";
31
29
  const terms = [q.tw];
32
- if (q.overlayTw)
33
- terms.push(q.overlayTw);
30
+ if (q.overlayTw) terms.push(q.overlayTw);
31
+ if (q.divideTw) terms.push(q.divideTw);
34
32
  const data = await getData({ filter: q.filter, filter0: q.filter0, terms, __protected__: q.__protected__ }, ds);
35
- if (data.error)
36
- throw data.error;
33
+ if (data.error) throw data.error;
37
34
  const sampleType = `All ${data.sampleType?.plural_name || "samples"}`;
38
35
  const overlayTerm = q.overlayTw;
39
- const { absMin, absMax, key2values, uncomputableValues } = parseValues(
36
+ const divideTerm = q.divideTw;
37
+ const { absMin, absMax, chart2plot2values, uncomputableValues } = parseValues(
40
38
  q,
41
39
  data,
42
40
  sampleType,
43
41
  q.isLogScale,
44
- overlayTerm
42
+ overlayTerm,
43
+ divideTerm
45
44
  );
46
- const plots = [];
47
- for (const [key, values] of sortKey2values(data, key2values, overlayTerm)) {
48
- const sortedValues = values.sort((a, b) => a - b);
49
- const vs = sortedValues.map((v) => {
50
- const value = { value: v };
51
- return value;
52
- });
53
- const boxplot = boxplot_getvalue(vs);
54
- if (!boxplot)
55
- throw "boxplot_getvalue failed [termdb.boxplot init()]";
56
- const descrStats = setDescrStats(boxplot, sortedValues);
57
- const _plot = {
58
- boxplot,
59
- descrStats
60
- };
61
- if (overlayTerm) {
62
- const _key = overlayTerm?.term?.values?.[key]?.label || key;
63
- const plotLabel = `${_key}, n=${values.length}`;
64
- const overlayBins = numericBins(overlayTerm, data);
65
- const plot = Object.assign(_plot, {
66
- color: overlayTerm?.term?.values?.[key]?.color || null,
67
- key: _key,
68
- overlayBins: overlayBins.has(key) ? overlayBins.get(key) : null,
69
- seriesId: key
45
+ if (!absMin && absMin !== 0) throw "absMin is undefined [termdb.boxplot init()]";
46
+ if (!absMax && absMax !== 0) throw "absMax is undefined [termdb.boxplot init()]";
47
+ const charts = {};
48
+ for (const [chart, plot2values] of chart2plot2values) {
49
+ const plots = [];
50
+ for (const [key, values] of sortPlot2Values(data, plot2values, overlayTerm)) {
51
+ const sortedValues = values.sort((a, b) => a - b);
52
+ const vs = sortedValues.map((v) => {
53
+ const value = { value: v };
54
+ return value;
70
55
  });
71
- plot.boxplot.label = plotLabel;
72
- plots.push(plot);
73
- } else {
74
- const plotLabel = `${sampleType}, n=${values.length}`;
75
- const plot = Object.assign(_plot, {
76
- key: sampleType
77
- });
78
- plot.boxplot.label = plotLabel;
79
- plots.push(plot);
56
+ const boxplot = boxplot_getvalue(vs);
57
+ if (!boxplot) throw "boxplot_getvalue failed [termdb.boxplot init()]";
58
+ const descrStats = setDescrStats(boxplot, sortedValues);
59
+ const _plot = {
60
+ boxplot,
61
+ descrStats
62
+ };
63
+ if (overlayTerm) {
64
+ const _key = overlayTerm?.term?.values?.[key]?.label || key;
65
+ const plotLabel = `${_key}, n=${values.length}`;
66
+ const overlayBins = numericBins(overlayTerm, data);
67
+ const plot = Object.assign(_plot, {
68
+ color: overlayTerm?.term?.values?.[key]?.color || null,
69
+ key: _key,
70
+ overlayBins: overlayBins.has(key) ? overlayBins.get(key) : null,
71
+ seriesId: key
72
+ });
73
+ plot.boxplot.label = plotLabel;
74
+ plots.push(plot);
75
+ } else {
76
+ const plotLabel = `${sampleType}, n=${values.length}`;
77
+ const plot = Object.assign(_plot, {
78
+ key: sampleType
79
+ });
80
+ plot.boxplot.label = plotLabel;
81
+ plots.push(plot);
82
+ }
80
83
  }
81
- }
82
- if (absMin == null || absMax == null)
83
- throw "absMin or absMax is null [termdb.boxplot init()]";
84
- if (q.tw.term?.values)
85
- setHiddenPlots(q.tw, plots);
86
- if (overlayTerm && overlayTerm.term?.values)
87
- setHiddenPlots(overlayTerm, plots);
88
- if (q.orderByMedian == true) {
89
- plots.sort((a, b) => a.boxplot.p50 - b.boxplot.p50);
84
+ if (q.tw.term?.values) setHiddenPlots(q.tw, plots);
85
+ if (overlayTerm && overlayTerm.term?.values) setHiddenPlots(overlayTerm, plots);
86
+ if (q.orderByMedian == true) {
87
+ plots.sort((a, b) => a.boxplot.p50 - b.boxplot.p50);
88
+ }
89
+ charts[chart] = { chartId: chart, plots };
90
90
  }
91
91
  const returnData = {
92
92
  absMin,
93
93
  absMax,
94
- plots,
94
+ charts,
95
95
  uncomputableValues: setUncomputableValues(uncomputableValues)
96
96
  };
97
97
  res.send(returnData);
98
98
  } catch (e) {
99
99
  res.send({ error: e?.message || e });
100
- if (e instanceof Error && e.stack)
101
- console.error(e);
100
+ if (e instanceof Error && e.stack) console.error(e);
102
101
  }
103
102
  };
104
103
  }
105
104
  function setHiddenPlots(term, plots) {
106
105
  for (const v of Object.values(term.term?.values)) {
107
106
  const plot = plots.find((p) => p.key === v.label);
108
- if (plot)
109
- plot.isHidden = v?.uncomputable;
107
+ if (plot) plot.isHidden = v?.uncomputable;
110
108
  }
111
109
  if (term.q?.hiddenValues) {
112
110
  for (const key of Object.keys(term.q.hiddenValues)) {
113
111
  const plot = plots.find((p) => p.key === key);
114
- if (plot)
115
- plot.isHidden = true;
112
+ if (plot) plot.isHidden = true;
116
113
  }
117
114
  }
118
115
  return plots;
119
116
  }
120
117
  function setDescrStats(boxplot, sortedValues) {
121
- if (sortedValues.length < minSampleSize)
122
- return [{ id: "total", label: "Total", value: sortedValues.length }];
118
+ if (sortedValues.length < minSampleSize) return [{ id: "total", label: "Total", value: sortedValues.length }];
123
119
  const mean = getMean(sortedValues);
124
120
  const variance = getVariance(sortedValues);
125
121
  const sd = Math.sqrt(variance);
@@ -139,46 +135,50 @@ function setDescrStats(boxplot, sortedValues) {
139
135
  function setUncomputableValues(values) {
140
136
  if (Object.entries(values)?.length) {
141
137
  return Object.entries(values).map(([label, v]) => ({ label, value: v }));
142
- } else
143
- return null;
138
+ } else return null;
144
139
  }
145
- function parseValues(q, data, sampleType, isLog, overlayTerm) {
146
- const key2values = /* @__PURE__ */ new Map();
140
+ function parseValues(q, data, sampleType, isLog, overlayTerm, divideTerm) {
141
+ const chart2plot2values = /* @__PURE__ */ new Map();
147
142
  const uncomputableValues = {};
148
143
  let absMin = null, absMax = null;
149
144
  for (const val of Object.values(data.samples)) {
150
145
  const value = val[q.tw.$id];
151
- if (!Number.isFinite(value?.value))
152
- continue;
146
+ if (!Number.isFinite(value?.value)) continue;
153
147
  if (q.tw.term.values?.[value.value]?.uncomputable) {
154
148
  const label = q.tw.term.values[value.value].label;
155
149
  uncomputableValues[label] = (uncomputableValues[label] || 0) + 1;
156
150
  continue;
157
151
  }
158
- if (isLog && value.value <= 0)
159
- continue;
152
+ if (isLog && value.value <= 0) continue;
153
+ let chart = "";
154
+ let plot = sampleType;
155
+ if (divideTerm) {
156
+ if (!val[divideTerm?.$id]) continue;
157
+ const value0 = val[divideTerm.$id];
158
+ if (divideTerm.term?.values?.[value0.key]?.uncomputable) {
159
+ const label = divideTerm.term.values[value0?.key]?.label;
160
+ uncomputableValues[label] = (uncomputableValues[label] || 0) + 1;
161
+ }
162
+ chart = value0.key;
163
+ }
160
164
  if (overlayTerm) {
161
- if (!val[overlayTerm?.$id])
162
- continue;
165
+ if (!val[overlayTerm?.$id]) continue;
163
166
  const value2 = val[overlayTerm.$id];
164
167
  if (overlayTerm.term?.values?.[value2.key]?.uncomputable) {
165
168
  const label = overlayTerm.term.values[value2?.key]?.label;
166
169
  uncomputableValues[label] = (uncomputableValues[label] || 0) + 1;
167
170
  }
168
- if (!key2values.has(value2.key))
169
- key2values.set(value2.key, []);
170
- key2values.get(value2.key).push(value.value);
171
- } else {
172
- if (!key2values.has(sampleType))
173
- key2values.set(sampleType, []);
174
- key2values.get(sampleType).push(value.value);
171
+ plot = value2.key;
175
172
  }
176
- if (absMin === null || value.value < absMin)
177
- absMin = value.value;
178
- if (absMax === null || value.value > absMax)
179
- absMax = value.value;
173
+ if (!chart2plot2values.has(chart)) chart2plot2values.set(chart, /* @__PURE__ */ new Map());
174
+ const plot2values = chart2plot2values.get(chart);
175
+ if (!plot2values.has(plot)) plot2values.set(plot, []);
176
+ const values = plot2values.get(plot);
177
+ values.push(value.value);
178
+ if (absMin === null || value.value < absMin) absMin = value.value;
179
+ if (absMax === null || value.value > absMax) absMax = value.value;
180
180
  }
181
- return { absMax, absMin, key2values, uncomputableValues };
181
+ return { absMax, absMin, chart2plot2values, uncomputableValues };
182
182
  }
183
183
  function numericBins(overlayTerm, data) {
184
184
  const overlayBins = data.refs.byTermId[overlayTerm?.$id]?.bins ?? [];
@@ -19,25 +19,20 @@ function init({ genomes }) {
19
19
  const q = req.query;
20
20
  try {
21
21
  const g = genomes[req.query.genome];
22
- if (!g)
23
- throw "invalid genome name";
22
+ if (!g) throw "invalid genome name";
24
23
  const ds = g.datasets[req.query.dslabel];
25
- if (!ds)
26
- throw "invalid dataset name";
24
+ if (!ds) throw "invalid dataset name";
27
25
  const tdb = ds.cohort.termdb;
28
- if (!tdb)
29
- throw "invalid termdb object";
26
+ if (!tdb) throw "invalid termdb object";
30
27
  await trigger_getcategories(q, res, tdb, ds);
31
28
  } catch (e) {
32
29
  res.send({ error: e?.message || e });
33
- if (e instanceof Error && e.stack)
34
- console.log(e);
30
+ if (e instanceof Error && e.stack) console.log(e);
35
31
  }
36
32
  };
37
33
  }
38
34
  async function trigger_getcategories(q, res, tdb, ds) {
39
- if (!q.tw.$id)
40
- q.tw.$id = "_";
35
+ if (!q.tw.$id) q.tw.$id = "_";
41
36
  const $id = q.tw.$id;
42
37
  const arg = {
43
38
  filter: q.filter,
@@ -50,8 +45,7 @@ async function trigger_getcategories(q, res, tdb, ds) {
50
45
  __protected__: q.__protected__
51
46
  };
52
47
  const data = await getData(arg, ds);
53
- if (data.error)
54
- throw data.error;
48
+ if (data.error) throw data.error;
55
49
  const [lst, orderedLabels] = getCategories(data, q, ds, $id);
56
50
  res.send({
57
51
  lst,
@@ -74,8 +68,7 @@ function getCategories(data, q, ds, $id) {
74
68
  const sampleCountedFor = /* @__PURE__ */ new Set();
75
69
  for (const sampleData of Object.values(samples)) {
76
70
  const key = $id;
77
- if (!Object.keys(sampleData).includes(key))
78
- continue;
71
+ if (!Object.keys(sampleData).includes(key)) continue;
79
72
  const values = sampleData[key].values;
80
73
  sampleCountedFor.clear();
81
74
  for (const value of values) {
@@ -114,10 +107,8 @@ function getCategories(data, q, ds, $id) {
114
107
  const key2count = /* @__PURE__ */ new Map();
115
108
  for (const sid in data.samples) {
116
109
  const v = data.samples[sid][$id];
117
- if (!v)
118
- continue;
119
- if (!("key" in v))
120
- continue;
110
+ if (!v) continue;
111
+ if (!("key" in v)) continue;
121
112
  key2count.set(v.key, 1 + (key2count.get(v.key) || 0));
122
113
  }
123
114
  for (const [key, count] of key2count) {
@@ -31,20 +31,16 @@ function init({ genomes }) {
31
31
  let result;
32
32
  try {
33
33
  const g = genomes[q.genome];
34
- if (!g)
35
- throw "invalid genome name";
34
+ if (!g) throw "invalid genome name";
36
35
  const ds = g.datasets[q.dslabel];
37
- if (!ds)
38
- throw "invalid dataset name";
36
+ if (!ds) throw "invalid dataset name";
39
37
  if (ds.label === "GDC" && !ds.__gdc?.doneCaching)
40
38
  throw "The server has not finished caching the case IDs: try again in about 2 minutes.";
41
39
  if ([TermTypes.GENE_EXPRESSION, TermTypes.METABOLITE_INTENSITY, NUMERIC_DICTIONARY_TERM].includes(q.dataType)) {
42
40
  if (!ds.queries?.[q.dataType] && q.dataType !== NUMERIC_DICTIONARY_TERM)
43
41
  throw `no ${q.dataType} data on this dataset`;
44
- if (!q.terms)
45
- throw `missing gene list`;
46
- if (!Array.isArray(q.terms))
47
- throw `gene list is not an array`;
42
+ if (!q.terms) throw `missing gene list`;
43
+ if (!Array.isArray(q.terms)) throw `gene list is not an array`;
48
44
  if (q.terms.length < 3)
49
45
  throw `A minimum of three genes is required for clustering. Please refresh this page to clear this error.`;
50
46
  result = await getResult(q, ds);
@@ -52,8 +48,7 @@ function init({ genomes }) {
52
48
  throw "unknown q.dataType " + q.dataType;
53
49
  }
54
50
  } catch (e) {
55
- if (e.stack)
56
- console.log(e.stack);
51
+ if (e.stack) console.log(e.stack);
57
52
  result = {
58
53
  status: e.status || 400,
59
54
  error: e.message || e
@@ -94,8 +89,7 @@ async function getResult(q, ds) {
94
89
  if (skippedSexChrGenes?.length) {
95
90
  removedHierClusterTerms.push({ text: "Skipped sex chromosome genes", lst: skippedSexChrGenes });
96
91
  }
97
- if (term2sample2value.size == 0)
98
- throw "no data";
92
+ if (term2sample2value.size == 0) throw "no data";
99
93
  if (term2sample2value.size == 1) {
100
94
  const g = Array.from(term2sample2value.keys())[0];
101
95
  return { term: { gene: g, type: TermTypes.GENE_EXPRESSION }, data: term2sample2value.get(g) };
@@ -104,8 +98,7 @@ async function getResult(q, ds) {
104
98
  const clustering = await doClustering(term2sample2value, q, Object.keys(bySampleId).length);
105
99
  mayLog("clustering done:", formatElapsedTime(Date.now() - t));
106
100
  const result = { clustering, byTermId, bySampleId };
107
- if (removedHierClusterTerms.length)
108
- result.removedHierClusterTerms = removedHierClusterTerms;
101
+ if (removedHierClusterTerms.length) result.removedHierClusterTerms = removedHierClusterTerms;
109
102
  return result;
110
103
  }
111
104
  async function getNumericDictTermAnnotation(q, ds) {
@@ -149,10 +142,8 @@ async function doClustering(data, q, numCases = 1e3) {
149
142
  throw `termdb.cluster: There are no overlapping tested samples shared across the selected ${termType2label(
150
143
  q.dataType
151
144
  )}`;
152
- if (!clusterMethodLst.find((i) => i.value == q.clusterMethod))
153
- throw "Invalid cluster method";
154
- if (!distanceMethodLst.find((i) => i.value == q.distanceMethod))
155
- throw "Invalid distance method";
145
+ if (!clusterMethodLst.find((i) => i.value == q.clusterMethod)) throw "Invalid cluster method";
146
+ if (!distanceMethodLst.find((i) => i.value == q.distanceMethod)) throw "Invalid distance method";
156
147
  const inputData = {
157
148
  matrix: [],
158
149
  row_names: [],
@@ -172,8 +163,7 @@ async function doClustering(data, q, numCases = 1e3) {
172
163
  }
173
164
  inputData.matrix.push(q.zScoreTransformation ? getZscore(row) : row);
174
165
  }
175
- if (inputData.matrix.length == 0)
176
- throw "Clustering matrix is empty";
166
+ if (inputData.matrix.length == 0) throw "Clustering matrix is empty";
177
167
  const Routput = JSON.parse(await run_R("hclust.R", JSON.stringify(inputData)));
178
168
  const row_names_index = Routput.RowOrder.map((row) => inputData.row_names.indexOf(row.name));
179
169
  const col_names_index = Routput.ColOrder.map((col) => inputData.col_names.indexOf(col.name));
@@ -211,8 +201,7 @@ function getZscore(l) {
211
201
  }
212
202
  async function validate_query_geneExpression(ds, genome) {
213
203
  const q = ds.queries.geneExpression;
214
- if (!q)
215
- return;
204
+ if (!q) return;
216
205
  q.geneExpression2bins = {};
217
206
  if (q.src == "gdcapi") {
218
207
  gdc_validate_query_geneExpression(ds, genome);
@@ -268,25 +257,20 @@ async function validateNative(q, ds) {
268
257
  tmp = await run_rust("validateHDF5", JSON.stringify({ hdf5_file: q.file }));
269
258
  }
270
259
  const vr = JSON.parse(tmp);
271
- if (vr.status !== "success")
272
- throw vr.message;
260
+ if (vr.status !== "success") throw vr.message;
273
261
  if (q.newformat) {
274
- if (!vr.samples?.length)
275
- throw "HDF5 file has no samples, please check file.";
262
+ if (!vr.samples?.length) throw "HDF5 file has no samples, please check file.";
276
263
  for (const sn of vr.samples) {
277
264
  const si = ds.cohort.termdb.q.sampleName2id(sn);
278
- if (si == void 0)
279
- throw `unknown sample ${sn} from HDF5 ${q.file}`;
265
+ if (si == void 0) throw `unknown sample ${sn} from HDF5 ${q.file}`;
280
266
  q.samples.push(si);
281
267
  }
282
268
  console.log(`${ds.label}: geneExpression HDF5 file validated. Format: ${vr.format}, Samples:`, vr.samples.length);
283
269
  } else {
284
- if (!vr.sampleNames?.length)
285
- throw "HDF5 file has no samples, please check file.";
270
+ if (!vr.sampleNames?.length) throw "HDF5 file has no samples, please check file.";
286
271
  for (const sn of vr.sampleNames) {
287
272
  const si = ds.cohort.termdb.q.sampleName2id(sn);
288
- if (si == void 0)
289
- throw `unknown sample ${sn} from HDF5 ${q.file}`;
273
+ if (si == void 0) throw `unknown sample ${sn} from HDF5 ${q.file}`;
290
274
  q.samples.push(si);
291
275
  }
292
276
  console.log(
@@ -335,11 +319,9 @@ async function validateNative(q, ds) {
335
319
  mayLog("Time taken to run gene query:", formatElapsedTime(Date.now() - time1));
336
320
  if (q.newformat) {
337
321
  const genesData = geneData.query_output || {};
338
- if (!genesData)
339
- throw "No expression data returned from HDF5 query";
322
+ if (!genesData) throw "No expression data returned from HDF5 query";
340
323
  for (const tw of param.terms) {
341
- if (!tw.term.gene)
342
- continue;
324
+ if (!tw.term.gene) continue;
343
325
  const geneResult = genesData[tw.term.gene];
344
326
  if (!geneResult) {
345
327
  console.warn(`No data found for gene ${tw.term.gene} in the response`);
@@ -349,10 +331,8 @@ async function validateNative(q, ds) {
349
331
  const s2v = {};
350
332
  for (const sampleName in samplesData) {
351
333
  const sampleId = ds.cohort.termdb.q.sampleName2id(sampleName);
352
- if (!sampleId)
353
- continue;
354
- if (limitSamples && !limitSamples.has(sampleId))
355
- continue;
334
+ if (!sampleId) continue;
335
+ if (limitSamples && !limitSamples.has(sampleId)) continue;
356
336
  s2v[sampleId] = samplesData[sampleName];
357
337
  }
358
338
  if (Object.keys(s2v).length) {
@@ -365,8 +345,7 @@ async function validateNative(q, ds) {
365
345
  } else {
366
346
  const genesData = geneData.genes || { [geneNames[0]]: geneData };
367
347
  for (const tw of param.terms) {
368
- if (!tw.term.gene)
369
- continue;
348
+ if (!tw.term.gene) continue;
370
349
  const geneResult = genesData[tw.term.gene];
371
350
  if (!geneResult) {
372
351
  console.warn(`No data found for gene ${tw.term.gene} in the response`);
@@ -376,10 +355,8 @@ async function validateNative(q, ds) {
376
355
  const s2v = {};
377
356
  for (const [sampleName, value] of Object.entries(samplesData)) {
378
357
  const sampleId = ds.cohort.termdb.q.sampleName2id(sampleName);
379
- if (!sampleId)
380
- continue;
381
- if (limitSamples && !limitSamples.has(sampleId))
382
- continue;
358
+ if (!sampleId) continue;
359
+ if (limitSamples && !limitSamples.has(sampleId)) continue;
383
360
  s2v[sampleId] = value;
384
361
  }
385
362
  if (Object.keys(s2v).length) {
@@ -16,17 +16,14 @@ function init({ genomes }) {
16
16
  mayCopyFromCookie(q, req.cookies);
17
17
  try {
18
18
  const genome = genomes[q.genome];
19
- if (!genome)
20
- throw "invalid genome";
19
+ if (!genome) throw "invalid genome";
21
20
  const [ds] = get_ds_tdb(genome, q);
22
21
  const count = ds.cohort.termdb.q?.getCohortSampleCount?.(q.cohort) || 1;
23
22
  res.send({ count });
24
23
  } catch (e) {
25
24
  res.send({ error: e.message || e });
26
- if (e.stack)
27
- console.log(e.stack);
28
- else
29
- console.log(e);
25
+ if (e.stack) console.log(e.stack);
26
+ else console.log(e);
30
27
  }
31
28
  };
32
29
  }
@@ -16,23 +16,19 @@ function init({ genomes }) {
16
16
  mayCopyFromCookie(q, req.cookies);
17
17
  try {
18
18
  const genome = genomes[q.genome];
19
- if (!genome)
20
- throw "invalid genome";
19
+ if (!genome) throw "invalid genome";
21
20
  const [ds] = get_ds_tdb(genome, q);
22
21
  const result = getCohortsData(ds);
23
22
  res.send(result);
24
23
  } catch (e) {
25
24
  res.send({ error: e.message || e });
26
- if (e.stack)
27
- console.log(e.stack);
28
- else
29
- console.log(e);
25
+ if (e.stack) console.log(e.stack);
26
+ else console.log(e);
30
27
  }
31
28
  };
32
29
  }
33
30
  function getCohortsData(ds) {
34
- if (!ds.cohort.db)
35
- return { cohorts: [], features: [], cfeatures: [] };
31
+ if (!ds.cohort.db) return { cohorts: [], features: [], cfeatures: [] };
36
32
  const features = ds.cohort.db.connection.prepare("select * from features").all();
37
33
  const cohorts = ds.cohort.db.connection.prepare(
38
34
  `select * from cohorts where cohort in (select distinct(cohort) from cohort_features)