{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n\n# Background on projectors and projections\n\nThis tutorial provides background information on projectors and Signal Space\nProjection (SSP), and covers loading and saving projectors, adding and removing\nprojectors from Raw objects, the difference between \"applied\" and \"unapplied\"\nprojectors, and at what stages MNE-Python applies projectors automatically.\n\nWe'll start by importing the Python modules we need; we'll also define a short\nfunction to make it easier to make several plots that look similar:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Authors: The MNE-Python contributors.\n# License: BSD-3-Clause\n# Copyright the MNE-Python contributors." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom mpl_toolkits.mplot3d import Axes3D # noqa\nfrom scipy.linalg import svd\n\nimport mne\n\n\ndef setup_3d_axes():\n ax = plt.axes(projection=\"3d\")\n ax.view_init(azim=-105, elev=20)\n ax.set_xlabel(\"x\")\n ax.set_ylabel(\"y\")\n ax.set_zlabel(\"z\")\n ax.set_xlim(-1, 5)\n ax.set_ylim(-1, 5)\n ax.set_zlim(0, 5)\n return ax" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## What is a projection?\n\nIn the most basic terms, a *projection* is an operation that converts one set\nof points into another set of points, where repeating the projection\noperation on the resulting points has no effect. To give a simple geometric\nexample, imagine the point $(3, 2, 5)$ in 3-dimensional space. A\nprojection of that point onto the $x, y$ plane looks a lot like a\nshadow cast by that point if the sun were directly above it:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "ax = setup_3d_axes()\n\n# plot the vector (3, 2, 5)\norigin = np.zeros((3, 1))\npoint = np.array([[3, 2, 5]]).T\nvector = np.hstack([origin, point])\nax.plot(*vector, color=\"k\")\nax.plot(*point, color=\"k\", marker=\"o\")\n\n# project the vector onto the x,y plane and plot it\nxy_projection_matrix = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 0]])\nprojected_point = xy_projection_matrix @ point\nprojected_vector = xy_projection_matrix @ vector\nax.plot(*projected_vector, color=\"C0\")\nax.plot(*projected_point, color=\"C0\", marker=\"o\")\n\n# add dashed arrow showing projection\narrow_coords = np.concatenate([point, projected_point - point]).flatten()\nax.quiver3D(\n *arrow_coords,\n length=0.96,\n arrow_length_ratio=0.1,\n color=\"C1\",\n linewidth=1,\n linestyle=\"dashed\",\n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
The ``@`` symbol indicates matrix multiplication on NumPy arrays, and was\n introduced in Python 3.5 / NumPy 1.10. The notation ``plot(*point)`` uses\n Python `argument expansion`_ to \"unpack\" the elements of ``point`` into\n separate positional arguments to the function. In other words,\n ``plot(*point)`` expands to ``plot(3, 2, 5)``.
It is best to compute projectors only on channels that will be\n used (e.g., excluding bad channels). This ensures that\n projection vectors will remain ortho-normalized and that they\n properly capture the activity of interest.
By convention, MNE-Python expects projectors to be saved with a filename\n ending in ``-proj.fif`` (or ``-proj.fif.gz``), and will issue a warning\n if you forgo this recommendation.
Remember that once a projector is applied, it can't be un-applied, so\n during interactive / exploratory analysis it's a good idea to use the\n object's :meth:`~mne.io.Raw.copy` method before applying projectors.