@sjcrh/proteinpaint-server 2.189.0 → 2.190.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.
Files changed (82) hide show
  1. package/package.json +9 -12
  2. package/routes/aiProjectAdmin.js +2 -28
  3. package/routes/aiProjectSelectedWSImages.js +2 -16
  4. package/routes/brainImaging.js +1 -15
  5. package/routes/brainImagingSamples.js +1 -15
  6. package/routes/burden.js +1 -15
  7. package/routes/correlationVolcano.js +1 -15
  8. package/routes/dataset.js +1 -16
  9. package/routes/deleteWSITileSelection.js +2 -12
  10. package/routes/dsdata.js +1 -19
  11. package/routes/gdc.grin2.list.js +1 -15
  12. package/routes/gdc.grin2.run.js +1 -15
  13. package/routes/gdc.maf.js +1 -15
  14. package/routes/gdc.mafBuild.js +1 -15
  15. package/routes/genesetEnrichment.js +129 -97
  16. package/routes/grin2.js +110 -79
  17. package/routes/saveWSIAnnotation.js +2 -13
  18. package/routes/termdb.DE.js +137 -54
  19. package/routes/termdb.categories.js +2 -16
  20. package/routes/termdb.chat.js +169 -1076
  21. package/routes/termdb.cluster.js +5 -16
  22. package/routes/termdb.config.js +12 -17
  23. package/routes/termdb.descrstats.js +2 -16
  24. package/routes/termdb.diffMeth.js +100 -21
  25. package/routes/termdb.geneRanking.js +139 -0
  26. package/routes/termdb.proteome.js +1 -15
  27. package/routes/termdb.runChart.js +16 -30
  28. package/routes/termdb.sampleScatter.js +7 -97
  29. package/routes/termdb.singleCellPlots.js +159 -0
  30. package/routes/termdb.singlecellSamples.js +6 -16
  31. package/routes/termdb.violinBox.js +1 -15
  32. package/routes/wsimages.js +1 -16
  33. package/src/app.js +4028 -4116
  34. package/routes/_template_.js +0 -33
  35. package/routes/aiProjectTrainModel.js +0 -68
  36. package/routes/alphaGenome.js +0 -41
  37. package/routes/alphaGenomeTypes.js +0 -36
  38. package/routes/dzimages.js +0 -55
  39. package/routes/gene2canonicalisoform.js +0 -37
  40. package/routes/genelookup.js +0 -32
  41. package/routes/genesetOverrepresentation.js +0 -49
  42. package/routes/genomes.js +0 -150
  43. package/routes/healthcheck.js +0 -35
  44. package/routes/hicdata.js +0 -74
  45. package/routes/hicgenome.js +0 -75
  46. package/routes/hicstat.js +0 -35
  47. package/routes/img.js +0 -46
  48. package/routes/isoformlst.js +0 -48
  49. package/routes/ntseq.js +0 -36
  50. package/routes/pdomain.js +0 -53
  51. package/routes/profile.barchart2.js +0 -114
  52. package/routes/profile.forms2.js +0 -107
  53. package/routes/profile.polar2.js +0 -101
  54. package/routes/profile.radar2.js +0 -112
  55. package/routes/profile.radarFacility2.js +0 -148
  56. package/routes/sampledzimages.js +0 -48
  57. package/routes/samplewsimages.js +0 -60
  58. package/routes/snp.js +0 -98
  59. package/routes/termdb.chat2.js +0 -217
  60. package/routes/termdb.chat3.js +0 -209
  61. package/routes/termdb.cohort.summary.js +0 -37
  62. package/routes/termdb.cohorts.js +0 -41
  63. package/routes/termdb.dapVolcano.js +0 -80
  64. package/routes/termdb.dmr.js +0 -93
  65. package/routes/termdb.filterTermValues.js +0 -89
  66. package/routes/termdb.isoformAvailability.js +0 -35
  67. package/routes/termdb.numericcategories.js +0 -46
  68. package/routes/termdb.percentile.js +0 -66
  69. package/routes/termdb.profileFormScores.js +0 -92
  70. package/routes/termdb.profileScores.js +0 -113
  71. package/routes/termdb.rootterm.js +0 -39
  72. package/routes/termdb.sampleImages.js +0 -63
  73. package/routes/termdb.singleSampleMutation.js +0 -75
  74. package/routes/termdb.singlecellDEgenes.js +0 -55
  75. package/routes/termdb.singlecellData.js +0 -39
  76. package/routes/termdb.termchildren.js +0 -42
  77. package/routes/termdb.termsbyids.js +0 -50
  78. package/routes/termdb.topMutatedGenes.js +0 -127
  79. package/routes/termdb.topTermsByType.js +0 -96
  80. package/routes/termdb.topVariablyExpressedGenes.js +0 -132
  81. package/routes/tileserver.js +0 -68
  82. package/routes/wsisamples.js +0 -71
