@sjcrh/proteinpaint-server 2.27.2 → 2.29.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/cards/hic.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "ribbonMessage": "Versions 7, 8 and 9 Hi-C files are accepted.",
2
+ "ribbonMessage": "Versions 7, 8 and 9 Hi-C files are accepted.<br> See the new example for displaying a hic data across two chromosomes.",
3
3
  "ppcalls": [
4
4
  {
5
5
  "label": "Hi-C",
@@ -12,19 +12,61 @@
12
12
  "genome": "hg19",
13
13
  "position": "chr7:13749862-20841903",
14
14
  "nativetracks": "RefGene",
15
- "tracks": [{
16
- "type": "hicstraw",
17
- "file": "proteinpaint_demo/hg19/hic/hic_demo.hic",
18
- "name": "Hi-C Demo",
19
- "percentile_max": 95,
20
- "mincutoff": 1,
21
- "pyramidup": 1,
22
- "enzyme": "MboI",
23
- "normalizationmethod":"VC"
24
- }]
15
+ "tracks": [
16
+ {
17
+ "type": "hicstraw",
18
+ "file": "proteinpaint_demo/hg19/hic/hic_demo.hic",
19
+ "name": "Hi-C Demo",
20
+ "percentile_max": 95,
21
+ "mincutoff": 1,
22
+ "pyramidup": 1,
23
+ "enzyme": "MboI",
24
+ "normalizationmethod": "VC"
25
+ }
26
+ ]
25
27
  },
26
28
  "testSpec": {
27
- "expected": {"image": 1 }
29
+ "expected": {
30
+ "image": 1
31
+ }
32
+ }
33
+ },
34
+ {
35
+ "label": "Two chromosome view",
36
+ "runargs": {
37
+ "parseurl": true,
38
+ "block": true,
39
+ "nobox": true,
40
+ "noheader": true,
41
+ "genome": "hg19",
42
+ "position": "chr8:128688997-128888997",
43
+ "nativetracks": "RefGene",
44
+ "width": 300,
45
+ "subpanels": [
46
+ {
47
+ "chr": "chr4",
48
+ "start": 174408608,
49
+ "stop": 175268609,
50
+ "width": 600,
51
+ "leftborder": "rgba(200,0,0,.1)"
52
+ }
53
+ ],
54
+ "tracks": [
55
+ {
56
+ "type": "hicstraw",
57
+ "file": "files/hg19/nbl-hic/hic_NB69.inter.hic",
58
+ "name": "SJNBL046418_C1/NB69 Hi-C",
59
+ "percentile_max": 95,
60
+ "mincutoff": 1,
61
+ "pyramidup": 1,
62
+ "enzyme": "MboI"
63
+ }
64
+ ]
65
+ },
66
+ "testSpec": {
67
+ "expected": {
68
+ "image": 1
69
+ }
28
70
  }
29
71
  }
30
72
  ],
@@ -34,4 +76,4 @@
34
76
  "link": "https://docs.google.com/document/d/1MQ0Z_AD5moDmaSx2tcn7DyVKGp49TS63pO0cceGL_Ns/edit"
35
77
  }
36
78
  ]
37
- }
79
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjcrh/proteinpaint-server",
3
- "version": "2.27.2",
3
+ "version": "2.29.0",
4
4
  "description": "a genomics visualization tool for exploring a cohort's genotype and phenotype data",
5
5
  "main": "server.js",
6
6
  "bin": "start.js",
@@ -74,7 +74,7 @@
74
74
  "micromatch": "^4.0.5",
75
75
  "minimatch": "^3.1.2",
76
76
  "node-fetch": "^2.6.1",
77
- "partjson": "^0.58.1",
77
+ "partjson": "^0.58.2",
78
78
  "tiny-async-pool": "^1.2.0",
79
79
  "typedoc-plugin-missing-exports": "^2.0.1"
80
80
  },
