def test_read_freesurfer_lut(fname, tmpdir): """Test reading volume label names.""" atlas_ids, colors = read_freesurfer_lut(fname) assert list(atlas_ids).count('Brain-Stem') == 1 assert len(colors) == len(atlas_ids) == 1266 label_names, label_colors = get_volume_labels_from_aseg(aseg_fname, return_colors=True) assert isinstance(label_names, list) assert isinstance(label_colors, list) assert label_names.count('Brain-Stem') == 1 for c in label_colors: assert isinstance(c, np.ndarray) assert c.shape == (4, ) assert len(label_names) == len(label_colors) == 46 with pytest.raises(ValueError, match='must be False'): get_volume_labels_from_aseg(aseg_fname, return_colors=True, atlas_ids=atlas_ids) label_names_2 = get_volume_labels_from_aseg(aseg_fname, atlas_ids=atlas_ids) assert label_names == label_names_2 # long name (only test on one run) if fname is not None: return fname = str(tmpdir.join('long.txt')) names = [ 'Anterior_Cingulate_and_Medial_Prefrontal_Cortex-' + hemi for hemi in ('lh', 'rh') ] ids = np.arange(1, len(names) + 1) colors = [(id_, ) * 4 for id_ in ids] with open(fname, 'w') as fid: for name, id_, color in zip(names, ids, colors): out_color = ' '.join('%3d' % x for x in color) line = '%d %s %s\n' % (id_, name, out_color) fid.write(line) lut, got_colors = read_freesurfer_lut(fname) assert len(lut) == len(got_colors) == len(names) == len(ids) for name, id_, color in zip(names, ids, colors): assert name in lut assert name in got_colors assert_array_equal(got_colors[name][:3], color[:3]) assert lut[name] == id_ with open(fname, 'w') as fid: for name, id_, color in zip(names, ids, colors): out_color = ' '.join('%3d' % x for x in color[:3]) # wrong length! line = '%d %s %s\n' % (id_, name, out_color) fid.write(line) with pytest.raises(RuntimeError, match='formatted'): read_freesurfer_lut(fname)
def test_suggest(): """Test suggestions.""" names = mne.get_volume_labels_from_aseg(fname_mgz) sug = _suggest('', names) assert sug == '' # nothing sug = _suggest('Left-cerebellum', names) assert sug == " Did you mean 'Left-Cerebellum-Cortex'?" sug = _suggest('Cerebellum-Cortex', names) assert sug == " Did you mean one of ['Left-Cerebellum-Cortex', 'Right-Cerebellum-Cortex', 'Left-Cerebral-Cortex']?" # noqa: E501
def test_volume_labels_morph(tmpdir, sl, n_real, n_mri, n_orig): """Test generating a source space from volume label.""" import nibabel as nib n_use = (sl.stop - sl.start) // (sl.step or 1) # see gh-5224 evoked = mne.read_evokeds(fname_evoked)[0].crop(0, 0) evoked.pick_channels(evoked.ch_names[:306:8]) evoked.info.normalize_proj() n_ch = len(evoked.ch_names) lut, _ = read_freesurfer_lut() label_names = sorted(get_volume_labels_from_aseg(fname_aseg)) use_label_names = label_names[sl] src = setup_volume_source_space('sample', subjects_dir=subjects_dir, volume_label=use_label_names, mri=fname_aseg) assert len(src) == n_use assert src.kind == 'volume' n_src = sum(s['nuse'] for s in src) sphere = make_sphere_model('auto', 'auto', evoked.info) fwd = make_forward_solution(evoked.info, fname_trans, src, sphere) assert fwd['sol']['data'].shape == (n_ch, n_src * 3) inv = make_inverse_operator(evoked.info, fwd, make_ad_hoc_cov(evoked.info), loose=1.) stc = apply_inverse(evoked, inv) assert stc.data.shape == (n_src, 1) img = stc.as_volume(src, mri_resolution=True) assert img.shape == (86, 86, 86, 1) n_on = np.array(img.dataobj).astype(bool).sum() aseg_img = _get_img_fdata(nib.load(fname_aseg)) n_got_real = np.in1d(aseg_img.ravel(), [lut[name] for name in use_label_names]).sum() assert n_got_real == n_real # - This was 291 on `main` before gh-5590 # - Refactoring transforms it became 279 with a < 1e-8 change in vox_mri_t # - Dropped to 123 once nearest-voxel was used in gh-7653 # - Jumped back up to 330 with morphing fixes actually correctly # interpolating across all volumes assert aseg_img.shape == img.shape[:3] assert n_on == n_mri for ii in range(2): # should work with (ii=0) or without (ii=1) the interpolator if ii: src[0]['interpolator'] = None img = stc.as_volume(src, mri_resolution=False) n_on = np.array(img.dataobj).astype(bool).sum() # was 20 on `main` before gh-5590 # then 44 before gh-7653, which took it back to 20 assert n_on == n_orig # without the interpolator, this should fail assert src[0]['interpolator'] is None with pytest.raises(RuntimeError, match=r'.*src\[0\], .* mri_resolution'): stc.as_volume(src, mri_resolution=True)
def src_volume_labels(): """Create a 7mm source space with labels.""" volume_labels = mne.get_volume_labels_from_aseg(fname_aseg) src = mne.setup_volume_source_space( 'sample', 7., mri='aseg.mgz', volume_label=volume_labels, add_interpolator=False, bem=fname_bem, subjects_dir=subjects_dir) lut, _ = mne.read_freesurfer_lut() assert len(volume_labels) == 46 assert volume_labels[0] == 'Unknown' assert lut['Unknown'] == 0 # it will be excluded during label gen return src, tuple(volume_labels), lut
def src_volume_labels(): """Create a 7mm source space with labels.""" pytest.importorskip('nibabel') volume_labels = mne.get_volume_labels_from_aseg(fname_aseg) with pytest.warns(RuntimeWarning, match='Found no usable.*Left-vessel.*'): src = mne.setup_volume_source_space( 'sample', 7., mri='aseg.mgz', volume_label=volume_labels, add_interpolator=False, bem=fname_bem, subjects_dir=subjects_dir) lut, _ = mne.read_freesurfer_lut() assert len(volume_labels) == 46 assert volume_labels[0] == 'Unknown' assert lut['Unknown'] == 0 # it will be excluded during label gen return src, tuple(volume_labels), lut
def test_forward_mixed_source_space(tmp_path): """Test making the forward solution for a mixed source space.""" # get the surface source space rng = np.random.RandomState(0) surf = read_source_spaces(fname_src) # setup two volume source spaces label_names = get_volume_labels_from_aseg(fname_aseg) vol_labels = rng.choice(label_names, 2) with pytest.warns(RuntimeWarning, match='Found no usable.*CC_Mid_Ant.*'): vol1 = setup_volume_source_space('sample', pos=20., mri=fname_aseg, volume_label=vol_labels[0], add_interpolator=False) vol2 = setup_volume_source_space('sample', pos=20., mri=fname_aseg, volume_label=vol_labels[1], add_interpolator=False) # merge surfaces and volume src = surf + vol1 + vol2 # calculate forward solution fwd = make_forward_solution(fname_raw, fname_trans, src, fname_bem) assert (repr(fwd)) # extract source spaces src_from_fwd = fwd['src'] # get the coordinate frame of each source space coord_frames = np.array([s['coord_frame'] for s in src_from_fwd]) # assert that all source spaces are in head coordinates assert ((coord_frames == FIFF.FIFFV_COORD_HEAD).all()) # run tests for SourceSpaces.export_volume fname_img = tmp_path / 'temp-image.mgz' # head coordinates and mri_resolution, but trans file with pytest.raises(ValueError, match='trans containing mri to head'): src_from_fwd.export_volume(fname_img, mri_resolution=True, trans=None) # head coordinates and mri_resolution, but wrong trans file vox_mri_t = vol1[0]['vox_mri_t'] with pytest.raises(ValueError, match='head<->mri, got mri_voxel->mri'): src_from_fwd.export_volume(fname_img, mri_resolution=True, trans=vox_mri_t)
# For this visualization, ``nilearn`` must be installed. # This visualization is interactive. Click on any of the anatomical slices # to explore the time series. Clicking on any time point will bring up the # corresponding anatomical map. # # We could visualize the source estimate on a glass brain. Unlike the previous # visualization, a glass brain does not show us one slice but what we would # see if the brain was transparent like glass. stc.plot(src, subject='sample', subjects_dir=subjects_dir, mode='glass_brain') ############################################################################### # You can also extract label time courses using volumetric atlases. Here we'll # use the built-in ``aparc.a2009s+aseg.mgz``: fname_aseg = op.join(subjects_dir, 'sample', 'mri', 'aparc.a2009s+aseg.mgz') label_names = mne.get_volume_labels_from_aseg(fname_aseg) label_tc = stc.extract_label_time_course(fname_aseg, src=src, trans=inv['mri_head_t']) lidx, tidx = np.unravel_index(np.argmax(label_tc), label_tc.shape) fig, ax = plt.subplots(1) ax.plot(stc.times, label_tc.T, 'k', lw=1., alpha=0.5) xy = np.array([stc.times[tidx], label_tc[lidx, tidx]]) xytext = xy + [0.01, 1] ax.annotate(label_names[lidx], xy, xytext, arrowprops=dict(arrowstyle='->'), color='r') ax.set(xlim=stc.times[[0, -1]], xlabel='Time (s)', ylabel='Activation') for key in ('right', 'top'):
def test_volume_source_morph_round_trip(tmpdir, subject_from, subject_to, lower, upper, dtype, morph_mat, monkeypatch): """Test volume source estimate morph round-trips well.""" import nibabel as nib from nibabel.processing import resample_from_to src = dict() if morph_mat: # ~1.5 minutes with pos=7. (4157 morphs!) for sample, so only test # morph_mat computation mode with a few labels label_names = sorted(get_volume_labels_from_aseg(fname_aseg))[1:2] if 'sample' in (subject_from, subject_to): src['sample'] = setup_volume_source_space( 'sample', subjects_dir=subjects_dir, volume_label=label_names, mri=fname_aseg) assert sum(s['nuse'] for s in src['sample']) == 12 if 'fsaverage' in (subject_from, subject_to): src['fsaverage'] = setup_volume_source_space( 'fsaverage', subjects_dir=subjects_dir, volume_label=label_names[:3], mri=fname_aseg_fs) assert sum(s['nuse'] for s in src['fsaverage']) == 16 else: assert not morph_mat if 'sample' in (subject_from, subject_to): src['sample'] = mne.read_source_spaces(fname_vol) src['sample'][0]['subject_his_id'] = 'sample' assert src['sample'][0]['nuse'] == 4157 if 'fsaverage' in (subject_from, subject_to): # Created to save space with: # # bem = op.join(op.dirname(mne.__file__), 'data', 'fsaverage', # 'fsaverage-inner_skull-bem.fif') # src_fsaverage = mne.setup_volume_source_space( # 'fsaverage', pos=7., bem=bem, mindist=0, # subjects_dir=subjects_dir, add_interpolator=False) # mne.write_source_spaces(fname_fs_vol, src_fsaverage, # overwrite=True) # # For speed we do it without the interpolator because it's huge. src['fsaverage'] = mne.read_source_spaces(fname_fs_vol) src['fsaverage'][0].update(vol_dims=np.array([23, 29, 25]), seg_name='brain') _add_interpolator(src['fsaverage']) assert src['fsaverage'][0]['nuse'] == 6379 src_to, src_from = src[subject_to], src[subject_from] del src # No SDR just for speed once everything works kwargs = dict(niter_sdr=(), niter_affine=(1, ), subjects_dir=subjects_dir, verbose=True) morph_from_to = compute_source_morph(src=src_from, src_to=src_to, subject_to=subject_to, **kwargs) morph_to_from = compute_source_morph(src=src_to, src_to=src_from, subject_to=subject_from, **kwargs) nuse = sum(s['nuse'] for s in src_from) assert nuse > 10 use = np.linspace(0, nuse - 1, 10).round().astype(int) data = np.eye(nuse)[:, use] if dtype is complex: data = data * 1j vertices = [s['vertno'] for s in src_from] stc_from = VolSourceEstimate(data, vertices, 0, 1) with catch_logging() as log: stc_from_rt = morph_to_from.apply( morph_from_to.apply(stc_from, verbose='debug')) log = log.getvalue() assert 'individual volume morph' in log maxs = np.argmax(stc_from_rt.data, axis=0) src_rr = np.concatenate([s['rr'][s['vertno']] for s in src_from]) dists = 1000 * np.linalg.norm(src_rr[use] - src_rr[maxs], axis=1) mu = np.mean(dists) # fsaverage=5.99; 7.97 without additional src_ras_t fix # fsaverage=7.97; 25.4 without src_ras_t fix assert lower <= mu < upper, f'round-trip distance {mu}' # check that pre_affine is close to identity when subject_to==subject_from if subject_to == subject_from: for morph in (morph_to_from, morph_from_to): assert_allclose(morph.pre_affine.affine, np.eye(4), atol=1e-2) # check that power is more or less preserved (labelizing messes with this) if morph_mat: if subject_to == 'fsaverage': limits = (14.0, 14.2) else: limits = (7, 7.5) else: limits = (1, 1.2) stc_from_unit = stc_from.copy().crop(0, 0) stc_from_unit._data.fill(1.) stc_from_unit_rt = morph_to_from.apply(morph_from_to.apply(stc_from_unit)) assert_power_preserved(stc_from_unit, stc_from_unit_rt, limits=limits) if morph_mat: fname = tmpdir.join('temp-morph.h5') morph_to_from.save(fname) morph_to_from = read_source_morph(fname) assert morph_to_from.vol_morph_mat is None morph_to_from.compute_vol_morph_mat(verbose=True) morph_to_from.save(fname, overwrite=True) morph_to_from = read_source_morph(fname) assert isinstance(morph_to_from.vol_morph_mat, csr_matrix), 'csr' # equivalence (plus automatic calling) assert morph_from_to.vol_morph_mat is None monkeypatch.setattr(mne.morph, '_VOL_MAT_CHECK_RATIO', 0.) with catch_logging() as log: with pytest.warns(RuntimeWarning, match=r'calling morph\.compute'): stc_from_rt_lin = morph_to_from.apply( morph_from_to.apply(stc_from, verbose='debug')) assert isinstance(morph_from_to.vol_morph_mat, csr_matrix), 'csr' log = log.getvalue() assert 'sparse volume morph matrix' in log assert_allclose(stc_from_rt.data, stc_from_rt_lin.data) del stc_from_rt_lin stc_from_unit_rt_lin = morph_to_from.apply( morph_from_to.apply(stc_from_unit)) assert_allclose(stc_from_unit_rt.data, stc_from_unit_rt_lin.data) del stc_from_unit_rt_lin del stc_from, stc_from_rt # before and after morph, check the proportion of vertices # that are inside and outside the brainmask.mgz brain = nib.load(op.join(subjects_dir, subject_from, 'mri', 'brain.mgz')) mask = _get_img_fdata(brain) > 0 if subject_from == subject_to == 'sample': for stc in [stc_from_unit, stc_from_unit_rt]: img = stc.as_volume(src_from, mri_resolution=True) img = nib.Nifti1Image( # abs to convert complex np.abs(_get_img_fdata(img)[:, :, :, 0]), img.affine) img = _get_img_fdata(resample_from_to(img, brain, order=1)) assert img.shape == mask.shape in_ = img[mask].astype(bool).mean() out = img[~mask].astype(bool).mean() if morph_mat: out_max = 0.001 in_min, in_max = 0.005, 0.007 else: out_max = 0.02 in_min, in_max = 0.97, 0.98 assert out < out_max, f'proportion out of volume {out}' assert in_min < in_ < in_max, f'proportion inside volume {in_}'
eeg=False) fwd_disc = mne.convert_forward_solution(fwd_disc, surf_ori=True, force_fixed=True) mne.write_forward_solution(vfname.fwd_discrete, fwd_disc, overwrite=False) else: fwd_disc = mne.read_forward_solution(vfname.fwd_discrete) ############################################################################### # Create trials of simulated data ############################################################################### volume_labels = mne.get_volume_labels_from_aseg(vfname.aseg) n_noise_dipoles = config.n_noise_dipoles_vol # select n_noise_dipoles entries from rr and their corresponding entries from nn poss_indices = np.arange(rr.shape[0]) raw_list = [] for i in range(config.n_trials): ########################################################################### # Simulate random noise dipoles ########################################################################### stc_noise = simulate_sparse_stc(src, n_noise_dipoles, times, data_fun=generate_random,