@abi-software/flatmapvuer 0.6.3-vue.3.9 → 1.0.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.
Files changed (38) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +120 -120
  3. package/cypress.config.js +23 -23
  4. package/dist/flatmapvuer.js +15894 -16259
  5. package/dist/flatmapvuer.umd.cjs +132 -145
  6. package/dist/index.html +17 -17
  7. package/dist/style.css +1 -1
  8. package/package.json +95 -95
  9. package/public/index.html +17 -17
  10. package/reporter-config.json +9 -9
  11. package/src/App.vue +310 -310
  12. package/src/assets/_variables.scss +43 -43
  13. package/src/assets/styles.scss +5 -5
  14. package/src/components/AnnotationTool.vue +450 -446
  15. package/src/components/EventBus.js +3 -3
  16. package/src/components/ExternalResourceCard.vue +107 -107
  17. package/src/components/FlatmapVuer.vue +2600 -2531
  18. package/src/components/MultiFlatmapVuer.vue +731 -731
  19. package/src/components/ProvenancePopup.vue +503 -495
  20. package/src/components/SelectionsGroup.vue +255 -255
  21. package/src/components/Tooltip.vue +50 -50
  22. package/src/components/TreeControls.vue +231 -231
  23. package/src/components/index.js +7 -7
  24. package/src/components/legends/DynamicLegends.vue +106 -106
  25. package/src/components/legends/SvgLegends.vue +112 -112
  26. package/src/icons/flatmap-marker.js +1 -1
  27. package/src/icons/fonts/mapicon-species.svg +14 -14
  28. package/src/icons/fonts/mapicon-species.ttf +0 -0
  29. package/src/icons/fonts/mapicon-species.woff +0 -0
  30. package/src/icons/mapicon-species-style.css +42 -42
  31. package/src/icons/yellowstar.js +5 -5
  32. package/src/legends/legend.svg +25 -25
  33. package/src/main.js +19 -19
  34. package/src/services/flatmapQueries.js +453 -453
  35. package/src/store/index.js +23 -23
  36. package/vite.config.js +73 -73
  37. package/vite.static-build.js +12 -12
  38. package/vuese-generator.js +64 -64