@@ -1,24 +1,15 @@
1
- import path from "path";
2
- import { diffExpPayload } from "#types/checkers";
3
1
  import { mayLog } from "#src/helpers.ts";
4
2
  import serverconfig from "../src/serverconfig.js";
5
- import { get_header_txt } from "#src/utils.js";
3
+ import { run_R } from "@sjcrh/proteinpaint-r";
6
4
  import { run_rust } from "@sjcrh/proteinpaint-rust";
5
+ import { formatElapsedTime } from "#shared";
7
6
  import { renderVolcano } from "../src/renderVolcano.ts";
8
- import { readCacheFileOrRecompute, resolveDaContext, resolveSampleGroups } from "../src/diffAnalysis.ts";
9
- const api = {
10
- endpoint: "termdb/DE",
11
- methods: {
12
- get: {
13
- ...diffExpPayload,
14
- init
15
- },
16
- post: {
17
- ...diffExpPayload,
18
- init
19
- }
20
- }
21
- };
7
+ import { cacheOrRecompute } from "#src/utils/cacheOrRecompute.ts";
8
+ import {
9
+ buildGroupValues,
10
+ canonicalizeSamplelst,
11
+ resolveDaContext
12
+ } from "#src/utils/sampleGroups.ts";
22
13
  function init({ genomes }) {
23
14
  return async (req, res) => {
24
15
  try {
@@ -37,57 +28,149 @@ function init({ genomes }) {
37
28
  });
38
29
  return;
39
30
  }
40
- const result = await readCacheFileOrRecompute({ daRequest: q, genomes });
41
- if (result.kind !== "DE") throw new Error("expected DE result from readCacheFileOrRecompute");
42
- const rendered = await renderVolcano(result.geneData, q.volcanoRender);
43
- rendered.cacheId = result.cacheId;
31
+ const { result, cacheId, images } = await loadDeForResponse(q, genomes);
32
+ const rendered = await renderVolcano(result.geneRows, q.volcanoRender);
33
+ rendered.cacheId = cacheId;
44
34
  const output = {
45
35
  data: rendered,
46
36
  sample_size1: result.sample_size1,
47
37
  sample_size2: result.sample_size2,
48
- method: result.method,
49
- images: result.images
38
+ method: result.method
50
39
  };
40
+ if (images.length) output.images = images;
51
41
  if (result.bcv != null) output.bcv = result.bcv;
52
42
  res.send(output);
53
43
  } catch (e) {
54
- res.send({ status: "error", error: e.message || e });
44
+ res.status(e.status || 500).send({ status: "error", error: e.message || e, code: e.code });
55
45
  if (e instanceof Error && e.stack) console.log(e);
56
46
  }
57
47
  };
58
48
  }
