|
8 | 8 | import re |
9 | 9 | from collections import defaultdict |
10 | 10 | from colorsys import hsv_to_rgb, rgb_to_hsv |
| 11 | +from pathlib import Path |
11 | 12 |
|
12 | 13 | import numpy as np |
13 | 14 | from scipy import linalg |
14 | 15 |
|
| 16 | +from ._freesurfer import get_volume_labels_from_aseg |
15 | 17 | from .fixes import _safe_svd |
16 | 18 | from .morph_map import read_morph_map |
17 | 19 | from .parallel import parallel_func |
18 | 20 | from .source_estimate import ( |
19 | 21 | SourceEstimate, |
20 | 22 | VolSourceEstimate, |
21 | 23 | _center_of_mass, |
| 24 | + _volume_labels, |
22 | 25 | extract_label_time_course, |
23 | 26 | spatial_src_adjacency, |
24 | 27 | ) |
@@ -3043,3 +3046,130 @@ def select_sources( |
3043 | 3046 | ) |
3044 | 3047 |
|
3045 | 3048 | return new_label |
| 3049 | + |
| 3050 | + |
| 3051 | +def label_adjacency(labels, src): |
| 3052 | + """Compute adjacency between labels. |
| 3053 | +
|
| 3054 | + Two labels are considered adjacent if one of their vertices are adjacent in the |
| 3055 | + source space. |
| 3056 | +
|
| 3057 | + Parameters |
| 3058 | + ---------- |
| 3059 | + labels : list of mne.Label |
| 3060 | + The labels between which to compute adjacency. |
| 3061 | + src : mne.SourceSpaces |
| 3062 | + The source space on which the labels are defined. |
| 3063 | +
|
| 3064 | + Returns |
| 3065 | + ------- |
| 3066 | + label_adjacency : scipy.sparse.coo_matrix |
| 3067 | + A sparse adjacency matrix containing a 1 for labels that are adjacent and 0 |
| 3068 | + otherwise. |
| 3069 | +
|
| 3070 | + See Also |
| 3071 | + -------- |
| 3072 | + volume_label_adjacency |
| 3073 | +
|
| 3074 | + Notes |
| 3075 | + ----- |
| 3076 | + .. versionadded:: 1.13 |
| 3077 | + """ |
| 3078 | + from scipy.sparse import coo_matrix |
| 3079 | + |
| 3080 | + src_adjacency = spatial_src_adjacency(src).tocsr() |
| 3081 | + label_src_ind = list() |
| 3082 | + for label in labels: |
| 3083 | + src_hemi = src[0] if label.hemi == "lh" else src[1] |
| 3084 | + label_verts = label.get_vertices_used(src_hemi["vertno"]) |
| 3085 | + src_ind = np.searchsorted(src_hemi["vertno"], label_verts) |
| 3086 | + if label.hemi == "rh": |
| 3087 | + src_ind += src[0]["nuse"] |
| 3088 | + label_src_ind.append(src_ind) |
| 3089 | + |
| 3090 | + adjacent_label_inds = list() # list of pairs of label indices |
| 3091 | + for ind1, label1 in enumerate(labels): |
| 3092 | + for ind2, label2 in enumerate(labels): |
| 3093 | + # If the labels are on different hemispheres, they are not adjacent. |
| 3094 | + if label1.hemi != label2.hemi: |
| 3095 | + continue |
| 3096 | + |
| 3097 | + # Get adjacent vertices if any. |
| 3098 | + adj_verts = src_adjacency[label_src_ind[ind1], :][:, label_src_ind[ind2]] |
| 3099 | + if adj_verts.data.any(): |
| 3100 | + adjacent_label_inds.append((ind1, ind2)) |
| 3101 | + return coo_matrix( |
| 3102 | + (np.ones(len(adjacent_label_inds)), tuple(zip(*adjacent_label_inds))), |
| 3103 | + shape=(len(labels), len(labels)), |
| 3104 | + ) |
| 3105 | + |
| 3106 | + |
| 3107 | +@fill_doc |
| 3108 | +def volume_label_adjacency(src, subject, subjects_dir, *, aseg="auto", labels=None): |
| 3109 | + """Compute adjacency between volume labels. |
| 3110 | +
|
| 3111 | + Two labels are considered adjacent if one of their voxels are adjacent in the |
| 3112 | + (volumetric) source space. |
| 3113 | +
|
| 3114 | + Parameters |
| 3115 | + ---------- |
| 3116 | + src : mne.SourceSpaces |
| 3117 | + The volumetric source space on which the labels are defined. |
| 3118 | + %(subject)s |
| 3119 | + %(subjects_dir)s |
| 3120 | + %(aseg)s |
| 3121 | + %(labels_aseg)s |
| 3122 | +
|
| 3123 | + Returns |
| 3124 | + ------- |
| 3125 | + label_adjacency : scipy.sparse.coo_matrix |
| 3126 | + A sparse adjacency matrix containing a 1 for labels that are adjacent and 0 |
| 3127 | + otherwise. |
| 3128 | + labels : list of str |
| 3129 | + The names of the labels which contain at least one source point. |
| 3130 | +
|
| 3131 | + See Also |
| 3132 | + -------- |
| 3133 | + label_adjacency |
| 3134 | +
|
| 3135 | + Notes |
| 3136 | + ----- |
| 3137 | + .. versionadded:: 1.13 |
| 3138 | + """ |
| 3139 | + from scipy import sparse |
| 3140 | + |
| 3141 | + subjects_dir = Path(get_subjects_dir(subjects_dir, raise_error=True)) |
| 3142 | + if aseg == "auto": # use aparc+aseg if auto |
| 3143 | + aseg = _check_fname( |
| 3144 | + subjects_dir / subject / "mri" / "aparc+aseg.mgz", |
| 3145 | + overwrite="read", |
| 3146 | + must_exist=False, |
| 3147 | + ) |
| 3148 | + if not aseg: # if doesn't exist use wmparc |
| 3149 | + aseg = subjects_dir / subject / "mri" / "wmparc.mgz" |
| 3150 | + else: |
| 3151 | + aseg = subjects_dir / subject / "mri" / f"{aseg}.mgz" |
| 3152 | + |
| 3153 | + if labels is None: |
| 3154 | + labels = get_volume_labels_from_aseg(aseg) |
| 3155 | + |
| 3156 | + vol_labels = _volume_labels(src, (aseg, labels), mri_resolution=False) |
| 3157 | + src_adjacency = spatial_src_adjacency(src).tocsr() |
| 3158 | + |
| 3159 | + label_verts = list() |
| 3160 | + for label in vol_labels: |
| 3161 | + label_verts.append(np.searchsorted(src[0]["vertno"], label.vertices)) |
| 3162 | + |
| 3163 | + adjacent_label_inds = list() # list of pairs of label indices |
| 3164 | + for ind1, verts1 in enumerate(label_verts): |
| 3165 | + for ind2, verts2 in enumerate(label_verts): |
| 3166 | + # Get adjacent vertices if any. |
| 3167 | + adj_verts = src_adjacency[verts1, :][:, verts2] |
| 3168 | + if adj_verts.data.any(): |
| 3169 | + adjacent_label_inds.append((ind1, ind2)) |
| 3170 | + |
| 3171 | + adj = sparse.coo_matrix( |
| 3172 | + (np.ones(len(adjacent_label_inds)), tuple(zip(*adjacent_label_inds))), |
| 3173 | + shape=(len(labels), len(labels)), |
| 3174 | + ) |
| 3175 | + return adj, labels |
0 commit comments