def get_aligned_artifacts(info=None, trans=None, subject=None, subjects_dir=None, coord_frame='mri', head_surf=None): head_mri_t, _ = _get_trans(trans, 'head', 'mri') dev_head_t, _ = _get_trans(info['dev_head_t'], 'meg', 'head') head_trans = head_mri_t mri_trans = Transform('mri', 'mri') mri_fiducials = mne.coreg.get_mni_fiducials(subject, subjects_dir) fid_loc = _fiducial_coords(mri_fiducials, FIFF.FIFFV_COORD_MRI) fid_loc = apply_trans(mri_trans, fid_loc) fid_loc = pd.DataFrame(fid_loc, index=[fid["ident"]._name.split("_")[-1] for fid in mri_fiducials], columns=["x", "y", "z"]) if head_surf is None: subject_dir = Path(get_subjects_dir(subjects_dir, raise_error=True)) / subject fname = subject_dir / 'bem' / 'sample-head.fif' head_surf = read_bem_surfaces(fname)[0] head_surf = transform_surface_to(head_surf, coord_frame, [mri_trans, head_trans], copy=True) eeg_picks = mne.pick_types(info, meg=False, eeg=True, ref_meg=False) eeg_loc = np.array([info['chs'][k]['loc'][:3] for k in eeg_picks]) eeg_loc = apply_trans(head_trans, eeg_loc) eegp_loc = _project_onto_surface(eeg_loc, head_surf, project_rrs=True, return_nn=True)[2] eegp_loc = pd.DataFrame(eegp_loc, index=[ch["ch_name"] for ch in info['chs']], columns=["x", "y", "z"]) return eegp_loc, fid_loc, head_surf
def test_helmet(): """Test loading helmet surfaces.""" base_dir = op.join(op.dirname(__file__), '..', 'io') fname_raw = op.join(base_dir, 'tests', 'data', 'test_raw.fif') fname_kit_raw = op.join(base_dir, 'kit', 'tests', 'data', 'test_bin_raw.fif') fname_bti_raw = op.join(base_dir, 'bti', 'tests', 'data', 'exported4D_linux_raw.fif') fname_ctf_raw = op.join(base_dir, 'tests', 'data', 'test_ctf_raw.fif') fname_trans = op.join(base_dir, 'tests', 'data', 'sample-audvis-raw-trans.txt') trans = _get_trans(fname_trans)[0] new_info = read_info(fname_raw) artemis_info = new_info.copy() for pick in pick_types(new_info): new_info['chs'][pick]['coil_type'] = 9999 artemis_info['chs'][pick]['coil_type'] = \ FIFF.FIFFV_COIL_ARTEMIS123_GRAD for info, n, name in [(read_info(fname_raw), 304, '306m'), (read_info(fname_kit_raw), 304, 'KIT'), (read_info(fname_bti_raw), 304, 'Magnes'), (read_info(fname_ctf_raw), 342, 'CTF'), (new_info, 102, 'unknown'), (artemis_info, 102, 'ARTEMIS123') ]: with catch_logging() as log: helmet = get_meg_helmet_surf(info, trans, verbose=True) log = log.getvalue() assert name in log assert_equal(len(helmet['rr']), n) assert_equal(len(helmet['rr']), len(helmet['nn']))
def _compute_coreg_dist(subject, trans_fname, info_fname, subjects_dir): """Assess quality of coregistration.""" trans = mne.read_trans(trans_fname) high_res_surf = subjects_dir + "/%s/surf/lh.seghead" % subject low_res_surf = subjects_dir + "/%s/bem/%s-outer_skull.surf" % (subject, subject) low_res_surf_2 = subjects_dir + "/%s/bem/outer_skull.surf" % subject if os.path.exists(high_res_surf): pts, _ = mne.read_surface(high_res_surf, verbose=False) pts /= 1e3 # convert to mm elif os.path.exists(low_res_surf): warnings.warn("""Using low resolution head surface, the average distance will be potentially overestimated""") pts, _ = mne.read_surface(low_res_surf, verbose=False) pts /= 1e3 # convert to mm elif os.path.exists(low_res_surf_2): warnings.warn("""Using low resolution head surface, the average distance will be potentially overestimated""") pts, _ = mne.read_surface(low_res_surf_2, verbose=False) pts /= 1e3 # convert to mm else: raise FileNotFoundError("No MRI surface was found!") trans = _get_trans(trans, fro="mri", to="head")[0] pts = apply_trans(trans, pts) info = mne.io.read_info(info_fname, verbose=False) info_dig = np.stack([list(x["r"]) for x in info["dig"]], axis=0) M = euclidean_distances(info_dig, pts) idx = np.argmin(M, axis=1) dist = M[np.arange(len(info_dig)), idx].mean() return dist
def test_nirx_15_2(): """Test reading NIRX files.""" raw = read_raw_nirx(fname_nirx_15_2, preload=True) # Test data import assert raw._data.shape == (64, 67) assert raw.info['sfreq'] == 3.90625 # Test channel naming assert raw.info['ch_names'][:4] == [ "S1_D1 760", "S1_D1 850", "S1_D10 760", "S1_D10 850" ] # Test info import assert raw.info['subject_info'] == dict(sex=1, first_name="TestRecording") # Test trigger events assert_array_equal(raw.annotations.description, ['4.0', '6.0', '2.0']) # Test location of detectors allowed_dist_error = 0.0002 locs = [ch['loc'][6:9] for ch in raw.info['chs']] head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri') mni_locs = apply_trans(head_mri_t, locs) assert raw.info['ch_names'][0][3:5] == 'D1' assert_allclose(mni_locs[0], [-0.0292, 0.0852, -0.0142], atol=allowed_dist_error) assert raw.info['ch_names'][15][3:5] == 'D4' assert_allclose(mni_locs[15], [-0.0739, -0.0756, -0.0075], atol=allowed_dist_error)
def _find_closest_standard_location(position, reference, *, out='label'): """Return closest montage label to coordinates. Parameters ---------- position : array, shape (3,) Coordinates. reference : dataframe As generated by _generate_montage_locations. trans_pos : str Apply a transformation to positions to specified frame. Use None for no transformation. """ from scipy.spatial.distance import cdist p0 = np.array(position) p0.shape = (-1, 3) head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri') p0 = apply_trans(head_mri_t, p0) dists = cdist(p0, np.asarray(reference[['x', 'y', 'z']], float)) if out == 'label': min_idx = np.argmin(dists) return reference["label"][min_idx] else: assert out == 'dists' return dists
def test_helmet(): """Test loading helmet surfaces.""" base_dir = op.join(op.dirname(__file__), '..', 'io') fname_raw = op.join(base_dir, 'tests', 'data', 'test_raw.fif') fname_kit_raw = op.join(base_dir, 'kit', 'tests', 'data', 'test_bin_raw.fif') fname_bti_raw = op.join(base_dir, 'bti', 'tests', 'data', 'exported4D_linux_raw.fif') fname_ctf_raw = op.join(base_dir, 'tests', 'data', 'test_ctf_raw.fif') fname_trans = op.join(base_dir, 'tests', 'data', 'sample-audvis-raw-trans.txt') trans = _get_trans(fname_trans)[0] new_info = read_info(fname_raw) artemis_info = new_info.copy() for pick in pick_types(new_info, meg=True): new_info['chs'][pick]['coil_type'] = 9999 artemis_info['chs'][pick]['coil_type'] = \ FIFF.FIFFV_COIL_ARTEMIS123_GRAD for info, n, name in [(read_info(fname_raw), 304, '306m'), (read_info(fname_kit_raw), 304, 'KIT'), (read_info(fname_bti_raw), 304, 'Magnes'), (read_info(fname_ctf_raw), 342, 'CTF'), (new_info, 102, 'unknown'), (artemis_info, 102, 'ARTEMIS123')]: with catch_logging() as log: helmet = get_meg_helmet_surf(info, trans, verbose=True) log = log.getvalue() assert name in log assert_equal(len(helmet['rr']), n) assert_equal(len(helmet['rr']), len(helmet['nn']))
def test_get_trans(): """Test converting '-trans.txt' to '-trans.fif'""" trans = read_trans(fname) trans = invert_transform(trans) # starts out as head->MRI, so invert trans_2 = _get_trans(fname_trans)[0] assert_equal(trans['from'], trans_2['from']) assert_equal(trans['to'], trans_2['to']) assert_allclose(trans['trans'], trans_2['trans'], rtol=1e-5, atol=1e-5)
def test_nirx_15_0(): """Test reading NIRX files.""" raw = read_raw_nirx(fname_nirx_15_0, preload=True) # Test data import assert raw._data.shape == (20, 92) assert raw.info['sfreq'] == 6.25 assert raw.info['meas_date'] == dt.datetime(2019, 10, 27, 13, 53, 34, 209000, tzinfo=dt.timezone.utc) # Test channel naming assert raw.info['ch_names'][:12] == [ "S1_D1 760", "S1_D1 850", "S2_D2 760", "S2_D2 850", "S3_D3 760", "S3_D3 850", "S4_D4 760", "S4_D4 850", "S5_D5 760", "S5_D5 850", "S6_D6 760", "S6_D6 850" ] # Test info import assert raw.info['subject_info'] == { 'birthday': (2004, 10, 27), 'first_name': 'NIRX', 'last_name': 'Test', 'sex': FIFF.FIFFV_SUBJ_SEX_UNKNOWN, 'his_id': "NIRX_Test" } # Test trigger events assert_array_equal(raw.annotations.description, ['1.0', '2.0', '2.0']) # Test location of detectors allowed_dist_error = 0.0002 locs = [ch['loc'][6:9] for ch in raw.info['chs']] head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri') mni_locs = apply_trans(head_mri_t, locs) assert raw.info['ch_names'][0][3:5] == 'D1' assert_allclose(mni_locs[0], [0.0287, -0.1143, -0.0332], atol=allowed_dist_error) assert raw.info['ch_names'][15][3:5] == 'D8' assert_allclose(mni_locs[15], [-0.0693, -0.0480, 0.0657], atol=allowed_dist_error) # Test distance between optodes matches values from allowed_distance_error = 0.0002 assert_allclose(source_detector_distances( raw.copy().pick("S1_D1 760").info), [0.0300], atol=allowed_distance_error) assert_allclose(source_detector_distances( raw.copy().pick("S7_D7 760").info), [0.0392], atol=allowed_distance_error)
def _compute_depth(dip, fname_bem, fname_trans, subject, subjects_dir): """Compute dipole depth.""" trans = _get_trans(fname_trans)[0] bem = read_bem_solution(fname_bem) surf = _bem_find_surface(bem, 'inner_skull') points = surf['rr'] points = apply_trans(trans['trans'], points) depth = _compute_nearest(points, dip.pos, return_dists=True)[1][0] return np.ravel(depth)
def test_nirx_15_2(): """Test reading NIRX files.""" raw = read_raw_nirx(fname_nirx_15_2, preload=True) # Test data import assert raw._data.shape == (64, 67) assert raw.info['sfreq'] == 3.90625 assert raw.info['meas_date'] == dt.datetime(2019, 10, 2, 9, 8, 47, 511000, tzinfo=dt.timezone.utc) # Test channel naming assert raw.info['ch_names'][:4] == [ "S1_D1 760", "S1_D1 850", "S1_D10 760", "S1_D10 850" ] # Test info import assert raw.info['subject_info'] == dict(sex=1, first_name="TestRecording", birthday=(1989, 10, 2)) # Test trigger events assert_array_equal(raw.annotations.description, ['4.0', '6.0', '2.0']) print(raw.annotations.onset) # Test location of detectors allowed_dist_error = 0.0002 locs = [ch['loc'][6:9] for ch in raw.info['chs']] head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri') mni_locs = apply_trans(head_mri_t, locs) assert raw.info['ch_names'][0][3:5] == 'D1' assert_allclose(mni_locs[0], [-0.0292, 0.0852, -0.0142], atol=allowed_dist_error) assert raw.info['ch_names'][15][3:5] == 'D4' assert_allclose(mni_locs[15], [-0.0739, -0.0756, -0.0075], atol=allowed_dist_error) # Old name aliases for backward compat assert 'fnirs_cw_amplitude' in raw with pytest.deprecated_call(): assert 'fnirs_raw' in raw assert 'fnirs_od' not in raw picks = pick_types(raw.info, fnirs='fnirs_cw_amplitude') with pytest.deprecated_call(): picks_alias = pick_types(raw.info, fnirs='fnirs_raw') assert_array_equal(picks, picks_alias)
def test_set_montage_artinis_fsaverage(kind): """Test that artinis montages match fsaverage's head<->MRI transform.""" # Compare OctaMon and Brite23 to fsaverage trans_fs, _ = _get_trans('fsaverage') montage = make_standard_montage(f'artinis-{kind}') trans = compute_native_head_t(montage) assert trans['to'] == trans_fs['to'] assert trans['from'] == trans_fs['from'] translation = 1000 * np.linalg.norm(trans['trans'][:3, 3] - trans_fs['trans'][:3, 3]) assert 0 < translation < 1 # mm rotation = np.rad2deg( _angle_between_quats(rot_to_quat(trans['trans'][:3, :3]), rot_to_quat(trans_fs['trans'][:3, :3]))) assert 0 < rotation < 1 # degrees
def test_helmet(): """Test loading helmet surfaces.""" base_dir = op.join(op.dirname(__file__), '..', 'io') fname_raw = op.join(base_dir, 'tests', 'data', 'test_raw.fif') fname_kit_raw = op.join(base_dir, 'kit', 'tests', 'data', 'test_bin_raw.fif') fname_bti_raw = op.join(base_dir, 'bti', 'tests', 'data', 'exported4D_linux_raw.fif') fname_ctf_raw = op.join(base_dir, 'tests', 'data', 'test_ctf_raw.fif') fname_trans = op.join(base_dir, 'tests', 'data', 'sample-audvis-raw-trans.txt') trans = _get_trans(fname_trans)[0] for fname in [fname_raw, fname_kit_raw, fname_bti_raw, fname_ctf_raw]: helmet = get_meg_helmet_surf(read_info(fname), trans) assert_equal(len(helmet['rr']), 304) # they all have 304 verts assert_equal(len(helmet['rr']), len(helmet['nn']))
def test_nirx_15_0(): """Test reading NIRX files.""" raw = read_raw_nirx(fname_nirx_15_0, preload=True) # Test data import assert raw._data.shape == (20, 92) assert raw.info['sfreq'] == 6.25 # Test channel naming assert raw.info['ch_names'][:12] == [ "S1_D1 760", "S1_D1 850", "S2_D2 760", "S2_D2 850", "S3_D3 760", "S3_D3 850", "S4_D4 760", "S4_D4 850", "S5_D5 760", "S5_D5 850", "S6_D6 760", "S6_D6 850" ] # Test info import assert raw.info['subject_info'] == { 'first_name': 'NIRX', 'last_name': 'Test', 'sex': '0' } # Test trigger events assert_array_equal(raw.annotations.description, ['1.0', '2.0', '2.0']) # Test location of detectors allowed_dist_error = 0.0002 locs = [ch['loc'][6:9] for ch in raw.info['chs']] head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri') mni_locs = apply_trans(head_mri_t, locs) assert raw.info['ch_names'][0][3:5] == 'D1' assert_allclose(mni_locs[0], [0.0287, -0.1143, -0.0332], atol=allowed_dist_error) assert raw.info['ch_names'][15][3:5] == 'D8' assert_allclose(mni_locs[15], [-0.0693, -0.0480, 0.0657], atol=allowed_dist_error) # Test distance between optodes matches values from allowed_distance_error = 0.0002 distances = source_detector_distances(raw.info) assert_allclose(distances[::2], [ 0.0301, 0.0315, 0.0343, 0.0368, 0.0408, 0.0399, 0.0393, 0.0367, 0.0336, 0.0447 ], atol=allowed_distance_error)
def test_project_sensors_onto_brain(tmp_path): """Test projecting sensors onto the brain surface.""" tempdir = str(tmp_path) raw = mne.io.read_raw_fif(fname_raw) trans = _get_trans(fname_trans)[0] # test informative error for no surface first with pytest.raises(RuntimeError, match='requires generating a BEM'): project_sensors_onto_brain(raw.info, trans, 'sample', subjects_dir=tempdir) brain_surf_fname = op.join(tempdir, 'sample', 'bem', 'brain.surf') if not op.isdir(op.dirname(brain_surf_fname)): os.makedirs(op.dirname(brain_surf_fname)) if not op.isfile(brain_surf_fname): copyfile(op.join(subjects_dir, 'sample', 'bem', 'inner_skull.surf'), brain_surf_fname) # now make realistic ECoG grid raw.pick_types(meg=False, eeg=True) raw.load_data() raw.set_eeg_reference([]) raw.set_channel_types({ch: 'ecog' for ch in raw.ch_names}) pos = np.zeros((49, 3)) pos[:, :2] = np.array( np.meshgrid(np.linspace(0, 0.02, 7), np.linspace(0, 0.02, 7))).reshape(2, -1).T pos[:, 2] = 0.12 raw.drop_channels(raw.ch_names[49:]) raw.set_montage( mne.channels.make_dig_montage(ch_pos=dict(zip(raw.ch_names[:49], pos)), coord_frame='head')) raw.info = project_sensors_onto_brain(raw.info, trans, 'sample', subjects_dir=tempdir) # plot to check, should be projected down onto inner skull # brain = mne.viz.Brain('sample', subjects_dir=subjects_dir, alpha=0.5, # surf='white') # brain.add_sensors(raw.info, trans=trans) test_locs = [[0.00149, -0.001588, 0.133029], [0.004302, 0.001959, 0.133922], [0.008602, 0.00116, 0.133723]] for ch, test_loc in zip(raw.info['chs'][:3], test_locs): assert_allclose(ch['loc'][:3], test_loc, rtol=0.01)
def test_head_to_mni(): """Test conversion of aseg vertices to MNI coordinates.""" # obtained using freeview coords = np.array([[22.52, 11.24, 17.72], [22.52, 5.46, 21.58], [16.10, 5.46, 22.23], [21.24, 8.36, 22.23]]) / 1000. xfm = read_talxfm('sample', subjects_dir) coords_MNI = apply_trans(xfm['trans'], coords) * 1000. mri_head_t, _ = _get_trans(trans_fname, 'mri', 'head', allow_none=False) # obtained from sample_audvis-meg-oct-6-mixed-fwd.fif coo_right_amygdala = np.array([[0.01745682, 0.02665809, 0.03281873], [0.01014125, 0.02496262, 0.04233755], [0.01713642, 0.02505193, 0.04258181], [0.01720631, 0.03073877, 0.03850075]]) coords_MNI_2 = head_to_mni(coo_right_amygdala, 'sample', mri_head_t, subjects_dir) # less than 1mm error assert_allclose(coords_MNI, coords_MNI_2, atol=10.0)
def dip_depth(dip, fname_trans, subject, subjects_dir): trans = read_trans(fname_trans) trans = _get_trans(trans)[0] subjects_dir = get_subjects_dir(subjects_dir=subjects_dir) fname = os.path.join(subjects_dir, subject, 'bem', 'inner_skull.surf') points, faces = read_surface(fname) points = apply_trans(trans['trans'], points * 1e-3) pos = dip.pos ori = dip.ori from sklearn.neighbors import NearestNeighbors nn = NearestNeighbors() nn.fit(points) depth, idx = nn.kneighbors(pos, 1, return_distance=True) idx = np.ravel(idx) direction = pos - points[idx] direction /= np.sqrt(np.sum(direction**2, axis=1))[:, None] ori /= np.sqrt(np.sum(ori**2, axis=1))[:, None] radiality = np.abs(np.sum(ori * direction, axis=1)) return np.ravel(depth), radiality
def test_get_trans(): """Test converting '-trans.txt' to '-trans.fif'""" trans = read_trans(fname) trans = invert_transform(trans) # starts out as head->MRI, so invert trans_2 = _get_trans(fname_trans)[0] assert trans.__eq__(trans_2, atol=1e-5)
def test_snirf_nirsport2_w_positions(): """Test reading SNIRF files with known positions.""" raw = read_raw_snirf(nirx_nirsport2_103_2, preload=True, optode_frame="mri") # Test data import assert raw._data.shape == (40, 128) assert_almost_equal(raw.info['sfreq'], 10.2, decimal=1) # Test channel naming assert raw.info['ch_names'][:4] == [ 'S1_D1 760', 'S1_D1 850', 'S1_D6 760', 'S1_D6 850' ] assert raw.info['ch_names'][24:26] == ['S6_D4 760', 'S6_D4 850'] # Test frequency encoding assert raw.info['chs'][0]['loc'][9] == 760 assert raw.info['chs'][1]['loc'][9] == 850 assert sum(short_channels(raw.info)) == 16 # Test distance between optodes matches values from # nirsite https://github.com/mne-tools/mne-testing-data/pull/86 # figure 3 allowed_distance_error = 0.005 distances = source_detector_distances(raw.info) assert_allclose(distances[::2][:14], [ 0.0304, 0.0411, 0.008, 0.0400, 0.008, 0.0310, 0.0411, 0.008, 0.0299, 0.008, 0.0370, 0.008, 0.0404, 0.008 ], atol=allowed_distance_error) # Test location of detectors # The locations of detectors can be seen in the first # figure on this page... # https://github.com/mne-tools/mne-testing-data/pull/86 allowed_dist_error = 0.0002 locs = [ch['loc'][6:9] for ch in raw.info['chs']] head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri') mni_locs = apply_trans(head_mri_t, locs) assert raw.info['ch_names'][0][3:5] == 'D1' assert_allclose(mni_locs[0], [-0.0841, -0.0464, -0.0129], atol=allowed_dist_error) assert raw.info['ch_names'][2][3:5] == 'D6' assert_allclose(mni_locs[2], [-0.0841, -0.0138, 0.0248], atol=allowed_dist_error) assert raw.info['ch_names'][34][3:5] == 'D5' assert_allclose(mni_locs[34], [0.0845, -0.0451, -0.0123], atol=allowed_dist_error) # Test location of sensors # The locations of sensors can be seen in the second # figure on this page... # https://github.com/mne-tools/mne-testing-data/pull/86 allowed_dist_error = 0.0002 locs = [ch['loc'][3:6] for ch in raw.info['chs']] head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri') mni_locs = apply_trans(head_mri_t, locs) assert raw.info['ch_names'][0][:2] == 'S1' assert_allclose(mni_locs[0], [-0.0848, -0.0162, -0.0163], atol=allowed_dist_error) assert raw.info['ch_names'][9][:2] == 'S2' assert_allclose(mni_locs[9], [-0.0, -0.1195, 0.0142], atol=allowed_dist_error) assert raw.info['ch_names'][34][:2] == 'S8' assert_allclose(mni_locs[34], [0.0828, -0.046, 0.0285], atol=allowed_dist_error) mon = raw.get_montage() assert len(mon.dig) == 43
def write_anat(bids_root, subject, t1w, session=None, acquisition=None, raw=None, trans=None, deface=False, overwrite=False, verbose=False): """Put anatomical MRI data into a BIDS format. Given a BIDS directory and a T1 weighted MRI scan for a certain subject, format the MRI scan to be in BIDS format and put it into the correct location in the bids_dir. If a transformation matrix is supplied, a sidecar JSON file will be written for the T1 weighted data. Parameters ---------- bids_root : str Path to root of the BIDS folder subject : str Subject label as in 'sub-<label>', for example: '01' t1w : str | nibabel image object Path to a T1 weighted MRI scan of the subject. Can be in any format readable by nibabel. Can also be a nibabel image object of a T1 weighted MRI scan. Will be written as a .nii.gz file. session : str | None The session for `t1w`. Corresponds to "ses" acquisition: str | None The acquisition parameters for `t1w`. Corresponds to "acq" raw : instance of Raw | None The raw data of `subject` corresponding to `t1w`. If `raw` is None, `trans` has to be None as well trans : instance of mne.transforms.Transform | str | None The transformation matrix from head coordinates to MRI coordinates. Can also be a string pointing to a .trans file containing the transformation matrix. If None, no sidecar JSON file will be written for `t1w` deface : bool | dict If False, no defacing is performed. If True, deface with default parameters. `trans` and `raw` must not be `None` if True. If dict, accepts the following keys: `inset`: how far back in millimeters to start defacing relative to the nasion (default 20) `theta`: is the angle of the defacing shear in degrees relative to the normal to the plane passing through the anatomical landmarks (default 35). overwrite : bool Whether to overwrite existing files or data in files. Defaults to False. If overwrite is True, any existing files with the same BIDS parameters will be overwritten with the exception of the `participants.tsv` and `scans.tsv` files. For these files, parts of pre-existing data that match the current data will be replaced. If overwrite is False, no existing data will be overwritten or replaced. verbose : bool If verbose is True, this will print a snippet of the sidecar files. If False, no content will be printed. Returns ------- anat_dir : str Path to the anatomical scan in the `bids_dir` """ if not has_nibabel(): # pragma: no cover raise ImportError('This function requires nibabel.') import nibabel as nib if deface and (trans is None or raw is None): raise ValueError('The raw object, trans and raw must be provided to ' 'deface the T1') # Make directory for anatomical data anat_dir = op.join(bids_root, 'sub-{}'.format(subject)) # Session is optional if session is not None: anat_dir = op.join(anat_dir, 'ses-{}'.format(session)) anat_dir = op.join(anat_dir, 'anat') if not op.exists(anat_dir): os.makedirs(anat_dir) # Try to read our T1 file and convert to MGH representation if isinstance(t1w, str): t1w = nib.load(t1w) elif type(t1w) not in nib.all_image_classes: raise ValueError('`t1w` must be a path to a T1 weighted MRI data file ' ', or a nibabel image object, but it is of type ' '"{}"'.format(type(t1w))) t1w = nib.Nifti1Image(t1w.dataobj, t1w.affine) # XYZT_UNITS = NIFT_UNITS_MM (10 in binary or 2 in decimal) # seems to be the default for Nifti files # https://nifti.nimh.nih.gov/nifti-1/documentation/nifti1fields/nifti1fields_pages/xyzt_units.html if t1w.header['xyzt_units'] == 0: t1w.header['xyzt_units'] = np.array(10, dtype='uint8') # Now give the NIfTI file a BIDS name and write it to the BIDS location t1w_basename = make_bids_basename(subject=subject, session=session, acquisition=acquisition, prefix=anat_dir, suffix='T1w.nii.gz') # Check if we have necessary conditions for writing a sidecar JSON if trans is not None: # get trans and ensure it is from head to MRI trans, _ = _get_trans(trans, fro='head', to='mri') if not isinstance(raw, BaseRaw): raise ValueError('`raw` must be specified if `trans` is not None') # Prepare to write the sidecar JSON # extract MEG landmarks coords_dict = _extract_landmarks(raw.info['dig']) meg_landmarks = np.asarray((coords_dict['LPA'], coords_dict['NAS'], coords_dict['RPA'])) # Transform MEG landmarks into MRI space, adjust units by * 1e3 mri_landmarks = apply_trans(trans, meg_landmarks, move=True) * 1e3 # Get landmarks in voxel space, using the mgh version of our T1 data t1_mgh = nib.MGHImage(t1w.dataobj, t1w.affine) vox2ras_tkr = t1_mgh.header.get_vox2ras_tkr() ras2vox_tkr = np.linalg.inv(vox2ras_tkr) mri_landmarks = apply_trans(ras2vox_tkr, mri_landmarks) # in vox # Write sidecar.json t1w_json = dict() t1w_json['AnatomicalLandmarkCoordinates'] = \ {'LPA': list(mri_landmarks[0, :]), 'NAS': list(mri_landmarks[1, :]), 'RPA': list(mri_landmarks[2, :])} fname = t1w_basename.replace('.nii.gz', '.json') if op.isfile(fname) and not overwrite: raise IOError('Wanted to write a file but it already exists and ' '`overwrite` is set to False. File: "{}"' .format(fname)) _write_json(fname, t1w_json, overwrite, verbose) if deface: t1w = _deface(t1w, mri_landmarks, deface, trans, raw) # Save anatomical data if op.exists(t1w_basename): if overwrite: os.remove(t1w_basename) else: raise IOError('Wanted to write a file but it already exists and ' '`overwrite` is set to False. File: "{}"' .format(t1w_basename)) nib.save(t1w, t1w_basename) return anat_dir
def test_nirsport_v2(): """Test NIRSport2 file.""" raw = read_raw_nirx(nirsport2, preload=True) assert raw._data.shape == (40, 128) # Test distance between optodes matches values from # nirsite https://github.com/mne-tools/mne-testing-data/pull/86 # figure 3 allowed_distance_error = 0.005 distances = source_detector_distances(raw.info) assert_allclose(distances[::2][:14], [ 0.0304, 0.0411, 0.008, 0.0400, 0.008, 0.0310, 0.0411, 0.008, 0.0299, 0.008, 0.0370, 0.008, 0.0404, 0.008 ], atol=allowed_distance_error) # Test location of detectors # The locations of detectors can be seen in the first # figure on this page... # https://github.com/mne-tools/mne-testing-data/pull/86 allowed_dist_error = 0.0002 locs = [ch['loc'][6:9] for ch in raw.info['chs']] head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri') mni_locs = apply_trans(head_mri_t, locs) assert raw.info['ch_names'][0][3:5] == 'D1' assert_allclose(mni_locs[0], [-0.0841, -0.0464, -0.0129], atol=allowed_dist_error) assert raw.info['ch_names'][2][3:5] == 'D6' assert_allclose(mni_locs[2], [-0.0841, -0.0138, 0.0248], atol=allowed_dist_error) assert raw.info['ch_names'][34][3:5] == 'D5' assert_allclose(mni_locs[34], [0.0845, -0.0451, -0.0123], atol=allowed_dist_error) # Test location of sensors # The locations of sensors can be seen in the second # figure on this page... # https://github.com/mne-tools/mne-testing-data/pull/86 locs = [ch['loc'][3:6] for ch in raw.info['chs']] head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri') mni_locs = apply_trans(head_mri_t, locs) assert raw.info['ch_names'][0][:2] == 'S1' assert_allclose(mni_locs[0], [-0.0848, -0.0162, -0.0163], atol=allowed_dist_error) assert raw.info['ch_names'][9][:2] == 'S2' assert_allclose(mni_locs[9], [-0.0, -0.1195, 0.0142], atol=allowed_dist_error) assert raw.info['ch_names'][34][:2] == 'S8' assert_allclose(mni_locs[34], [0.0828, -0.046, 0.0285], atol=allowed_dist_error) assert len(raw.annotations) == 3 assert raw.annotations.description[0] == '1.0' assert raw.annotations.description[2] == '6.0' # Lose tolerance as I am eyeballing the time differences on screen assert_allclose(np.diff(raw.annotations.onset), [2.3, 3.1], atol=0.1) mon = raw.get_montage() assert len(mon.dig) == 43
def test_nirx_15_3_short(): """Test reading NIRX files.""" raw = read_raw_nirx(fname_nirx_15_3_short, preload=True) # Test data import assert raw._data.shape == (26, 220) assert raw.info['sfreq'] == 12.5 # Test channel naming assert raw.info['ch_names'][:4] == [ "S1_D2 760", "S1_D2 850", "S1_D9 760", "S1_D9 850" ] assert raw.info['ch_names'][24:26] == ["S5_D13 760", "S5_D13 850"] # Test frequency encoding assert raw.info['chs'][0]['loc'][9] == 760 assert raw.info['chs'][1]['loc'][9] == 850 # Test info import assert raw.info['subject_info'] == dict(birthday=(2020, 8, 18), sex=0, first_name="testMontage\\0A" "TestMontage", his_id="testMontage\\0A" "TestMontage") # Test distance between optodes matches values from # https://github.com/mne-tools/mne-testing-data/pull/72 allowed_distance_error = 0.001 distances = source_detector_distances(raw.info) assert_allclose(distances[::2], [ 0.0304, 0.0078, 0.0310, 0.0086, 0.0416, 0.0072, 0.0389, 0.0075, 0.0558, 0.0562, 0.0561, 0.0565, 0.0077 ], atol=allowed_distance_error) # Test which channels are short # These are the ones marked as red at # https://github.com/mne-tools/mne-testing-data/pull/72 is_short = short_channels(raw.info) assert_array_equal(is_short[:9:2], [False, True, False, True, False]) is_short = short_channels(raw.info, threshold=0.003) assert_array_equal(is_short[:3:2], [False, False]) is_short = short_channels(raw.info, threshold=50) assert_array_equal(is_short[:3:2], [True, True]) # Test trigger events assert_array_equal(raw.annotations.description, ['4.0', '2.0', '1.0']) # Test location of detectors # The locations of detectors can be seen in the first # figure on this page... # https://github.com/mne-tools/mne-testing-data/pull/72 # And have been manually copied below allowed_dist_error = 0.0002 locs = [ch['loc'][6:9] for ch in raw.info['chs']] head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri') mni_locs = apply_trans(head_mri_t, locs) assert raw.info['ch_names'][0][3:5] == 'D2' assert_allclose(mni_locs[0], [-0.0841, -0.0464, -0.0129], atol=allowed_dist_error) assert raw.info['ch_names'][4][3:5] == 'D1' assert_allclose(mni_locs[4], [0.0846, -0.0142, -0.0156], atol=allowed_dist_error) assert raw.info['ch_names'][8][3:5] == 'D3' assert_allclose(mni_locs[8], [0.0207, -0.1062, 0.0484], atol=allowed_dist_error) assert raw.info['ch_names'][12][3:5] == 'D4' assert_allclose(mni_locs[12], [-0.0196, 0.0821, 0.0275], atol=allowed_dist_error) assert raw.info['ch_names'][16][3:5] == 'D5' assert_allclose(mni_locs[16], [-0.0360, 0.0276, 0.0778], atol=allowed_dist_error) assert raw.info['ch_names'][19][3:5] == 'D6' assert_allclose(mni_locs[19], [0.0388, -0.0477, 0.0932], atol=allowed_dist_error) assert raw.info['ch_names'][21][3:5] == 'D7' assert_allclose(mni_locs[21], [-0.0394, -0.0483, 0.0928], atol=allowed_dist_error)
def test_nirx_15_2_short(): """Test reading NIRX files.""" raw = read_raw_nirx(fname_nirx_15_2_short, preload=True) # Test data import assert raw._data.shape == (26, 145) assert raw.info['sfreq'] == 12.5 assert raw.info['meas_date'] == dt.datetime(2019, 8, 23, 7, 37, 4, 540000, tzinfo=dt.timezone.utc) # Test channel naming assert raw.info['ch_names'][:4] == [ "S1_D1 760", "S1_D1 850", "S1_D9 760", "S1_D9 850" ] assert raw.info['ch_names'][24:26] == ["S5_D13 760", "S5_D13 850"] # Test frequency encoding assert raw.info['chs'][0]['loc'][9] == 760 assert raw.info['chs'][1]['loc'][9] == 850 # Test info import assert raw.info['subject_info'] == dict(sex=1, first_name="MNE", middle_name="Test", last_name="Recording", birthday=(2014, 8, 23), his_id="MNE_Test_Recording") # Test distance between optodes matches values from # nirsite https://github.com/mne-tools/mne-testing-data/pull/51 # step 4 figure 2 allowed_distance_error = 0.0002 distances = source_detector_distances(raw.info) assert_allclose(distances[::2], [ 0.0304, 0.0078, 0.0310, 0.0086, 0.0416, 0.0072, 0.0389, 0.0075, 0.0558, 0.0562, 0.0561, 0.0565, 0.0077 ], atol=allowed_distance_error) # Test which channels are short # These are the ones marked as red at # https://github.com/mne-tools/mne-testing-data/pull/51 step 4 figure 2 is_short = short_channels(raw.info) assert_array_equal(is_short[:9:2], [False, True, False, True, False]) is_short = short_channels(raw.info, threshold=0.003) assert_array_equal(is_short[:3:2], [False, False]) is_short = short_channels(raw.info, threshold=50) assert_array_equal(is_short[:3:2], [True, True]) # Test trigger events assert_array_equal(raw.annotations.description, ['3.0', '2.0', '1.0']) # Test location of detectors # The locations of detectors can be seen in the first # figure on this page... # https://github.com/mne-tools/mne-testing-data/pull/51 # And have been manually copied below # These values were reported in mm, but according to this page... # https://mne.tools/stable/auto_tutorials/intro/plot_40_sensor_locations.html # 3d locations should be specified in meters, so that's what's tested below # Detector locations are stored in the third three loc values allowed_dist_error = 0.0002 locs = [ch['loc'][6:9] for ch in raw.info['chs']] head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri') mni_locs = apply_trans(head_mri_t, locs) assert raw.info['ch_names'][0][3:5] == 'D1' assert_allclose(mni_locs[0], [-0.0841, -0.0464, -0.0129], atol=allowed_dist_error) assert raw.info['ch_names'][4][3:5] == 'D3' assert_allclose(mni_locs[4], [0.0846, -0.0142, -0.0156], atol=allowed_dist_error) assert raw.info['ch_names'][8][3:5] == 'D2' assert_allclose(mni_locs[8], [0.0207, -0.1062, 0.0484], atol=allowed_dist_error) assert raw.info['ch_names'][12][3:5] == 'D4' assert_allclose(mni_locs[12], [-0.0196, 0.0821, 0.0275], atol=allowed_dist_error) assert raw.info['ch_names'][16][3:5] == 'D5' assert_allclose(mni_locs[16], [-0.0360, 0.0276, 0.0778], atol=allowed_dist_error) assert raw.info['ch_names'][19][3:5] == 'D6' assert_allclose(mni_locs[19], [0.0352, 0.0283, 0.0780], atol=allowed_dist_error) assert raw.info['ch_names'][21][3:5] == 'D7' assert_allclose(mni_locs[21], [0.0388, -0.0477, 0.0932], atol=allowed_dist_error)
def make_pert_forward_solution(info, trans, src, bem, perts, meg=True, eeg=True, mindist=0.0, ignore_ref=False, n_jobs=1, verbose=None): """Calculate a forward solution for a subject. Parameters ---------- info : instance of mne.Info | str If str, then it should be a filename to a Raw, Epochs, or Evoked file with measurement information. If dict, should be an info dict (such as one from Raw, Epochs, or Evoked). trans : dict | str | None Either a transformation filename (usually made using mne_analyze) or an info dict (usually opened using read_trans()). If string, an ending of `.fif` or `.fif.gz` will be assumed to be in FIF format, any other ending will be assumed to be a text file with a 4x4 transformation matrix (like the `--trans` MNE-C option). Can be None to use the identity transform. src : str | instance of SourceSpaces If string, should be a source space filename. Can also be an instance of loaded or generated SourceSpaces. bem : dict | str Filename of the BEM (e.g., "sample-5120-5120-5120-bem-sol.fif") to use, or a loaded sphere model (dict). meg : bool If True (Default), include MEG computations. eeg : bool If True (Default), include EEG computations. mindist : float Minimum distance of sources from inner skull surface (in mm). ignore_ref : bool If True, do not include reference channels in compensation. This option should be True for KIT files, since forward computation with reference channels is not currently supported. n_jobs : int Number of jobs to run in parallel. perts : dict A dictionary containing perturbation parameters for gradiometer imbalance, sensor miscalibration, and misalignment verbose : bool, str, int, or None If not None, override default verbose level (see :func:`mne.verbose` and :ref:`Logging documentation <tut_logging>` for more). Returns ------- fwd : instance of Forward The forward solution. See Also -------- convert_forward_solution Notes ----- The ``--grad`` option from MNE-C (to compute gradients) is not implemented here. To create a fixed-orientation forward solution, use this function followed by :func:`mne.convert_forward_solution`. """ # Currently not (sup)ported: # 1. --grad option (gradients of the field, not used much) # 2. --fixed option (can be computed post-hoc) # 3. --mricoord option (probably not necessary) # read the transformation from MRI to HEAD coordinates # (could also be HEAD to MRI) mri_head_t, trans = _get_trans(trans) if isinstance(bem, ConductorModel): bem_extra = 'instance of ConductorModel' else: bem_extra = bem if not isinstance(info, (Info, string_types)): raise TypeError('info should be an instance of Info or string') if isinstance(info, string_types): info_extra = op.split(info)[1] info = read_info(info, verbose=False) else: info_extra = 'instance of Info' n_jobs = check_n_jobs(n_jobs) # Report the setup logger.info('Source space : %s' % src) logger.info('MRI -> head transform : %s' % trans) logger.info('Measurement data : %s' % info_extra) if isinstance(bem, ConductorModel) and bem['is_sphere']: logger.info('Sphere model : origin at %s mm' % (bem['r0'], )) logger.info('Standard field computations') else: logger.info('Conductor model : %s' % bem_extra) logger.info('Accurate field computations') logger.info('Do computations in %s coordinates', _coord_frame_name(FIFF.FIFFV_COORD_HEAD)) logger.info('Free source orientations') megcoils, meg_info, compcoils, megnames, eegels, eegnames, rr, info, \ update_kwargs, bem = _prepare_for_forward( src, mri_head_t, info, bem, mindist, n_jobs, perts, bem_extra, trans, info_extra, meg, eeg, ignore_ref) del (src, mri_head_t, trans, info_extra, bem_extra, mindist, meg, eeg, ignore_ref) # Time to do the heavy lifting: MEG first, then EEG coil_types = ['meg', 'eeg'] coils = [megcoils, eegels] ccoils = [compcoils, None] infos = [meg_info, None] megfwd, eegfwd = _compute_forwards(rr, bem, coils, ccoils, infos, coil_types, n_jobs) # merge forwards fwd = _merge_meg_eeg_fwds(_to_forward_dict(megfwd, megnames), _to_forward_dict(eegfwd, eegnames), verbose=False) logger.info('') # Don't transform the source spaces back into MRI coordinates (which is # done in the C code) because mne-python assumes forward solution source # spaces are in head coords. fwd.update(**update_kwargs) logger.info('Finished.') return fwd
# House funcs here so PertInv is just scripting import mne from _make_perturbed_forward import make_pert_forward_solution, make_pert_forward_dipole from mne.datasets import sample import numpy as np # noqa from mne.transforms import (_ensure_trans, transform_surface_to, apply_trans, _get_trans, invert_transform, _print_coord_trans, _coord_frame_name, Transform) # local_data_path = 'C:\MEG\Local_mne_data' data_path = sample.data_path() # local copy of mne sample data raw_fname = data_path + '/MEG/sample/sample_audvis_raw.fif' cov_fname = data_path + '/MEG/sample/sample_audvis-cov.fif' subjects_dir = data_path + '/subjects' subject = 'sample' trans = data_path + '\MEG\sample/sample_audvis_raw-trans.fif' mri_head_t, trans = _get_trans(trans) head_mri_t = invert_transform(mri_head_t) cov = mne.read_cov(cov_fname) info = mne.io.read_info(raw_fname) def fit_dips(min_rad, max_rad, nn, sphere, perts, sourcenorm): testsources = dict(rr=[], nn=[]) nsources = max_rad - min_rad + 1 vertices = np.zeros((nsources, 1)) for i in range(min_rad, max_rad + 1): ex, ey, ez = sourcenorm[0], sourcenorm[1], sourcenorm[2] source = [.001*i*ex, .001*i*ey, .001*i*ez] normal = [nn[0], nn[1], nn[2]] testsources['rr'].append(source) testsources['nn'].append(normal)
def plot_3d_montage(info, view_map, *, src_det_names='auto', ch_names='numbered', subject='fsaverage', trans='fsaverage', surface='pial', subjects_dir=None, verbose=None): """ Plot a 3D sensor montage. Parameters ---------- info : instance of Info Measurement info. view_map : dict Dict of view (key) to channel-pair-numbers (value) to use when plotting. Note that, because these get plotted as 1-based channel *numbers*, the values should be 1-based rather than 0-based. The keys are of the form: ``'{side}-{view}'`` For views like ``'left-lat'`` or ``'right-frontal'`` where the side matters. ``'{view}'`` For views like ``'caudal'`` that are along the midline. See :meth:`mne.viz.Brain.show_view` for ``view`` options, and the Examples section below for usage examples. src_det_names : None | dict | str Source and detector names to use. "auto" (default) will see if the channel locations correspond to standard 10-20 locations and will use those if they do (otherwise will act like None). None will use S1, S2, ..., D1, D2, ..., etc. Can also be an explicit dict mapping, for example:: src_det_names=dict(S1='Fz', D1='FCz', ...) ch_names : str | dict | None If ``'numbered'`` (default), use ``['1', '2', ...]`` for the channel names, or ``None`` to use ``['S1_D2', 'S2_D1', ...]``. Can also be a dict to provide a mapping from the ``'S1_D2'``-style names (keys) to other names, e.g., ``defaultdict(lambda: '')`` will prevent showing the names altogether. .. versionadded:: 0.3 subject : str The subject. trans : str | Transform The subjects head<->MRI transform. surface : str The FreeSurfer surface name (e.g., 'pial', 'white'). subjects_dir : str The subjects directory. %(verbose)s Returns ------- figure : matplotlib.figure.Figure The matplotlib figimage. Examples -------- For a Hitachi system with two sets of 12 source-detector arrangements, one on each side of the head, showing 1-12 on the left and 13-24 on the right can be accomplished using the following ``view_map``:: >>> view_map = { ... 'left-lat': np.arange(1, 13), ... 'right-lat': np.arange(13, 25), ... } NIRx typically involves more complicated arrangements. See :ref:`the 3D tutorial <tut-fnirs-vis-brain-plot-3d-montage>` for an advanced example that incorporates the ``'caudal'`` view as well. """ # noqa: E501 import matplotlib.pyplot as plt from scipy.spatial.distance import cdist _validate_type(info, Info, 'info') _validate_type(view_map, dict, 'views') _validate_type(src_det_names, (None, dict, str), 'src_det_names') _validate_type(ch_names, (dict, str, None), 'ch_names') info = pick_info(info, pick_types(info, fnirs=True, exclude=())[::2]) if isinstance(ch_names, str): _check_option('ch_names', ch_names, ('numbered', ), extra='when str') ch_names = { name.split()[0]: str(ni) for ni, name in enumerate(info['ch_names'], 1) } info['bads'] = [] if isinstance(src_det_names, str): _check_option('src_det_names', src_det_names, ('auto', ), extra='when str') # Decide if we can map to 10-20 locations names, pos = zip( *transform_to_head(make_standard_montage( 'standard_1020')).get_positions()['ch_pos'].items()) pos = np.array(pos, float) locs = dict() bad = False for ch in info['chs']: name = ch['ch_name'] s_name, d_name = name.split()[0].split('_') for name, loc in [(s_name, ch['loc'][3:6]), (d_name, ch['loc'][6:9])]: if name in locs: continue # see if it's close enough idx = np.where(cdist(loc[np.newaxis], pos)[0] < 1e-3)[0] if len(idx) < 1: bad = True break # Some are duplicated (e.g., T7+T3) but we can rely on the # first one being the canonical one locs[name] = names[idx[0]] if bad: break if bad: src_det_names = None logger.info('Could not automatically map source/detector names to ' '10-20 locations.') else: src_det_names = locs logger.info('Source-detector names automatically mapped to 10-20 ' 'locations') head_mri_t = _get_trans(trans, 'head', 'mri')[0] del trans views = list() for key, num in view_map.items(): _validate_type(key, str, f'view_map key {repr(key)}') _validate_type(num, np.ndarray, f'view_map[{repr(key)}]') if '-' in key: hemi, v = key.split('-', maxsplit=1) hemi = dict(left='lh', right='rh')[hemi] views.append((hemi, v, num)) else: views.append(('lh', key, num)) del view_map size = (400 * len(views), 400) brain = Brain(subject, 'both', surface, views=['lat'] * len(views), size=size, background='w', units='m', view_layout='horizontal', subjects_dir=subjects_dir) with _safe_brain_close(brain): brain.add_head(dense=False, alpha=0.1) brain.add_sensors(info, trans=head_mri_t, fnirs=['channels', 'pairs', 'sources', 'detectors']) add_text_kwargs = dict() if 'render' in _get_args(brain.plotter.add_text): add_text_kwargs['render'] = False for col, view in enumerate(views): plotted = set() brain.show_view(view[1], hemi=view[0], focalpoint=(0, -0.02, 0.02), distance=0.4, row=0, col=col) brain.plotter.subplot(0, col) vp = brain.plotter.renderer for ci in view[2]: # figure out what we need to plot this_ch = info['chs'][ci - 1] ch_name = this_ch['ch_name'].split()[0] s_name, d_name = ch_name.split('_') needed = [ (ch_names, 'ch_names', ch_name, this_ch['loc'][:3], 12, 'Centered'), (src_det_names, 'src_det_names', s_name, this_ch['loc'][3:6], 8, 'Bottom'), (src_det_names, 'src_det_names', d_name, this_ch['loc'][6:9], 8, 'Bottom'), ] for lookup, lname, name, ch_pos, font_size, va in needed: if name in plotted: continue plotted.add(name) orig_name = name if lookup is not None: name = lookup[name] _validate_type(name, str, f'{lname}[{repr(orig_name)}]') ch_pos = apply_trans(head_mri_t, ch_pos) vp.SetWorldPoint(np.r_[ch_pos, 1.]) vp.WorldToDisplay() ch_pos = (np.array(vp.GetDisplayPoint()[:2]) - np.array(vp.GetOrigin())) actor = brain.plotter.add_text(name, ch_pos, font_size=font_size, color=(0., 0., 0.), **add_text_kwargs) prop = actor.GetTextProperty() getattr(prop, f'SetVerticalJustificationTo{va}')() prop.SetJustificationToCentered() actor.SetTextProperty(prop) prop.SetBold(True) img = brain.screenshot() return plt.figimage(img, resize=True).figure
def test_get_trans(): """Test converting '-trans.txt' to '-trans.fif'.""" trans = read_trans(fname) trans = invert_transform(trans) # starts out as head->MRI, so invert trans_2 = _get_trans(fname_trans)[0] assert trans.__eq__(trans_2, atol=1e-5)