59
- async function validate_query_rnaseqGeneCount(ds) {
60
- const q = ds.queries.rnaseqGeneCount;
61
- if (!q) return;
62
- if (!q.file) throw new Error("unknown data type for rnaseqGeneCount");
63
- q.file = path.join(serverconfig.tpmasterdir, q.file);
64
- {
65
- let samples = [];
66
- if (ds.queries.rnaseqGeneCount.storage_type == "text") {
67
- samples = (await get_header_txt(q.file, null)).split(" ").slice(4);
68
- } else if (ds.queries.rnaseqGeneCount.storage_type == "HDF5") {
69
- const get_samples_from_hdf5 = {
70
- hdf5_file: q.file,
71
- validate: true
72
- };
73
- const time1 = (/* @__PURE__ */ new Date()).valueOf();
74
- const result = await run_rust("readH5", JSON.stringify(get_samples_from_hdf5));
75
- const time2 = (/* @__PURE__ */ new Date()).valueOf();
76
- mayLog("Time taken to query gene expression:", time2 - time1, "ms");
77
- const vr = JSON.parse(result);
78
- if (vr.status !== "success") throw new Error(vr.message);
79
- if (!Array.isArray(vr.samples)) throw new Error("HDF5 file has no samples, please check file.");
80
- samples = vr.samples;
81
- } else throw new Error("unknown storage type:" + ds.queries.rnaseqGeneCount.storage_type);
82
- q.allSampleSet = new Set(samples);
83
- const unknownSamples = [];
84
- for (const n of q.allSampleSet) {
85
- if (!ds.cohort.termdb.q.sampleName2id(n)) unknownSamples.push(n);
49
+ function deKeyInputs(req) {
50
+ return {
51
+ genome: req.genome,
52
+ dslabel: req.dslabel,
53
+ samplelst: canonicalizeSamplelst(req.samplelst),
54
+ min_count: req.min_count,
55
+ min_total_count: req.min_total_count,
56
+ cpm_cutoff: req.cpm_cutoff,
57
+ method: req.method ?? null,
58
+ tw: req.tw ?? null,
59
+ tw2: req.tw2 ?? null,
60
+ filter: req.filter ?? null,
61
+ filter0: req.filter0 ?? null
62
+ };
63
+ }
64
+ async function loadDeForResponse(req, genomes) {
65
+ const { result, cacheId } = await getDeCacheResult(req, genomes);
66
+ const images = [];
67
+ if (result.qlImage) images.push(result.qlImage);
68
+ if (result.mdsImage) images.push(result.mdsImage);
69
+ return { result, cacheId, images };
70
+ }
71
+ async function getDeCacheResult(req, genomes) {
72
+ const { result, cacheId } = await cacheOrRecompute({
73
+ computeArgument: deKeyInputs(req),
74
+ cacheSubdir: "de",
75
+ computeFresh: async () => {
76
+ const { ds, term_results, term_results2 } = await resolveDaContext(req, genomes);
77
+ return runDeFresh(req, ds, term_results, term_results2);
86
78
  }
87
- console.log(q.allSampleSet.size, `rnaseqGeneCount samples from ${ds.label}`);
79
+ });
80
+ return { result, cacheId };
81
+ }
82
+ async function runDeFresh(param, ds, term_results, term_results2) {
83
+ const groups = resolveSampleGroups(param, ds, term_results, term_results2);
84
+ if (groups.alerts.length) throw new Error(groups.alerts.join(" | "));
85
+ const q = ds.queries.rnaseqGeneCount;
86
+ const expression_input = {
87
+ case: groups.group2names.join(","),
88
+ control: groups.group1names.join(","),
89
+ data_type: "do_DE",
90
+ input_file: q.file,
91
+ cachedir: serverconfig.cachedir,
92
+ storage_type: q.storage_type,
93
+ DE_method: param.method,
94
+ mds_cutoff: 1e4,
95
+ min_count: param.min_count,
96
+ min_total_count: param.min_total_count,
97
+ cpm_cutoff: param.cpm_cutoff
98
+ };
99
+ if (param.tw) {
100
+ expression_input.conf1 = [...groups.conf1_group2, ...groups.conf1_group1];
101
+ expression_input.conf1_mode = param.tw.q.mode;
102
+ if (new Set(expression_input.conf1).size === 1) throw new Error("Confounding variable 1 has only one value");
103
+ }
104
+ if (param.tw2) {
105
+ expression_input.conf2 = [...groups.conf2_group2, ...groups.conf2_group1];
106
+ expression_input.conf2_mode = param.tw2.q.mode;
107
+ if (new Set(expression_input.conf2).size === 1) throw new Error("Confounding variable 2 has only one value");
88
108
  }
109
+ const small = groups.group1names.length <= 8 && groups.group2names.length <= 8;
110
+ const engine = small || param.method === "edgeR" || param.method === "limma" ? "edgeR" : "wilcoxon";
111
+ if (engine === "edgeR") {
112
+ const time12 = (/* @__PURE__ */ new Date()).valueOf();
113
+ const result2 = JSON.parse(await run_R("edge_newh5.R", JSON.stringify(expression_input)));
114
+ mayLog("Time taken to run edgeR:", formatElapsedTime(Date.now() - time12));
115
+ param.method = "edgeR";
116
+ const qlImage = deImageFromB64(result2.ql_image_b64, "ql_image");
117
+ const mdsImage = deImageFromB64(result2.mds_image_b64, "mds_image");
118
+ const cacheResult2 = {
119
+ geneRows: result2.gene_data,
120
+ sample_size1: result2.num_controls[0],
121
+ sample_size2: result2.num_cases[0],
122
+ method: param.method,
123
+ bcv: result2.bcv && result2.bcv[0] != null ? result2.bcv[0] : void 0,
124
+ ...qlImage ? { qlImage } : {},
125
+ ...mdsImage ? { mdsImage } : {}
126
+ };
127
+ return cacheResult2;
128
+ }
129
+ const time1 = (/* @__PURE__ */ new Date()).valueOf();
130
+ const result = JSON.parse(await run_rust("DEanalysis", JSON.stringify(expression_input)));
131
+ mayLog("Time taken to run rust DE pipeline:", formatElapsedTime(Date.now() - time1));
132
+ param.method = "wilcoxon";
133
+ const cacheResult = {
134
+ geneRows: result,
135
+ sample_size1: groups.group1names.length,
136
+ sample_size2: groups.group2names.length,
137
+ method: param.method
138
+ };
139
+ return cacheResult;
140
+ }
141
+ function resolveSampleGroups(param, ds, term_results, term_results2) {
142
+ if (param.samplelst?.groups?.length != 2) throw new Error(".samplelst.groups.length!=2");
143
+ if (param.samplelst.groups[0].values?.length < 1) throw new Error("samplelst.groups[0].values.length<1");
144
+ if (param.samplelst.groups[1].values?.length < 1) throw new Error("samplelst.groups[1].values.length<1");
145
+ const q = ds.queries.rnaseqGeneCount;
146
+ if (!q) throw new Error("rnaseqGeneCount query missing on ds");
147
+ if (!q.file) throw new Error("unknown data type for rnaseqGeneCount");
148
+ if (!q.storage_type) throw new Error("storage_type is not defined");
149
+ const g1 = buildGroupValues(param.samplelst.groups[0].values, q, ds, param.tw, param.tw2, term_results, term_results2);
150
+ const g2 = buildGroupValues(param.samplelst.groups[1].values, q, ds, param.tw, param.tw2, term_results, term_results2);
151
+ const alerts = [];
152
+ if (g1.names.length < 1) alerts.push("sample size of group1 < 1");
153
+ if (g2.names.length < 1) alerts.push("sample size of group2 < 1");
154
+ const commonnames = g1.names.filter((x) => g2.names.includes(x));
155
+ if (commonnames.length) alerts.push(`Common elements found between both groups: ${commonnames.join(", ")}`);
156
+ return {
157
+ group1names: g1.names,
158
+ group2names: g2.names,
159
+ conf1_group1: g1.conf1,
160
+ conf1_group2: g2.conf1,
161
+ conf2_group1: g1.conf2,
162
+ conf2_group2: g2.conf2,
163
+ alerts
164
+ };
165
+ }
166
+ function deImageFromB64(b64, key) {
167
+ if (!b64) return null;
168
+ const padding = b64.endsWith("==") ? 2 : b64.endsWith("=") ? 1 : 0;
169
+ const size = Math.floor(b64.length * 3 / 4) - padding;
170
+ return { src: `data:image/png;base64,${b64}`, size, key };
89
171
  }
90
172
  export {
91
- api,
92
- validate_query_rnaseqGeneCount
173
+ getDeCacheResult,
174
+ init,
175
+ resolveSampleGroups
93
176
  };
@@ -1,19 +1,5 @@
1
- import { termdbCategoriesPayload } from "#types/checkers";
2
1
  import { getOrderedLabels } from "#src/termdb.barchart.js";
3
2
  import { getData } from "#src/termdb.matrix.js";
4
- const api = {
5
- endpoint: "termdb/categories",
6
- methods: {
7
- get: {
8
- ...termdbCategoriesPayload,
9
- init
10
- },
11
- post: {
12
- ...termdbCategoriesPayload,
13
- init
14
- }
15
- }
16
- };
17
3
  function init({ genomes }) {
18
4
  return async (req, res) => {
19
5
  const q = req.query;
@@ -132,6 +118,6 @@ function getCategories(data, q, ds, $id) {
132
118
  return [lst, orderedLabels];
133
119
  }
134
120
  export {
135
- api,
136
- getCategories
121
+ getCategories,
122
+ init
137
123
  };