{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n\n# Working with sEEG data\n\nMNE-Python supports working with more than just MEG and EEG data. Here we show\nsome of the functions that can be used to facilitate working with\nstereoelectroencephalography (sEEG) data.\n\nThis example shows how to use:\n\n- sEEG data\n- channel locations in MNI space\n- projection into a volume\n\nNote that our sample sEEG electrodes are already assumed to be in MNI\nspace. If you want to map positions from your subject MRI space to MNI\nfsaverage space, you must apply the FreeSurfer's talairach.xfm transform\nfor your dataset. You can take a look at `tut-freesurfer-mne` for more\ninformation.\n\nFor an example that involves ECoG data, channel locations in a subject-specific MRI, or\nprojection into a surface, see `tut-working-with-ecog`. In the ECoG example, we\nshow how to visualize surface grid channels on the brain.\n\nPlease note that this tutorial requires 3D plotting dependencies,\nsee `manual-install`.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Authors: Eric Larson \n# Adam Li \n# Alex Rockhill \n#\n# License: BSD-3-Clause\n# Copyright the MNE-Python contributors." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import numpy as np\n\nimport mne\nfrom mne.datasets import fetch_fsaverage\n\n# paths to mne datasets - sample sEEG and FreeSurfer's fsaverage subject\n# which is in MNI space\nmisc_path = mne.datasets.misc.data_path()\nsample_path = mne.datasets.sample.data_path()\nsubjects_dir = sample_path / \"subjects\"\n\n# use mne-python's fsaverage data\nfetch_fsaverage(subjects_dir=subjects_dir, verbose=True) # downloads if needed" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's load some sEEG data with channel locations and make epochs.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "raw = mne.io.read_raw(misc_path / \"seeg\" / \"sample_seeg_ieeg.fif\")\n\nepochs = mne.Epochs(raw, detrend=1, baseline=None)\nepochs = epochs[\"Response\"][0] # just process one epoch of data for speed" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let use the Talairach transform computed in the Freesurfer recon-all\nto apply the Freesurfer surface RAS ('mri') to MNI ('mni_tal') transform.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "montage = epochs.get_montage()\n\n# first we need a head to mri transform since the data is stored in \"head\"\n# coordinates, let's load the mri to head transform and invert it\nthis_subject_dir = misc_path / \"seeg\"\nhead_mri_t = mne.coreg.estimate_head_mri_t(\"sample_seeg\", this_subject_dir)\n# apply the transform to our montage\nmontage.apply_trans(head_mri_t)\n\n# now let's load our Talairach transform and apply it\nmri_mni_t = mne.read_talxfm(\"sample_seeg\", misc_path / \"seeg\")\nmontage.apply_trans(mri_mni_t) # mri to mni_tal (MNI Taliarach)\n\n# for fsaverage, \"mri\" and \"mni_tal\" are equivalent and, since\n# we want to plot in fsaverage \"mri\" space, we need use an identity\n# transform to equate these coordinate frames\nmontage.apply_trans(mne.transforms.Transform(fro=\"mni_tal\", to=\"mri\", trans=np.eye(4)))\n\nepochs.set_montage(montage)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's check to make sure everything is aligned.\n\n

Note

The most rostral electrode in the temporal lobe is outside the\n fsaverage template brain. This is not ideal but it is the best that\n the linear Talairach transform can accomplish. A more complex\n transform is necessary for more accurate warping, see\n `tut-ieeg-localize`.

\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# compute the transform to head for plotting\ntrans = mne.channels.compute_native_head_t(montage)\n# note that this is the same as:\n# ``mne.transforms.invert_transform(\n# mne.transforms.combine_transforms(head_mri_t, mri_mni_t))``\n\nview_kwargs = dict(azimuth=105, elevation=100, focalpoint=(0, 0, -15))\nbrain = mne.viz.Brain(\n \"fsaverage\",\n subjects_dir=subjects_dir,\n cortex=\"low_contrast\",\n alpha=0.25,\n background=\"white\",\n)\nbrain.add_sensors(epochs.info, trans=trans)\nbrain.add_head(alpha=0.25, color=\"tan\")\nbrain.show_view(distance=400, **view_kwargs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, let's project onto the inflated brain surface for visualization.\nThis video may be helpful for understanding the how the annotations on\nthe pial surface translate to the inflated brain and flat map:\n\n.. youtube:: OOy7t1yq8IM\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "brain = mne.viz.Brain(\n \"fsaverage\", subjects_dir=subjects_dir, surf=\"inflated\", background=\"black\"\n)\nbrain.add_annotation(\"aparc.a2009s\")\nbrain.add_sensors(epochs.info, trans=trans)\nbrain.show_view(distance=500, **view_kwargs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's also show the sensors on a flat brain.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "brain = mne.viz.Brain(\n \"fsaverage\", subjects_dir=subjects_dir, surf=\"flat\", background=\"black\"\n)\nbrain.add_annotation(\"aparc.a2009s\")\nbrain.add_sensors(epochs.info, trans=trans)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's also look at which regions of interest are nearby our electrode\ncontacts.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "aseg = \"aparc+aseg\" # parcellation/anatomical segmentation atlas\nlabels, colors = mne.get_montage_volume_labels(\n montage, \"fsaverage\", subjects_dir=subjects_dir, aseg=aseg\n)\n\n# separate by electrodes which have names like LAMY 1\nelectrodes = set(\n [\n \"\".join([lttr for lttr in ch_name if not lttr.isdigit() and lttr != \" \"])\n for ch_name in montage.ch_names\n ]\n)\nprint(f\"Electrodes in the dataset: {electrodes}\")\n\nelectrodes = (\"LPM\", \"LSMA\") # choose two for this example\nfor elec in electrodes:\n picks = [ch_name for ch_name in epochs.ch_names if elec in ch_name]\n fig, ax = mne.viz.plot_channel_labels_circle(labels, colors, picks=picks)\n fig.text(0.3, 0.9, \"Anatomical Labels\", color=\"white\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, let's the electrodes and a few regions of interest that the contacts\nof the electrode are proximal to.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "picks = [\n ii\n for ii, ch_name in enumerate(epochs.ch_names)\n if any([elec in ch_name for elec in electrodes])\n]\nlabels = (\n \"ctx-lh-caudalmiddlefrontal\",\n \"ctx-lh-precentral\",\n \"ctx-lh-superiorfrontal\",\n \"Left-Putamen\",\n)\n\nfig = mne.viz.plot_alignment(\n mne.pick_info(epochs.info, picks),\n trans,\n \"fsaverage\",\n subjects_dir=subjects_dir,\n surfaces=[],\n coord_frame=\"mri\",\n)\n\nbrain = mne.viz.Brain(\n \"fsaverage\",\n alpha=0.1,\n cortex=\"low_contrast\",\n subjects_dir=subjects_dir,\n units=\"m\",\n figure=fig,\n)\nbrain.add_volume_labels(aseg=\"aparc+aseg\", labels=labels)\nbrain.show_view(azimuth=120, elevation=90, distance=0.25)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, we'll get the epoch data and plot its amplitude over time.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "epochs.plot(events=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can visualize this raw data on the ``fsaverage`` brain (in MNI space) as\na heatmap. This works by first creating an ``Evoked`` data structure\nfrom the data of interest (in this example, it is just the raw LFP).\nThen one should generate a ``stc`` data structure, which will be able\nto visualize source activity on the brain in various different formats.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# get standard fsaverage volume (5mm grid) source space\nfname_src = subjects_dir / \"fsaverage\" / \"bem\" / \"fsaverage-vol-5-src.fif\"\nvol_src = mne.read_source_spaces(fname_src)\n\nevoked = epochs.average()\nstc = mne.stc_near_sensors(\n evoked,\n trans,\n \"fsaverage\",\n subjects_dir=subjects_dir,\n src=vol_src,\n surface=None,\n verbose=\"error\",\n)\nstc = abs(stc) # just look at magnitude\nclim = dict(kind=\"value\", lims=np.percentile(abs(evoked.data), [10, 50, 75]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Plot 3D source (brain region) visualization:\n\nBy default, `stc.plot_3d() ` will show a time\ncourse of the source with the largest absolute value across any time point.\nIn this example, it is simply the source with the largest raw signal value.\nIts location is marked on the brain by a small blue sphere.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "brain = stc.plot_3d(\n src=vol_src,\n subjects_dir=subjects_dir,\n view_layout=\"horizontal\",\n views=[\"axial\", \"coronal\", \"sagittal\"],\n size=(800, 300),\n show_traces=0.4,\n clim=clim,\n add_data_kwargs=dict(colorbar_kwargs=dict(label_font_size=8)),\n)\n\n# You can save a movie like the one on our documentation website with:\n# brain.save_movie(time_dilation=3, interpolation='linear', framerate=5,\n# time_viewer=True, filename='./mne-test-seeg.m4')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this tutorial, we used a BEM surface for the ``fsaverage`` subject from\nFreeSurfer.\n\nFor additional common analyses of interest, see the following:\n\n- For volumetric plotting options, including limiting to a specific area of\n the volume specified by say an atlas, or plotting different types of\n source visualizations see:\n `tut-viz-stcs`.\n- For extracting activation within a specific FreeSurfer volume and using\n different FreeSurfer volumes, see: `tut-freesurfer-mne`.\n- For working with BEM surfaces and using FreeSurfer, or MNE to generate\n them, see: `tut-forward`.\n\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.2" } }, "nbformat": 4, "nbformat_minor": 0 }