def xmain(bids_dir, freesurfer_dir, acquisition='clinical', noparallel=False): """ assign electrodes to brain regions', Parameters ---------- bids_dir : path freesurfer_dir : path acquisition : str acquisition type of the electrode files noparallel : bool if it should run serially (i.e. not parallely, mostly for debugging) """ args = [] for electrode_path in find_in_bids(bids_dir, generator=True, acquisition=acquisition, modality='electrodes', extension='.tsv'): elec = Electrodes(electrode_path) fs = Freesurfer(freesurfer_dir / ('sub-' + elec.subject)) args.append((elec, fs)) if noparallel: for arg in args: assign_regions(*arg) else: with Pool(processes=4) as p: p.starmap(assign_regions, args)
def calc_fmri_at_elec(measure_nii, electrodes_file, distance, kernels, graymatter, output_dir): """ Calculate the (weighted) average of fMRI values at electrode locations """ electrodes = Electrodes(electrodes_file) img = nload(str(measure_nii)) mri = img.get_data() mri[mri == 0] = NaN labels = electrodes.electrodes.get(map_lambda=lambda x: x['name']) chan_xyz = array(electrodes.get_xyz()) nd = array(list(ndindex(mri.shape))) ndi = from_mrifile_to_chan(img, nd) if graymatter: gm_mri = nload(str(graymatter)).get_data().astype(bool) mri[~gm_mri] = NaN lg.debug( f'Computing fMRI values for {measure_nii.name} at {len(labels)} electrodes and {len(kernels)} "{distance}" kernels' ) fmri_vals, n_voxels = compute_kernels(kernels, chan_xyz, mri, ndi, distance) fmri_vals_tsv = output_dir / replace_underscore(measure_nii.name, 'compare.tsv') n_voxels_tsv = output_dir / replace_underscore(measure_nii.name, 'nvoxels.tsv') with fmri_vals_tsv.open('w') as f: f.write('channel\t' + '\t'.join(str(one_k) for one_k in kernels) + '\n') for one_label, val_at_elec in zip(labels, fmri_vals): f.write(one_label + '\t' + '\t'.join(str(one_val) for one_val in val_at_elec) + '\n') with n_voxels_tsv.open('w') as f: f.write('channel\t' + '\t'.join(str(one_k) for one_k in kernels) + '\n') for one_label, val_at_elec in zip(labels, n_voxels): f.write(one_label + '\t' + '\t'.join(str(one_val) for one_val in val_at_elec) + '\n') return fmri_vals_tsv, n_voxels_tsv
def read_ieeg_block(filename, electrode_file, conditions, minimalduration, output_dir): d = Dataset(filename, bids=True) markers = d.read_markers() electrodes = Electrodes(electrode_file) elec_names = [x['name'] for x in electrodes.electrodes.tsv] elec_names = [x for x in elec_names if x in d.header['chan_name'] ] # exclude elec location that have no corresponding channel all_conditions = [x for v in conditions.values() for x in v] clean_labels = _reject_channels(d, elec_names, all_conditions, minimalduration) outputs = [] for active_baseline, data_conds in conditions.items(): block_beg = [] block_end = [] for mrk in markers: if mrk['name'] in data_conds: dur = (mrk['end'] - mrk['start']) if dur >= minimalduration: block_beg.append(mrk['start']) block_end.append(mrk['end']) data = d.read_data(begtime=block_beg, endtime=block_end, chan=clean_labels) output_task = Task(filename) output_task.extension = '.pkl' output_task.task += active_baseline output_file = output_dir / output_task.get_filename() with output_file.open('wb') as f: dump(data, f) outputs.append(output_file) return outputs
def assign_regions(elec, freesurfer): bids_dir = find_root(elec.filename) elec.acquisition += 'regions' tsv_electrodes = elec.get_filename(bids_dir) with tsv_electrodes.open('w') as f: f.write('name\tx\ty\tz\ttype\tsize\tmaterial\tregion\n' ) # TODO: region is not in BEP010 for _tsv in elec.electrodes.tsv: xyz = array([float(_tsv['x']), float(_tsv['y']), float(_tsv['z'])]) region = freesurfer.find_brain_region( xyz, exclude_regions=('White', 'WM', 'Unknown'))[0] f.write( f'{_tsv["name"]}\t{_tsv["x"]}\t{_tsv["y"]}\t{_tsv["z"]}\t{_tsv["type"]}\t{_tsv["size"]}\t{_tsv["material"]}\t{region}\n' ) elec.coordframe.json[ 'iEEGCoordinateProcessingDescription'] += '; Assign brain regions' # TODO: better description + remove None new_json = replace_underscore(tsv_electrodes, 'coordsystem.json') with new_json.open('w') as f: dump(elec.coordframe.json, f, indent=2) return Electrodes(tsv_electrodes)
def xmain(bids_dir, analysis_dir, freesurfer_dir, output_dir, acquisition='clinical', measure_modality="", measure_column=""): """ plot electrodes onto the brain surface, Parameters ---------- bids_dir : path analysis_dir : path freesurfer_dir : path output_dir : path acquisition : str acquisition type of the electrode files measure_modality : str modality measure_column : str column """ img_dir = output_dir / ELECSURF_DIR rmtree(img_dir, ignore_errors=True) img_dir.mkdir(exist_ok=True, parents=True) for electrode_path in find_in_bids(bids_dir, generator=True, acquisition=acquisition, modality='electrodes', extension='.tsv'): lg.debug(f'Reading electrodes from {electrode_path}') elec = Electrodes(electrode_path) fs = Freesurfer(freesurfer_dir / ('sub-' + elec.subject)) labels = None if measure_modality != "": try: ecog_file = find_in_bids(analysis_dir, subject=elec.subject, modality=measure_modality, extension='.tsv') except FileNotFoundError as err: lg.warning(err) continue lg.debug(f'Reading {measure_column} from {ecog_file}') ecog_tsv = read_tsv(ecog_file) labels = [x['name'] for x in elec.electrodes.tsv] labels, vals = read_channels(ecog_tsv, labels, measure_column) else: vals = None v = plot_electrodes(elec, fs, labels, vals) png_file = img_dir / replace_underscore(elec.get_filename(), 'surfaceplot.png') lg.debug(f'Saving electrode plot on {png_file}') v.save(png_file) v.close()
def plot_surface(parameters, frequency_band, subject, surf): elec_file = get_path(parameters, 'elec', subject=subject) ieeg_file = get_path(parameters, 'ieeg_tsv', frequency_band=frequency_band, subject=subject) fmri_file = get_path(parameters, 'fmri_nii', subject=subject) if elec_file is None or ieeg_file is None or fmri_file is None: return freesurfer_dir = parameters['paths'][ 'freesurfer_subjects_dir'] / f'sub-{subject}' compare_ieeg = read_tsv(ieeg_file) fs = Freesurfer(freesurfer_dir) electrodes = Electrodes(elec_file) elec = electrodes.electrodes.tsv all_elec = [] labels = [] for chan in compare_ieeg: i_chan = where(elec['name'] == chan['channel'])[0] all_elec.append(elec[i_chan]) labels.append(f"{chan['channel']} = {chan['measure']:0.3f}") elec = concatenate(all_elec) if mean(elec['x']) > 0: right_or_left = 1 hemi = 'rh' else: right_or_left = -1 hemi = 'lh' fs = Freesurfer(freesurfer_dir) pial = getattr(fs.read_brain(), hemi) vert = pial.vert + fs.surface_ras_shift if subject in surf: fmri_vals = surf[subject] else: print(f'Computing surf for {subject}') fmri_vals = project_mri_to_surf( fmri_file, vert, parameters['plot']['surface']['kernel']) surf[subject] = fmri_vals colorscale = 'balance' traces = [ go.Scatter3d( x=elec['x'], y=elec['y'], z=elec['z'], text=labels, mode='markers', hoverinfo='text', marker=dict( size=5, color=compare_ieeg['measure'], colorscale=colorscale, showscale=True, cmid=0, colorbar=dict( title='electrodes', titleside="top", ticks="outside", ticklabelposition="outside", x=0, ), ), ), go.Mesh3d( x=vert[:, 0], y=vert[:, 1], z=vert[:, 2], i=pial.tri[:, 0], j=pial.tri[:, 1], k=pial.tri[:, 2], intensity=fmri_vals, cmid=0, colorscale='Balance', hoverinfo='skip', flatshading=False, colorbar=dict( title='fmri', titleside="top", ticks="outside", ticklabelposition="outside", x=1, ), lighting=dict( ambient=0.18, diffuse=1, fresnel=0.1, specular=1, roughness=0.1, ), lightposition=dict( x=0, y=0, z=-1, ), ), ] fig = go.Figure( data=traces, layout=go.Layout(scene=dict( xaxis=AXIS, yaxis=AXIS, zaxis=AXIS, camera=dict( eye=dict( x=right_or_left, y=0, z=0, ), projection=dict(type='orthographic', ), ), ), ), ) return to_div(fig)
def test_Electrodes_get_xyz(): elec = Electrodes(elec_ct.get_filename(BIDS_PATH)) assert len(elec.get_xyz()) == 28 assert len(elec.get_xyz(['grid01', ])) == 1
def paper_plot_surf_bold(parameters, subject): elec_file = get_path(parameters, 'elec', subject=subject) fmri_file = get_path(parameters, 'fmri_nii', subject=subject) freesurfer_dir = parameters['paths']['freesurfer_subjects_dir'] / f'sub-{subject}' fs = Freesurfer(freesurfer_dir) electrodes = Electrodes(elec_file) elec = electrodes.electrodes.tsv if mean(elec['x']) > 0: right_or_left = 1 hemi = 'rh' else: right_or_left = -1 hemi = 'lh' fs = Freesurfer(freesurfer_dir) pial = getattr(fs.read_brain(), hemi) vert = pial.vert + fs.surface_ras_shift fmri_vals = project_mri_to_surf(fmri_file, vert, parameters['plot']['surface']['kernel']) colorscale = 'balance' traces = [ go.Scatter3d( x=elec['x'] + right_or_left, y=elec['y'], z=elec['z'] + 1, mode='markers', hoverinfo='text', marker=dict( size=5, color='black', ), ), go.Mesh3d( x=vert[:, 0], y=vert[:, 1], z=vert[:, 2], i=pial.tri[:, 0], j=pial.tri[:, 1], k=pial.tri[:, 2], intensity=fmri_vals, cmax=4, cmin=-4, colorscale=colorscale, hoverinfo='skip', flatshading=False, showscale=False, lighting=dict( ambient=0.18, diffuse=1, fresnel=0.1, specular=1, roughness=0.1, ), lightposition=dict( x=0, y=0, z=-1, ), ), ] fig = go.Figure( data=traces, layout=go.Layout( scene=dict( xaxis=AXIS, yaxis=AXIS, zaxis=AXIS, camera=dict( eye=dict( x=right_or_left, y=0, z=1, ), projection=dict( type='orthographic', ), ), ), ), ) return fig
def project_electrodes(elec, freesurfer, analysis_dir): elec.acquisition += 'projected' bids_root = find_root(elec.filename) tsv_electrodes = elec.get_filename(bids_root) elec_realigned = {} HEMI = { 'L': 'lh', 'R': 'rh', } groups = {x['group'] for x in elec.electrodes.tsv} for group in groups: print(group) anat_dir = analysis_dir / ('sub-' + elec.subject) / 'anat' anat_dir.mkdir(exist_ok=True, parents=True) labels = [ x['name'] for x in elec.electrodes.tsv if x['group'] == group ] hemi = [ x['hemisphere'] for x in elec.electrodes.tsv if x['group'] == group ][0] elec_type = [ x['type'] for x in elec.electrodes.tsv if x['group'] == group ][0] if not elec_type == 'surface': print(f'not realigning {group} because its type is {elec_type}') for _elec in elec.electrodes_tsv: if _elec['group'] == group: elec_realigned[_elec['label']] = (float(_elec['x']), float(_elec['y']), float(_elec['z'])) anat_file = anat_dir / (HEMI[hemi] + '.smooth') if not anat_file.exists(): surf = getattr(freesurfer.read_brain('pial'), HEMI[hemi]) fill_surface(surf.surf_file, anat_file) xyz = array([(float(x['x']), float(x['y']), float(x['z'])) for x in elec.electrodes.tsv if x['group'] == group]) xyz -= freesurfer.surface_ras_shift xyz_realigned = snap_elec_to_surf(xyz, anat_file) for label, xyz_ in zip(labels, xyz_realigned): elec_realigned[label] = xyz_ + freesurfer.surface_ras_shift with tsv_electrodes.open('w') as f: f.write('name\tgroup\tx\ty\tz\tsize\ttype\tmaterial\themisphere\n') for _elec in elec.electrodes.tsv: label = _elec['name'] xyz = "\t".join(f'{x:f}' for x in elec_realigned[label]) one_chans = [x for x in elec.electrodes.tsv if x['name'] == label][0] group = one_chans['group'] elec_type = one_chans['type'] size = one_chans['size'] material = one_chans['material'] hemisphere = one_chans['hemisphere'] f.write( f'{label}\t{group}\t{xyz}\t{size}\t{elec_type}\t{material}\t{hemisphere}\n' ) elec.coordframe.json[ 'iEEGCoordinateProcessingDescription'] += '; Dijkstra et al.' # TODO: better description + remove None new_json = replace_underscore(tsv_electrodes, 'coordsystem.json') with new_json.open('w') as f: dump(elec.coordframe.json, f, indent=2) return Electrodes(tsv_electrodes)