@sjcrh/proteinpaint-server 2.135.3-1 → 2.136.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.
@@ -111,6 +111,7 @@ function termdb_test_default() {
111
111
  plotConfigByCohort: {
112
112
  default: {
113
113
  report: {
114
+ filterTWs: [{ id: "diaggrp" }],
114
115
  sections: [
115
116
  {
116
117
  name: "Demographics",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjcrh/proteinpaint-server",
3
- "version": "2.135.3-1",
3
+ "version": "2.136.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",
@@ -47,7 +47,6 @@
47
47
  "babel-loader": "^8.2.2",
48
48
  "c8": "^10.1.3",
49
49
  "esbuild": "^0.19.12",
50
- "glob": "^10.4.5",
51
50
  "monocart-coverage-reports": "^2.12.1",
52
51
  "node-notifier": "^9.0.1",
53
52
  "node-watch": "^0.7.1",
@@ -60,12 +59,12 @@
60
59
  "typescript": "^5.6.3"
61
60
  },
62
61
  "dependencies": {
63
- "@sjcrh/augen": "2.121.0",
62
+ "@sjcrh/augen": "2.136.0",
64
63
  "@sjcrh/proteinpaint-python": "2.135.2-0",
65
64
  "@sjcrh/proteinpaint-r": "2.130.0",
66
- "@sjcrh/proteinpaint-rust": "2.135.3-1",
67
- "@sjcrh/proteinpaint-shared": "2.135.2-0",
68
- "@sjcrh/proteinpaint-types": "2.135.2-0",
65
+ "@sjcrh/proteinpaint-rust": "2.136.0",
66
+ "@sjcrh/proteinpaint-shared": "2.136.0",
67
+ "@sjcrh/proteinpaint-types": "2.136.0",
69
68
  "@types/express": "^5.0.0",
70
69
  "@types/express-session": "^1.18.1",
71
70
  "better-sqlite3": "^9.4.1",
@@ -35,7 +35,8 @@ function getList(samplesPerFilter, filtersData, tw) {
35
35
  for (const sample of twSamples) {
36
36
  data.push(filtersData.samples[sample]);
37
37
  }
38
- const sampleValues = Array.from(new Set(data.map((sample) => sample[tw.$id]?.value)));
38
+ const annotations = data.filter((s) => s != void 0).map((sample) => sample[tw.$id]?.value);
39
+ const sampleValues = Array.from(new Set(annotations));
39
40
  for (const value of values) {
40
41
  value.value = value.label;
41
42
  const label = value.label;
@@ -51,12 +51,20 @@ async function trigger_getcategories(q, res, tdb, ds, genome) {
51
51
  const data = await getData(arg, ds, genome);
52
52
  if (data.error)
53
53
  throw data.error;
54
+ const [lst, orderedLabels] = getCategories(data, q, ds, $id);
55
+ res.send({
56
+ lst,
57
+ orderedLabels
58
+ });
59
+ }
60
+ function getCategories(data, q, ds, $id) {
54
61
  const lst = [];
55
62
  if (q.tw.term.type == "geneVariant" && q.tw.q.type != "predefined-groupset" && q.tw.q.type != "custom-groupset") {
56
63
  const samples = data.samples;
57
64
  const dtClassMap = /* @__PURE__ */ new Map();
58
65
  if (ds.assayAvailability?.byDt) {
59
- for (const [dtType, dtValue] of Object.entries(ds.assayAvailability.byDt)) {
66
+ for (const [dtType, _dtValue] of Object.entries(ds.assayAvailability.byDt)) {
67
+ const dtValue = _dtValue;
60
68
  if (dtValue.byOrigin) {
61
69
  dtClassMap.set(parseInt(dtType), { byOrigin: { germline: {}, somatic: {} } });
62
70
  }
@@ -65,6 +73,8 @@ async function trigger_getcategories(q, res, tdb, ds, genome) {
65
73
  const sampleCountedFor = /* @__PURE__ */ new Set();
66
74
  for (const sampleData of Object.values(samples)) {
67
75
  const key = $id;
76
+ if (!Object.keys(sampleData).includes(key))
77
+ continue;
68
78
  const values = sampleData[key].values;
69
79
  sampleCountedFor.clear();
70
80
  for (const value of values) {
@@ -126,11 +136,9 @@ async function trigger_getcategories(q, res, tdb, ds, genome) {
126
136
  if (orderedLabels.length) {
127
137
  lst.sort((a, b) => orderedLabels.indexOf(a.label) - orderedLabels.indexOf(b.label));
128
138
  }
129
- res.send({
130
- lst,
131
- orderedLabels
132
- });
139
+ return [lst, orderedLabels];
133
140
  }
134
141
  export {
135
- api
142
+ api,
143
+ getCategories
136
144
  };
@@ -51,9 +51,14 @@ async function validate_query_singleCell(ds, genome) {
51
51
  const q = ds.queries.singleCell;
52
52
  if (!q)
53
53
  return;
54
- if (typeof q.samples.get != "function") {
54
+ if (typeof q.samples != "object")
55
+ throw "singleCell.samples{} not object";
56
+ if (typeof q.samples.get == "function") {
57
+ } else {
55
58
  validateSamplesNative(q.samples, q.data, ds);
56
59
  }
60
+ if (typeof q.data != "object")
61
+ throw "singleCell.data{} not object";
57
62
  if (q.data.src == "gdcapi") {
58
63
  gdc_validate_query_singleCell_data(ds, genome);
59
64
  } else if (q.data.src == "native") {
@@ -62,6 +67,8 @@ async function validate_query_singleCell(ds, genome) {
62
67
  throw "unknown singleCell.data.src";
63
68
  }
64
69
  if (q.geneExpression) {
70
+ if (typeof q.geneExpression != "object")
71
+ throw "singleCell.geneExpression not object";
65
72
  if (q.geneExpression.src == "native") {
66
73
  validateGeneExpressionNative(q.geneExpression);
67
74
  } else if (q.geneExpression.src == "gdcapi") {
@@ -71,9 +78,13 @@ async function validate_query_singleCell(ds, genome) {
71
78
  }
72
79
  }
73
80
  if (q.DEgenes) {
81
+ if (typeof q.DEgenes != "object")
82
+ throw "singleCell.DEgenes not object";
74
83
  validate_query_singleCell_DEgenes(ds);
75
84
  }
76
85
  if (q.images) {
86
+ if (typeof q.images != "object")
87
+ throw "singleCell.images not object";
77
88
  validateImages(q.images);
78
89
  }
79
90
  }
@@ -127,68 +138,69 @@ function validateDataNative(D, ds) {
127
138
  if (nameSet.has(plot.name))
128
139
  throw "duplicate plot.name";
129
140
  nameSet.add(plot.name);
141
+ if (!plot.folder)
142
+ throw "plot.folder missing";
130
143
  }
144
+ const file2Lines = {};
131
145
  D.get = async (q) => {
132
- try {
133
- const plots = [];
134
- let geneExpMap;
135
- if (ds.queries.singleCell.geneExpression && q.gene) {
136
- geneExpMap = await ds.queries.singleCell.geneExpression.get({ sample: q.sample, gene: q.gene });
137
- }
138
- const file2Lines = {};
139
- for (const plot of D.plots) {
140
- if (!q.plots.includes(plot.name))
141
- continue;
142
- const tsvfile = path.join(
143
- serverconfig.tpmasterdir,
144
- plot.folder,
145
- (q.sample.eID || q.sample.sID) + plot.fileSuffix
146
- );
147
- if (!file2Lines[tsvfile]) {
148
- await file_is_readable(tsvfile);
149
- file2Lines[tsvfile] = (await read_file(tsvfile)).trim().split("\n");
150
- }
151
- const colorColumn = plot.colorColumns.find((c) => c.name == q.colorBy?.[plot.name]) || plot.colorColumns[0];
152
- const lines = file2Lines[tsvfile];
153
- const expCells = [];
154
- const noExpCells = [];
155
- for (let i = 1; i < lines.length; i++) {
156
- const l = lines[i].split(" ");
157
- const cellId = lines.length > 3 ? l[0] : void 0, x = Number(l[plot.coordsColumns.x]), y = Number(l[plot.coordsColumns.y]);
158
- const category = l[colorColumn?.index] || "";
159
- if (!cellId)
160
- throw "cell id missing";
161
- if (!Number.isFinite(x) || !Number.isFinite(y))
162
- throw "x/y not number";
163
- const cell = { cellId, x, y, category };
164
- if (geneExpMap) {
165
- if (geneExpMap[cellId] !== void 0) {
166
- cell.geneExp = geneExpMap[cellId];
167
- expCells.push(cell);
168
- } else {
169
- noExpCells.push(cell);
170
- }
171
- } else
172
- noExpCells.push(cell);
146
+ const plots = [];
147
+ let geneExpMap;
148
+ if (ds.queries.singleCell.geneExpression && q.gene) {
149
+ geneExpMap = await ds.queries.singleCell.geneExpression.get({ sample: q.sample, gene: q.gene });
150
+ }
151
+ for (const plot of D.plots) {
152
+ if (!q.plots.includes(plot.name))
153
+ continue;
154
+ const tsvfile = path.join(serverconfig.tpmasterdir, plot.folder, (q.sample.eID || q.sample.sID) + plot.fileSuffix);
155
+ if (!file2Lines[tsvfile]) {
156
+ await file_is_readable(tsvfile);
157
+ const text = await read_file(tsvfile);
158
+ const lines = text.trim().split("\n");
159
+ let first = true;
160
+ const lines2 = [];
161
+ for (const line of lines) {
162
+ if (first) {
163
+ first = false;
164
+ continue;
165
+ }
166
+ lines2.push(line.split(" "));
173
167
  }
174
- plots.push({
175
- name: plot.name,
176
- expCells,
177
- noExpCells,
178
- colorColumns: plot.colorColumns.map((c) => c.name),
179
- colorBy: colorColumn?.name,
180
- colorMap: colorColumn?.colorMap
181
- });
168
+ file2Lines[tsvfile] = lines2;
182
169
  }
183
- if (plots.length == 0) {
184
- return { nodata: true };
170
+ const colorColumn = plot.colorColumns.find((c) => c.name == q.colorBy?.[plot.name]) || plot.colorColumns[0];
171
+ const expCells = [];
172
+ const noExpCells = [];
173
+ for (const l of file2Lines[tsvfile]) {
174
+ const cellId = l[0], x = Number(l[plot.coordsColumns.x]), y = Number(l[plot.coordsColumns.y]);
175
+ const category = l[colorColumn?.index] || "";
176
+ if (!cellId)
177
+ throw "cell id missing";
178
+ if (!Number.isFinite(x) || !Number.isFinite(y))
179
+ throw "x/y not number";
180
+ const cell = { cellId, x, y, category };
181
+ if (geneExpMap) {
182
+ if (geneExpMap[cellId] !== void 0) {
183
+ cell.geneExp = geneExpMap[cellId];
184
+ expCells.push(cell);
185
+ } else {
186
+ noExpCells.push(cell);
187
+ }
188
+ } else
189
+ noExpCells.push(cell);
185
190
  }
186
- return { plots };
187
- } catch (e) {
188
- if (e.stack)
189
- console.log(e.stack);
190
- return { error: e.message || e };
191
+ plots.push({
192
+ name: plot.name,
193
+ expCells,
194
+ noExpCells,
195
+ colorColumns: plot.colorColumns.map((c) => c.name),
196
+ colorBy: colorColumn?.name,
197
+ colorMap: colorColumn?.colorMap
198
+ });
199
+ }
200
+ if (plots.length == 0) {
201
+ return { nodata: true };
191
202
  }
203
+ return { plots };
192
204
  };
193
205
  }
194
206
  function validateGeneExpressionNative(G) {