@abi-software/map-utilities 1.6.0-beta.1 → 1.6.1-beta.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
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Competency Queries
|
|
3
|
+
*
|
|
4
|
+
* competencyQuery: base function
|
|
5
|
+
* query[functionName]: specific queries
|
|
6
|
+
*
|
|
7
|
+
* Note: use named-export for better tree-shaking.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
async function postRequest(API_URL, payload) {
|
|
11
|
+
try {
|
|
12
|
+
const response = await fetch(API_URL, {
|
|
13
|
+
method: "POST",
|
|
14
|
+
headers: {
|
|
15
|
+
"Content-Type": "application/json",
|
|
16
|
+
},
|
|
17
|
+
body: JSON.stringify(payload),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
throw new Error(`API Error: ${response.status} ${response.statusText}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return await response.json();
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error("Request failed:", error);
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Competency Query
|
|
33
|
+
*
|
|
34
|
+
* @param {Object} options - Query options.
|
|
35
|
+
* @param {string} options.flatmapAPI - Base URL of the flatmap server.
|
|
36
|
+
* @param {string} options.knowledgeSource - SCKAN source ID.
|
|
37
|
+
* @param {string} options.queryId - Competency query ID.
|
|
38
|
+
* @param {Array} options.parameters - Parameters specific to the query.
|
|
39
|
+
* @param {string} [options.orderId] - Optional order ID for sorting.
|
|
40
|
+
* @returns {Promise<any>} - JSON response.
|
|
41
|
+
*/
|
|
42
|
+
async function competencyQuery(options) {
|
|
43
|
+
const { flatmapAPI, knowledgeSource, queryId, parameters, orderId } = options;
|
|
44
|
+
const API_URL = `${flatmapAPI}competency/query`;
|
|
45
|
+
|
|
46
|
+
const params = Array.isArray(parameters) ? [...parameters] : [];
|
|
47
|
+
|
|
48
|
+
params.push({
|
|
49
|
+
"column": "source_id",
|
|
50
|
+
"value": knowledgeSource,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
let queryIdStr;
|
|
54
|
+
if (typeof queryId === 'number') {
|
|
55
|
+
queryIdStr = queryId.toString();
|
|
56
|
+
} else if (typeof queryId === 'string') {
|
|
57
|
+
queryIdStr = queryId;
|
|
58
|
+
} else {
|
|
59
|
+
throw new TypeError('queryId must be a string or a number convertible to string.');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const payload = {
|
|
63
|
+
"query_id": queryIdStr,
|
|
64
|
+
"parameters": params,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Currently only query 12 has an order parameter
|
|
68
|
+
if (orderId) {
|
|
69
|
+
payload.order = [orderId];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return postRequest(API_URL, payload);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Neuron populations associated with a location [query id => 1] (or)
|
|
76
|
+
// Neuron populations that share at least one edge with another neuron population [query id => 23]
|
|
77
|
+
async function queryAllConnectedPaths(flatmapAPI, knowledgeSource, featureId) {
|
|
78
|
+
const featureIds = Array.isArray(featureId) ? featureId : [featureId];
|
|
79
|
+
const queryId = featureIds[0].startsWith('ilxtr:') ? 23 : 1;
|
|
80
|
+
const data = await competencyQuery({
|
|
81
|
+
flatmapAPI: flatmapAPI,
|
|
82
|
+
knowledgeSource: knowledgeSource,
|
|
83
|
+
queryId: queryId,
|
|
84
|
+
parameters: [
|
|
85
|
+
{
|
|
86
|
+
column: 'feature_id',
|
|
87
|
+
value: featureIds
|
|
88
|
+
},
|
|
89
|
+
]
|
|
90
|
+
});
|
|
91
|
+
if (data?.results?.values) {
|
|
92
|
+
const paths = data.results.values.map((value) => {
|
|
93
|
+
// value => [ 'source_id', 'path_id', 'axon_terminal']
|
|
94
|
+
return value[1];
|
|
95
|
+
});
|
|
96
|
+
// remove duplicates
|
|
97
|
+
return [...new Set(paths)];
|
|
98
|
+
}
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Neuron populations beginning at a location
|
|
103
|
+
async function queryPathsByOrigin(flatmapAPI, knowledgeSource, featureId) {
|
|
104
|
+
const data = await competencyQuery({
|
|
105
|
+
flatmapAPI: flatmapAPI,
|
|
106
|
+
knowledgeSource: knowledgeSource,
|
|
107
|
+
queryId: 1, // TODO: to update to a specific query ID for origins
|
|
108
|
+
parameters: [
|
|
109
|
+
{
|
|
110
|
+
column: 'feature_id',
|
|
111
|
+
value: featureId
|
|
112
|
+
},
|
|
113
|
+
]
|
|
114
|
+
});
|
|
115
|
+
if (data?.results?.values) {
|
|
116
|
+
const paths = data.results.values.map((value) => {
|
|
117
|
+
// value => [ 'source_id', 'path_id', 'axon_terminal']
|
|
118
|
+
return value[1];
|
|
119
|
+
});
|
|
120
|
+
// remove duplicates
|
|
121
|
+
return [...new Set(paths)];
|
|
122
|
+
}
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Neuron populations via a location
|
|
127
|
+
async function queryPathsByViaLocation(flatmapAPI, knowledgeSource, featureId) {
|
|
128
|
+
const data = await competencyQuery({
|
|
129
|
+
flatmapAPI: flatmapAPI,
|
|
130
|
+
knowledgeSource: knowledgeSource,
|
|
131
|
+
queryId: 1, // TODO: to update to a specific query ID for via
|
|
132
|
+
parameters: [
|
|
133
|
+
{
|
|
134
|
+
column: 'feature_id',
|
|
135
|
+
value: featureId
|
|
136
|
+
},
|
|
137
|
+
]
|
|
138
|
+
});
|
|
139
|
+
if (data?.results?.values) {
|
|
140
|
+
const paths = data.results.values.map((value) => {
|
|
141
|
+
// value => [ 'source_id', 'path_id', 'axon_terminal']
|
|
142
|
+
return value[1];
|
|
143
|
+
});
|
|
144
|
+
// remove duplicates
|
|
145
|
+
return [...new Set(paths)];
|
|
146
|
+
}
|
|
147
|
+
return [];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Neuron populations terminating at a location
|
|
151
|
+
async function queryPathsByDestination(flatmapAPI, knowledgeSource, featureId) {
|
|
152
|
+
const data = await competencyQuery({
|
|
153
|
+
flatmapAPI: flatmapAPI,
|
|
154
|
+
knowledgeSource: knowledgeSource,
|
|
155
|
+
queryId: 2,
|
|
156
|
+
parameters: [
|
|
157
|
+
{
|
|
158
|
+
column: 'feature_id',
|
|
159
|
+
value: featureId
|
|
160
|
+
},
|
|
161
|
+
]
|
|
162
|
+
});
|
|
163
|
+
if (data?.results?.values) {
|
|
164
|
+
const paths = data.results.values.map((value) => {
|
|
165
|
+
// value => [ 'source_id', 'path_id', 'axon_terminal']
|
|
166
|
+
return value[1];
|
|
167
|
+
});
|
|
168
|
+
// remove duplicates
|
|
169
|
+
return [...new Set(paths)];
|
|
170
|
+
}
|
|
171
|
+
return [];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export {
|
|
175
|
+
competencyQuery,
|
|
176
|
+
queryAllConnectedPaths,
|
|
177
|
+
queryPathsByOrigin,
|
|
178
|
+
queryPathsByViaLocation,
|
|
179
|
+
queryPathsByDestination,
|
|
180
|
+
};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// origins = ilxtr:hasSomaLocatedIn
|
|
2
|
+
// destinations = ilxtr:hasAxonPresynapticElementIn, ilxtr:hasAxonSensorySubcellularElementIn
|
|
3
|
+
// via = ilxtr:hasAxonLeadingToSensorySubcellularElementIn, ilxtr:hasAxonLocatedIn
|
|
4
|
+
|
|
5
|
+
function filterOrigins(item) {
|
|
6
|
+
const soma = item["node-phenotypes"]?.["ilxtr:hasSomaLocatedIn"];
|
|
7
|
+
return Array.isArray(item.connectivity) &&
|
|
8
|
+
item.connectivity.length > 0 &&
|
|
9
|
+
Array.isArray(soma) &&
|
|
10
|
+
soma.length > 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function filterDestinations(item) {
|
|
14
|
+
const axonPresyn = item["node-phenotypes"]?.["ilxtr:hasAxonPresynapticElementIn"];
|
|
15
|
+
const axonSensory = item["node-phenotypes"]?.["ilxtr:hasAxonSensorySubcellularElementIn"];
|
|
16
|
+
const hasDest =
|
|
17
|
+
(Array.isArray(axonPresyn) && axonPresyn.length > 0) ||
|
|
18
|
+
(Array.isArray(axonSensory) && axonSensory.length > 0);
|
|
19
|
+
return Array.isArray(item.connectivity) &&
|
|
20
|
+
item.connectivity.length > 0 &&
|
|
21
|
+
hasDest;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function filterViaLocations(item) {
|
|
25
|
+
if (!Array.isArray(item.connectivity) || item.connectivity.length === 0) return false;
|
|
26
|
+
|
|
27
|
+
const origins = new Set(
|
|
28
|
+
(item["node-phenotypes"]?.["ilxtr:hasSomaLocatedIn"] || []).map(arr => arr[0])
|
|
29
|
+
);
|
|
30
|
+
const destinations = new Set([
|
|
31
|
+
...((item["node-phenotypes"]?.["ilxtr:hasAxonPresynapticElementIn"] || []).map(arr => arr[0])),
|
|
32
|
+
...((item["node-phenotypes"]?.["ilxtr:hasAxonSensorySubcellularElementIn"] || []).map(arr => arr[0]))
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
return item.connectivity.some(pair => {
|
|
36
|
+
const [from, to] = pair;
|
|
37
|
+
const fromId = from[0];
|
|
38
|
+
const toId = to[0];
|
|
39
|
+
return (
|
|
40
|
+
!origins.has(fromId) &&
|
|
41
|
+
!destinations.has(toId)
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getConnectivityItems(obj) {
|
|
47
|
+
if (!Array.isArray(obj.connectivity)) return [];
|
|
48
|
+
const items = new Set();
|
|
49
|
+
|
|
50
|
+
obj.connectivity.forEach((pair) => {
|
|
51
|
+
if (Array.isArray(pair) && pair.length) {
|
|
52
|
+
pair.forEach((endpoint) => {
|
|
53
|
+
if (Array.isArray(endpoint) && typeof endpoint[0] === 'string') {
|
|
54
|
+
const stringifyEndpoint = JSON.stringify(endpoint);
|
|
55
|
+
items.add(stringifyEndpoint);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
return Array.from(items);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getPhenotypeItems(obj, prop) {
|
|
64
|
+
const arr = obj["node-phenotypes"]?.[prop];
|
|
65
|
+
if (!Array.isArray(arr)) return [];
|
|
66
|
+
return arr;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function extractOriginItems(knowledge) {
|
|
70
|
+
const results = [];
|
|
71
|
+
knowledge.forEach(obj => {
|
|
72
|
+
if (!Array.isArray(obj.connectivity) || obj.connectivity.length === 0) return;
|
|
73
|
+
const connectivityItems = new Set(getConnectivityItems(obj));
|
|
74
|
+
getPhenotypeItems(obj, "ilxtr:hasSomaLocatedIn").forEach((item) => {
|
|
75
|
+
const stringifyItem = JSON.stringify(item);
|
|
76
|
+
if (connectivityItems.has(stringifyItem)) results.push(item);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
return Array.from(
|
|
80
|
+
new Map(results.map(item => [JSON.stringify(item), item])).values()
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function extractDestinationItems(knowledge) {
|
|
85
|
+
const results = [];
|
|
86
|
+
knowledge.forEach(obj => {
|
|
87
|
+
if (!Array.isArray(obj.connectivity) || obj.connectivity.length === 0) return;
|
|
88
|
+
const connectivityItems = new Set(getConnectivityItems(obj));
|
|
89
|
+
[
|
|
90
|
+
...getPhenotypeItems(obj, "ilxtr:hasAxonPresynapticElementIn"),
|
|
91
|
+
...getPhenotypeItems(obj, "ilxtr:hasAxonSensorySubcellularElementIn")
|
|
92
|
+
].forEach(item => {
|
|
93
|
+
const stringifyItem = JSON.stringify(item);
|
|
94
|
+
if (connectivityItems.has(stringifyItem)) results.push(item);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
return Array.from(
|
|
98
|
+
new Map(results.map(item => [JSON.stringify(item), item])).values()
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function extractViaItems(knowledge) {
|
|
103
|
+
const results = [];
|
|
104
|
+
knowledge.forEach(obj => {
|
|
105
|
+
if (!Array.isArray(obj.connectivity) || obj.connectivity.length === 0) return;
|
|
106
|
+
const connectivityItems = new Set(getConnectivityItems(obj));
|
|
107
|
+
[
|
|
108
|
+
...getPhenotypeItems(obj, "ilxtr:hasAxonLeadingToSensorySubcellularElementIn"),
|
|
109
|
+
...getPhenotypeItems(obj, "ilxtr:hasAxonLocatedIn")
|
|
110
|
+
].forEach(item => {
|
|
111
|
+
const stringifyItem = JSON.stringify(item);
|
|
112
|
+
if (connectivityItems.has(stringifyItem)) results.push(item);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
return Array.from(
|
|
116
|
+
new Map(results.map(item => [JSON.stringify(item), item])).values()
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function findPathsByOriginItem(knowledge, originItem) {
|
|
121
|
+
return knowledge.filter(obj => {
|
|
122
|
+
if (!Array.isArray(obj.connectivity) || obj.connectivity.length === 0) return false;
|
|
123
|
+
const origins = getPhenotypeItems(obj, "ilxtr:hasSomaLocatedIn");
|
|
124
|
+
return origins.some(item => JSON.stringify(item) === JSON.stringify(originItem));
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function findPathsByDestinationItem(knowledge, destinationItem) {
|
|
129
|
+
return knowledge.filter(obj => {
|
|
130
|
+
if (!Array.isArray(obj.connectivity) || obj.connectivity.length === 0) return false;
|
|
131
|
+
const destinations = [
|
|
132
|
+
...getPhenotypeItems(obj, "ilxtr:hasAxonPresynapticElementIn"),
|
|
133
|
+
...getPhenotypeItems(obj, "ilxtr:hasAxonSensorySubcellularElementIn")
|
|
134
|
+
];
|
|
135
|
+
return destinations.some(item => JSON.stringify(item) === JSON.stringify(destinationItem));
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function findPathsByViaItem(knowledge, viaItem) {
|
|
140
|
+
return knowledge.filter(obj => {
|
|
141
|
+
if (!Array.isArray(obj.connectivity) || obj.connectivity.length === 0) return false;
|
|
142
|
+
const vias = [
|
|
143
|
+
...getPhenotypeItems(obj, "ilxtr:hasAxonLeadingToSensorySubcellularElementIn"),
|
|
144
|
+
...getPhenotypeItems(obj, "ilxtr:hasAxonLocatedIn")
|
|
145
|
+
];
|
|
146
|
+
return vias.some(item => JSON.stringify(item) === JSON.stringify(viaItem));
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export {
|
|
151
|
+
filterOrigins,
|
|
152
|
+
filterDestinations,
|
|
153
|
+
filterViaLocations,
|
|
154
|
+
extractOriginItems,
|
|
155
|
+
extractDestinationItems,
|
|
156
|
+
extractViaItems,
|
|
157
|
+
findPathsByOriginItem,
|
|
158
|
+
findPathsByDestinationItem,
|
|
159
|
+
findPathsByViaItem,
|
|
160
|
+
}
|
package/src/components/index.js
CHANGED
|
@@ -8,6 +8,24 @@ import HelpModeDialog from "./HelpModeDialog/HelpModeDialog.vue";
|
|
|
8
8
|
import Tooltip from "./Tooltip/Tooltip.vue";
|
|
9
9
|
import TreeControls from "./TreeControls/TreeControls.vue";
|
|
10
10
|
import ExternalResourceCard from "./Tooltip/ExternalResourceCard.vue";
|
|
11
|
+
import {
|
|
12
|
+
competencyQuery,
|
|
13
|
+
queryAllConnectedPaths,
|
|
14
|
+
queryPathsByOrigin,
|
|
15
|
+
queryPathsByViaLocation,
|
|
16
|
+
queryPathsByDestination,
|
|
17
|
+
} from "./CompetencyQueries/CompetencyQueries.js";
|
|
18
|
+
import {
|
|
19
|
+
filterOrigins,
|
|
20
|
+
filterDestinations,
|
|
21
|
+
filterViaLocations,
|
|
22
|
+
extractOriginItems,
|
|
23
|
+
extractDestinationItems,
|
|
24
|
+
extractViaItems,
|
|
25
|
+
findPathsByOriginItem,
|
|
26
|
+
findPathsByDestinationItem,
|
|
27
|
+
findPathsByViaItem,
|
|
28
|
+
} from "./CompetencyQueries/knowledgeQueries.js";
|
|
11
29
|
|
|
12
30
|
export {
|
|
13
31
|
AnnotationPopup,
|
|
@@ -20,4 +38,18 @@ export {
|
|
|
20
38
|
Tooltip,
|
|
21
39
|
TreeControls,
|
|
22
40
|
ExternalResourceCard,
|
|
41
|
+
competencyQuery,
|
|
42
|
+
queryAllConnectedPaths,
|
|
43
|
+
queryPathsByOrigin,
|
|
44
|
+
queryPathsByViaLocation,
|
|
45
|
+
queryPathsByDestination,
|
|
46
|
+
filterOrigins,
|
|
47
|
+
filterDestinations,
|
|
48
|
+
filterViaLocations,
|
|
49
|
+
extractOriginItems,
|
|
50
|
+
extractDestinationItems,
|
|
51
|
+
extractViaItems,
|
|
52
|
+
findPathsByOriginItem,
|
|
53
|
+
findPathsByDestinationItem,
|
|
54
|
+
findPathsByViaItem,
|
|
23
55
|
};
|