def test_grow_labels(): """Test generation of circular source labels.""" seeds = [0, 50000] # these were chosen manually in mne_analyze should_be_in = [[49, 227], [51207, 48794]] hemis = [0, 1] names = ['aneurism', 'tumor'] labels = grow_labels('sample', seeds, 3, hemis, subjects_dir, names=names) tgt_names = ['aneurism-lh', 'tumor-rh'] tgt_hemis = ['lh', 'rh'] for label, seed, hemi, sh, name in zip(labels, seeds, tgt_hemis, should_be_in, tgt_names): assert (np.any(label.vertices == seed)) assert (np.all(np.in1d(sh, label.vertices))) assert_equal(label.hemi, hemi) assert_equal(label.name, name) # grow labels with and without overlap seeds = [57532, [58887, 6304]] l01, l02 = grow_labels('fsaverage', seeds, 20, [0, 0], subjects_dir) seeds = [57532, [58887, 6304]] l11, l12 = grow_labels('fsaverage', seeds, 20, [0, 0], subjects_dir, overlap=False) # test label naming assert_equal(l01.name, 'Label_0-lh') assert_equal(l02.name, 'Label_1-lh') assert_equal(l11.name, 'Label_0-lh') assert_equal(l12.name, 'Label_1-lh') # test color assignment l11_c, l12_c = grow_labels('fsaverage', seeds, 20, [0, 0], subjects_dir, overlap=False, colors=None) assert_equal(l11_c.color, _n_colors(2)[0]) assert_equal(l12_c.color, _n_colors(2)[1]) lab_colors = np.array([[0, 0, 1, 1], [1, 0, 0, 1]]) l11_c, l12_c = grow_labels('fsaverage', seeds, 20, [0, 0], subjects_dir, overlap=False, colors=lab_colors) assert_array_equal(l11_c.color, lab_colors[0, :]) assert_array_equal(l12_c.color, lab_colors[1, :]) lab_colors = np.array([.1, .2, .3, .9]) l11_c, l12_c = grow_labels('fsaverage', seeds, 20, [0, 0], subjects_dir, overlap=False, colors=lab_colors) assert_array_equal(l11_c.color, lab_colors) assert_array_equal(l12_c.color, lab_colors) # make sure set 1 does not overlap overlap = np.intersect1d(l11.vertices, l12.vertices, True) assert_array_equal(overlap, []) # make sure both sets cover the same vertices l0 = l01 + l02 l1 = l11 + l12 assert_array_equal(l1.vertices, l0.vertices)
def labels_from_clusters(clusters, names=None): """Create Labels from source space clusters Parameters ---------- clusters : NDVar NDVar which is non-zero on the cluster. Can have a case dimension, but does not have to. names : None | list of str | str Label names corresponding to clusters (default is "cluster%i"). Returns ------- labels : list of mne.Label One label for each cluster. """ from mne.label import _n_colors if isinstance(names, basestring): names = [names] source = clusters.source source_space = clusters.source.get_source_space() subject = source.subject collapse = tuple(dim for dim in clusters.dimnames if dim not in ('case', 'source')) clusters_index = clusters.any(collapse) if clusters_index.has_case: n_clusters = len(clusters) else: n_clusters = 1 clusters_index = (clusters_index,) if names is None: names = ("cluster%i" % i for i in xrange(n_clusters)) elif len(names) != n_clusters: err = "Number of names difference from number of clusters." raise ValueError(err) colors = _n_colors(n_clusters) labels = [] for cluster, color, name in izip(clusters_index, colors, names): lh_vertices = source.lh_vertno[cluster.x[:source.lh_n]] rh_vertices = source.rh_vertno[cluster.x[source.lh_n:]] if len(lh_vertices) and len(rh_vertices): lh = Label(lh_vertices, hemi='lh', name=name + '-lh', subject=subject, color=color).fill(source_space) rh = Label(rh_vertices, hemi='rh', name=name + '-rh', subject=subject, color=color).fill(source_space) label = BiHemiLabel(lh, rh, name, color) elif len(lh_vertices): label = Label(lh_vertices, hemi='lh', name=name + '-lh', subject=subject, color=color).fill(source_space) elif len(rh_vertices): label = Label(rh_vertices, hemi='rh', name=name + '-lh', subject=subject, color=color).fill(source_space) else: raise ValueError("Empty Cluster") labels.append(label) return labels
def labels_from_clusters(clusters, names=None): """Create Labels from source space clusters Parameters ---------- clusters : NDVar NDVar which is non-zero on the cluster. Can have a case dimension, but does not have to. names : None | list of str | str Label names corresponding to clusters (default is "cluster%i"). Returns ------- labels : list of mne.Label One label for each cluster. """ from mne.label import _n_colors if isinstance(names, str): names = [names] source = clusters.source source_space = clusters.source.get_source_space() subject = source.subject collapse = tuple(dim for dim in clusters.dimnames if dim not in ('case', 'source')) clusters_index = clusters.any(collapse) if clusters_index.has_case: n_clusters = len(clusters) else: n_clusters = 1 clusters_index = (clusters_index,) if names is None: names = ("cluster%i" % i for i in range(n_clusters)) elif len(names) != n_clusters: err = "Number of names difference from number of clusters." raise ValueError(err) colors = _n_colors(n_clusters) labels = [] for cluster, color, name in zip(clusters_index, colors, names): lh_vertices = source.lh_vertno[cluster.x[:source.lh_n]] rh_vertices = source.rh_vertno[cluster.x[source.lh_n:]] if len(lh_vertices) and len(rh_vertices): lh = Label(lh_vertices, hemi='lh', name=name + '-lh', subject=subject, color=color).fill(source_space) rh = Label(rh_vertices, hemi='rh', name=name + '-rh', subject=subject, color=color).fill(source_space) label = BiHemiLabel(lh, rh, name, color) elif len(lh_vertices): label = Label(lh_vertices, hemi='lh', name=name + '-lh', subject=subject, color=color).fill(source_space) elif len(rh_vertices): label = Label(rh_vertices, hemi='rh', name=name + '-lh', subject=subject, color=color).fill(source_space) else: raise ValueError("Empty Cluster") labels.append(label) return labels
def labels_from_clusters(clusters, names=None): """Create Labels from source space clusters Parameters ---------- clusters : NDVar NDVar which is non-zero on the cluster. Can have a case dimension. names : None | list of str | str Label names corresponding to clusters (default is "clusterX"). Returns ------- labels : list of mne.Label One label for each cluster. """ from mne.label import _n_colors source = clusters.source source_space = clusters.source.get_source_space() subject = source.subject if clusters.has_case: n_clusters = len(clusters) x = clusters.x else: n_clusters = 1 x = clusters.x[None, :] if isinstance(names, basestring) and n_clusters == 1: names = [names] elif names is None: names = ("cluster%i" % i for i in xrange(n_clusters)) elif len(names) != n_clusters: err = "Number of names difference from number of clusters." raise ValueError(err) colors = _n_colors(n_clusters) labels = [] for i, color, name in izip(xrange(n_clusters), colors, names): idx = (x[i] != 0) where = np.nonzero(idx)[0] src_in_lh = (where < source.lh_n) if np.all(src_in_lh): hemi = 'lh' hemi_vertices = source.lh_vertno elif np.any(src_in_lh): raise ValueError("Can't have clusters spanning both hemispheres") else: hemi = 'rh' hemi_vertices = source.rh_vertno where -= source.lh_n vertices = hemi_vertices[where] label = Label(vertices, hemi=hemi, name=name, subject=subject, color=color).fill(source_space) labels.append(label) return labels
def labels_from_clusters(clusters, names=None): """Create Labels from source space clusters Parameters ---------- clusters : NDVar NDVar which is non-zero on the cluster. Can have a case dimension. names : None | list of str | str Label names corresponding to clusters (default is "clusterX"). Returns ------- labels : list of mne.Label One label for each cluster. """ from mne.label import _n_colors source = clusters.source source_space = clusters.source.get_source_space() subject = source.subject if clusters.has_case: n_clusters = len(clusters) x = clusters.x else: n_clusters = 1 x = clusters.x[None, :] if isinstance(names, basestring) and n_clusters == 1: names = [names] elif names is None: names = ("cluster%i" % i for i in xrange(n_clusters)) elif len(names) != n_clusters: err = "Number of names difference from number of clusters." raise ValueError(err) colors = _n_colors(n_clusters) labels = [] for i, color, name in izip(xrange(n_clusters), colors, names): idx = (x[i] != 0) where = np.nonzero(idx)[0] src_in_lh = (where < source.lh_n) if np.all(src_in_lh): hemi = 'lh' hemi_vertices = source.lh_vertno elif np.any(src_in_lh): raise ValueError("Can't have clusters spanning both hemispheres") else: hemi = 'rh' hemi_vertices = source.rh_vertno where -= source.lh_n vertices = hemi_vertices[where] label = Label(vertices, hemi=hemi, name=name, subject=subject, color=color, src=source_space) labels.append(label) return labels
def _stc_to_label(stc, src, smooth, subjects_dir=None): """Compute a label from the non-zero sources in an stc object. Parameters ---------- stc : SourceEstimate The source estimates. src : SourceSpaces | str | None The source space over which the source estimates are defined. If it's a string it should the subject name (e.g. fsaverage). Can be None if stc.subject is not None. smooth : int Number of smoothing iterations. subjects_dir : str | None Path to SUBJECTS_DIR if it is not set in the environment. Returns ------- labels : list of Labels | list of list of Labels The generated labels. If connected is False, it returns a list of Labels (one per hemisphere). If no Label is available in a hemisphere, None is returned. If connected is True, it returns for each hemisphere a list of connected labels ordered in decreasing order depending of the maximum value in the stc. If no Label is available in an hemisphere, an empty list is returned. """ src = stc.subject if src is None else src if isinstance(src, string_types): subject = src else: subject = stc.subject if isinstance(src, string_types): subjects_dir = get_subjects_dir(subjects_dir) surf_path_from = op.join(subjects_dir, src, 'surf') rr_lh, tris_lh = read_surface(op.join(surf_path_from, 'lh.white')) rr_rh, tris_rh = read_surface(op.join(surf_path_from, 'rh.white')) rr = [rr_lh, rr_rh] tris = [tris_lh, tris_rh] else: if not isinstance(src, SourceSpaces): raise TypeError('src must be a string or a set of source spaces') if len(src) != 2: raise ValueError('source space should contain the 2 hemispheres') rr = [1e3 * src[0]['rr'], 1e3 * src[1]['rr']] tris = [src[0]['tris'], src[1]['tris']] labels = [] cnt = 0 for hemi_idx, (hemi, this_vertno, this_tris, this_rr) in enumerate( zip(['lh', 'rh'], stc.vertices, tris, rr)): this_data = stc.data[cnt:cnt + len(this_vertno)] e = mesh_edges(this_tris) e.data[e.data == 2] = 1 n_vertices = e.shape[0] e = e + sparse.eye(n_vertices, n_vertices) clusters = [this_vertno[np.any(this_data, axis=1)]] cnt += len(this_vertno) clusters = [c for c in clusters if len(c) > 0] if len(clusters) == 0: this_labels = None else: this_labels = [] colors = _n_colors(len(clusters)) for c, color in zip(clusters, colors): idx_use = c for k in range(smooth): e_use = e[:, idx_use] data1 = e_use * np.ones(len(idx_use)) idx_use = np.where(data1)[0] label = Label(idx_use, this_rr[idx_use], None, hemi, 'Label from stc', subject=subject, color=color) this_labels.append(label) this_labels = this_labels[0] labels.append(this_labels) return labels
def write_labels_to_annot(labels, subject=None, parc=None, overwrite=False, subjects_dir=None, annot_fname=None, colormap='hsv', hemi='both'): """Create a FreeSurfer annotation from a list of labels FIX: always write both hemispheres Parameters ---------- labels : list with instances of mne.Label The labels to create a parcellation from. subject : str | None The subject for which to write the parcellation for. parc : str | None The parcellation name to use. overwrite : bool Overwrite files if they already exist. subjects_dir : string, or None Path to SUBJECTS_DIR if it is not set in the environment. annot_fname : str | None Filename of the .annot file. If not None, only this file is written and 'parc' and 'subject' are ignored. colormap : str Colormap to use to generate label colors for labels that do not have a color specified. hemi : 'both' | 'lh' | 'rh' The hemisphere(s) for which to write *.annot files (only applies if annot_fname is not specified; default is 'both'). verbose : bool, str, int, or None If not None, override default verbose level (see mne.verbose). Notes ----- Vertices that are not covered by any of the labels are assigned to a label named "unknown". """ subjects_dir = get_subjects_dir(subjects_dir) # get the .annot filenames and hemispheres annot_fname, hemis = _get_annot_fname(annot_fname, subject, hemi, parc, subjects_dir) if not overwrite: for fname in annot_fname: if op.exists(fname): raise ValueError('File %s exists. Use "overwrite=True" to ' 'overwrite it' % fname) # prepare container for data to save: to_save = [] # keep track of issues found in the labels duplicate_colors = [] invalid_colors = [] overlap = [] no_color = (-1, -1, -1, -1) no_color_rgb = (-1, -1, -1) for hemi, fname in zip(hemis, annot_fname): hemi_labels = [label for label in labels if label.hemi == hemi] n_hemi_labels = len(hemi_labels) if n_hemi_labels == 0: ctab = np.empty((0, 4), dtype=np.int32) ctab_rgb = ctab[:, :3] else: hemi_labels.sort(key=lambda label: label.name) # convert colors to 0-255 RGBA tuples hemi_colors = [ no_color if label.color is None else tuple( int(round(255 * i)) for i in label.color) for label in hemi_labels ] ctab = np.array(hemi_colors, dtype=np.int32) ctab_rgb = ctab[:, :3] # make color dict (for annot ID, only R, G and B count) labels_by_color = defaultdict(list) for label, color in zip(hemi_labels, ctab_rgb): labels_by_color[tuple(color)].append(label.name) # check label colors for color, names in labels_by_color.items(): if color == no_color_rgb: continue if color == (0, 0, 0): # we cannot have an all-zero color, otherw. e.g. tksurfer # refuses to read the parcellation msg = ('At least one label contains a color with, "r=0, ' 'g=0, b=0" value. Some FreeSurfer tools may fail ' 'to read the parcellation') logger.warning(msg) if any(i > 255 for i in color): msg = ("%s: %s (%s)" % (color, ', '.join(names), hemi)) invalid_colors.append(msg) if len(names) > 1: msg = "%s: %s (%s)" % (color, ', '.join(names), hemi) duplicate_colors.append(msg) # replace None values (labels with unspecified color) if labels_by_color[no_color_rgb]: default_colors = _n_colors(n_hemi_labels, bytes_=True, cmap=colormap) safe_color_i = 0 # keep track of colors known to be in hemi_colors for i in xrange(n_hemi_labels): if ctab[i, 0] == -1: color = default_colors[i] # make sure to add no duplicate color while np.any(np.all(color[:3] == ctab_rgb, 1)): color = default_colors[safe_color_i] safe_color_i += 1 # assign the color ctab[i] = color # find number of vertices in surface if subject is not None and subjects_dir is not None: fpath = op.join(subjects_dir, subject, 'surf', '%s.white' % hemi) points, _ = read_surface(fpath) n_vertices = len(points) else: if len(hemi_labels) > 0: max_vert = max(np.max(label.vertices) for label in hemi_labels) n_vertices = max_vert + 1 else: n_vertices = 1 msg = (' Number of vertices in the surface could not be ' 'verified because the surface file could not be found; ' 'specify subject and subjects_dir parameters.') logger.warning(msg) # Create annot and color table array to write annot = np.empty(n_vertices, dtype=np.intp) annot[:] = -1 # create the annotation ids from the colors annot_id_coding = np.array((1, 2**8, 2**16)) annot_ids = list(np.sum(ctab_rgb * annot_id_coding, axis=1)) for label, annot_id in zip(hemi_labels, annot_ids): # make sure the label is not overwriting another label if np.any(annot[label.vertices] != -1): other_ids = set(annot[label.vertices]) other_ids.discard(-1) other_indices = (annot_ids.index(i) for i in other_ids) other_names = (hemi_labels[i].name for i in other_indices) other_repr = ', '.join(other_names) msg = "%s: %s overlaps %s" % (hemi, label.name, other_repr) overlap.append(msg) annot[label.vertices] = annot_id hemi_names = [label.name for label in hemi_labels] # Assign unlabeled vertices to an "unknown" label unlabeled = (annot == -1) if np.any(unlabeled): msg = ("Assigning %i unlabeled vertices to " "'unknown-%s'" % (unlabeled.sum(), hemi)) logger.info(msg) # find an unused color (try shades of gray first) for i in range(1, 257): if not np.any(np.all((i, i, i) == ctab_rgb, 1)): break if i < 256: color = (i, i, i, 0) else: err = ("Need one free shade of gray for 'unknown' label. " "Please modify your label colors, or assign the " "unlabeled vertices to another label.") raise ValueError(err) # find the id annot_id = np.sum(annot_id_coding * color[:3]) # update data to write annot[unlabeled] = annot_id ctab = np.vstack((ctab, color)) hemi_names.append("unknown") # convert to FreeSurfer alpha values ctab[:, 3] = 255 - ctab[:, 3] # remove hemi ending in names hemi_names = [ name[:-3] if name.endswith(hemi) else name for name in hemi_names ] to_save.append((fname, annot, ctab, hemi_names)) issues = [] if duplicate_colors: msg = ("Some labels have the same color values (all labels in one " "hemisphere must have a unique color):") duplicate_colors.insert(0, msg) issues.append('\n'.join(duplicate_colors)) if invalid_colors: msg = ("Some labels have invalid color values (all colors should be " "RGBA tuples with values between 0 and 1)") invalid_colors.insert(0, msg) issues.append('\n'.join(invalid_colors)) if overlap: msg = ("Some labels occupy vertices that are also occupied by one or " "more other labels. Each vertex can only be occupied by a " "single label in *.annot files.") overlap.insert(0, msg) issues.append('\n'.join(overlap)) if issues: raise ValueError('\n\n'.join(issues)) # write it for fname, annot, ctab, hemi_names in to_save: logger.info(' writing %d labels to %s' % (len(hemi_names), fname)) _write_annot(fname, annot, ctab, hemi_names) logger.info('[done]')
# Compute goodness of fit gof = _sesame.goodness_of_fit() print(' Goodness of fit with the recorded data: {0}%'.format( round(gof, 4) * 100)) ############################################################################### # Visualize amplitude of the estimated sources as function of time. est_n_dips = _sesame.est_n_dips[-1] est_locs = _sesame.est_locs[-1] times = evoked.times[_sesame.s_min:_sesame.s_max + 1] amplitude = np.array([ np.linalg.norm(_sesame.est_dip_moms[:, 3 * i_d:3 * (i_d + 1)], axis=1) for i_d in range(est_n_dips) ]) colors = _n_colors(est_n_dips) plt.figure() for idx, amp in enumerate(amplitude): plt.plot(times, 1e9 * amp, color=colors[idx], linewidth=2) plt.xlabel('Time (s)') plt.ylabel('Source amplitude (nAm)') plt.show() ############################################################################### # Visualize the posterior map of the dipoles' location # :math:`p(r| \textbf{y}, 2)` as an overlay onto the MRI. stc = _sesame.compute_stc(subject) peak_vertex, peak_time = stc.get_peak(vert_as_index=True, time_as_index=True) peak_pos = fwd['source_rr'][peak_vertex] peak_mri_pos = head_to_mri(peak_pos,
def write_labels_to_annot(labels, subject=None, parc=None, overwrite=False, subjects_dir=None, annot_fname=None, colormap='hsv', hemi='both'): """Create a FreeSurfer annotation from a list of labels FIX: always write both hemispheres Parameters ---------- labels : list with instances of mne.Label The labels to create a parcellation from. subject : str | None The subject for which to write the parcellation for. parc : str | None The parcellation name to use. overwrite : bool Overwrite files if they already exist. subjects_dir : string, or None Path to SUBJECTS_DIR if it is not set in the environment. annot_fname : str | None Filename of the .annot file. If not None, only this file is written and 'parc' and 'subject' are ignored. colormap : str Colormap to use to generate label colors for labels that do not have a color specified. hemi : 'both' | 'lh' | 'rh' The hemisphere(s) for which to write *.annot files (only applies if annot_fname is not specified; default is 'both'). verbose : bool, str, int, or None If not None, override default verbose level (see mne.verbose). Notes ----- Vertices that are not covered by any of the labels are assigned to a label named "unknown". """ subjects_dir = get_subjects_dir(subjects_dir) # get the .annot filenames and hemispheres annot_fname, hemis = _get_annot_fname(annot_fname, subject, hemi, parc, subjects_dir) if not overwrite: for fname in annot_fname: if op.exists(fname): raise ValueError('File %s exists. Use "overwrite=True" to ' 'overwrite it' % fname) # prepare container for data to save: to_save = [] # keep track of issues found in the labels duplicate_colors = [] invalid_colors = [] overlap = [] no_color = (-1, -1, -1, -1) no_color_rgb = (-1, -1, -1) for hemi, fname in zip(hemis, annot_fname): hemi_labels = [label for label in labels if label.hemi == hemi] n_hemi_labels = len(hemi_labels) if n_hemi_labels == 0: ctab = np.empty((0, 4), dtype=np.int32) ctab_rgb = ctab[:, :3] else: hemi_labels.sort(key=lambda label: label.name) # convert colors to 0-255 RGBA tuples hemi_colors = [no_color if label.color is None else tuple(int(round(255 * i)) for i in label.color) for label in hemi_labels] ctab = np.array(hemi_colors, dtype=np.int32) ctab_rgb = ctab[:, :3] # make color dict (for annot ID, only R, G and B count) labels_by_color = defaultdict(list) for label, color in zip(hemi_labels, ctab_rgb): labels_by_color[tuple(color)].append(label.name) # check label colors for color, names in labels_by_color.items(): if color == no_color_rgb: continue if color == (0, 0, 0): # we cannot have an all-zero color, otherw. e.g. tksurfer # refuses to read the parcellation msg = ('At least one label contains a color with, "r=0, ' 'g=0, b=0" value. Some FreeSurfer tools may fail ' 'to read the parcellation') logger.warning(msg) if any(i > 255 for i in color): msg = ("%s: %s (%s)" % (color, ', '.join(names), hemi)) invalid_colors.append(msg) if len(names) > 1: msg = "%s: %s (%s)" % (color, ', '.join(names), hemi) duplicate_colors.append(msg) # replace None values (labels with unspecified color) if labels_by_color[no_color_rgb]: default_colors = _n_colors(n_hemi_labels, bytes_=True, cmap=colormap) safe_color_i = 0 # keep track of colors known to be in hemi_colors for i in xrange(n_hemi_labels): if ctab[i, 0] == -1: color = default_colors[i] # make sure to add no duplicate color while np.any(np.all(color[:3] == ctab_rgb, 1)): color = default_colors[safe_color_i] safe_color_i += 1 # assign the color ctab[i] = color # find number of vertices in surface if subject is not None and subjects_dir is not None: fpath = os.path.join(subjects_dir, subject, 'surf', '%s.white' % hemi) points, _ = read_surface(fpath) n_vertices = len(points) else: if len(hemi_labels) > 0: max_vert = max(np.max(label.vertices) for label in hemi_labels) n_vertices = max_vert + 1 else: n_vertices = 1 msg = (' Number of vertices in the surface could not be ' 'verified because the surface file could not be found; ' 'specify subject and subjects_dir parameters.') logger.warning(msg) # Create annot and color table array to write annot = np.empty(n_vertices, dtype=np.int) annot[:] = -1 # create the annotation ids from the colors annot_id_coding = np.array((1, 2 ** 8, 2 ** 16)) annot_ids = list(np.sum(ctab_rgb * annot_id_coding, axis=1)) for label, annot_id in zip(hemi_labels, annot_ids): # make sure the label is not overwriting another label if np.any(annot[label.vertices] != -1): other_ids = set(annot[label.vertices]) other_ids.discard(-1) other_indices = (annot_ids.index(i) for i in other_ids) other_names = (hemi_labels[i].name for i in other_indices) other_repr = ', '.join(other_names) msg = "%s: %s overlaps %s" % (hemi, label.name, other_repr) overlap.append(msg) annot[label.vertices] = annot_id hemi_names = [label.name for label in hemi_labels] # Assign unlabeled vertices to an "unknown" label unlabeled = (annot == -1) if np.any(unlabeled): msg = ("Assigning %i unlabeled vertices to " "'unknown-%s'" % (unlabeled.sum(), hemi)) logger.info(msg) # find an unused color (try shades of gray first) for i in range(1, 257): if not np.any(np.all((i, i, i) == ctab_rgb, 1)): break if i < 256: color = (i, i, i, 0) else: err = ("Need one free shade of gray for 'unknown' label. " "Please modify your label colors, or assign the " "unlabeled vertices to another label.") raise ValueError(err) # find the id annot_id = np.sum(annot_id_coding * color[:3]) # update data to write annot[unlabeled] = annot_id ctab = np.vstack((ctab, color)) hemi_names.append("unknown") # convert to FreeSurfer alpha values ctab[:, 3] = 255 - ctab[:, 3] # remove hemi ending in names hemi_names = [name[:-3] if name.endswith(hemi) else name for name in hemi_names] to_save.append((fname, annot, ctab, hemi_names)) issues = [] if duplicate_colors: msg = ("Some labels have the same color values (all labels in one " "hemisphere must have a unique color):") duplicate_colors.insert(0, msg) issues.append(os.linesep.join(duplicate_colors)) if invalid_colors: msg = ("Some labels have invalid color values (all colors should be " "RGBA tuples with values between 0 and 1)") invalid_colors.insert(0, msg) issues.append(os.linesep.join(invalid_colors)) if overlap: msg = ("Some labels occupy vertices that are also occupied by one or " "more other labels. Each vertex can only be occupied by a " "single label in *.annot files.") overlap.insert(0, msg) issues.append(os.linesep.join(overlap)) if issues: raise ValueError('\n\n'.join(issues)) # write it for fname, annot, ctab, hemi_names in to_save: logger.info(' writing %d labels to %s' % (len(hemi_names), fname)) _write_annot(fname, annot, ctab, hemi_names) logger.info('[done]')