{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n\n# Interpolate MEG or EEG data to any montage\n\nThis example demonstrates both EEG montage interpolation and MEG system\ntransformation.\n\nFor EEG, this can be useful for standardizing\nEEG channel layouts across different datasets (see :footcite:`MellotEtAl2024`).\n\n- Using the field interpolation for EEG data.\n- Using the target montage \"biosemi16\".\n- Using the MNE interpolation for MEG data to transform from Neuromag\n (planar gradiometers and magnetometers) to CTF (axial gradiometers).\n\n\nIn the first example, the data from the original EEG channels will be\ninterpolated onto the positions defined by the \"biosemi16\" montage.\n\nIn the second example, we will interpolate MEG data from a 306-sensor Neuromag\nto 275-sensor CTF system.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Authors: Antoine Collas \n# Konstantinos Tsilimparis \n# License: BSD-3-Clause\n# Copyright the MNE-Python contributors.\n\nimport matplotlib.pyplot as plt\n\nimport mne\nfrom mne.channels import make_standard_montage\nfrom mne.datasets import sample\n\nprint(__doc__)\nylim = (-10, 10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Part 1: EEG System Transformation\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Load EEG data\ndata_path = sample.data_path()\neeg_file_path = data_path / \"MEG\" / \"sample\" / \"sample_audvis-ave.fif\"\nevoked = mne.read_evokeds(eeg_file_path, condition=\"Left Auditory\", baseline=(None, 0))\n\n# Select only EEG channels\nevoked.pick(\"eeg\")\n\n# Plot the original EEG layout\nevoked.plot(exclude=[], picks=\"eeg\", ylim=dict(eeg=ylim))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Define the target montage\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "standard_montage = make_standard_montage(\"biosemi16\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Use interpolate_to to project EEG data to the standard montage\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "evoked_interpolated_spline = evoked.copy().interpolate_to(\n standard_montage, method=\"spline\"\n)\n\n# Plot the interpolated EEG layout\nevoked_interpolated_spline.plot(exclude=[], picks=\"eeg\", ylim=dict(eeg=ylim))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Use interpolate_to to project EEG data to the standard montage\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "evoked_interpolated_mne = evoked.copy().interpolate_to(standard_montage, method=\"MNE\")\n\n# Plot the interpolated EEG layout\nevoked_interpolated_mne.plot(exclude=[], picks=\"eeg\", ylim=dict(eeg=ylim))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Comparing before and after interpolation\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, axs = plt.subplots(3, 1, figsize=(8, 6), constrained_layout=True)\nevoked.plot(exclude=[], picks=\"eeg\", axes=axs[0], show=False, ylim=dict(eeg=ylim))\naxs[0].set_title(\"Original EEG Layout\")\nevoked_interpolated_spline.plot(\n exclude=[], picks=\"eeg\", axes=axs[1], show=False, ylim=dict(eeg=ylim)\n)\naxs[1].set_title(\"Interpolated to Standard 1020 Montage using spline interpolation\")\nevoked_interpolated_mne.plot(\n exclude=[], picks=\"eeg\", axes=axs[2], show=False, ylim=dict(eeg=ylim)\n)\naxs[2].set_title(\"Interpolated to Standard 1020 Montage using MNE interpolation\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Part 2: MEG System Transformation\nWe demonstrate transforming MEG data from Neuromag (planar gradiometers\nand magnetometers) to CTF (axial gradiometers) sensor configuration.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Load the full evoked data with MEG channels\nevoked_meg = mne.read_evokeds(\n eeg_file_path, condition=\"Left Auditory\", baseline=(None, 0)\n)\nevoked_meg.pick(\"meg\")\n\nprint(\"Original Neuromag system:\")\nprint(f\" Number of magnetometers: {len(mne.pick_types(evoked_meg.info, meg='mag'))}\")\nprint(f\" Number of gradiometers: {len(mne.pick_types(evoked_meg.info, meg='grad'))}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Transform to CTF sensor configuration\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Interpolate Neuromag to CTF\nevoked_ctf = evoked_meg.copy().interpolate_to(\"ctf275\", mode=\"accurate\")\n\nprint(\"\\nTransformed to CTF system:\")\nprint(f\" Number of MEG channels: {len(mne.pick_types(evoked_ctf.info, meg=True))}\")\nprint(f\" Bad channels in original: {evoked_meg.info['bads']}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Compare evoked responses: Original Neuromag vs Transformed CTF\nThe data should be similar but projected onto different sensor arrays\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Set consistent y-limits for comparison\nylim_meg = dict(grad=[-300, 300], mag=[-600, 600], meg=[-300, 300])\n\nfig, axes = plt.subplots(3, 1, figsize=(10, 8), layout=\"constrained\")\n\n# Plot original Neuromag gradiometers\nevoked_meg.copy().pick(\"grad\").plot(\n axes=axes[0], show=False, spatial_colors=True, ylim=ylim_meg, time_unit=\"s\"\n)\naxes[0].set_title(\"Original Neuromag Planar Gradiometers\", fontsize=14)\n\n\n# Plot original Neuromag magnetometers\nevoked_meg.copy().pick(\"mag\").plot(\n axes=axes[1], show=False, spatial_colors=True, ylim=ylim_meg, time_unit=\"s\"\n)\naxes[1].set_title(\"Original Neuromag Magnetometers\", fontsize=14)\n\n# Plot transformed CTF gradiometers\nevoked_ctf.plot(\n axes=axes[2], show=False, spatial_colors=True, ylim=ylim_meg, time_unit=\"s\"\n)\naxes[2].set_title(\"Transformed to CTF275 Axial Gradiometers\", fontsize=14)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### References\n.. footbibliography::\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.3" } }, "nbformat": 4, "nbformat_minor": 0 }