@sjcrh/proteinpaint-server 2.72.0 → 2.73.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjcrh/proteinpaint-server",
3
- "version": "2.72.0",
3
+ "version": "2.73.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",
@@ -62,7 +62,7 @@
62
62
  },
63
63
  "dependencies": {
64
64
  "@sjcrh/augen": "2.46.0",
65
- "@sjcrh/proteinpaint-rust": "2.61.1",
65
+ "@sjcrh/proteinpaint-rust": "2.73.0",
66
66
  "better-sqlite3": "^9.4.1",
67
67
  "body-parser": "^1.15.2",
68
68
  "canvas": "~2.11.2",
@@ -22,13 +22,14 @@ const api = {
22
22
  function init({ genomes }) {
23
23
  return async (req, res) => {
24
24
  try {
25
- const g = genomes[req.query.genome];
25
+ const query = req.query;
26
+ const g = genomes[query.genome];
26
27
  if (!g)
27
28
  throw "invalid genome name";
28
- const ds = g.datasets[req.query.dslabel];
29
+ const ds = g.datasets[query.dslabel];
29
30
  if (!ds)
30
31
  throw "invalid dataset name";
31
- const sampleId = req.query.sample_id;
32
+ const sampleId = query.sample_id;
32
33
  const sampleWSImagesPath = path.join(
33
34
  `${serverconfig.tpmasterdir}/${ds.queries.WSImages.imageBySampleFolder}`,
34
35
  sampleId
@@ -92,7 +92,7 @@ async function trigger_getcategories(q, res, tdb, ds, genome) {
92
92
  if (data.error)
93
93
  throw data.error;
94
94
  const lst = [];
95
- if (q.tw.term.type == "geneVariant" && !q.tw.q.groupsetting?.inuse) {
95
+ if (q.tw.term.type == "geneVariant" && q.tw.q.type != "predefined-groupset" && q.tw.q.type != "custom-groupset") {
96
96
  const samples = data.samples;
97
97
  const dtClassMap = /* @__PURE__ */ new Map();
98
98
  if (ds.assayAvailability?.byDt) {
@@ -192,11 +192,10 @@ async function validateNative(q, ds, genome) {
192
192
  }
193
193
  }
194
194
  const term2sample2value = /* @__PURE__ */ new Map();
195
- for (const g of param.terms) {
196
- const geneTerm = g;
195
+ for (const geneTerm of param.terms) {
197
196
  if (!geneTerm.gene)
198
197
  continue;
199
- if (!geneTerm.chr) {
198
+ if (!geneTerm.chr || !Number.isInteger(geneTerm.start) || !Number.isInteger(geneTerm.stop)) {
200
199
  const re = getResultGene(genome, { input: geneTerm.gene, deep: 1 });
201
200
  if (!re.gmlst || re.gmlst.length == 0) {
202
201
  console.warn("unknown gene:" + geneTerm.gene);
@@ -208,12 +207,13 @@ async function validateNative(q, ds, genome) {
208
207
  geneTerm.chr = i.chr;
209
208
  }
210
209
  const s2v = {};
210
+ if (!geneTerm.chr || !Number.isInteger(geneTerm.start) || !Number.isInteger(geneTerm.stop))
211
+ throw "missing chr/start/stop";
211
212
  await utils.get_lines_bigfile({
212
213
  args: [
213
214
  q.file,
214
- (q.nochr ? geneTerm.chr?.replace("chr", "") : geneTerm.chr) + ":" + geneTerm.start + "-" + geneTerm.stop
215
+ (q.nochr ? geneTerm.chr.replace("chr", "") : geneTerm.chr) + ":" + geneTerm.start + "-" + geneTerm.stop
215
216
  ],
216
- // must do g.chr?.replace to avoid tsc error
217
217
  callback: (line) => {
218
218
  const l = line.split(" ");
219
219
  if (l[3].toLowerCase() != geneTerm.gene.toLowerCase())
@@ -84,7 +84,11 @@ function init({ genomes }) {
84
84
  }
85
85
  values.push(Number(value));
86
86
  }
87
- result = Summarystats(values);
87
+ if (values.length) {
88
+ result = Summarystats(values);
89
+ } else {
90
+ result = {};
91
+ }
88
92
  } catch (e) {
89
93
  if (e instanceof Error && e.stack)
90
94
  console.log(e);
@@ -45,7 +45,7 @@ async function trigger_gettermsbyid(q, res, tdb) {
45
45
  for (const id of q.ids) {
46
46
  const term = tdb.q.termjsonByOneid(id);
47
47
  if (term) {
48
- if (term.type == "categorical" && !term.values && !term.groupsetting?.inuse) {
48
+ if (term.type == "categorical" && !term.values) {
49
49
  term.values = {};
50
50
  term.samplecount = {};
51
51
  }
@@ -61,6 +61,7 @@ function nativeValidateQuery(ds) {
61
61
  throw "topVariablyExpressedGenes query given but geneExpression missing";
62
62
  if (gE.src != "native")
63
63
  throw "topVariablyExpressedGenes is native but geneExpression.src is not native";
64
+ addTopVEarg(ds.queries.topVariablyExpressedGenes);
64
65
  ds.queries.topVariablyExpressedGenes.getGenes = async (q) => {
65
66
  const samples = [];
66
67
  if (q.filter) {
@@ -81,18 +82,81 @@ function nativeValidateQuery(ds) {
81
82
  samples.push(n);
82
83
  }
83
84
  }
84
- const genes = await computeGenes4nativeDs(q, ds, gE.file, samples);
85
+ const genes = await computeGenes4nativeDs(q, gE.file, samples);
85
86
  return genes;
86
87
  };
87
88
  }
88
- async function computeGenes4nativeDs(q, ds, matrixFile, samples) {
89
+ function addTopVEarg(q) {
90
+ const arglst = [
91
+ { id: "maxGenes", label: "Gene Count", type: "number", value: 100 },
92
+ {
93
+ id: "filter_extreme_values",
94
+ label: "Filter Extreme Values",
95
+ type: "boolean",
96
+ value: true,
97
+ options: [
98
+ {
99
+ id: "min_count",
100
+ label: "Min count",
101
+ type: "number",
102
+ value: 10
103
+ },
104
+ {
105
+ id: "min_total_count",
106
+ label: "Min total count",
107
+ type: "number",
108
+ value: 15
109
+ }
110
+ ]
111
+ },
112
+ {
113
+ id: "rank_type",
114
+ label: "Rank by:",
115
+ type: "radio",
116
+ options: [
117
+ /** The param option in input JSON is very important.
118
+ * It instructs what method will be used to calculate variation in the counts for a particular gene.
119
+ * It supports variance as well as interquartile region.
120
+ * This is based on the recommendation of this article:
121
+ * https://www.frontiersin.org/articles/10.3389/fgene.2021.632620/full.
122
+ * This article recommends using interquartile region over variance.*/
123
+ {
124
+ type: "boolean",
125
+ label: "Variance",
126
+ value: "var"
127
+ },
128
+ {
129
+ type: "boolean",
130
+ label: "Interquartile Region",
131
+ value: "iqr"
132
+ }
133
+ ]
134
+ }
135
+ ];
136
+ if (q.arguments) {
137
+ for (const a of q.arguments) {
138
+ if (!a.id)
139
+ throw "missing id of topVE.arguments[]";
140
+ const item = arglst.find((i) => i.id == a.id);
141
+ if (!item)
142
+ throw "unknown id of topVE.arguments[]";
143
+ Object.assign(item, a);
144
+ }
145
+ }
146
+ q.arguments = arglst;
147
+ }
148
+ async function computeGenes4nativeDs(q, matrixFile, samples) {
89
149
  const input_json = {
90
150
  input_file: matrixFile,
91
151
  samples: samples.join(","),
92
- filter_extreme_values: true,
152
+ filter_extreme_values: q.filter_extreme_values,
93
153
  num_genes: q.maxGenes,
94
- param: "var"
154
+ rank_type: q.rank_type?.type
95
155
  };
156
+ if (q.filter_extreme_values == 1) {
157
+ input_json["min_count"] = q.min_count;
158
+ input_json["min_total_count"] = q.min_total_count;
159
+ }
96
160
  const rust_output = await run_rust("topGeneByExpressionVariance", JSON.stringify(input_json));
97
161
  const rust_output_list = rust_output.split("\n");
98
162
  let output_json;
@@ -109,7 +173,7 @@ async function computeGenes4nativeDs(q, ds, matrixFile, samples) {
109
173
  function gdcValidateQuery(ds, genome) {
110
174
  ds.queries.topVariablyExpressedGenes.getGenes = async (q) => {
111
175
  if (serverconfig.features.gdcGenes) {
112
- console.log(
176
+ console.error(
113
177
  "!!GDC!! using serverconfig.features.gdcGenes[] but not live api query. only use this on DEV and never on PROD!"
114
178
  );
115
179
  return serverconfig.features.gdcGenes;
@@ -142,7 +206,7 @@ function gdcValidateQuery(ds, genome) {
142
206
  }
143
207
  return genes;
144
208
  } catch (e) {
145
- console.log(e.stack || e);
209
+ console.error(e.stack || e);
146
210
  throw e;
147
211
  }
148
212
  };