@sjcrh/proteinpaint-server 2.117.0 → 2.118.1-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.
@@ -2,246 +2,245 @@ import serverconfig from "@sjcrh/proteinpaint-server/src/serverconfig.js";
2
2
  import * as path from "path";
3
3
  import { existsSync, unlinkSync, symlinkSync, access, constants } from "fs";
4
4
  copyDataFilesFromRepo2Tp();
5
- var termdb_test_default = {
6
- isMds3: true,
7
- cohort: {
8
- massNav: {
9
- tabs: {
10
- about: {
11
- dataRelease: {
12
- version: "?",
13
- link: "testLink"
14
- },
15
- additionalInfo: "<a href=testLink>Tutorial</a> <a href=testLink>Get help</a>"
5
+ function termdb_test_default() {
6
+ return {
7
+ isMds3: true,
8
+ cohort: {
9
+ massNav: {
10
+ tabs: {
11
+ about: {
12
+ dataRelease: {
13
+ version: "?",
14
+ link: "testLink"
15
+ },
16
+ additionalInfo: "<a href=testLink>Tutorial</a> <a href=testLink>Get help</a>"
17
+ }
16
18
  }
17
- }
18
- },
19
- db: {
20
- file: "files/hg38/TermdbTest/db"
21
- },
22
- termdb: {
23
- allowedTermTypes: ["geneVariant"],
24
- displaySampleIds: true,
25
- // allow to display sample-level data
26
- timeUnit: "years",
27
- minTimeSinceDx: 5,
28
- // enrollment in sjlife requires 5 years since cancer diagnosis
29
- ageEndOffset: 274e-5,
30
- // number of years to offset ending age of patients
31
- // for cox outcome with timeScale='age'
32
- // 1 day (i.e. 1/365 or 0.00274) needs to be added
33
- // to age_end to prevent age_end = age_start (which
34
- // would cause regression analysis to fail in R)
35
- cohortStartTimeMsg: "5 years post cancer diagnosis",
36
- selectCohort: {
37
- // wrap term.id into a term json object so as to use it in tvs;
38
- // the term is not required to exist in termdb
39
- // term.id is specific to this dataset, should not use literally in client/server code but always through a variable
40
- term: {
41
- id: "subcohort",
42
- type: "multivalue"
43
- },
44
- prompt: "Select a cohort and test the plots.",
45
- values: [
46
- // <ul><li> for items, with a radio button for each.
47
- {
48
- keys: ["ABC"],
49
- label: "ABC Cohort (ABC)",
50
- shortLabel: "ABC",
51
- isdefault: true
19
+ },
20
+ db: {
21
+ file: "files/hg38/TermdbTest/db"
22
+ },
23
+ termdb: {
24
+ allowedTermTypes: ["geneVariant"],
25
+ displaySampleIds: true,
26
+ // allow to display sample-level data
27
+ timeUnit: "years",
28
+ minTimeSinceDx: 5,
29
+ // enrollment in sjlife requires 5 years since cancer diagnosis
30
+ ageEndOffset: 274e-5,
31
+ // number of years to offset ending age of patients
32
+ // for cox outcome with timeScale='age'
33
+ // 1 day (i.e. 1/365 or 0.00274) needs to be added
34
+ // to age_end to prevent age_end = age_start (which
35
+ // would cause regression analysis to fail in R)
36
+ cohortStartTimeMsg: "5 years post cancer diagnosis",
37
+ selectCohort: {
38
+ // wrap term.id into a term json object so as to use it in tvs;
39
+ // the term is not required to exist in termdb
40
+ // term.id is specific to this dataset, should not use literally in client/server code but always through a variable
41
+ term: {
42
+ id: "subcohort",
43
+ type: "multivalue"
52
44
  },
53
- {
54
- keys: ["XYZ"],
55
- label: "XYZ cohort (XYZ)",
56
- shortLabel: "XYZ"
45
+ prompt: "Select a cohort and test the plots.",
46
+ values: [
47
+ // <ul><li> for items, with a radio button for each.
48
+ {
49
+ keys: ["ABC"],
50
+ label: "ABC Cohort (ABC)",
51
+ shortLabel: "ABC",
52
+ isdefault: true
53
+ },
54
+ {
55
+ keys: ["XYZ"],
56
+ label: "XYZ cohort (XYZ)",
57
+ shortLabel: "XYZ"
58
+ },
59
+ {
60
+ keys: ["ABC", "XYZ"],
61
+ label: "Combined ABC+XYZ*",
62
+ shortLabel: "ABC+XYZ"
63
+ // show note under label in smaller text size
64
+ }
65
+ ],
66
+ asterisk: "*fineprint on an item"
67
+ },
68
+ dataDownloadCatch: {
69
+ helpLink: "https://university.stjude.cloud/docs/visualization-community/data-download/",
70
+ missingAccess: {
71
+ message: "You are missing approval to one or more of the required datasets. Please go to <a target=_blank href='MISSING-ACCESS-LINK'>Genomics Platform Data Browser</a> to request access. For more information, please see this <a target=_blank href='https://university.stjude.cloud/docs/visualization-community/data-download/'>tutorial.</a>",
72
+ links: {
73
+ sjlife: "https://platform.stjude.cloud/data/cohorts?selected_tags=SJC-DS-1002",
74
+ ccss: "https://platform.stjude.cloud/data/cohorts?selected_tags=SJC-DS-1005",
75
+ "sjlife,ccss": "https://platform.stjude.cloud/data/cohorts?selected_tags=SJC-DS-1002,SJC-DS-1005",
76
+ fake: "https://platform.stjude.cloud/data/cohorts?selected_tags=SJC-DS-1002"
77
+ }
57
78
  },
58
- {
59
- keys: ["ABC", "XYZ"],
60
- label: "Combined ABC+XYZ*",
61
- shortLabel: "ABC+XYZ"
62
- // show note under label in smaller text size
79
+ jwt: {
80
+ "Invalid token": "https://university.stjude.cloud/docs/visualization-community/data-download/"
63
81
  }
64
- ],
65
- asterisk: "*fineprint on an item"
66
- },
67
- dataDownloadCatch: {
68
- helpLink: "https://university.stjude.cloud/docs/visualization-community/data-download/",
69
- missingAccess: {
70
- message: "You are missing approval to one or more of the required datasets. Please go to <a target=_blank href='MISSING-ACCESS-LINK'>Genomics Platform Data Browser</a> to request access. For more information, please see this <a target=_blank href='https://university.stjude.cloud/docs/visualization-community/data-download/'>tutorial.</a>",
71
- links: {
72
- sjlife: "https://platform.stjude.cloud/data/cohorts?selected_tags=SJC-DS-1002",
73
- ccss: "https://platform.stjude.cloud/data/cohorts?selected_tags=SJC-DS-1005",
74
- "sjlife,ccss": "https://platform.stjude.cloud/data/cohorts?selected_tags=SJC-DS-1002,SJC-DS-1005",
75
- fake: "https://platform.stjude.cloud/data/cohorts?selected_tags=SJC-DS-1002"
82
+ },
83
+ matrix: {
84
+ settings: {
85
+ ignoreCnvValues: true
76
86
  }
77
87
  },
78
- jwt: {
79
- "Invalid token": "https://university.stjude.cloud/docs/visualization-community/data-download/"
88
+ termid2totalsize2: {},
89
+ regression: {
90
+ settings: {
91
+ coxDisclaimer: "This is a test disclaimer for the cox regression analysis."
92
+ }
80
93
  }
81
94
  },
82
- matrix: {
83
- settings: {
84
- ignoreCnvValues: true
85
- }
95
+ scatterplots: {
96
+ plots: [
97
+ {
98
+ name: "TermdbTest TSNE",
99
+ dimension: 2,
100
+ file: "files/hg38/TermdbTest/tnse.txt",
101
+ colorTW: { id: "diaggrp" }
102
+ }
103
+ ]
86
104
  },
87
- termid2totalsize2: {},
88
- regression: {
89
- settings: {
90
- coxDisclaimer: "This is a test disclaimer for the cox regression analysis."
91
- }
105
+ matrixplots: {
106
+ plots: [
107
+ {
108
+ name: "Matrix plot",
109
+ file: "files/hg38/TermdbTest/TermdbTest_matrix.json"
110
+ }
111
+ ]
92
112
  }
93
113
  },
94
- scatterplots: {
95
- plots: [
96
- {
97
- name: "TermdbTest TSNE",
98
- dimension: 2,
99
- file: "files/hg38/TermdbTest/tnse.txt",
100
- colorTW: { id: "diaggrp" }
101
- }
102
- ]
103
- },
104
- matrixplots: {
105
- plots: [
106
- {
107
- name: "Matrix plot",
108
- file: "files/hg38/TermdbTest/TermdbTest_matrix.json"
114
+ customTwQByType: {
115
+ // dataset-specific termsetting configs on certain term types
116
+ geneVariant: {
117
+ default: { cnvGainCutoff: 0.1, cnvLossCutoff: -0.1, cnvMaxLength: 0 },
118
+ byGene: {
119
+ // key is term.name, thus possible to use non-gene names e.g. C19MC
120
+ MYCN: { cnvGainCutoff: 0.5, cnvLossCutoff: -0.1, cnvMaxLength: 0 }
109
121
  }
110
- ]
111
- }
112
- },
113
- customTwQByType: {
114
- // dataset-specific termsetting configs on certain term types
115
- geneVariant: {
116
- default: { cnvGainCutoff: 0.1, cnvLossCutoff: -0.1, cnvMaxLength: 0 },
117
- byGene: {
118
- // key is term.name, thus possible to use non-gene names e.g. C19MC
119
- MYCN: { cnvGainCutoff: 0.5, cnvLossCutoff: -0.1, cnvMaxLength: 0 }
120
- }
121
- }
122
- },
123
- variant2samples: {
124
- variantkey: "ssm_id",
125
- // required, tells client to return ssm_id for identifying variants
126
- // list of term ids as sample details
127
- twLst: [
128
- { id: "sex", q: {} },
129
- { id: "diaggrp", q: {} },
130
- { id: "agedx", q: {} }
131
- ],
132
- // small list of terms for sunburst rings
133
- sunburst_twLst: [{ id: "sex", q: {} }]
134
- },
135
- queries: {
136
- snvindel: {
137
- forTrack: true,
138
- byrange: {
139
- bcffile: "files/hg38/TermdbTest/TermdbTest.bcf.gz"
140
- },
141
- skewerRim: {
142
- type: "format",
143
- formatKey: "origin",
144
- rim1value: "germline",
145
- noRimValue: "somatic"
146
122
  }
147
123
  },
148
- svfusion: {
149
- byrange: {
150
- file: "files/hg38/TermdbTest/TermdbTest_Fusion.gz"
151
- }
124
+ variant2samples: {
125
+ variantkey: "ssm_id",
126
+ // required, tells client to return ssm_id for identifying variants
127
+ // list of term ids as sample details
128
+ twLst: [
129
+ { id: "sex", q: {} },
130
+ { id: "diaggrp", q: {} },
131
+ { id: "agedx", q: {} }
132
+ ],
133
+ // small list of terms for sunburst rings
134
+ sunburst_twLst: [{ id: "sex", q: {} }]
152
135
  },
153
- cnv: {
154
- byrange: {
155
- src: "native",
136
+ queries: {
137
+ snvindel: {
138
+ forTrack: true,
139
+ byrange: {
140
+ bcffile: "files/hg38/TermdbTest/TermdbTest.bcf.gz"
141
+ },
142
+ skewerRim: {
143
+ type: "format",
144
+ formatKey: "origin",
145
+ rim1value: "germline",
146
+ noRimValue: "somatic"
147
+ }
148
+ },
149
+ svfusion: {
150
+ byrange: {
151
+ file: "files/hg38/TermdbTest/TermdbTest_Fusion.gz"
152
+ }
153
+ },
154
+ cnv: {
156
155
  file: "files/hg38/TermdbTest/TermdbTest_CNV_gene.gz"
156
+ },
157
+ /*
158
+ on the fly cnv calls from gene body probe signals are no longer used
159
+ probe2cnv:{
160
+ file: 'files/hg19/pnet/PNET.probesignals.gz'
157
161
  }
158
- },
159
- /*
160
- on the fly cnv calls from gene body probe signals are no longer used
161
- probe2cnv:{
162
- file: 'files/hg19/pnet/PNET.probesignals.gz'
163
- }
164
- */
165
- singleSampleMutation: {
166
- src: "native",
167
- sample_id_key: "sample_id",
168
- folder: "files/hg38/TermdbTest/mutationpersample/"
169
- },
170
- singleSampleGenomeQuantification: {
171
- // to show genome-wide quantification plot for a sample
172
- MethylationArray: {
173
- description: "Genome-wide copy number variation based on tumor/normal methylation array, averaged at genomic bins.",
174
- min: -1.2,
175
- max: 1.2,
176
- sample_id_key: "sample_id",
177
- folder: "files/hg38/TermdbTest/methylationArrayNormalSubtracted_bins/",
178
- // binned data, not probe-level
179
- positiveColor: "#a35069",
180
- negativeColor: "#5051a3",
181
- singleSampleGbtk: "methylationProbeSignal"
182
- }
183
- },
184
- singleSampleGbtk: {
185
- methylationProbeSignal: {
186
- description: "Probe signals from methylation array.",
187
- min: -1.2,
188
- max: 1.2,
162
+ */
163
+ singleSampleMutation: {
164
+ src: "native",
189
165
  sample_id_key: "sample_id",
190
- folder: "files/hg38/TermdbTest/methylationArrayNormalSubtracted/"
191
- // probe-level data, only for locus view as genome browser track
192
- // each file is 1.gz and 1.gz.tbi, bedgraph format
166
+ folder: "files/hg38/TermdbTest/mutationpersample/"
167
+ },
168
+ singleSampleGenomeQuantification: {
169
+ // to show genome-wide quantification plot for a sample
170
+ MethylationArray: {
171
+ description: "Genome-wide copy number variation based on tumor/normal methylation array, averaged at genomic bins.",
172
+ min: -1.2,
173
+ max: 1.2,
174
+ sample_id_key: "sample_id",
175
+ folder: "files/hg38/TermdbTest/methylationArrayNormalSubtracted_bins/",
176
+ // binned data, not probe-level
177
+ positiveColor: "#a35069",
178
+ negativeColor: "#5051a3",
179
+ singleSampleGbtk: "methylationProbeSignal"
180
+ }
181
+ },
182
+ singleSampleGbtk: {
183
+ methylationProbeSignal: {
184
+ description: "Probe signals from methylation array.",
185
+ min: -1.2,
186
+ max: 1.2,
187
+ sample_id_key: "sample_id",
188
+ folder: "files/hg38/TermdbTest/methylationArrayNormalSubtracted/"
189
+ // probe-level data, only for locus view as genome browser track
190
+ // each file is 1.gz and 1.gz.tbi, bedgraph format
191
+ }
192
+ },
193
+ geneExpression: {
194
+ src: "native",
195
+ hdf5File: true,
196
+ file: "files/hg38/TermdbTest/TermdbTest.fpkm.matrix.h5"
197
+ },
198
+ topVariablyExpressedGenes: {
199
+ src: "native"
200
+ },
201
+ WSImages: {
202
+ type: "H&E",
203
+ imageBySampleFolder: "files/hg38/TermdbTest/wsimages"
193
204
  }
194
205
  },
195
- geneExpression: {
196
- src: "native",
197
- hdf5File: true,
198
- file: "files/hg38/TermdbTest/TermdbTest.fpkm.matrix.h5"
199
- },
200
- topVariablyExpressedGenes: {
201
- src: "native"
202
- },
203
- WSImages: {
204
- type: "H&E",
205
- imageBySampleFolder: "files/hg38/TermdbTest/wsimages"
206
- }
207
- },
208
- assayAvailability: {
209
- // term used below must be annotated on samples rather than patients(root). otherwise matrix will pull wrong samples for geneVariant term
210
- byDt: {
211
- // snvindel, differentiating sample origin
212
- 1: {
213
- byOrigin: {
214
- germline: {
215
- term_id: "assayavailability_germline",
216
- label: "Germline",
217
- // human readable label of this origin
218
- yes: { value: ["1"] },
219
- no: { value: ["2"] }
220
- },
221
- somatic: {
222
- term_id: "wgs_curated",
223
- label: "Somatic",
224
- yes: { value: ["1"] },
225
- no: { value: ["0"] }
226
- // the category doesn't exist in termdb but is still supplied since somatic.no{} is required
206
+ assayAvailability: {
207
+ // term used below must be annotated on samples rather than patients(root). otherwise matrix will pull wrong samples for geneVariant term
208
+ byDt: {
209
+ // snvindel, differentiating sample origin
210
+ 1: {
211
+ byOrigin: {
212
+ germline: {
213
+ term_id: "assayavailability_germline",
214
+ label: "Germline",
215
+ // human readable label of this origin
216
+ yes: { value: ["1"] },
217
+ no: { value: ["2"] }
218
+ },
219
+ somatic: {
220
+ term_id: "wgs_curated",
221
+ label: "Somatic",
222
+ yes: { value: ["1"] },
223
+ no: { value: ["0"] }
224
+ // the category doesn't exist in termdb but is still supplied since somatic.no{} is required
225
+ }
227
226
  }
227
+ },
228
+ // fusion
229
+ 2: {
230
+ term_id: "assayavailability_fusion",
231
+ yes: { value: ["1"] },
232
+ no: { value: ["2"] }
233
+ },
234
+ // cnv
235
+ 4: {
236
+ term_id: "assayavailability_cnv",
237
+ yes: { value: ["1"] },
238
+ no: { value: ["2"] }
228
239
  }
229
- },
230
- // fusion
231
- 2: {
232
- term_id: "assayavailability_fusion",
233
- yes: { value: ["1"] },
234
- no: { value: ["2"] }
235
- },
236
- // cnv
237
- 4: {
238
- term_id: "assayavailability_cnv",
239
- yes: { value: ["1"] },
240
- no: { value: ["2"] }
241
240
  }
242
241
  }
243
- }
244
- };
242
+ };
243
+ }
245
244
  function copyDataFilesFromRepo2Tp() {
246
245
  if (existsSync("/home/root/pp"))
247
246
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjcrh/proteinpaint-server",
3
- "version": "2.117.0",
3
+ "version": "2.118.1-1",
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",
@@ -66,9 +66,10 @@
66
66
  },
67
67
  "dependencies": {
68
68
  "@sjcrh/augen": "2.116.0",
69
+ "@sjcrh/proteinpaint-python": "2.118.0",
69
70
  "@sjcrh/proteinpaint-rust": "2.117.0",
70
- "@sjcrh/proteinpaint-shared": "2.117.0",
71
- "@sjcrh/proteinpaint-types": "2.117.0",
71
+ "@sjcrh/proteinpaint-shared": "2.118.0",
72
+ "@sjcrh/proteinpaint-types": "2.118.1-1",
72
73
  "@types/express": "^5.0.0",
73
74
  "@types/express-session": "^1.18.1",
74
75
  "better-sqlite3": "^9.4.1",
@@ -1,10 +1,10 @@
1
1
  import path from "path";
2
2
  import serverconfig from "#src/serverconfig.js";
3
3
  import { brainImagingPayload } from "#types/checkers";
4
- import { spawn } from "child_process";
5
4
  import { getData } from "../src/termdb.matrix.js";
6
5
  import { isNumericTerm } from "@sjcrh/proteinpaint-shared/terms.js";
7
6
  import { getColors } from "#shared/common.js";
7
+ import { run_python } from "@sjcrh/proteinpaint-python";
8
8
  const api = {
9
9
  endpoint: "brainImaging",
10
10
  methods: {
@@ -124,7 +124,20 @@ async function getBrainImage(query, genomes, plane, index) {
124
124
  if (!legend[category])
125
125
  legend[category] = { color: filesByCat[category].color, maxLength };
126
126
  }
127
- const url = await generateBrainImage(refFile, plane, index, maxLength, JSON.stringify(filesByCat));
127
+ const arg = {
128
+ refFile,
129
+ plane,
130
+ index,
131
+ maxLength,
132
+ filesByCat: JSON.stringify(filesByCat)
133
+ };
134
+ let url;
135
+ try {
136
+ url = await run_python("plotBrainImaging.py", JSON.stringify(arg));
137
+ } catch (error) {
138
+ const errmsg = "Error running Python script:" + error;
139
+ throw new Error(errmsg);
140
+ }
128
141
  brainImageDict[dcategory] = { url, catNum };
129
142
  }
130
143
  if (query.legendFilter) {
@@ -141,30 +154,6 @@ async function getBrainImage(query, genomes, plane, index) {
141
154
  throw "no reference or sample files";
142
155
  }
143
156
  }
144
- async function generateBrainImage(refFile, plane, index, maxLength, filesJson) {
145
- return new Promise((resolve, reject) => {
146
- const cmd = [`${serverconfig.binpath}/utils/plotBrainImaging.py`, refFile, plane, index, maxLength, filesJson];
147
- const ps = spawn(serverconfig.python, cmd);
148
- const imgData = [];
149
- ps.stdout.on("data", (data) => {
150
- imgData.push(data);
151
- });
152
- ps.stderr.on("data", (data) => {
153
- console.error(`stderr: ${data}`);
154
- reject(new Error(`Python script filed: ${data}`));
155
- });
156
- ps.on("close", (code) => {
157
- if (code === 0) {
158
- const imageBuffer = Buffer.concat(imgData);
159
- const base64Data = imageBuffer.toString("base64");
160
- const imgUrl = `data:image/png;base64,${base64Data}`;
161
- resolve(imgUrl);
162
- } else {
163
- reject(new Error(`Python script exited with code ${code}`));
164
- }
165
- });
166
- });
167
- }
168
157
  export {
169
158
  api
170
159
  };
@@ -1,7 +1,6 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
3
  import serverconfig from "#src/serverconfig.js";
4
- import { spawn } from "child_process";
5
4
  const api = {
6
5
  endpoint: "brainImagingSamples",
7
6
  methods: {
@@ -62,59 +61,6 @@ async function getBrainImageSamples(query, genomes) {
62
61
  throw "no reference or sample files";
63
62
  }
64
63
  }
65
- async function validate_query_NIdata(ds) {
66
- const q = ds.queries.NIdata;
67
- if (!q || !serverconfig.features?.showBrainImaging)
68
- return;
69
- for (const key in q) {
70
- if (q[key].referenceFile && q[key].samples) {
71
- q[key].get = async (sampleName, l, f, t) => {
72
- const refFile = path.join(serverconfig.tpmasterdir, q[key].referenceFile);
73
- const sampleFile = path.join(serverconfig.tpmasterdir, q[key].samples, sampleName);
74
- try {
75
- await fs.promises.stat(sampleFile);
76
- } catch (e) {
77
- if (e.code == "EACCES")
78
- throw "cannot read file, permission denied";
79
- if (e.code == "ENOENT")
80
- throw "no data for this sample";
81
- throw "failed to load data";
82
- }
83
- return new Promise((resolve, reject) => {
84
- const ps = spawn(serverconfig.python, [
85
- `${serverconfig.binpath}/utils/plotBrainImaging.py`,
86
- refFile,
87
- sampleFile,
88
- l,
89
- f,
90
- t
91
- ]);
92
- const imgData = [];
93
- ps.stdout.on("data", (data) => {
94
- imgData.push(data);
95
- });
96
- ps.stderr.on("data", (data) => {
97
- console.error(`stderr: ${data}`);
98
- reject(new Error(`Python script filed: ${data}`));
99
- });
100
- ps.on("close", (code) => {
101
- if (code === 0) {
102
- const imageBuffer = Buffer.concat(imgData);
103
- const base64Data = imageBuffer.toString("base64");
104
- const imgUrl = `data:image/png;base64,${base64Data}`;
105
- resolve(imgUrl);
106
- } else {
107
- reject(new Error(`Python script exited with code ${code}`));
108
- }
109
- });
110
- });
111
- };
112
- } else {
113
- throw "no reference or sample files";
114
- }
115
- }
116
- }
117
64
  export {
118
- api,
119
- validate_query_NIdata
65
+ api
120
66
  };