{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n\n# Compute MNE inverse solution on evoked data with a mixed source space\n\nCreate a mixed source space and compute an MNE inverse solution on an\nevoked dataset.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Author: Annalisa Pascarella \n#\n# License: BSD-3-Clause\n# Copyright the MNE-Python contributors." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\nfrom nilearn import plotting\n\nimport mne\nfrom mne.minimum_norm import apply_inverse, make_inverse_operator\n\n# Set dir\ndata_path = mne.datasets.sample.data_path()\nsubject = \"sample\"\ndata_dir = data_path / \"MEG\" / subject\nsubjects_dir = data_path / \"subjects\"\nbem_dir = subjects_dir / subject / \"bem\"\n\n# Set file names\nfname_mixed_src = bem_dir / f\"{subject}-oct-6-mixed-src.fif\"\nfname_aseg = subjects_dir / subject / \"mri\" / \"aseg.mgz\"\n\nfname_model = bem_dir / f\"{subject}-5120-bem.fif\"\nfname_bem = bem_dir / f\"{subject}-5120-bem-sol.fif\"\n\nfname_evoked = data_dir / f\"{subject}_audvis-ave.fif\"\nfname_trans = data_dir / f\"{subject}_audvis_raw-trans.fif\"\nfname_fwd = data_dir / f\"{subject}_audvis-meg-oct-6-mixed-fwd.fif\"\nfname_cov = data_dir / f\"{subject}_audvis-shrunk-cov.fif\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Set up our source space\nList substructures we are interested in. We select only the\nsub structures we want to include in the source space:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "labels_vol = [\n \"Left-Amygdala\",\n \"Left-Thalamus-Proper\",\n \"Left-Cerebellum-Cortex\",\n \"Brain-Stem\",\n \"Right-Amygdala\",\n \"Right-Thalamus-Proper\",\n \"Right-Cerebellum-Cortex\",\n]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Get a surface-based source space, here with few source points for speed\nin this demonstration, in general you should use oct6 spacing!\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "src = mne.setup_source_space(\n subject, spacing=\"oct5\", add_dist=False, subjects_dir=subjects_dir\n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we create a mixed src space by adding the volume regions specified in the\nlist labels_vol. First, read the aseg file and the source space bounds\nusing the inner skull surface (here using 10mm spacing to save time,\nwe recommend something smaller like 5.0 in actual analyses):\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "vol_src = mne.setup_volume_source_space(\n subject,\n mri=fname_aseg,\n pos=10.0,\n bem=fname_model,\n volume_label=labels_vol,\n subjects_dir=subjects_dir,\n add_interpolator=False, # just for speed, usually this should be True\n verbose=True,\n)\n\n# Generate the mixed source space\nsrc += vol_src\nprint(\n f\"The source space contains {len(src)} spaces and \"\n f\"{sum(s['nuse'] for s in src)} vertices\"\n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## View the source space\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "src.plot(subjects_dir=subjects_dir)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We could write the mixed source space with::\n\n >>> write_source_spaces(fname_mixed_src, src, overwrite=True)\n\nWe can also export source positions to NIfTI file and visualize it again:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "nii_fname = bem_dir / f\"{subject}-mixed-src.nii\"\nsrc.export_volume(nii_fname, mri_resolution=True, overwrite=True)\nplotting.plot_img(str(nii_fname), cmap=\"nipy_spectral\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Compute the fwd matrix\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fwd = mne.make_forward_solution(\n fname_evoked,\n fname_trans,\n src,\n fname_bem,\n mindist=5.0, # ignore sources<=5mm from innerskull\n meg=True,\n eeg=False,\n n_jobs=None,\n)\ndel src # save memory\n\nleadfield = fwd[\"sol\"][\"data\"]\nns, nd = leadfield.shape\nprint(f\"Leadfield size : {ns} sensors x {nd} dipoles\")\nprint(\n f\"The fwd source space contains {len(fwd['src'])} spaces and \"\n f\"{sum(s['nuse'] for s in fwd['src'])} vertices\"\n)\n\n# Load data\ncondition = \"Left Auditory\"\nevoked = mne.read_evokeds(fname_evoked, condition=condition, baseline=(None, 0))\nnoise_cov = mne.read_cov(fname_cov)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Compute inverse solution\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "snr = 3.0 # use smaller SNR for raw data\ninv_method = \"dSPM\" # sLORETA, MNE, dSPM\nparc = \"aparc\" # the parcellation to use, e.g., 'aparc' 'aparc.a2009s'\nloose = dict(surface=0.2, volume=1.0)\n\nlambda2 = 1.0 / snr**2\n\ninverse_operator = make_inverse_operator(\n evoked.info, fwd, noise_cov, depth=None, loose=loose, verbose=True\n)\ndel fwd\n\nstc = apply_inverse(evoked, inverse_operator, lambda2, inv_method, pick_ori=None)\nsrc = inverse_operator[\"src\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot the mixed source estimate\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "initial_time = 0.1\nstc_vec = apply_inverse(\n evoked, inverse_operator, lambda2, inv_method, pick_ori=\"vector\"\n)\nbrain = stc_vec.plot(\n hemi=\"both\",\n src=inverse_operator[\"src\"],\n views=\"coronal\",\n initial_time=initial_time,\n subjects_dir=subjects_dir,\n brain_kwargs=dict(silhouette=True),\n smoothing_steps=7,\n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot the surface\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "brain = stc.surface().plot(\n initial_time=initial_time, subjects_dir=subjects_dir, smoothing_steps=7\n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot the volume\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig = stc.volume().plot(initial_time=initial_time, src=src, subjects_dir=subjects_dir)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Process labels\nAverage the source estimates within each label of the cortical parcellation\nand each sub structure contained in the src space\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Get labels for FreeSurfer 'aparc' cortical parcellation with 34 labels/hemi\nlabels_parc = mne.read_labels_from_annot(subject, parc=parc, subjects_dir=subjects_dir)\n\nlabel_ts = mne.extract_label_time_course(\n [stc], labels_parc, src, mode=\"mean\", allow_empty=True\n)\n\n# plot the times series of 2 labels\nfig, axes = plt.subplots(1, layout=\"constrained\")\naxes.plot(1e3 * stc.times, label_ts[0][0, :], \"k\", label=\"bankssts-lh\")\naxes.plot(1e3 * stc.times, label_ts[0][-1, :].T, \"r\", label=\"Brain-stem\")\naxes.set(xlabel=\"Time (ms)\", ylabel=\"MNE current (nAm)\")\naxes.legend()" ] } ], "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 }