def plot_ecd(sub): ecd_dips = sub.load_ecd() trans = sub.load_transformation() for trial in ecd_dips: for dipole in ecd_dips[trial]: fig = dipole.plot_locations(trans, sub.subtomri, sub.subjects_dir, mode='orthoview', idx='gof') fig.suptitle(sub.name, horizontalalignment='right') plot_save(sub, 'ECD', subfolder=dipole, trial=trial, matplotlib_figure=fig) # find time point with highest GOF to plot best_idx = np.argmax(dipole.gof) best_time = dipole.times[best_idx] print( f'Highest GOF {dipole.gof[best_idx]:.2f}% at t={best_time * 1000:.1f} ms with confidence volume' f'{dipole.conf["vol"][best_idx] * 100 ** 3} cm^3') mri_pos = mne.head_to_mri(dipole.pos, sub.subtomri, trans, sub.subjects_dir) save_path_anat = join( sub.sub.figures_path, 'ECD', dipole, trial, f'{sub.name}-{trial}_{sub.pr.p_preset}_ECD-{dipole}{sub.img_format}' ) t1_path = join(sub.subjects_dir, sub.subtomri, 'mri', 'T1.mgz') plot_anat(t1_path, cut_coords=mri_pos[best_idx], output_file=save_path_anat, title=f'{sub.name}-{trial}_{dipole}', annotate=True, draw_cross=True) plot_anat(t1_path, cut_coords=mri_pos[best_idx], title=f'{sub.name}-{trial}_{dipole}', annotate=True, draw_cross=True)
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, mri_head_t=trans, subject=subject, subjects_dir=subjects_dir) _time = stc.times[-1] stc.crop(_time - 1, _time) img = stc.as_volume(fwd['src'], mri_resolution=True) plot_stat_map(index_img(img, -1), fname_t1, threshold=0.001, cut_coords=peak_mri_pos) plt.show() ####################################################################################### # Save results.
# Compute evokeds tmin = 0.03 tmax = 0.05 evoked_grad = epochs_grad.average().crop(tmin, tmax) evoked_mag = epochs_mag.average().crop(tmin, tmax) evoked_joint = epochs_joint.average().crop(tmin, tmax) ############################################################################### # read dipole created by 06_dipole.py ############################################################################### dip = mne.read_dipole(somato_fname.ecd) # get the position of the dipole in MRI coordinates mri_pos = mne.head_to_mri(dip.pos, mri_head_t=trans, subject=subject_id, subjects_dir=somato_fname.subjects_dir) # get true_vert_idx rr = fwd['src'][0]['rr'] inuse = fwd['src'][0]['inuse'] indices = np.where(fwd['src'][0]['inuse'])[0] rr_inuse = rr[indices] true_vert_idx = np.where( np.linalg.norm(rr_inuse - dip.pos, axis=1) == np.linalg.norm( rr_inuse - dip.pos, axis=1).min())[0][0] ############################################################################### # HTML settings ###############################################################################
# Plot the result in 3D brain with the MRI image. dip.plot_locations(fname_trans, 'sample', subjects_dir, mode='orthoview') # Plot the result in 3D brain with the MRI image using Nilearn # In MRI coordinates and in MNI coordinates (template brain) trans = mne.read_trans(fname_trans) subject = 'sample' mni_pos = mne.head_to_mni(dip.pos, mri_head_t=trans, subject=subject, subjects_dir=subjects_dir) mri_pos = mne.head_to_mri(dip.pos, mri_head_t=trans, subject=subject, subjects_dir=subjects_dir) t1_fname = op.join(subjects_dir, subject, 'mri', 'T1.mgz') fig = plot_anat(t1_fname, cut_coords=mri_pos[0], title='Dipole loc.') template = load_mni152_template() fig = plot_anat(template, cut_coords=mni_pos[0], title='Dipole loc. (MNI Space)') ############################################################################### # Calculate and visualise magnetic field predicted by dipole with maximum GOF # and compare to the measured data, highlighting the ipsilateral (right) source fwd, stc = make_forward_dipole(dip, fname_bem, evoked.info, fname_trans) pred_evoked = simulate_evoked(fwd, stc, evoked.info, cov=None, nave=np.inf)
def create_mxne_summary( subjects, p, morph_subject=None, n_display=None, pattern_in='', pattern_out='_mxne', path_out='./', title='%s Dipoles', ): '''Create a report and spreadsheet about mixed-norm dipoles.''' src_file = os.path.join(p.subjects_dir, 'fsaverage', 'bem', 'fsaverage-ico-5-src.fif') src_fsavg = mne.read_source_spaces(src_file) src_file = os.path.join(p.subjects_dir, '14mo_surr', 'bem', '14mo_surr-oct-6-src.fif') src_14mo = mne.read_source_spaces(src_file) mni_labels = mne.read_labels_from_annot('fsaverage', 'HCPMMP1', subjects_dir=p.subjects_dir) labels = mne.read_labels_from_annot('14mo_surr', use_parc, subjects_dir=p.subjects_dir) for subject in subjects: # Load STCs and other saved data # cond = p.stc_params['condition'] stc_path = os.path.join(p.work_dir, subject, p.stc_dir) stc_stem = subject + '_' + cond + pattern_in stc_file = os.path.join(stc_path, stc_stem) if not os.path.isfile(stc_file + '-lh.stc'): print(f'** STC file matching {stc_stem} not found ********.\n') continue stc_mxne = mne.read_source_estimate(stc_file) n_dipoles, n_times = stc_mxne.data.shape meta_data = np.load(stc_file + '.npy', allow_pickle=True) gof_mxne = meta_data[0] residual_mxne = meta_data[1] evk_path = os.path.join(p.work_dir, subject, p.inverse_dir) evk_file = f'Locations_40-sss_eq_{subject}-ave.fif' evk_file = os.path.join(evk_path, evk_file) evoked = mne.read_evokeds(evk_file, condition=cond, kind='average') evoked.pick_types(meg=True) cov_path = os.path.join(p.work_dir, subject, p.cov_dir) cov_file = f'{subject}-40-sss-cov.fif' cov_file = os.path.join(cov_path, cov_file) cov = mne.read_cov(cov_file) trans_path = os.path.join(p.work_dir, subject, p.trans_dir) trans_file = f'{subject}-trans.fif' trans_file = os.path.join(trans_path, trans_file) trans = mne.read_trans(trans_file, verbose=False) fwd_path = os.path.join(p.work_dir, subject, p.forward_dir) fwd_file = f'{subject}-sss-fwd.fif' fwd_file = os.path.join(fwd_path, fwd_file) fwd = mne.read_forward_solution(fwd_file, verbose=False) assert fwd['src'][0]['nuse'] == src_14mo[0]['nuse'] assert fwd['src'][1]['nuse'] == src_14mo[1]['nuse'] # Run analysis on the dipoles, then sort then by goodness-of-fit # results = analyze_dipoles(stc_mxne, gof_mxne, evoked, cov, p.stc_params['gof_t_range']) results, sort_idx = sort_dipoles(results) # stc still unsorted gof_results, amp_results = results assert len(gof_results) == n_dipoles # Collect info for the top dipoles, in order # n_show = n_dipoles if n_display: n_show = min(n_display, n_show) n_left = len(stc_mxne.vertices[0]) # .data stacked lh then rh postop, mnitop, wavtop = [], [], [] for i in range(n_dipoles): di = sort_idx[i] hemid = int(di >= n_left) vidx = di - hemid * n_left vert = stc_mxne.vertices[hemid][vidx] pos = fwd['src'][hemid]['rr'][vert] postop.append(pos) mni = mne.vertex_to_mni(vert, hemid, subject, subjects_dir=p.subjects_dir) mnitop.append(mni) wav = stc_mxne.data[di, :] wavtop.append(wav) assert wav[amp_results[i].pidx] == amp_results[i].peak # check last # Make various figures # figure_list, figure_info, figure_comment = [], [], [] # 1) Top dipoles in one set of surface maps. if morph_subject: src_subject = morph_subject caption = 'Surface Plots | ' + morph_subject else: src_subject = subject caption = 'Surface Plots | Coreg.' fig_surface = make_surfaceplots(stc_mxne, src_subject, p.subjects_dir, sort_idx, parc=use_parc) figure_list.append(fig_surface) figure_info.append([caption, 'Surface Plots']) figure_comment.append(color_comment) # 2) Top dipoles in 3D slices (non-morphed and MNI). mri_file = os.path.join(p.subjects_dir, subject, 'mri', 'T1.mgz') postop_mri = mne.head_to_mri(postop, mri_head_t=trans, subject=subject, subjects_dir=p.subjects_dir) postop_mni = mne.head_to_mni(postop, mri_head_t=trans, subject=subject, subjects_dir=p.subjects_dir) assert_allclose(mnitop[0], postop_mni[0], atol=0.01) assert_allclose(mnitop[-1], postop_mni[-1], atol=0.01) fig_orthog1 = make_orthogplots(mri_file, postop_mri[:n_show]) fig_orthog2 = make_orthogplots(mni_template, postop_mni[:n_show]) figure_list.append(fig_orthog1) figure_info.append(['Orthogonal Plots | Coreg.', 'Orthogonal Plots']) figure_comment.append(None) figure_list.append(fig_orthog2) figure_info.append(['Orthogonal Plots | MNI)', 'Orthogonal Plots']) figure_comment.append(f'Top {n_show} of {n_dipoles} dipoles ' 'displayed.') # 3) Top dipoles' time waveforms. fig_wav = make_sourcewavs(wavtop, stc_mxne.times, p.stc_params['gof_t_range']) figure_list.append(fig_wav) figure_info.append(['STC Time Course', 'Temporal Waveforms']) figure_comment.append(None) # 4) Evoked and residual waveforms (averages across sensors) fig_sensor = make_sensorwavs(evoked, residual_mxne) figure_list.append(fig_sensor) figure_info.append(['Sensor Time Course', 'Temporal Waveforms']) figure_comment.append(None) # Determine 14-mo surrogate "aparc" label for each dipole # labels_stc = [] # note these are not gof-ordered for hh, hemi in enumerate(('lh', 'rh')): for vert in stc_mxne.vertices[hh]: label = which_label(vert, hemi, labels) if label: labels_stc.append(label.name) else: labels_stc.append('no_label') # Expand the sparse STC so it can be morphed (X='expanded') # # v_lh = fwd['src'][0]['vertno'] # the full source space # v_rh = fwd['src'][1]['vertno'] # n_vtotal = vertices = len(v_lh) + len(v_rh) # data_mxneX = np.zeros((n_vtotal, n_times)) # idx_vrts = np.isin(v_lh, stc_mxne.vertices[0]) # idx_vrts = np.where(idx_vrts)[0] # data_mxneX[idx_vrts, :] = stc_mxne.data[:n_left, :] # idx_vrts = np.isin(v_rh, stc_mxne.vertices[1]) # idx_vrts = np.where(idx_vrts)[0] # data_mxneX[idx_vrts, :] = stc_mxne.data[n_left:, :] # stc_mxneX = mne.SourceEstimate(data_mxneX, [v_lh, v_rh], # tmin=stc_mxne.tmin, tstep=stc_mxne.tstep, # subject=stc_mxne.subject) # Determine fsaverage "HCPMMP1" labels for each dipole # # Note: 'sparse' doesn't give a 1-to-1 mapping. morph_fcn = mne.compute_source_morph(stc_mxne, src_to=src_fsavg, smooth='nearest', spacing=None, warn=False, subjects_dir=p.subjects_dir, niter_sdr=(), sparse=True, subject_from=subject, subject_to='fsaverage') mlabels_stc = [] # like above, but now for fsaverage:HCPMMP1 verts_mni = [] for di in range(n_dipoles): stc_temp = stc_mxne.copy() # zero all but dipole of interest stc_temp.data = np.zeros((n_dipoles, n_times)) stc_temp.data[di, :] = stc_mxne.data[di, :] mstc_temp = morph_fcn.apply(stc_temp) vidx = np.where(mstc_temp.data[:, 0] > 0)[0] vidx_lh = [i for i in vidx if i < n_left] # don't assume hemi vidx_rh = [i - n_left for i in vidx if i >= n_left] verts_byhemi = [None, None] verts_byhemi[0] = mstc_temp.vertices[0][vidx_lh] verts_byhemi[1] = mstc_temp.vertices[1][vidx_rh] verts_mni.append(verts_byhemi) cnt = 0 for verts, hemi, prefix in zip(verts_byhemi, ['lh', 'rh'], ['L_', 'R_']): if not verts: continue vert = verts[0] # should only be one with sparse arg. lbl = which_label(vert, hemi, mni_labels) if lbl: lbl = lbl.name else: lbl = 'no_label' lbl = re.sub(rf"^{prefix}", "", lbl) lbl = re.sub(r"_ROI", "", lbl) cnt += 1 assert cnt == 1 # only one hemisphere should be valid mlabels_stc.append(lbl) # Create formatted tables for a report section # # SMB: Saving as string objects in case they can be added to report. strobj1 = StringIO() # TABLE 1: sorted gof and amplitude info sprint = lambda *x: print(*x, file=strobj1, end='') ff = '<8.2f' # format: center on 8-char field, 2 decimal places sprint(f'{"Dip #":^6} {"Peak/Mean Amp":<16} ' f'{"Peak/Mean GOF":<16} {"GOF Time":<8}\n') for i in range(n_dipoles): amp_m = 1e9 * amp_results[i].mean amp_p = 1e9 * amp_results[i].peak gof_m = gof_results[i].mean gof_p = gof_results[i].peak time_p = evoked.times[gof_results[i].pidx] sprint(f'{i:^6} {amp_p:{ff}}{amp_m:{ff}} ' f'{gof_p:{ff}}{gof_m:{ff}} ' f'{time_p:{"<8.3f"}}\n') sprint('\n') strobj2 = StringIO() # TABLE 2: coordinate and label info sprint = lambda *x: print(*x, file=strobj2, end='') ff = '<20' sprint(f'{"Dip #":^6} {"14mo Coord":{ff}} {"MNI Coord":{ff}} ' f'{"14mo Aparc | Fsavg HCPMMP1":{ff}}\n') for i in range(n_dipoles): di = sort_idx[i] hemid = int(di >= n_left) # hemi = 'rh' if hemid else 'lh' vidx = di - hemid * n_left vert = stc_mxne.vertices[hemid][vidx] coord = src_14mo[hemid]['rr'][vert] * 1000 coord_str = ' '.join([f'{x:.1f}' for x in coord]) vert = verts_mni[di][hemid][0] # just the first one coord = src_fsavg[hemid]['rr'][vert] * 1000 mcoord_str = ' '.join([f'{x:.1f}' for x in coord]) sprint(f'{i:^6} {coord_str:{ff}} {mcoord_str:{ff}} ' f'{labels_stc[di]:{ff}}\n {"":<47} ' f'{mlabels_stc[di]:{ff}}\n') # Print out the tables # print(f'\nGOF-sorted dipole info for {subject}:') strobj1.seek(0) print(strobj1.read()) strobj1.close() print(f'\nGOF-sorted position info for {subject}:') strobj2.seek(0) print(strobj2.read()) strobj2.close() # Compile all figures into a report # print(f'Compiling report for {subject}.') if not os.path.exists(path_out): os.mkdir(path_out) if '%s ' in title: title_use = title.replace('%s ', 'Group') else: title_use = title report = mne.Report(title=title_use, image_format='png') for fig, info, cstr in zip(figure_list, figure_info, figure_comment): report.add_figs_to_section(fig, captions=info[0], scale=1.0, section=info[1], comments=cstr) report_file = os.path.join(path_out, subject + pattern_out + '.html') report.save(report_file, open_browser=False, overwrite=True)
## ECD from nilearn.plotting import plot_anat from mne.evoked import combine_evoked from mne.simulation import simulate_evoked from mne.forward import make_forward_dipole # evoked=evoked_full evoked_full = evoked.copy() evoked.crop(0.14, 0.16) # Fit a dipole dip = mne.fit_dipole(evoked, cov, bem, trans)[0] # Plot the result in 3D brain with the MRI image. dip.plot_locations(trans, mri_partic, subjects_dir=mri_dir, mode='orthoview') #plot on scan mni_pos = mne.head_to_mni(dip.pos, mri_head_t=trans,subject=mri_partic, subjects_dir=mri_dir) mri_pos = mne.head_to_mri(dip.pos, mri_head_t=trans,subject=mri_partic, subjects_dir=mri_dir) t1_fname = mri_dir+'\\'+ mri_partic+ '\\mri\\T1.mgz' fig_T1 = plot_anat(t1_fname, cut_coords=mri_pos[0], title='Dipole loc.') # #plot on standard # from nilearn.datasets import load_mni152_template # template = load_mni152_template() # fig_template = plot_anat(template, cut_coords=mni_pos[0],title='Dipole loc. (MNI Space)') #plot fied predicted by dipole with max goodness of fit, compare to data and take diff fwd_dip, stc_dip = make_forward_dipole(dip, bem, evoked.info, trans) pred_evoked = simulate_evoked(fwd_dip, stc_dip, evoked.info, cov=None, nave=np.inf) # find time point with highest goodness of fit (gof) best_idx = np.argmax(dip.gof) best_time = dip.times[best_idx]
# Fit a dipole dip = mne.fit_dipole(evoked, fname_cov, fname_bem, fname_trans)[0] # Plot the result in 3D brain with the MRI image. dip.plot_locations(fname_trans, 'sample', subjects_dir, mode='orthoview') # Plot the result in 3D brain with the MRI image using Nilearn # In MRI coordinates and in MNI coordinates (template brain) trans = mne.read_trans(fname_trans) subject = 'sample' mni_pos = mne.head_to_mni(dip.pos, mri_head_t=trans, subject=subject, subjects_dir=subjects_dir) mri_pos = mne.head_to_mri(dip.pos, mri_head_t=trans, subject=subject, subjects_dir=subjects_dir) t1_fname = op.join(subjects_dir, subject, 'mri', 'T1.mgz') fig_T1 = plot_anat(t1_fname, cut_coords=mri_pos[0], title='Dipole loc.') template = load_mni152_template() fig_template = plot_anat(template, cut_coords=mni_pos[0], title='Dipole loc. (MNI Space)') ############################################################################### # Calculate and visualise magnetic field predicted by dipole with maximum GOF # and compare to the measured data, highlighting the ipsilateral (right) source fwd, stc = make_forward_dipole(dip, fname_bem, evoked.info, fname_trans) pred_evoked = simulate_evoked(fwd, stc, evoked.info, cov=None, nave=np.inf) # find time point with highest GOF to plot
peak_time = (mag_peak + grad_peak) / 2 evoked = epochs.average().crop(peak_time - 0.005, peak_time + 0.005) print(evoked) dip, res = mne.fit_dipole(evoked, noise_cov, bem, trans, n_jobs=n_jobs, verbose=True) dip = dip[int(np.argmax(dip.gof))] dip.save(fname.ecd(subject=subject), overwrite=True) # Plot the result in 3D brain with the MRI image using Nilearn mri_pos = mne.head_to_mri(dip.pos, mri_head_t=trans, subject=fname.subject_id(subject=subject), subjects_dir=fname.subjects_dir) t1_fname = op.join(fname.subjects_dir, fname.subject_id(subject=subject), 'mri', 'T1.mgz') fig = plt.figure() plot_anat(t1_fname, cut_coords=mri_pos[np.argmax(dip.gof)], title='Dipole loc.', figure=fig) with mne.open_report(fname.report(subject=subject)) as report: report.add_figs_to_section(fig, 'ECD source location', 'Source level', replace=True) report.save(fname.report_html(subject=subject), overwrite=True,
def main(): #splitter = "\\" if platform.system().lower().startswith("win") else "/" parser = argparse.ArgumentParser() parser.add_argument("--subject", action="store", type=str, required=False, help="Name of the Patient/ Subject to process") parser.add_argument("--bidsroot", action="store", type=str, required=False, help="Specify a different BIDS root directory to use") parser.add_argument("--inputfolder", action="store", type=str, required=False, help="Specify a different data input folder") parser.add_argument( "--fsonly", action="store", type=str, required=False, help="Use --fsonly true if you only want to do a freesurfer segmentation" ) # do only freesurfer segmentation parser.add_argument("--openmp", action="store", type=str, required=False, help="Specify how many jobs/ processor cores to use") parser.add_argument("--srcspacing", action="store", type=str, required=False, help="Source spacing: \ -defaults to ico4 --> 2562 Source points \ || other options: \ oct5 --> 1026 Source points \ || oct6 --> 4098 Source points \ || ico5 --> 10242 Source points") parser.add_argument("--extras", action="store", type=str, required=False, help="Specify directory containing extras for report") args = parser.parse_args() # additional arguments if args.bidsroot: bids_root = args.bidsroot else: bids_root = os.environ.get("BIDS_ROOT") if args.openmp: n_jobs = openmp = int(args.openmp) else: n_jobs = openmp = int(os.environ.get("OPENMP")) if n_jobs == None: n_jobs = openmp = int(1) if args.inputfolder: input_folder = args.inputfolder else: input_folder = os.environ.get("INPUT_FOLDER") if args.extras: extras_directory = args.extras else: extras_directory = os.environ.get("EXTRAS_DIRECTORY") # define subject subject = args.subject if not subject: poss = [s for s in os.listdir(input_folder)] print( f"No subject specified, maybe you want to choose from those:\n {poss}" ) subject = input() if not subject.startswith("sub-"): ject = str(subject) subject = "sub-" + subject else: ject = subject.split("sub-")[-1] # create folder structure and copy dfc = Folderer.DerivativesFoldersCreator(BIDS_root=bids_root, extras_directory=extras_directory, subject=subject) dfc.make_derivatives_folders() # logging logfile = opj(dfc.freport, "SourceLocPipeline.log") logging.basicConfig(filename=logfile, filemode="w", format="\n%(levelname)s --> %(message)s") rootlog = logging.getLogger() rootlog.setLevel(logging.INFO) rootlog.info("Now running SourceLoc pipeline...") # log parameters rootlog.info(f"*" * 20) rootlog.info("Parameters") rootlog.info(f"*" * 20) rootlog.info(f"Subject name = {ject}") rootlog.info(f"Input folder is set to: {input_folder}.") rootlog.info(f"BIDS root is set to: {bids_root}.") rootlog.info(f"Extras directory is set to: {extras_directory}.") rootlog.info(f"Using {openmp} processor cores/ jobs.") rootlog.info("Folder structure has been created.") # check if freesurfer subjects_dir exists FS_SUBJECTS_DIR = str(os.environ.get("SUBJECTS_DIR")) if FS_SUBJECTS_DIR == None: print(f"It seems freesurfer is not properly set up on your computer") rootlog.warning( "No working freesurfer environment found - SUBJECTS_DIR is not set" ) # check if source spacing was set + is valid if not args.srcspacing: spacing = str(os.environ.get("SRCSPACING")) if not spacing: spacing = "oct6" else: spacing = args.srcspacing if spacing not in ["ico4", "oct5", "oct6", "ico5"]: spacing = "oct6" print('The desired spacing isn\'t allowed, typo?\n \ Options are: "ico4", "oct5", "oct6", "ico5"\n \ --> spacing was automatically set to "oct6".') rootlog.warning( "Spacing was set to \"oct6\", as input given was invalid.") rootlog.info(f"Final source spacing is {spacing}.") # MRI to nii.gz, then freesurfer, then hippocampal subfields # Naturally, this only works with a freesurfer environment # and this will take some time... anafolder = opj(input_folder, ject) if os.path.isdir(anafolder): rootlog.setLevel(logging.ERROR) rap = Anatomist.RawAnatomyProcessor(anafolder, FS_SUBJECTS_DIR, n_jobs=n_jobs) try: rap.run_anatomy_pipeline() except Exception as e: rootlog.error( f"Something went wrong while processing anatomy: {e}") rootlog.setLevel(logging.INFO) # Check if only freesurfer segmentation was desired and comply, if true if args.fsonly and args.fsonly.lower() == "true": rootlog.info( "Only freesurfer segmentation was desired - finished without errors." ) exit() # copy freesurfer files to local subjects_dir try: segmentation = opj(FS_SUBJECTS_DIR, subject) target = opj(dfc.fanat, subject) if not os.path.isdir(target): os.mkdir(target) rootlog.info( f"Copying freesurfer segmentation {segmentation} to {target}") dfc._recursive_overwrite(segmentation, target) except Exception as e: rootlog.error(f"Couldn't copy freesurfer segmentation\n--> {e}.") # create source models sourcerer = Anatomist.SourceModeler(subjects_dir=dfc.fanat, subject=subject, spacing=spacing, n_jobs=n_jobs) sourcerer.calculate_source_models() # process raw fifs raws = glob.glob(input_folder + "/*.fif") raws = [f for f in raws if ject in f] epo_filename = opj(dfc.spikes, str(subject) + "-epo.fif") concatname = opj(os.path.dirname(raws[0]), str(subject) + "_concat.fif") def raw_processing_already_done(): r = os.path.isfile(concatname) c = os.path.isfile(epo_filename) return r and c if not raw_processing_already_done(): # parse list of appropriate raws rootlog.info( f"The following raw files were found for preprocessing:\n{raws}") prepper = u.RawPreprocessor() for run, rawfile in enumerate(raws): if "tsss" in rawfile and ject in rawfile and not "-epo" in rawfile: # --> search for matching eventfile and combine rawname = rawfile.strip(".fif") + "_prep.fif" if not "_prep" in rawfile: # epochs epochs = prepper.raw_to_epoch(rawfile) if epochs is not None: epochs = epochs.load_data().filter( l_freq=l_freq, fir_design=fir_design, h_freq=h_freq, n_jobs=n_jobs) epo_filename = rawfile.strip(".fif") + "-epo.fif" epochs.save(epo_filename, overwrite=True) # preprocessing raw = mne.io.read_raw(rawfile, preload=False, on_split_missing="ignore") raw = prepper.filter_raw(raw, l_freq=l_freq, fir_design=fir_design, h_freq=h_freq, n_jobs=n_jobs) raw = prepper.resample_raw(raw, s_freq=s_freq, n_jobs=n_jobs) # # Artifacts # ECG artifacts # It's smarter to supervise this step (--> look at the topomaps!) raw.load_data() try: ecg_projs, _ = mne.preprocessing.compute_proj_ecg( raw, n_grad=n_grad, n_mag=n_mag, n_eeg=n_eeg, reject=None) raw.add_proj(ecg_projs, remove_existing=False) fig = mne.viz.plot_projs_topomap(ecg_projs, info=raw.info, show=False) savename = os.path.join(dfc.fprep, "ECG_projs_Topomap.png") fig.savefig(savename) except Exception as e: rootlog.error( f"ECG - Atrifact correction failed --> {e}") #EOG artifacts # It's a bad idea to do this in an automated step try: eog_evoked = mne.preprocessing.create_eog_epochs( raw).average() #eog_evoked.apply_baseline((None, None)) eog_projs, _ = mne.preprocessing.compute_proj_eog( raw, n_grad=n_grad, n_mag=n_mag, n_eeg=n_eeg, n_jobs=n_jobs, reject=None) raw.add_proj( eog_projs, remove_existing=False ) # --> don't do this in the early stages - see documentation figs = eog_evoked.plot_joint(show=False) for idx, fig in enumerate(figs): savename = os.path.join( dfc.fprep, "EOG Topomap_" + str(idx) + ".png") fig.savefig(savename) except Exception as e: rootlog.error( f"EOG - Atrifact correction failed --> {e}") # save raw, store projs all_projs = raw.info["projs"] raw.save(rawname, overwrite=True) del (raw) # concatenate epochs epo_filename = opj(dfc.spikes, str(subject) + "-epo.fif") if not os.path.isfile(epo_filename): epoch_files = glob.glob(input_folder + "/*-epo.fif") epoch_files = [f for f in epoch_files if ject in f] all_epochs = dict() rootlog.info("Concatenating epochs now...") for f in epoch_files: all_epochs[f] = mne.read_epochs(f) concat_epochs = mne.concatenate_epochs( [all_epochs[f] for f in epoch_files]) concat_epochs.add_proj(all_projs, remove_existing=True) concat_epochs.apply_proj() rootlog.info(f"Saving concatenated epoch file as {epo_filename}") concat_epochs.save(epo_filename) # concatenate filtered and resampled files raws = glob.glob(input_folder + "/*.fif") raws = [f for f in raws if ject in f] raws = [f for f in raws if "_prep" in f] all_raws = dict() concatname = opj(os.path.dirname(raws[0]), str(subject) + "_concat.fif") if not os.path.isfile(concatname): for r in raws: all_raws[r] = mne.io.read_raw(r, preload=False) all_raws[r].del_proj() rootlog.info( f"Concatenating the following (filtered and resampled) raw files: {raws}" ) try: raw = mne.concatenate_raws( [all_raws[r] for r in all_raws.keys()]) rootlog.info( "Rawfiles have successfully been concatenated....") except Exception as e: rootlog.error( f"Failed trying to concatenate raw file\n {r} --> {e}") #print("Loading only first raw file!") #raw = mne.io.read_raw(raws[0]) rootlog.info("Applying SSP projectors on concatenated file...") raw.add_proj(all_projs, remove_existing=True) raw.apply_proj() rootlog.info(f"Saving concatenated rawfile as {concatname}") raw.save(concatname) # Save in BIDS format derivatives_root = opj(bids_root, "derivatives") # meg bids_path = BIDSPath(subject=ject, session="resting", task="resting", root=derivatives_root, processing="concat") raw = mne.io.read_raw(concatname, preload=False) write_raw_bids(raw, bids_path, overwrite=True) # anatomy rootlog.info("Running dicom2nifti on MRI...") derivatives_root = opj(bids_root, "derivatives") # meg bids_path = BIDSPath(subject=ject, session="resting", task="resting", root=bids_root, processing="concat") nii = glob.glob(opj(input_folder, ject, "*.nii*")) try: for n in nii: write_anat(n, bids_path=bids_path, overwrite=True) except Exception as e: rootlog.error(f"Conversion of MRI to nift failed --> {e}") # Create Dataset the_roots = [bids_root, derivatives_root] rootlog.info("Creating BIDS dataset...") for r in the_roots: make_dataset_description(r, name="CDK Epilepsy Dataset", data_license="closed", authors="Rudi Kreidenhuber", overwrite=True) # Coregistration --> this doesn't work with WSLg - from here on # run on windows, if you are on a windows machine transfile = opj(dfc.ftrans, subject + "-trans.fif") rootlog.info("Starting coregistration...") if os.path.isfile(transfile): rootlog.info( f"Skipping coregistration, because a transfile ({transfile}) already exists" ) else: print(f"\n\n\n--> Transfile should be called: {transfile}\n\n\n") try: mne.gui.coregistration( subject=subject, subjects_dir=dfc.fanat, inst=bids_path, advanced_rendering=False) # BIDS: inst=raw.filenames[0]) except: print("failed with bids_derivatives folder") rawfile = opj(dfc.fbase, "ses-resting", "meg", "*concat_meg.fif") rawfile = glob.glob(rawfile)[0] rootlog.info( f"Coregistration with BIDS-file failed, Rawfile used was: {rawfile}" ) mne.gui.coregistration(subject=subject, subjects_dir=dfc.fanat, inst=rawfile, advanced_rendering=False) # frequency spectrum if do_frequencies: rootlog.info("Calculating frequency spectrum...") bem_sol = opj(dfc.fsrc, subject + "-3-layer-BEM-sol.fif") if not os.path.isfile(bem_sol) and use_single_shell_model: rootlog.warning("Working with a single shell head model") bem_sol = opj(dfc.fsrc, subject + "-single-shell-BEM-sol.fif") fwd_name = opj(dfc.fsrc, subject + "-fwd.fif") srcfilename = opj(dfc.fsrc, subject + "-" + spacing + "-src.fif") filebase = str(subject) + "_Freqs" all_stcs_filename = (filebase + '-stc-psd-MNE.pkl') all_stcs_filename = opj(dfc.freq, all_stcs_filename) sensor_psd_filename = (filebase + '-sensor-psd-MNE.pkl') sensor_psd_filename = opj(dfc.freq, sensor_psd_filename) if not os.path.isfile(all_stcs_filename) or not os.path.isfile( sensor_psd_filename ): # so this should run only on the first file.. # load again in case preprocessing didn't happen before concatname = opj(input_folder, str(subject) + "_concat.fif") raw = mne.io.read_raw(concatname, preload=True) if os.path.isfile(fwd_name): fwd = mne.read_forward_solution(fwd_name) else: fwd = mne.make_forward_solution(raw.info, src=srcfilename, bem=bem_sol, trans=transfile, meg=True, eeg=False, mindist=0.2, ignore_ref=False, n_jobs=n_jobs, verbose=True) mne.write_forward_solution(fwd_name, fwd) noise_cov = mne.compute_raw_covariance(raw, method="empirical", n_jobs=n_jobs) inv = mne.minimum_norm.make_inverse_operator(raw.info, forward=fwd, noise_cov=noise_cov, loose="auto", depth=0.8) snr = 3. stc_psd, sensor_psd = mne.minimum_norm.compute_source_psd( raw, inv, lambda2=lambda2, method='MNE', fmin=1, fmax=45, n_fft=2048, n_jobs=n_jobs, return_sensor=True, verbose=True) pickle.dump(stc_psd, open(all_stcs_filename, "wb")) pickle.dump(sensor_psd, open(sensor_psd_filename, "wb")) else: stc_psd = pickle.load(open(all_stcs_filename, "rb")) sensor_psd = pickle.load(open(sensor_psd_filename, "rb")) # Visualization topos = dict() stcs = dict() topo_norm = sensor_psd.data.sum(axis=1, keepdims=True) stc_norm = stc_psd.sum() for band, limits in freq_bands.items(): # normalize... data = sensor_psd.copy().crop(*limits).data.sum(axis=1, keepdims=True) topos[band] = mne.EvokedArray(100 * data / topo_norm, sensor_psd.info) stcs[band] = 100 * stc_psd.copy().crop( *limits).sum() / stc_norm.data brain = dict() x_hemi_freq = dict() mne.viz.set_3d_backend('pyvista') for band in freq_bands.keys(): brain[band] = u.plot_freq_band_dors(stcs[band], band=band, subject=subject, subjects_dir=dfc.fanat, filebase=filebase) freqfilename3d = (filebase + '_' + band + '_freq_topomap_3d_dors.png') freqfilename3d = os.path.join(dfc.freq, freqfilename3d) image = brain[band].save_image(freqfilename3d) brain_lh, brain_rh = u.plot_freq_band_lat(stcs[band], band=band, subject=subject, subjects_dir=dfc.fanat, filebase=filebase) freqfilename3d = (filebase + '_' + band + '_freq_topomap_3d_lat_lh.png') freqfilename3d = os.path.join(dfc.freq, freqfilename3d) image = brain_lh.save_image(freqfilename3d) freqfilename3d = (filebase + '_' + band + '_freq_topomap_3d_lat_rh.png') freqfilename3d = os.path.join(dfc.freq, freqfilename3d) image = brain_rh.save_image(freqfilename3d) brain_lh, brain_rh = u.plot_freq_band_med(stcs[band], band=band, subject=subject, subjects_dir=dfc.fanat, filebase=filebase) freqfilename3d = (filebase + '_' + band + '_freq_topomap_3d_med_lh.png') freqfilename3d = os.path.join(dfc.freq, freqfilename3d) image = brain_lh.save_image(freqfilename3d) freqfilename3d = (filebase + '_' + band + '_freq_topomap_3d_med_rh.png') freqfilename3d = os.path.join(dfc.freq, freqfilename3d) image = brain_rh.save_image(freqfilename3d) # Cross hemisphere comparison # make sure fsaverage_sym exists in local subjects dir: rootlog.info( f"Calculating cross hemisphere comparison for {band}.") target = os.path.join(dfc.fanat, "fsaverage_sym") if not os.path.isdir(target): # try to find it in $SUBJECTS_DIR and copy os_subj_dir = os.environ.get("SUBJECTS_DIR") fs_avg_sym_dir = os.path.join(os_subj_dir, "fsaverage_sym") u.recursive_overwrite(fs_avg_sym_dir, target) if not os.path.isdir(target): rootlog.error("fsaverage_sym not found - aborting") raise Exception mstc = stcs[band].copy() mstc = mne.compute_source_morph(mstc, subject, 'fsaverage_sym', smooth=5, warn=False, subjects_dir=dfc.fanat).apply(mstc) morph = mne.compute_source_morph(mstc, 'fsaverage_sym', 'fsaverage_sym', spacing=mstc.vertices, warn=False, subjects_dir=dfc.fanat, xhemi=True, verbose='error') stc_xhemi = morph.apply(mstc) diff = mstc - stc_xhemi title = ('blue = RH; ' + subject + ' -Freq-x_hemi- ' + band) x_hemi_freq[band] = diff.plot( hemi='lh', subjects_dir=dfc.fanat, size=(1200, 800), time_label=title, add_data_kwargs=dict(time_label_size=10)) freqfilename3d = (filebase + '_x_hemi_' + band + '.png') freqfilename3d = os.path.join(dfc.freq, freqfilename3d) image = x_hemi_freq[band].save_image(freqfilename3d) # Source localization rootlog.info("Now starting source localization...") epo_filename = opj(dfc.spikes, str(subject) + "-epo.fif") concat_epochs = mne.read_epochs(epo_filename) noise_cov_file = opj(dfc.spikes, "Spikes_noise_covariance.pkl") srcfilename = opj(dfc.fsrc, subject + "-" + spacing + "-src.fif") if not os.path.isfile(noise_cov_file): noise_cov = mne.compute_covariance(concat_epochs, tmax=-1., method='auto', n_jobs=n_jobs, rank="full") pickle.dump(noise_cov, open(noise_cov_file, "wb")) else: with open(noise_cov_file, 'rb') as f: noise_cov = pickle.load(f) rootlog.info( f"The following events have been found: \n{concat_epochs.event_id.keys()}" ) for event in concat_epochs.event_id.keys(): eventname = str(event) if eventname == "ignore_me" or eventname == "AAA" or eventname.startswith( "."): rootlog.info(f"Omitting event {event}") else: try: rootlog.info(f"Now localizing event: {event}") e = concat_epochs[eventname].load_data().crop( tmin=-0.5, tmax=0.5).average() e_folder = os.path.join(dfc.spikes, eventname) evoked_filename = opj(e_folder, ject + "_" + eventname + "-ave.fif") cp_folder = os.path.join(dfc.spikes, eventname, "custom_pics") cts_folder = os.path.join(dfc.spikes, eventname, "custom_time_series") gp_folder = os.path.join(dfc.spikes, eventname, "generic_pics") folders = [e_folder, cp_folder, cts_folder, gp_folder] if not os.path.isdir(e_folder): for f in folders: os.mkdir(f) e.save(evoked_filename) src = mne.read_source_spaces(srcfilename) bem_sol = opj(dfc.fsrc, subject + "-3-layer-BEM-sol.fif") if not os.path.isfile(bem_sol) and use_single_shell_model: bem_sol = opj(dfc.fsrc, subject + "-single-shell-BEM-sol.fif") fwd_name = opj(dfc.fsrc, subject + "-fwd.fif") if os.path.isfile(fwd_name): fwd = mne.read_forward_solution(fwd_name) else: fwd = mne.make_forward_solution(e.info, src=src, bem=bem_sol, trans=transfile, meg=True, eeg=False, mindist=0.2, ignore_ref=False, n_jobs=n_jobs, verbose=True) # inv for cortical surface inv = mne.minimum_norm.make_inverse_operator( e.info, forward=fwd, noise_cov=noise_cov, loose=0.2, depth=0.8) # inv with volume source space vol_srcfilename = opj(dfc.fsrc, subject + "-vol-src.fif") src_vol = mne.read_source_spaces(vol_srcfilename) fwd_vol = mne.make_forward_solution(e.info, src=src_vol, bem=bem_sol, trans=transfile, meg=True, eeg=False, mindist=0.2, ignore_ref=False, n_jobs=n_jobs, verbose=True) inv_vol = mne.minimum_norm.make_inverse_operator( e.info, forward=fwd_vol, noise_cov=noise_cov, loose=1, depth=0.8) # Distributed source models for m in source_loc_methods: stc_name = 'stc_' + m if m == 'dSPM': # calculate vector solution in volume source space try: rootlog.info( "Now calculating dSPM vector solution...") stc_name = mne.minimum_norm.apply_inverse( e, inv_vol, lambda2, method='dSPM', pick_ori='vector') surfer_kwargs = dict( subjects_dir=dfc.fanat, # hemi='split', clim=dict(kind='percent', lims=[90, 96, 99.85]), views=['lat', 'med'], colorbar=True, initial_time=0, time_unit='ms', size=(1000, 800), smoothing_steps=10) brain = stc_name.plot(**surfer_kwargs) label = str(ject + " - " + eventname + " - Vector solution") brain.add_text(0.1, 0.9, label, 'title', font_size=10) img_f_name = ('img_stc_' + ject + '_' + eventname + '_' + m + '.png') img_f_name = os.path.join(gp_folder, img_f_name) brain.save_image(img_f_name) stc_f_name = ("stc_" + ject + '_' + eventname + '_' + m + ".h5") stc_f_name = os.path.join(e_folder, stc_f_name) stc_name = stc_name.crop(tmin=stc_tmin, tmax=stc_tmax) rootlog.info("Saving dSPM vector solution.") stc_name.save(stc_f_name) except Exception as ex: rootlog.error(f"dSPM failed --> {ex}") else: stc_name = mne.minimum_norm.apply_inverse( e, inv, lambda2, method=m, pick_ori=None) surfer_kwargs = dict(hemi='split', subjects_dir=dfc.fanat, clim=dict(kind='percent', lims=[90, 96, 99.85]), views=['lat', 'med'], colorbar=True, initial_time=0, time_unit='ms', size=(1000, 800), smoothing_steps=10) brain = stc_name.plot(**surfer_kwargs) label = str(ject + " - " + eventname + " - " + m) brain.add_text(0.1, 0.9, label, 'title', font_size=10) img_f_name = ('img_stc_' + ject + '_' + eventname + '_' + m + '.png') img_f_name = os.path.join(gp_folder, img_f_name) brain.save_image(img_f_name) stc_f_name = ('stc_' + ject + '_' + eventname + '_' + m) stc_f_name = os.path.join(e_folder, stc_f_name) stc_name = stc_name.crop(tmin=stc_tmin, tmax=stc_tmax) rootlog.info("Saving eLORETA.") stc_name.save(stc_f_name) if m == "eLORETA": try: rootlog.info( "Now calculating eLORETA with peaks...") rh_peaks = u.get_peak_points( stc_name, hemi='rh', tmin=peaks_tmin, tmax=peaks_tmax, nr_points=peaks_nr_of_points, mode=peaks_mode) lh_peaks = u.get_peak_points( stc_name, hemi='lh', tmin=peaks_tmin, tmax=peaks_tmax, nr_points=peaks_nr_of_points, mode=peaks_mode) label = str(ject + " - " + eventname + " - " + m + " - max. activation points") brain.add_text(0.1, 0.9, label, font_size=10) #, 'title' for p in rh_peaks: brain.add_foci(p, color='green', coords_as_verts=True, hemi='rh', scale_factor=0.6, alpha=0.9) for p in lh_peaks: brain.add_foci(p, color='green', coords_as_verts=True, hemi='lh', scale_factor=0.6, alpha=0.9) stc_f_name = ('stc_' + ject + '_' + eventname + '_' + m + "_with_peaks-ave") stc_f_name = os.path.join(e_folder, stc_f_name) stc_name.save(stc_f_name) img_f_name = ('img_stc_' + ject + '_' + eventname + '_' + m + '_with_peaks.png') img_f_name = os.path.join( gp_folder, img_f_name) brain.save_image(img_f_name) except Exception as ex: rootlog.error( f"eLORETA with peaks failed --> {ex}") # Dipoles rootlog.info("Now calculating ECD.") try: for start, stop in dip_times.values(): dip_epoch = e.copy().crop(start, stop).pick('meg') ecd = mne.fit_dipole(dip_epoch, noise_cov, bem_sol, trans=transfile)[0] best_idx = np.argmax(ecd.gof) best_time = ecd.times[best_idx] trans = mne.read_trans(transfile) mri_pos = mne.head_to_mri(ecd.pos, mri_head_t=trans, subject=subject, subjects_dir=dfc.fanat) t1_file_name = os.path.join(dfc.fanat, subject, 'mri', 'T1.mgz') stoptime = str(abs(int(stop * int(e.info["sfreq"])))) if stoptime == "5": stoptime = "05" title = str(eventname + ' - ECD @ minus ' + stoptime + ' ms') t1_fig = plot_anat(t1_file_name, cut_coords=mri_pos[0], title=title) t1_f_name_pic = ('img_ecd_' + eventname + '_' + '_Dipol_' + stoptime + '.png') t1_f_name_pic = os.path.join(e_folder, "generic_pics", t1_f_name_pic) t1_fig.savefig(t1_f_name_pic) fig_3d = ecd.plot_locations(trans, subject, dfc.fanat, mode="orthoview") fig_3d_pic = ('img_3d_ecd_' + eventname + '_' + '_Dipol_' + stoptime + '.png') fig_3d_pic = os.path.join(e_folder, "generic_pics", fig_3d_pic) fig_3d.savefig(fig_3d_pic) plt.close("all") except Exception as ex: rootlog.error(f"ECD calculation failed --> {ex}") except Exception as ex: rootlog.error(f"Source localization failed because of:\n {ex}") # Create report if do_report: reporter = Reporter.EpilepsyReportBuilder( derivatives_root=derivatives_root, subject=subject, extras_dir=extras_directory) reporter.create_report() # Last words logging.info("Finished SourceLocPipeline.") print("SourceLocPipeline completed!")
def plot_mixn(sub, mne_evoked_time, parcellation): trans = sub.load_transformation() dipole_dict = sub.load_mixn_dipoles() for trial in dipole_dict: dipoles = dipole_dict[trial] # Plot Dipole Amplitues (derived from Source Code with added legend) colors = plt.cm.get_cmap(name='hsv', lut=len(dipoles) + 1) fig1, ax = plt.subplots(1, 1) xlim = [np.inf, -np.inf] for i, dip in enumerate(dipoles): ax.plot(dip.times, dip.amplitude * 1e9, color=colors(i), linewidth=1.5, label=f'dipole {i + 1}') xlim[0] = min(xlim[0], dip.times[0]) xlim[1] = max(xlim[1], dip.times[-1]) ax.set(xlim=xlim, xlabel='Time (s)', ylabel='Amplitude (nAm)') ax.legend() fig1.suptitle(f'Dipoles Amplitudes', fontsize=16) fig1.show(warn=False) plot_save(sub, 'mixed-norm-estimate', subfolder='dipoles', trial=trial, matplotlib_figure=fig1) for idx, dipole in enumerate(dipoles): # Assumption right in Head Coordinates? if dipole.pos[0, 0] < 0: side = 'left' hemi = 'lh' else: side = 'right' hemi = 'rh' fig2 = mne.viz.plot_dipole_locations(dipole, trans=trans, subject=sub.subtomri, subjects_dir=sub.subjects_dir, coord_frame='mri') fig2.suptitle(f'Dipole {idx + 1} {side}', fontsize=16) plot_save(sub, 'mixed-norm-estimate', subfolder='dipoles', trial=trial, idx=idx, matplotlib_figure=fig2) brain = Brain(sub.subtomri, hemi=hemi, surf='pial', views='lat') dip_loc = mne.head_to_mri(dipole.pos, sub.subtomri, trans, subjects_dir=sub.subjects_dir) brain.add_foci(dip_loc[0]) brain.add_annotation(parcellation) # Todo: Comparision with label plot_save(sub, 'mixed-norm-estimate', subfolder='dipoles', trial=trial, idx=idx, brain=brain) stcs = sub.load_mixn_source_estimates() brain_plot(sub, stcs, 'mixed-norm-estimate/stc', sub.subtomri, mne_evoked_time)
# extract the location of Nasion, LPA, and RPA from the MEG file, apply our # transformation matrix :code:`trans`, and plot the results. # Get Landmarks from MEG file, 0, 1, and 2 correspond to LPA, NAS, RPA # and the 'r' key will provide us with the xyz coordinates. The coordinates # are expressed here in MEG Head coordinate system. pos = np.asarray((raw.info['dig'][0]['r'], raw.info['dig'][1]['r'], raw.info['dig'][2]['r'])) # We now use the ``head_to_mri`` function from MNE-Python to convert MEG # coordinates to MRI scanner RAS space. For the conversion we use our # estimated transformation matrix and the MEG coordinates extracted from the # raw file. `subjects` and `subjects_dir` are used internally, to point to # the T1-weighted MRI file: `t1_mgh_fname`. Coordinates are is mm. mri_pos = head_to_mri(pos=pos, subject='sample', mri_head_t=estim_trans, subjects_dir=fs_subjects_dir) # Our MRI written to BIDS, we got `anat_dir` from our `write_anat` function t1_nii_fname = op.join(anat_dir, 'sub-01_ses-01_T1w.nii.gz') # Plot it fig, axs = plt.subplots(3, 1, figsize=(7, 7), facecolor='k') for point_idx, label in enumerate(('LPA', 'NAS', 'RPA')): plot_anat(t1_nii_fname, axes=axs[point_idx], cut_coords=mri_pos[point_idx, :], title=label, vmax=160) plt.show()