{ "cells": [ { "cell_type": "markdown", "id": "5ad52697", "metadata": {}, "source": [ "# Processing monocular and binocular data" ] }, { "cell_type": "code", "execution_count": 1, "id": "c7655f3e", "metadata": { "execution": { "iopub.execute_input": "2026-11-09T18:03:53.191056Z", "iopub.status.busy": "2026-11-09T18:03:53.190627Z", "iopub.status.idle": "2026-11-09T18:03:53.461734Z", "shell.execute_reply": "2026-11-09T18:03:53.460165Z" } }, "outputs": [], "source": [ "import pypillometry as pp\n", "import numpy as np" ] }, { "cell_type": "markdown", "id": "fe099bbc", "metadata": {}, "source": [ "Data in `pypillometry` can contain different *variables* from different *eyes*. The variables and eyes supported when importing raw data are\n", "\n", "- `left_x`, `right_x` (x-coordinate in screen coordinates from the eyetracker)\n", "- `left_y`, `right_y` (y-coordinate in screen coordinates from the eyetracker)\n", "- `left_pupil`, `right_pupil` (pupil size from left and right eye)\n", "\n", "All of them are held in an `EyeData` object. Any of these variables can be left out, but at least one must be given, and the `x` and `y` of an eye go together:\n", "\n", "- pupil data only: at least one of `left_pupil`, `right_pupil` (or both)\n", "- gaze data only: at least one of `(left_x, left_y)` and/or `(right_x, right_y)`\n", "- both: `x`, `y` and `pupil` from at least one eye\n", "\n", "For example, let's simulate some basic data:" ] }, { "cell_type": "code", "execution_count": 2, "id": "b2605bfb", "metadata": { "execution": { "iopub.execute_input": "2026-11-09T18:03:53.465343Z", "iopub.status.busy": "2026-11-09T18:03:53.464944Z", "iopub.status.idle": "2026-11-09T18:03:53.480540Z", "shell.execute_reply": "2026-11-09T18:03:53.479442Z" } }, "outputs": [], "source": [ "rng = np.random.default_rng(42)\n", "n = 1000\n", "left_x, right_x = rng.normal(size=n), rng.normal(size=n)\n", "left_y, right_y = rng.normal(size=n), rng.normal(size=n)\n", "left_pupil, right_pupil = rng.normal(size=n), rng.normal(size=n)\n", "time = np.arange(n) # time in ms\n", "\n", "# these are all ok\n", "dpupil = pp.EyeData(left_pupil=left_pupil, right_pupil=right_pupil, time=time)\n", "dgaze = pp.EyeData(left_x=left_x, left_y=left_y, right_x=right_x, right_y=right_y, time=time)\n", "deye = pp.EyeData(left_x=left_x, left_y=left_y, left_pupil=left_pupil, time=time)" ] }, { "cell_type": "markdown", "id": "1acb48b1", "metadata": {}, "source": [ "The `x` and `y` of an eye go together, so giving only one of them (here, `left_x` without `left_y`) fails:" ] }, { "cell_type": "code", "execution_count": 3, "id": "ebd2d201", "metadata": { "execution": { "iopub.execute_input": "2026-11-09T18:03:53.484058Z", "iopub.status.busy": "2026-11-09T18:03:53.483682Z", "iopub.status.idle": "2026-11-09T18:03:53.773780Z", "shell.execute_reply": "2026-11-09T18:03:53.772489Z" }, "tags": [ "raises-exception" ] }, "outputs": [ { "ename": "ValueError", "evalue": "left_x and left_y must be provided together", "output_type": "error", "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mValueError\u001b[39m Traceback (most recent call last)", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[3]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m pp.EyeData(left_x=left_x, time=time)\n", "\u001b[36mFile \u001b[39m\u001b[32m~/Nextcloud/work/projects/pupil/pypillometry/pypillometry/eyedata/eyedata.py:245\u001b[39m, in \u001b[36mEyeData.__init__\u001b[39m\u001b[34m(self, time, left_x, left_y, left_pupil, right_x, right_y, right_pupil, event_onsets, event_labels, events, sampling_rate, experimental_setup, name, calibration, fill_time_discontinuities, keep_orig, info, inplace)\u001b[39m\n\u001b[32m 243\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m eye, x, y \u001b[38;5;129;01min\u001b[39;00m ((\u001b[33m\"\u001b[39m\u001b[33mleft\u001b[39m\u001b[33m\"\u001b[39m, left_x, left_y), (\u001b[33m\"\u001b[39m\u001b[33mright\u001b[39m\u001b[33m\"\u001b[39m, right_x, right_y)):\n\u001b[32m 244\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m (x \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m) != (y \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m):\n\u001b[32m--> \u001b[39m\u001b[32m245\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00meye\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m_x and \u001b[39m\u001b[38;5;132;01m{\u001b[39;00meye\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m_y must be provided together\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 246\u001b[39m \u001b[38;5;28mself\u001b[39m.data = EyeDataDict(left_x=left_x, left_y=left_y, left_pupil=left_pupil,\n\u001b[32m 247\u001b[39m right_x=right_x, right_y=right_y, right_pupil=right_pupil)\n\u001b[32m 249\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m events \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m (event_onsets \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mor\u001b[39;00m event_labels \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m):\n", "\u001b[31mValueError\u001b[39m: left_x and left_y must be provided together" ] } ], "source": [ "pp.EyeData(left_x=left_x, time=time)" ] }, { "cell_type": "markdown", "id": "e84c32e3", "metadata": {}, "source": [ "Once the data is loaded, we can check which variables and eyes are available using the `.eyes` and `.variables` attributes:" ] }, { "cell_type": "code", "execution_count": 4, "id": "53ff9ec0", "metadata": { "execution": { "iopub.execute_input": "2026-11-09T18:03:53.777847Z", "iopub.status.busy": "2026-11-09T18:03:53.777530Z", "iopub.status.idle": "2026-11-09T18:03:53.786716Z", "shell.execute_reply": "2026-11-09T18:03:53.785248Z" } }, "outputs": [ { "data": { "text/plain": [ "(['left'], ['x', 'y', 'pupil'])" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "deye.eyes, deye.variables" ] }, { "cell_type": "markdown", "id": "5a0a271e", "metadata": {}, "source": [ "Simply printing an object also shows which data are available and gives a glimpse into the data:" ] }, { "cell_type": "code", "execution_count": 5, "id": "264beb66", "metadata": { "execution": { "iopub.execute_input": "2026-11-09T18:03:53.790081Z", "iopub.status.busy": "2026-11-09T18:03:53.789562Z", "iopub.status.idle": "2026-11-09T18:03:54.396032Z", "shell.execute_reply": "2026-11-09T18:03:54.394528Z" } }, "outputs": [ { "data": { "text/html": [ "
EyeDataDict(vars=3,n=1000,shape=(1000,)): \n",
" left_x (float64): 0.3047, -1.04, 0.7505, 0.9406, -1.951...\n",
" left_y (float64): -0.452, -0.6659, 0.434, 0.2519, -1.4048...\n",
" left_pupil (float64): 0.2532, 0.8952, 0.2733, 2.2388, 1.4298...\n",
"\n",
" EyeDataDict(vars=2,n=1000,shape=(1000,)): \n",
" left_pupil (float64): 0.2532, 0.8952, 0.2733, 2.2388, 1.4298...\n",
" right_pupil (float64): -0.258, -0.2995, -0.6967, 0.4285, 0.2346...\n",
"\n",
" EyeDataDict(vars=4,n=1000,shape=(1000,)): \n",
" left_x (float64): 0.3374, -1.0226, 0.7882, 0.9805, -1.9441...\n",
" left_y (float64): -0.4779, -0.6884, 0.3939, 0.2147, -1.4156...\n",
" right_x (float64): 0.02179, -0.6389, -0.3285, 0.7054, 0.0832...\n",
" right_y (float64): 1.2814, 0.7062, 2.0163, -1.5846, -0.2704...\n",
"\n",
" EyeDataDict(vars=3,n=1000,shape=(1000,)): \n",
" left_pupil (float64): 0.2752, 0.9186, 0.2953, 2.2651, 1.4543...\n",
" right_pupil (float64): -0.3013, -0.342, -0.7317, 0.3722, 0.182...\n",
" mean_pupil (float64): -0.01307, 0.2883, -0.2182, 1.3186, 0.8181...\n",
"\n",
"