@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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abi-software/map-utilities",
3
- "version": "1.6.0-beta.1",
3
+ "version": "1.6.1-beta.0",
4
4
  "files": [
5
5
  "dist/*",
6
6
  "src/*",
@@ -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
+ }
@@ -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
  };