Skip to content

Commit 4f2b50d

Browse files
authored
Merge pull request #117 from liuzhenqi77/add-nav
2 parents 3dabd58 + c51168c commit 4f2b50d

File tree

1 file changed

+142
-0
lines changed

1 file changed

+142
-0
lines changed

netneurotools/metrics.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from the Brain Connectivity Toolbox (https://sites.google.com/site/bctnet/).
55
"""
66

7+
import itertools
78
import numpy as np
89
from scipy.linalg import expm
910
from scipy.stats import ttest_ind
@@ -184,3 +185,144 @@ def rich_feeder_peripheral(x, sc, stat='median'):
184185
equal_var=False, alternative='greater')
185186

186187
return rfp, pvals
188+
189+
190+
def navigation_wu(nav_dist_mat, sc_mat):
191+
"""
192+
Computes network navigation
193+
194+
Parameters
195+
----------
196+
nav_dist_mat : (N, N) array_like
197+
Connection length/distance matrix.
198+
sc_mat : (N, N) array_like
199+
Structural connectivity matrix, only used to get connectedness.
200+
201+
Returns
202+
-------
203+
nav_sr : float
204+
Overall navigation success rate
205+
nav_sr_node : list of float
206+
Nodal navigation success rate
207+
nav_path_len : (N, N) array_like
208+
Navigation path length matrix, infinite if no path exists.
209+
nav_path_hop : (N, N) array_like
210+
Navigation path hop matrix, infinite if no path exists.
211+
nav_paths : list
212+
List of tuples containing source node, target node, path length,
213+
path hops, and the full path.
214+
215+
References
216+
----------
217+
Seguin, C., Van Den Heuvel, M. P., & Zalesky, A. (2018). Navigation
218+
of brain networks. Proceedings of the National Academy of Sciences,
219+
115(24), 6297-6302.
220+
221+
Notes
222+
-----
223+
Euclidean distance between nodes are usually used for `nav_dist_mat`.
224+
Distances returned from this function are also calculated from
225+
`nav_dist_mat`.
226+
Use :meth:`netneurotools.metrics.get_navigation_path_length`
227+
to get path length in other metrics.
228+
229+
See Also
230+
--------
231+
netneurotools.metrics.get_navigation_path_length
232+
"""
233+
234+
nav_paths = [] # (source, target, distance, hops, path)
235+
# navigate to the node that is closest to target
236+
for src in range(len(nav_dist_mat)):
237+
for tar in range(len(nav_dist_mat)):
238+
curr_pos = src
239+
curr_path = [src]
240+
curr_dist = 0
241+
while curr_pos != tar:
242+
neig = np.where(sc_mat[curr_pos, :] != 0)[0]
243+
if len(neig) == 0: # not connected
244+
curr_path = []
245+
curr_dist = np.inf
246+
break
247+
neig_dist_to_tar = nav_dist_mat[neig, tar]
248+
min_dist_idx = np.argmin(neig_dist_to_tar)
249+
250+
new_pos = neig[min_dist_idx]
251+
# Assume it is connected, and only testing for loops.
252+
# if isempty(next_node)
253+
# || next_node == last_node
254+
# || pl_bin > max_hops
255+
if (new_pos in curr_path):
256+
curr_path = []
257+
curr_dist = np.inf
258+
break
259+
else:
260+
curr_path.append(new_pos)
261+
curr_dist += nav_dist_mat[curr_pos, new_pos]
262+
curr_pos = new_pos
263+
nav_paths.append(
264+
(src, tar, curr_dist, len(curr_path) - 1, curr_path))
265+
266+
nav_sr = len([_ for _ in nav_paths if _[3] != -1]) / len(nav_paths)
267+
268+
nav_sr_node = []
269+
for k, g in itertools.groupby(
270+
sorted(nav_paths, key=lambda x: x[0]), key=lambda x: x[0]
271+
):
272+
curr_path = list(g)
273+
nav_sr_node.append(
274+
len([_ for _ in curr_path if _[3] != -1]) / len(curr_path))
275+
276+
nav_path_len = np.zeros_like(nav_dist_mat)
277+
nav_path_hop = np.zeros_like(nav_dist_mat)
278+
for nav_item in nav_paths:
279+
i, j, length, hop, _ = nav_item
280+
if hop != -1:
281+
nav_path_len[i, j] = length
282+
nav_path_hop[i, j] = hop
283+
else:
284+
nav_path_len[i, j] = np.inf
285+
nav_path_hop[i, j] = np.inf
286+
287+
return nav_sr, nav_sr_node, nav_path_len, nav_path_hop, nav_paths
288+
289+
290+
def get_navigation_path_length(nav_paths, alt_dist_mat):
291+
"""
292+
Get navigation path length from navigation results
293+
294+
Parameters
295+
----------
296+
nav_paths : list
297+
Return from netneurotools.metrics.navigation_wu
298+
alt_dist_mat : (N, N) array_like
299+
Alternative distance matrix, e.g. geodesic distance.
300+
301+
Returns
302+
-------
303+
nav_path_len : (N, N) array_like
304+
Navigation path length matrix, in the alternative distance metric.
305+
306+
Notes
307+
-----
308+
Following the original BCT function.
309+
`pl_wei = get_navigation_path_length(nav_paths, L)`
310+
L is strength-to-length remapping of the connection weight matrix.
311+
`pl_dis = get_navigation_path_length(nav_paths, D)`
312+
D is Euclidean distance between node centroids.
313+
314+
See Also
315+
--------
316+
netneurotools.metrics.navigation_wu
317+
"""
318+
319+
nav_path_len = np.zeros_like(alt_dist_mat)
320+
for nav_item in nav_paths:
321+
i, j, _, hop, path = nav_item
322+
if hop != -1:
323+
nav_path_len[i, j] = np.sum(
324+
[alt_dist_mat[path[_], path[_ + 1]] for _ in range(hop)]
325+
)
326+
else:
327+
nav_path_len[i, j] = np.inf
328+
return nav_path_len

0 commit comments

Comments
 (0)