@sjcrh/proteinpaint-server 2.167.2 → 2.169.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.167.2",
3
+ "version": "2.169.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,11 +62,11 @@
62
62
  },
63
63
  "dependencies": {
64
64
  "@sjcrh/augen": "2.143.0",
65
- "@sjcrh/proteinpaint-python": "2.164.1",
65
+ "@sjcrh/proteinpaint-python": "2.169.0",
66
66
  "@sjcrh/proteinpaint-r": "2.152.1-0",
67
- "@sjcrh/proteinpaint-rust": "2.167.0",
68
- "@sjcrh/proteinpaint-shared": "2.167.0",
69
- "@sjcrh/proteinpaint-types": "2.167.0",
67
+ "@sjcrh/proteinpaint-rust": "2.169.0",
68
+ "@sjcrh/proteinpaint-shared": "2.169.0",
69
+ "@sjcrh/proteinpaint-types": "2.169.0",
70
70
  "@types/express": "^5.0.0",
71
71
  "@types/express-session": "^1.18.1",
72
72
  "better-sqlite3": "^12.4.1",
@@ -81,7 +81,12 @@ function validateQuery(ds, connection) {
81
81
  ) VALUES (?, ?, ?, ?, ?, ?, ?)
82
82
  `;
83
83
  const insertStmt = connection.prepare(insertSql);
84
- const userRow = connection.prepare(`SELECT id FROM project_users WHERE project_id = ? ORDER BY id ASC LIMIT 1`).get(projectId);
84
+ const userRow = connection.prepare(
85
+ `SELECT id
86
+ FROM project_users
87
+ ORDER BY id
88
+ LIMIT 1`
89
+ ).get();
85
90
  const userId = userRow?.id;
86
91
  insertStmt.run(projectId, userId, coords, timestamp, status, classId, imageId);
87
92
  return { status: "ok" };
@@ -2,8 +2,9 @@ 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 { getDescrStats } from "./termdb.descrstats.ts";
5
+ import { getDescrStats, getStdDev, getMean } from "./termdb.descrstats.ts";
6
6
  import { run_rust } from "@sjcrh/proteinpaint-rust";
7
+ import { roundValueAuto } from "#shared/roundValue.js";
7
8
  const api = {
8
9
  endpoint: "termdb/boxplot",
9
10
  methods: {
@@ -20,14 +21,14 @@ const api = {
20
21
  function init({ genomes }) {
21
22
  return async (req, res) => {
22
23
  const q = req.query;
24
+ const genome = genomes[q.genome];
25
+ if (!genome) throw new Error("invalid genome name");
26
+ const ds = genome.datasets?.[q.dslabel];
27
+ if (!ds) throw new Error("invalid ds");
28
+ const terms = [q.tw];
29
+ if (q.overlayTw) terms.push(q.overlayTw);
30
+ if (q.divideTw) terms.push(q.divideTw);
23
31
  try {
24
- const genome = genomes[q.genome];
25
- if (!genome) throw new Error("invalid genome name");
26
- const ds = genome.datasets?.[q.dslabel];
27
- if (!ds) throw new Error("invalid ds");
28
- const terms = [q.tw];
29
- if (q.overlayTw) terms.push(q.overlayTw);
30
- if (q.divideTw) terms.push(q.divideTw);
31
32
  const data = await getData({ filter: q.filter, filter0: q.filter0, terms, __protected__: q.__protected__ }, ds);
32
33
  if (data.error) throw new Error(data.error);
33
34
  const { absMin, absMax, charts, uncomputableValues, descrStats, outlierMin, outlierMax } = await processData(
@@ -89,9 +90,13 @@ async function processData(data, q) {
89
90
  if (q.orderByMedian == true) {
90
91
  plots.sort((a, b) => a.boxplot.p50 - b.boxplot.p50);
91
92
  }
92
- charts[chart] = { chartId: chart, plots };
93
+ const sampleCount = plots.reduce((total, p) => {
94
+ if (p.hidden) return total;
95
+ return total + p.descrStats.total.value;
96
+ }, 0);
97
+ charts[chart] = { chartId: chart, plots, sampleCount };
93
98
  }
94
- if (q.showAssocTests == true && overlayTerm) await getWilcoxonData(charts);
99
+ if (q.showAssocTests && overlayTerm) await getWilcoxonData(charts);
95
100
  Object.keys(charts).forEach((c) => charts[c].plots.forEach((p) => delete p.tempValues));
96
101
  return { absMin, absMax, charts, uncomputableValues, descrStats, outlierMin, outlierMax };
97
102
  }
@@ -109,7 +114,7 @@ function setPlotData(plots, values, key, sampleType, descrStats, q, data, outlie
109
114
  if (!boxplot) throw new Error("boxplot_getvalue failed [termdb.boxplot init()]");
110
115
  const _plot = {
111
116
  boxplot,
112
- descrStats,
117
+ descrStats: setIndividualBoxPlotStats(boxplot, sortedValues),
113
118
  //quick fix
114
119
  //to delete later
115
120
  tempValues: sortedValues
@@ -136,6 +141,22 @@ function setPlotData(plots, values, key, sampleType, descrStats, q, data, outlie
136
141
  }
137
142
  return [outlierMax, outlierMin];
138
143
  }
144
+ function setIndividualBoxPlotStats(boxplot, values) {
145
+ const stats = {
146
+ total: { key: "total", label: "Total", value: values.length },
147
+ min: { key: "min", label: "Minimum", value: values[0] },
148
+ p25: { key: "p25", label: "1st quartile", value: boxplot.p25 },
149
+ median: { key: "median", label: "Median", value: boxplot.p50 },
150
+ p75: { key: "p75", label: "3rd quartile", value: boxplot.p75 },
151
+ mean: { key: "mean", label: "Mean", value: getMean(values) },
152
+ max: { key: "max", label: "Maximum", value: values[values.length - 1] },
153
+ stdDev: { key: "stdDev", label: "Standard deviation", value: getStdDev(values) }
154
+ };
155
+ for (const key of Object.keys(stats)) {
156
+ stats[key].value = roundValueAuto(stats[key].value);
157
+ }
158
+ return stats;
159
+ }
139
160
  function setHiddenPlots(term, plots) {
140
161
  for (const v of Object.values(term.term?.values)) {
141
162
  const plot = plots.find((p) => p.key === v.label);
@@ -59,15 +59,19 @@ function init({ genomes }) {
59
59
  throw "llm_backend either needs to be 'SJ' or 'ollama'";
60
60
  }
61
61
  const chatbot_input = {
62
- // Just hardcoding variables here, these will later be defined in more appropriate places
63
62
  user_input: q.prompt,
64
63
  apilink,
65
64
  tpmasterdir: serverconfig.tpmasterdir,
66
65
  comp_model_name,
67
66
  embedding_model_name,
67
+ dataset_db: ds.cohort.db.file,
68
+ genedb: g.genedb.dbfile,
69
+ aiRoute: serverconfig.aiRoute,
70
+ // Route file for classifying chat request into various routes
68
71
  llm_backend_name: serverconfig.llm_backend,
69
72
  // The type of backend (engine) used for running the embedding and completion model. Currently "SJ" and "Ollama" are supported
70
73
  aifiles: serverconfig_ds_entries.aifiles,
74
+ // Dataset specific data containing data-specific routes, system prompts for agents and few-shot examples
71
75
  binpath: serverconfig.binpath
72
76
  };
73
77
  const time1 = (/* @__PURE__ */ new Date()).valueOf();
@@ -87,23 +91,48 @@ function init({ genomes }) {
87
91
  if (ai_output_json.plot.simpleFilter) {
88
92
  if (!Array.isArray(ai_output_json.plot.simpleFilter)) throw "ai_output_json.plot.simpleFilter is not array";
89
93
  const localfilter = { type: "tvslst", in: true, join: "", lst: [] };
94
+ if (ai_output_json.plot.simpleFilter.length > 1) localfilter.join = "and";
90
95
  for (const f of ai_output_json.plot.simpleFilter) {
91
96
  const term = ds.cohort.termdb.q.termjsonByOneid(f.term);
92
97
  if (!term) throw "invalid term id from simpleFilter[].term";
93
- if (term.type != "categorical") throw "term not categorical";
94
- let cat;
95
- for (const ck in term.values) {
96
- if (ck == f.category) cat = ck;
97
- else if (term.values[ck].label == f.category) cat = ck;
98
- }
99
- if (!cat) throw "invalid category from " + JSON.stringify(f);
100
- localfilter.lst.push({
101
- type: "tvs",
102
- tvs: {
103
- term,
104
- values: [{ key: cat }]
98
+ if (term.type == "categorical") {
99
+ let cat;
100
+ for (const ck in term.values) {
101
+ if (ck == f.category) cat = ck;
102
+ else if (term.values[ck].label == f.category) cat = ck;
103
+ }
104
+ if (!cat) throw "invalid category from " + JSON.stringify(f);
105
+ localfilter.lst.push({
106
+ type: "tvs",
107
+ tvs: {
108
+ term,
109
+ values: [{ key: cat }]
110
+ }
111
+ });
112
+ } else if (term.type == "float" || term.type == "integer") {
113
+ const numeric = {
114
+ type: "tvs",
115
+ tvs: {
116
+ term,
117
+ ranges: []
118
+ }
119
+ };
120
+ const range = {};
121
+ if (f.gt && !f.lt) {
122
+ range.start = Number(f.gt);
123
+ range.stopunbounded = true;
124
+ } else if (f.lt && !f.gt) {
125
+ range.stop = Number(f.lt);
126
+ range.startunbounded = true;
127
+ } else if (f.gt && f.lt) {
128
+ range.start = Number(f.gt);
129
+ range.stop = Number(f.lt);
130
+ } else {
131
+ throw "Neither greater or lesser defined";
105
132
  }
106
- });
133
+ numeric.tvs.ranges.push(range);
134
+ localfilter.lst.push(numeric);
135
+ }
107
136
  }
108
137
  delete ai_output_json.plot.simpleFilter;
109
138
  ai_output_json.plot.filter = localfilter;