@@ -1,453 +1,453 @@
1
- /* eslint-disable no-alert, no-console */
2
- // remove duplicates by stringifying the objects
3
- const removeDuplicates = function (arrayOfAnything) {
4
- if (!arrayOfAnything) return []
5
- return [...new Set(arrayOfAnything.map((e) => JSON.stringify(e)))].map((e) =>
6
- JSON.parse(e)
7
- )
8
- }
9
-
10
- const cachedLabels = {}
11
-
12
- const findTaxonomyLabel = async function (flatmapAPI, taxonomy) {
13
- if (cachedLabels && cachedLabels.hasOwnProperty(taxonomy)) {
14
- return cachedLabels[taxonomy]
15
- }
16
-
17
- return new Promise((resolve) => {
18
- fetch(`${flatmapAPI}knowledge/label/${taxonomy}`, {
19
- method: 'GET',
20
- })
21
- .then((response) => response.json())
22
- .then((data) => {
23
- let label = data.label
24
- if (label === 'Mammalia') {
25
- label = 'Mammalia not otherwise specified'
26
- }
27
- cachedLabels[taxonomy] = label
28
- resolve(label)
29
- })
30
- .catch((error) => {
31
- console.error('Error:', error)
32
- cachedLabels[taxonomy] = taxonomy
33
- resolve(taxonomy)
34
- })
35
- })
36
- }
37
-
38
- const inArray = function (ar1, ar2) {
39
- if (!ar1 || !ar2) return false
40
- let as1 = JSON.stringify(ar1)
41
- let as2 = JSON.stringify(ar2)
42
- return as1.indexOf(as2) !== -1
43
- }
44
-
45
- let FlatmapQueries = function () {
46
- this.initialise = function (flatmapApi) {
47
- this.flatmapApi = flatmapApi
48
- this.destinations = []
49
- this.origins = []
50
- this.components = []
51
- this.urls = []
52
- this.controller = undefined
53
- this.uberons = []
54
- this.lookUp = []
55
- }
56
-
57
- this.createTooltipData = async function (eventData) {
58
- let hyperlinks = []
59
- if (
60
- eventData.feature.hyperlinks &&
61
- eventData.feature.hyperlinks.length > 0
62
- ) {
63
- hyperlinks = eventData.feature.hyperlinks
64
- } else {
65
- hyperlinks = this.urls.map((url) => ({ url: url, id: 'pubmed' }))
66
- }
67
- let taxonomyLabel = undefined
68
- if (eventData.provenanceTaxonomy) {
69
- taxonomyLabel = []
70
- for (let i = 0; eventData.provenanceTaxonomy.length > i; i++) {
71
- taxonomyLabel.push(
72
- await findTaxonomyLabel(
73
- this.flatmapAPI,
74
- eventData.provenanceTaxonomy[i]
75
- )
76
- )
77
- }
78
- }
79
-
80
- let tooltipData = {
81
- destinations: this.destinations,
82
- origins: this.origins,
83
- components: this.components,
84
- destinationsWithDatasets: this.destinationsWithDatasets,
85
- originsWithDatasets: this.originsWithDatasets,
86
- componentsWithDatasets: this.componentsWithDatasets,
87
- title: eventData.label,
88
- featureId: eventData.resource,
89
- hyperlinks: hyperlinks,
90
- provenanceTaxonomy: eventData.provenanceTaxonomy,
91
- provenanceTaxonomyLabel: taxonomyLabel,
92
- }
93
- return tooltipData
94
- }
95
-
96
- this.createComponentsLabelList = function (components, lookUp) {
97
- let labelList = []
98
- components.forEach((n) => {
99
- labelList.push(this.createLabelFromNeuralNode(n[0]), lookUp)
100
- if (n.length === 2) {
101
- labelList.push(this.createLabelFromNeuralNode(n[1]), lookUp)
102
- }
103
- })
104
- return labelList
105
- }
106
-
107
- this.createLabelLookup = function (uberons) {
108
- return new Promise((resolve) => {
109
- let uberonMap = {}
110
- this.uberons = []
111
- const data = { sql: this.buildLabelSqlStatement(uberons) }
112
- fetch(`${this.flatmapApi}knowledge/query/`, {
113
- method: 'POST',
114
- headers: {
115
- 'Content-Type': 'application/json',
116
- },
117
- body: JSON.stringify(data),
118
- })
119
- .then((response) => response.json())
120
- .then((payload) => {
121
- const entity = payload.keys.indexOf('entity')
122
- const label = payload.keys.indexOf('label')
123
- if (entity > -1 && label > -1) {
124
- payload.values.forEach((pair) => {
125
- uberonMap[pair[entity]] = pair[label]
126
- this.uberons.push({
127
- id: pair[entity],
128
- name: pair[label],
129
- })
130
- })
131
- }
132
- resolve(uberonMap)
133
- })
134
- })
135
- }
136
-
137
- this.buildConnectivitySqlStatement = function (keastIds) {
138
- let sql = 'select knowledge from knowledge where entity in ('
139
- if (keastIds.length === 1) {
140
- sql += `'${keastIds[0]}')`
141
- } else if (keastIds.length > 1) {
142
- for (let i in keastIds) {
143
- sql += `'${keastIds[i]}'${i >= keastIds.length - 1 ? ')' : ','} `
144
- }
145
- }
146
- return sql
147
- }
148
-
149
- this.buildLabelSqlStatement = function (uberons) {
150
- let sql = 'select entity, label from labels where entity in ('
151
- if (uberons.length === 1) {
152
- sql += `'${uberons[0]}')`
153
- } else if (uberons.length > 1) {
154
- for (let i in uberons) {
155
- sql += `'${uberons[i]}'${i >= uberons.length - 1 ? ')' : ','} `
156
- }
157
- }
158
- return sql
159
- }
160
-
161
- this.findAllIdsFromConnectivity = function (connectivity) {
162
- let dnodes = connectivity.connectivity.flat() // get nodes from edgelist
163
- let nodes = [...new Set(dnodes)] // remove duplicates
164
- let found = []
165
- nodes.forEach((n) => {
166
- if (Array.isArray(n)) {
167
- found.push(n.flat())
168
- } else {
169
- found.push(n)
170
- }
171
- })
172
- return [...new Set(found.flat())]
173
- }
174
-
175
- this.flattenConntectivity = function (connectivity) {
176
- let dnodes = connectivity.flat() // get nodes from edgelist
177
- let nodes = [...new Set(dnodes)] // remove duplicates
178
- let found = []
179
- nodes.forEach((n) => {
180
- if (Array.isArray(n)) {
181
- found.push(n.flat())
182
- } else {
183
- found.push(n)
184
- }
185
- })
186
- return found.flat()
187
- }
188
-
189
- this.findComponents = function (connectivity) {
190
- let dnodes = connectivity.connectivity.flat() // get nodes from edgelist
191
- let nodes = removeDuplicates(dnodes)
192
-
193
- let found = []
194
- let terminal = false
195
- nodes.forEach((node) => {
196
- terminal = false
197
- // Check if the node is an destination or origin (note that they are labelled dendrite and axon as opposed to origin and destination)
198
- if (inArray(connectivity.axons, node)) {
199
- terminal = true
200
- }
201
- if (inArray(connectivity.dendrites, node)) {
202
- terminal = true
203
- }
204
- if (!terminal) {
205
- found.push(node)
206
- }
207
- })
208
-
209
- return found
210
- }
211
-
212
- this.retrieveFlatmapKnowledgeForEvent = async function (eventData) {
213
- // check if there is an existing query
214
- if (this.controller) this.controller.abort()
215
-
216
- // set up the abort controller
217
- this.controller = new AbortController()
218
- const signal = this.controller.signal
219
-
220
- const keastIds = eventData.resource
221
- this.destinations = []
222
- this.origins = []
223
- this.components = []
224
- if (!keastIds || keastIds.length == 0) return
225
- const data = { sql: this.buildConnectivitySqlStatement(keastIds) }
226
- let prom1 = new Promise((resolve) => {
227
- fetch(`${this.flatmapApi}knowledge/query/`, {
228
- method: 'POST',
229
- headers: {
230
- 'Content-Type': 'application/json',
231
- },
232
- body: JSON.stringify(data),
233
- signal: signal,
234
- })
235
- .then((response) => response.json())
236
- .then((data) => {
237
- if (this.connectivityExists(data)) {
238
- let connectivity = JSON.parse(data.values[0][0])
239
- this.processConnectivity(connectivity).then(() => {
240
- resolve(true)
241
- })
242
- } else {
243
- resolve(false)
244
- }
245
- })
246
- .catch((error) => {
247
- console.error('Error:', error)
248
- resolve(false)
249
- })
250
- })
251
- let prom2 = await this.pubmedQueryOnIds(eventData)
252
- let results = await Promise.all([prom1, prom2])
253
- return results
254
- }
255
-
256
- this.connectivityExists = function (data) {
257
- if (
258
- data.values &&
259
- data.values.length > 0 &&
260
- JSON.parse(data.values[0][0]).connectivity &&
261
- JSON.parse(data.values[0][0]).connectivity.length > 0
262
- ) {
263
- return true
264
- } else {
265
- return false
266
- }
267
- }
268
-
269
- this.createLabelFromNeuralNode = function (node, lookUp) {
270
- let label = lookUp[node[0]]
271
- if (node.length === 2 && node[1].length > 0) {
272
- node[1].forEach((n) => {
273
- if (lookUp[n] == undefined) {
274
- label += `, ${n}`
275
- } else {
276
- label += `, ${lookUp[n]}`
277
- }
278
- })
279
- }
280
- return label
281
- }
282
-
283
- this.flattenAndFindDatasets = function (components, axons, dendrites) {
284
- // process the nodes for finding datasets (Note this is not critical to the tooltip, only for the 'search on components' button)
285
- let componentsFlat = this.flattenConntectivity(components)
286
- let axonsFlat = this.flattenConntectivity(axons)
287
- let dendritesFlat = this.flattenConntectivity(dendrites)
288
-
289
- // Filter for the anatomy which is annotated on datasets
290
- this.destinationsWithDatasets = this.uberons.filter(
291
- (ub) => axonsFlat.indexOf(ub.id) !== -1
292
- )
293
- this.originsWithDatasets = this.uberons.filter(
294
- (ub) => dendritesFlat.indexOf(ub.id) !== -1
295
- )
296
- this.componentsWithDatasets = this.uberons.filter(
297
- (ub) => componentsFlat.indexOf(ub.id) !== -1
298
- )
299
- }
300
-
301
- this.processConnectivity = function (connectivity) {
302
- return new Promise((resolve) => {
303
- // Filter the origin and destinations from components
304
- let components = this.findComponents(connectivity)
305
-
306
- // Remove duplicates
307
- let axons = removeDuplicates(connectivity.axons)
308
- let dendrites = removeDuplicates(connectivity.dendrites)
309
-
310
- // Create list of ids to get labels for
311
- let conIds = this.findAllIdsFromConnectivity(connectivity)
312
-
313
- // Create readable labels from the nodes. Setting this to 'this.origins' updates the display
314
- this.createLabelLookup(conIds).then((lookUp) => {
315
- this.destinations = axons.map((a) =>
316
- this.createLabelFromNeuralNode(a, lookUp)
317
- )
318
- this.origins = dendrites.map((d) =>
319
- this.createLabelFromNeuralNode(d, lookUp)
320
- )
321
- this.components = components.map((c) =>
322
- this.createLabelFromNeuralNode(c, lookUp)
323
- )
324
- this.flattenAndFindDatasets(components, axons, dendrites)
325
- resolve(true)
326
- })
327
- })
328
- }
329
-
330
- this.flattenConntectivity = function (connectivity) {
331
- let dnodes = connectivity.flat() // get nodes from edgelist
332
- let nodes = [...new Set(dnodes)] // remove duplicates
333
- let found = []
334
- nodes.forEach((n) => {
335
- if (Array.isArray(n)) {
336
- found.push(n.flat())
337
- } else {
338
- found.push(n)
339
- }
340
- })
341
- return found.flat()
342
- }
343
-
344
- this.findComponents = function (connectivity) {
345
- let dnodes = connectivity.connectivity.flat() // get nodes from edgelist
346
- let nodes = removeDuplicates(dnodes)
347
-
348
- let found = []
349
- let terminal = false
350
- nodes.forEach((node) => {
351
- terminal = false
352
- // Check if the node is an destination or origin (note that they are labelled dendrite and axon as opposed to origin and destination)
353
- if (inArray(connectivity.axons, node)) {
354
- terminal = true
355
- }
356
- if (inArray(connectivity.dendrites, node)) {
357
- terminal = true
358
- }
359
- if (!terminal) {
360
- found.push(node)
361
- }
362
- })
363
-
364
- return found
365
- }
366
-
367
- this.stripPMIDPrefix = function (pubmedId) {
368
- return pubmedId.split(':')[1]
369
- }
370
-
371
- this.buildPubmedSqlStatement = function (keastIds) {
372
- let sql = 'select distinct publication from publications where entity in ('
373
- if (keastIds.length === 1) {
374
- sql += `'${keastIds[0]}')`
375
- } else if (keastIds.length > 1) {
376
- for (let i in keastIds) {
377
- sql += `'${keastIds[i]}'${i >= keastIds.length - 1 ? ')' : ','} `
378
- }
379
- }
380
- return sql
381
- }
382
-
383
- this.buildPubmedSqlStatementForModels = function (model) {
384
- return `select distinct publication from publications where entity = '${model}'`
385
- }
386
-
387
- this.flatmapQuery = function (sql) {
388
- const data = { sql: sql }
389
- return fetch(`${this.flatmapApi}knowledge/query/`, {
390
- method: 'POST',
391
- headers: {
392
- 'Content-Type': 'application/json',
393
- },
394
- body: JSON.stringify(data),
395
- })
396
- .then((response) => response.json())
397
- .catch((error) => {
398
- console.error('Error:', error)
399
- })
400
- }
401
- // Note that this functin WILL run to the end, as it doesn not catch the second level of promises
402
- this.pubmedQueryOnIds = function (eventData) {
403
- return new Promise((resolve) => {
404
- const keastIds = eventData.resource
405
- const source = eventData.feature.source
406
- if (!keastIds || keastIds.length === 0) return
407
- const sql = this.buildPubmedSqlStatement(keastIds)
408
- this.flatmapQuery(sql).then((data) => {
409
- // Create pubmed url on paths if we have them
410
- if (data.values.length > 0) {
411
- this.urls = [
412
- this.pubmedSearchUrl(
413
- data.values.map((id) => this.stripPMIDPrefix(id[0]))
414
- ),
415
- ]
416
- resolve(true)
417
- } else {
418
- // Create pubmed url on models
419
- this.pubmedQueryOnModels(source).then((result) => {
420
- resolve(result)
421
- })
422
- }
423
- })
424
- })
425
- }
426
-
427
- this.pubmedQueryOnModels = function (source) {
428
- return this.flatmapQuery(
429
- this.buildPubmedSqlStatementForModels(source)
430
- ).then((data) => {
431
- if (Array.isArray(data.values) && data.values.length > 0) {
432
- this.urls = [
433
- this.pubmedSearchUrl(
434
- data.values.map((id) => this.stripPMIDPrefix(id[0]))
435
- ),
436
- ]
437
- return true
438
- } else {
439
- this.urls = [] // Clears the pubmed search button
440
- }
441
- return false
442
- })
443
- }
444
-
445
- this.pubmedSearchUrl = function (ids) {
446
- let url = 'https://pubmed.ncbi.nlm.nih.gov/?'
447
- let params = new URLSearchParams()
448
- params.append('term', ids)
449
- return url + params.toString()
450
- }
451
- }
452
-
453
- export { FlatmapQueries, findTaxonomyLabel }
1
+ /* eslint-disable no-alert, no-console */
2
+ // remove duplicates by stringifying the objects
3
+ const removeDuplicates = function (arrayOfAnything) {
4
+ if (!arrayOfAnything) return []
5
+ return [...new Set(arrayOfAnything.map((e) => JSON.stringify(e)))].map((e) =>
6
+ JSON.parse(e)
7
+ )
8
+ }
9
+
10
+ const cachedLabels = {}
11
+
12
+ const findTaxonomyLabel = async function (flatmapAPI, taxonomy) {
13
+ if (cachedLabels && cachedLabels.hasOwnProperty(taxonomy)) {
14
+ return cachedLabels[taxonomy]
15
+ }
16
+
17
+ return new Promise((resolve) => {
18
+ fetch(`${flatmapAPI}knowledge/label/${taxonomy}`, {
19
+ method: 'GET',
20
+ })
21
+ .then((response) => response.json())
22
+ .then((data) => {
23
+ let label = data.label
24
+ if (label === 'Mammalia') {
25
+ label = 'Mammalia not otherwise specified'
26
+ }
27
+ cachedLabels[taxonomy] = label
28
+ resolve(label)
29
+ })
30
+ .catch((error) => {
31
+ console.error('Error:', error)
32
+ cachedLabels[taxonomy] = taxonomy
33
+ resolve(taxonomy)
34
+ })
35
+ })
36
+ }
37
+
38
+ const inArray = function (ar1, ar2) {
39
+ if (!ar1 || !ar2) return false
40
+ let as1 = JSON.stringify(ar1)
41
+ let as2 = JSON.stringify(ar2)
42
+ return as1.indexOf(as2) !== -1
43
+ }
44
+
45
+ let FlatmapQueries = function () {
46
+ this.initialise = function (flatmapApi) {
47
+ this.flatmapApi = flatmapApi
48
+ this.destinations = []
49
+ this.origins = []
50
+ this.components = []
51
+ this.urls = []
52
+ this.controller = undefined
53
+ this.uberons = []
54
+ this.lookUp = []
55
+ }
56
+
57
+ this.createTooltipData = async function (eventData) {
58
+ let hyperlinks = []
59
+ if (
60
+ eventData.feature.hyperlinks &&
61
+ eventData.feature.hyperlinks.length > 0
62
+ ) {
63
+ hyperlinks = eventData.feature.hyperlinks
64
+ } else {
65
+ hyperlinks = this.urls.map((url) => ({ url: url, id: 'pubmed' }))
66
+ }
67
+ let taxonomyLabel = undefined
68
+ if (eventData.provenanceTaxonomy) {
69
+ taxonomyLabel = []
70
+ for (let i = 0; eventData.provenanceTaxonomy.length > i; i++) {
71
+ taxonomyLabel.push(
72
+ await findTaxonomyLabel(
73
+ this.flatmapAPI,
74
+ eventData.provenanceTaxonomy[i]
75
+ )
76
+ )
77
+ }
78
+ }
79
+
80
+ let tooltipData = {
81
+ destinations: this.destinations,
82
+ origins: this.origins,
83
+ components: this.components,
84
+ destinationsWithDatasets: this.destinationsWithDatasets,
85
+ originsWithDatasets: this.originsWithDatasets,
86
+ componentsWithDatasets: this.componentsWithDatasets,
87
+ title: eventData.label,
88
+ featureId: eventData.resource,
89
+ hyperlinks: hyperlinks,
90
+ provenanceTaxonomy: eventData.provenanceTaxonomy,
91
+ provenanceTaxonomyLabel: taxonomyLabel,
92
+ }
93
+ return tooltipData
94
+ }
95
+
96
+ this.createComponentsLabelList = function (components, lookUp) {
97
+ let labelList = []
98
+ components.forEach((n) => {
99
+ labelList.push(this.createLabelFromNeuralNode(n[0]), lookUp)
100
+ if (n.length === 2) {
101
+ labelList.push(this.createLabelFromNeuralNode(n[1]), lookUp)
102
+ }
103
+ })
104
+ return labelList
105
+ }
106
+
107
+ this.createLabelLookup = function (uberons) {
108
+ return new Promise((resolve) => {
109
+ let uberonMap = {}
110
+ this.uberons = []
111
+ const data = { sql: this.buildLabelSqlStatement(uberons) }
112
+ fetch(`${this.flatmapApi}knowledge/query/`, {
113
+ method: 'POST',
114
+ headers: {
115
+ 'Content-Type': 'application/json',
116
+ },
117
+ body: JSON.stringify(data),
118
+ })
119
+ .then((response) => response.json())
120
+ .then((payload) => {
121
+ const entity = payload.keys.indexOf('entity')
122
+ const label = payload.keys.indexOf('label')
123
+ if (entity > -1 && label > -1) {
124
+ payload.values.forEach((pair) => {
125
+ uberonMap[pair[entity]] = pair[label]
126
+ this.uberons.push({
127
+ id: pair[entity],
128
+ name: pair[label],
129
+ })
130
+ })
131
+ }
132
+ resolve(uberonMap)
133
+ })
134
+ })
135
+ }
136
+
137
+ this.buildConnectivitySqlStatement = function (keastIds) {
138
+ let sql = 'select knowledge from knowledge where entity in ('
139
+ if (keastIds.length === 1) {
140
+ sql += `'${keastIds[0]}')`
141
+ } else if (keastIds.length > 1) {
142
+ for (let i in keastIds) {
143
+ sql += `'${keastIds[i]}'${i >= keastIds.length - 1 ? ')' : ','} `
144
+ }
145
+ }
146
+ return sql
147
+ }
148
+
149
+ this.buildLabelSqlStatement = function (uberons) {
150
+ let sql = 'select entity, label from labels where entity in ('
151
+ if (uberons.length === 1) {
152
+ sql += `'${uberons[0]}')`
153
+ } else if (uberons.length > 1) {
154
+ for (let i in uberons) {
155
+ sql += `'${uberons[i]}'${i >= uberons.length - 1 ? ')' : ','} `
156
+ }
157
+ }
158
+ return sql
159
+ }
160
+
161
+ this.findAllIdsFromConnectivity = function (connectivity) {
162
+ let dnodes = connectivity.connectivity.flat() // get nodes from edgelist
163
+ let nodes = [...new Set(dnodes)] // remove duplicates
164
+ let found = []
165
+ nodes.forEach((n) => {
166
+ if (Array.isArray(n)) {
167
+ found.push(n.flat())
168
+ } else {
169
+ found.push(n)
170
+ }
171
+ })
172
+ return [...new Set(found.flat())]
173
+ }
174
+
175
+ this.flattenConntectivity = function (connectivity) {
176
+ let dnodes = connectivity.flat() // get nodes from edgelist
177
+ let nodes = [...new Set(dnodes)] // remove duplicates
178
+ let found = []
179
+ nodes.forEach((n) => {
180
+ if (Array.isArray(n)) {
181
+ found.push(n.flat())
182
+ } else {
183
+ found.push(n)
184
+ }
185
+ })
186
+ return found.flat()
187
+ }
188
+
189
+ this.findComponents = function (connectivity) {
190
+ let dnodes = connectivity.connectivity.flat() // get nodes from edgelist
191
+ let nodes = removeDuplicates(dnodes)
192
+
193
+ let found = []
194
+ let terminal = false
195
+ nodes.forEach((node) => {
196
+ terminal = false
197
+ // Check if the node is an destination or origin (note that they are labelled dendrite and axon as opposed to origin and destination)
198
+ if (inArray(connectivity.axons, node)) {
199
+ terminal = true
200
+ }
201
+ if (inArray(connectivity.dendrites, node)) {
202
+ terminal = true
203
+ }
204
+ if (!terminal) {
205
+ found.push(node)
206
+ }
207
+ })
208
+
209
+ return found
210
+ }
211
+
212
+ this.retrieveFlatmapKnowledgeForEvent = async function (eventData) {
213
+ // check if there is an existing query
214
+ if (this.controller) this.controller.abort()
215
+
216
+ // set up the abort controller
217
+ this.controller = new AbortController()
218
+ const signal = this.controller.signal
219
+
220
+ const keastIds = eventData.resource
221
+ this.destinations = []
222
+ this.origins = []
223
+ this.components = []
224
+ if (!keastIds || keastIds.length == 0) return
225
+ const data = { sql: this.buildConnectivitySqlStatement(keastIds) }
226
+ let prom1 = new Promise((resolve) => {
227
+ fetch(`${this.flatmapApi}knowledge/query/`, {
228
+ method: 'POST',
229
+ headers: {
230
+ 'Content-Type': 'application/json',
231
+ },
232
+ body: JSON.stringify(data),
233
+ signal: signal,
234
+ })
235
+ .then((response) => response.json())
236
+ .then((data) => {
237
+ if (this.connectivityExists(data)) {
238
+ let connectivity = JSON.parse(data.values[0][0])
239
+ this.processConnectivity(connectivity).then(() => {
240
+ resolve(true)
241
+ })
242
+ } else {
243
+ resolve(false)
244
+ }
245
+ })
246
+ .catch((error) => {
247
+ console.error('Error:', error)
248
+ resolve(false)
249
+ })
250
+ })
251
+ let prom2 = await this.pubmedQueryOnIds(eventData)
252
+ let results = await Promise.all([prom1, prom2])
253
+ return results
254
+ }
255
+
256
+ this.connectivityExists = function (data) {
257
+ if (
258
+ data.values &&
259
+ data.values.length > 0 &&
260
+ JSON.parse(data.values[0][0]).connectivity &&
261
+ JSON.parse(data.values[0][0]).connectivity.length > 0
262
+ ) {
263
+ return true
264
+ } else {
265
+ return false
266
+ }
267
+ }
268
+
269
+ this.createLabelFromNeuralNode = function (node, lookUp) {
270
+ let label = lookUp[node[0]]
271
+ if (node.length === 2 && node[1].length > 0) {
272
+ node[1].forEach((n) => {
273
+ if (lookUp[n] == undefined) {
274
+ label += `, ${n}`
275
+ } else {
276
+ label += `, ${lookUp[n]}`
277
+ }
278
+ })
279
+ }
280
+ return label
281
+ }
282
+
283
+ this.flattenAndFindDatasets = function (components, axons, dendrites) {
284
+ // process the nodes for finding datasets (Note this is not critical to the tooltip, only for the 'search on components' button)
285
+ let componentsFlat = this.flattenConntectivity(components)
286
+ let axonsFlat = this.flattenConntectivity(axons)
287
+ let dendritesFlat = this.flattenConntectivity(dendrites)
288
+
289
+ // Filter for the anatomy which is annotated on datasets
290
+ this.destinationsWithDatasets = this.uberons.filter(
291
+ (ub) => axonsFlat.indexOf(ub.id) !== -1
292
+ )
293
+ this.originsWithDatasets = this.uberons.filter(
294
+ (ub) => dendritesFlat.indexOf(ub.id) !== -1
295
+ )
296
+ this.componentsWithDatasets = this.uberons.filter(
297
+ (ub) => componentsFlat.indexOf(ub.id) !== -1
298
+ )
299
+ }
300
+
301
+ this.processConnectivity = function (connectivity) {
302
+ return new Promise((resolve) => {
303
+ // Filter the origin and destinations from components
304
+ let components = this.findComponents(connectivity)
305
+
306
+ // Remove duplicates
307
+ let axons = removeDuplicates(connectivity.axons)
308
+ let dendrites = removeDuplicates(connectivity.dendrites)
309
+
310
+ // Create list of ids to get labels for
311
+ let conIds = this.findAllIdsFromConnectivity(connectivity)
312
+
313
+ // Create readable labels from the nodes. Setting this to 'this.origins' updates the display
314
+ this.createLabelLookup(conIds).then((lookUp) => {
315
+ this.destinations = axons.map((a) =>
316
+ this.createLabelFromNeuralNode(a, lookUp)
317
+ )
318
+ this.origins = dendrites.map((d) =>
319
+ this.createLabelFromNeuralNode(d, lookUp)
320
+ )
321
+ this.components = components.map((c) =>
322
+ this.createLabelFromNeuralNode(c, lookUp)
323
+ )
324
+ this.flattenAndFindDatasets(components, axons, dendrites)
325
+ resolve(true)
326
+ })
327
+ })
328
+ }
329
+
330
+ this.flattenConntectivity = function (connectivity) {
331
+ let dnodes = connectivity.flat() // get nodes from edgelist
332
+ let nodes = [...new Set(dnodes)] // remove duplicates
333
+ let found = []
334
+ nodes.forEach((n) => {
335
+ if (Array.isArray(n)) {
336
+ found.push(n.flat())
337
+ } else {
338
+ found.push(n)
339
+ }
340
+ })
341
+ return found.flat()
342
+ }
343
+
344
+ this.findComponents = function (connectivity) {
345
+ let dnodes = connectivity.connectivity.flat() // get nodes from edgelist
346
+ let nodes = removeDuplicates(dnodes)
347
+
348
+ let found = []
349
+ let terminal = false
350
+ nodes.forEach((node) => {
351
+ terminal = false
352
+ // Check if the node is an destination or origin (note that they are labelled dendrite and axon as opposed to origin and destination)
353
+ if (inArray(connectivity.axons, node)) {
354
+ terminal = true
355
+ }
356
+ if (inArray(connectivity.dendrites, node)) {
357
+ terminal = true
358
+ }
359
+ if (!terminal) {
360
+ found.push(node)
361
+ }
362
+ })
363
+
364
+ return found
365
+ }
366
+
367
+ this.stripPMIDPrefix = function (pubmedId) {
368
+ return pubmedId.split(':')[1]
369
+ }
370
+
371
+ this.buildPubmedSqlStatement = function (keastIds) {
372
+ let sql = 'select distinct publication from publications where entity in ('
373
+ if (keastIds.length === 1) {
374
+ sql += `'${keastIds[0]}')`
375
+ } else if (keastIds.length > 1) {
376
+ for (let i in keastIds) {
377
+ sql += `'${keastIds[i]}'${i >= keastIds.length - 1 ? ')' : ','} `
378
+ }
379
+ }
380
+ return sql
381
+ }
382
+
383
+ this.buildPubmedSqlStatementForModels = function (model) {
384
+ return `select distinct publication from publications where entity = '${model}'`
385
+ }
386
+
387
+ this.flatmapQuery = function (sql) {
388
+ const data = { sql: sql }
389
+ return fetch(`${this.flatmapApi}knowledge/query/`, {
390
+ method: 'POST',
391
+ headers: {
392
+ 'Content-Type': 'application/json',
393
+ },
394
+ body: JSON.stringify(data),
395
+ })
396
+ .then((response) => response.json())
397
+ .catch((error) => {
398
+ console.error('Error:', error)
399
+ })
400
+ }
401
+ // Note that this functin WILL run to the end, as it doesn not catch the second level of promises
402
+ this.pubmedQueryOnIds = function (eventData) {
403
+ return new Promise((resolve) => {
404
+ const keastIds = eventData.resource
405
+ const source = eventData.feature.source
406
+ if (!keastIds || keastIds.length === 0) return
407
+ const sql = this.buildPubmedSqlStatement(keastIds)
408
+ this.flatmapQuery(sql).then((data) => {
409
+ // Create pubmed url on paths if we have them
410
+ if (data.values.length > 0) {
411
+ this.urls = [
412
+ this.pubmedSearchUrl(
413
+ data.values.map((id) => this.stripPMIDPrefix(id[0]))
414
+ ),
415
+ ]
416
+ resolve(true)
417
+ } else {
418
+ // Create pubmed url on models
419
+ this.pubmedQueryOnModels(source).then((result) => {
420
+ resolve(result)
421
+ })
422
+ }
423
+ })
424
+ })
425
+ }
426
+
427
+ this.pubmedQueryOnModels = function (source) {
428
+ return this.flatmapQuery(
429
+ this.buildPubmedSqlStatementForModels(source)
430
+ ).then((data) => {
431
+ if (Array.isArray(data.values) && data.values.length > 0) {
432
+ this.urls = [
433
+ this.pubmedSearchUrl(
434
+ data.values.map((id) => this.stripPMIDPrefix(id[0]))
435
+ ),
436
+ ]
437
+ return true
438
+ } else {
439
+ this.urls = [] // Clears the pubmed search button
440
+ }
441
+ return false
442
+ })
443
+ }
444
+
445
+ this.pubmedSearchUrl = function (ids) {
446
+ let url = 'https://pubmed.ncbi.nlm.nih.gov/?'
447
+ let params = new URLSearchParams()
448
+ params.append('term', ids)
449
+ return url + params.toString()
450
+ }
451
+ }
452
+
453
+ export { FlatmapQueries, findTaxonomyLabel }