{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n\n# Plotting eye-tracking heatmaps in MNE-Python\n\nThis tutorial covers plotting eye-tracking position data as a heatmap.\n\n.. seealso::\n\n `tut-importing-eyetracking-data`\n `tut-eyetrack`\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": "markdown", "metadata": {}, "source": [ "## Data loading\n\nAs usual we start by importing the modules we need and loading some\n`example data `: eye-tracking data recorded from SR research's\n``'.asc'`` file format.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n\nimport mne\nfrom mne.viz.eyetracking import plot_gaze\n\ntask_fpath = mne.datasets.eyelink.data_path() / \"freeviewing\"\net_fpath = task_fpath / \"sub-01_task-freeview_eyetrack.asc\"\nstim_fpath = task_fpath / \"stim\" / \"naturalistic.png\"\n\nraw = mne.io.read_raw_eyelink(et_fpath)\ncalibration = mne.preprocessing.eyetracking.read_eyelink_calibration(\n et_fpath,\n screen_resolution=(1920, 1080),\n screen_size=(0.53, 0.3),\n screen_distance=0.9,\n)[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Process and epoch the data\n\nFirst we will interpolate missing data during blinks and epoch the data.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "mne.preprocessing.eyetracking.interpolate_blinks(raw, interpolate_gaze=True)\nraw.annotations.rename({\"dvns\": \"natural\"}) # more intuitive\n\nepochs = mne.Epochs(raw, event_id=[\"natural\"], tmin=0, tmax=20, baseline=None)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot a heatmap of the eye-tracking data\n\nTo make a heatmap of the eye-tracking data, we can use the function\n:func:`~mne.viz.eyetracking.plot_gaze`. We will need to define the dimensions of our\ncanvas; for this file, the eye position data are reported in pixels, so we'll use the\nscreen resolution of the participant screen (1920x1080) as the width and height. We\ncan also use the sigma parameter to smooth the plot.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "cmap = plt.get_cmap(\"viridis\")\nplot_gaze(epochs[\"natural\"], calibration=calibration, cmap=cmap, sigma=50)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Note

The (0, 0) pixel coordinates are at the top-left of the\n trackable area of the screen for many eye trackers.

\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Overlaying plots with images\n\nWe can use matplotlib to plot gaze heatmaps on top of stimuli images. We'll\ncustomize a :class:`~matplotlib.colors.Colormap` to make some values of the heatmap\ncompletely transparent. We'll then use the ``vlim`` parameter to force the heatmap to\nstart at a value greater than the darkest value in our previous heatmap, which will\nmake the darkest colors of the heatmap transparent.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "cmap.set_under(\"k\", alpha=0) # make the lowest values transparent\nax = plt.subplot()\nax.imshow(plt.imread(stim_fpath))\nplot_gaze(\n epochs[\"natural\"],\n calibration=calibration,\n vlim=(0.0003, None),\n sigma=50,\n cmap=cmap,\n axes=ax,\n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Displaying the heatmap in units of visual angle\n\nIn scientific publications it is common to report gaze data as the visual angle\nfrom the participants eye to the screen. We can convert the units of our gaze data to\nradians of visual angle before plotting the heatmap:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "epochs.load_data()\nmne.preprocessing.eyetracking.convert_units(epochs, calibration, to=\"radians\")\nplot_gaze(\n epochs[\"natural\"],\n calibration=calibration,\n sigma=50,\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 }