@@ -0,0 +1,212 @@
1
+ // import { getcategoriesRequest, getcategoriesResponse } from '#shared/types/routes/termdb.categories'
2
+ import { getOrderedLabels } from '#src/termdb.barchart.js'
3
+ import { getData } from '#src/termdb.matrix.js'
4
+
5
+ export const api: any = {
6
+ endpoint: 'termdb/categories',
7
+ methods: {
8
+ get: {
9
+ init,
10
+ request: {
11
+ typeId: 'getcategoriesRequest'
12
+ },
13
+ response: {
14
+ typeId: 'getcategoriesResponse'
15
+ },
16
+ examples: [
17
+ {
18
+ request: {
19
+ body: {
20
+ genome: 'hg38-test',
21
+ dslabel: 'TermdbTest',
22
+ embedder: 'localhost',
23
+ getcategories: 1,
24
+ tid: 'diaggrp',
25
+ filter: {
26
+ type: 'tvslst',
27
+ in: true,
28
+ join: '',
29
+ lst: [
30
+ {
31
+ tag: 'cohortFilter',
32
+ type: 'tvs',
33
+ tvs: {
34
+ term: {
35
+ name: 'Cohort',
36
+ type: 'categorical',
37
+ values: { ABC: { label: 'ABC' }, XYZ: { label: 'XYZ' } },
38
+ id: 'subcohort',
39
+ isleaf: false,
40
+ groupsetting: { disabled: true }
41
+ },
42
+ values: [{ key: 'ABC', label: 'ABC' }]
43
+ }
44
+ }
45
+ ]
46
+ }
47
+ }
48
+ },
49
+ response: {
50
+ header: { status: 200 }
51
+ }
52
+ }
53
+ ]
54
+ },
55
+ post: {
56
+ alternativeFor: 'get',
57
+ init
58
+ }
59
+ }
60
+ }
61
+
62
+ function init({ genomes }) {
63
+ return async (req: any, res: any): Promise<void> => {
64
+ const q = req.query // as getcategoriesRequest
65
+ try {
66
+ const g = genomes[req.query.genome]
67
+ const ds = g.datasets[req.query.dslabel]
68
+ const tdb = ds.cohort.termdb
69
+
70
+ if (!g) throw 'invalid genome name'
71
+ if (!ds) throw 'invalid dataset name'
72
+ if (!tdb) throw 'invalid termdb object'
73
+ await trigger_getcategories(q, res, tdb, ds, g) // as getcategoriesResponse
74
+ } catch (e) {
75
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
76
+ // @ts-ignore
77
+ res.send({ error: e?.message || e })
78
+ if (e instanceof Error && e.stack) console.log(e)
79
+ }
80
+ }
81
+ }
82
+
83
+ async function trigger_getcategories(q, res, tdb, ds, genome) {
84
+ // thin wrapper of get_summary
85
+ // works for all types of terms
86
+ if (!q.tid) throw '.tid missing'
87
+ const term =
88
+ q.type == 'geneVariant' ? { name: q.tid, type: 'geneVariant', isleaf: true } : tdb.q.termjsonByOneid(q.tid)
89
+ const arg = {
90
+ filter: q.filter,
91
+ terms:
92
+ q.type == 'geneVariant'
93
+ ? [{ term: term, q: { isAtomic: true } }]
94
+ : [{ id: q.tid, term, q: q.term1_q || getDefaultQ(term, q) }],
95
+ currentGeneNames: q.currentGeneNames
96
+ }
97
+
98
+ const data = await getData(arg, ds, genome)
99
+ if (data.error) throw data.error
100
+
101
+ const lst = []
102
+ if (q.type == 'geneVariant') {
103
+ const samples = data.samples
104
+ const dtClassMap = new Map()
105
+ if (ds.assayAvailability?.byDt) {
106
+ for (const [dtType, dtValue] of Object.entries(ds.assayAvailability.byDt)) {
107
+ if (dtValue.byOrigin) {
108
+ dtClassMap.set(parseInt(dtType), { byOrigin: { germline: {}, somatic: {} } })
109
+ }
110
+ }
111
+ }
112
+ const sampleCountedFor = new Set() // if the sample is conunted for the
113
+ for (const [sampleId, sampleData] of Object.entries(samples)) {
114
+ const values = sampleData[q.tid].values
115
+ sampleCountedFor.clear()
116
+ /* values here is an array of result entires, one or more entries for each dt. e.g.
117
+ [
118
+ { dt: 1, class: 'Blank', _SAMPLEID_: 1, origin: 'germline' },
119
+ { dt: 1, class: 'WT', _SAMPLEID_: 1, origin: 'somatic' },
120
+ { dt: 2, class: 'Blank', _SAMPLEID_: 1 },
121
+ { dt: 4, class: 'WT', _SAMPLEID_: 1 }
122
+ ]
123
+ */
124
+ for (const value of values) {
125
+ if (!dtClassMap.has(value.dt)) {
126
+ dtClassMap.set(value.dt, {})
127
+ }
128
+ const dtClasses = dtClassMap.get(value.dt)
129
+ if (dtClasses.byOrigin) {
130
+ if (!dtClasses.byOrigin[value.origin][value.class]) {
131
+ dtClasses.byOrigin[value.origin][value.class] = 1
132
+ sampleCountedFor.add(`${value.dt} ${value.origin} ${value.class}`)
133
+ }
134
+ if (!sampleCountedFor.has(`${value.dt} ${value.origin} ${value.class}`)) {
135
+ sampleCountedFor.add(`${value.dt} ${value.origin} ${value.class}`)
136
+ dtClasses.byOrigin[value.origin][value.class] += 1
137
+ }
138
+ } else {
139
+ if (!dtClasses[value.class]) {
140
+ sampleCountedFor.add(`${value.dt} ${value.class}`)
141
+ dtClasses[value.class] = 1
142
+ }
143
+ if (!sampleCountedFor.has(`${value.dt} ${value.class}`)) {
144
+ sampleCountedFor.add(`${value.dt} ${value.class}`)
145
+ dtClasses[value.class] += 1
146
+ }
147
+ }
148
+ }
149
+ }
150
+ for (const [dt, classes] of dtClassMap) {
151
+ lst.push({
152
+ dt,
153
+ classes
154
+ })
155
+ }
156
+ } else {
157
+ const key2count = new Map()
158
+ // k: category key
159
+ // v: number of samples
160
+ for (const sid in data.samples) {
161
+ const v = data.samples[sid][q.tid]
162
+ if (!v) continue
163
+ if (!('key' in v)) continue
164
+ key2count.set(v.key, 1 + (key2count.get(v.key) || 0))
165
+ }
166
+ for (const [key, count] of key2count) {
167
+ lst.push({
168
+ samplecount: count,
169
+ key,
170
+ label:
171
+ data.refs?.byTermId?.[q.tid]?.events?.find(e => e.event === key).label || term?.values?.[key]?.label || key
172
+ })
173
+ }
174
+ }
175
+
176
+ const orderedLabels = getOrderedLabels(
177
+ term,
178
+ data.refs?.byTermId?.[q.tid]?.bins || [],
179
+ data.refs?.byTermId?.[q.tid]?.events,
180
+ q.term1_q
181
+ )
182
+ if (orderedLabels.length) {
183
+ lst.sort((a, b) => orderedLabels.indexOf(a.label) - orderedLabels.indexOf(b.label))
184
+ }
185
+ res.send({
186
+ lst,
187
+ orderedLabels
188
+ })
189
+ }
190
+
191
+ function getDefaultQ(term, q) {
192
+ if (term.type == 'categorical') return {}
193
+ if (term.type == 'survival') return {}
194
+ if (term.type == 'integer' || term.type == 'float') return term.bins.default
195
+ if (term.type == 'condition') {
196
+ return {
197
+ mode: q.mode,
198
+ breaks: q.breaks,
199
+ bar_by_grade: q.bar_by_grade,
200
+ /*Leave this here until bug with term1_q not passing to getCategories is figured out.
201
+ Commented out b/c tvs condition tests fail.*/
202
+ //bar_by_children: term.subconditions || q.bar_by_children,
203
+ bar_by_children: q.bar_by_children,
204
+ value_by_max_grade: q.value_by_max_grade,
205
+ value_by_most_recent: q.value_by_most_recent,
206
+ //value_by_computable_grade: term.subconditions || q.value_by_computable_grade
207
+ value_by_computable_grade: q.value_by_computable_grade
208
+ }
209
+ }
210
+ if (term.type == 'geneVariant') return {}
211
+ throw 'unknown term type'
212
+ }
@@ -1,5 +1,5 @@
1
- import { trigger_getViolinPlotData } from '#src/termdb.violin.js'
2
1
  // import { getViolinRequest, getViolinResponse } from '#shared/types/routes/termdb.violin'
2
+ import { trigger_getViolinPlotData } from '#src/termdb.violin.js'
3
3
 
4
4
  export const api: any = {
5
5
  endpoint: 'termdb/violin',