Skip to content

Commit

Permalink
update doc
Browse files Browse the repository at this point in the history
  • Loading branch information
qian-chu committed Sep 25, 2024
1 parent 46fb50f commit fffa5d7
Show file tree
Hide file tree
Showing 20 changed files with 1,895 additions and 148 deletions.
Binary file modified docs/_images/tutorials_resample_and_concat_17_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
389 changes: 389 additions & 0 deletions docs/_sources/tutorials/epoching.ipynb.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,389 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Tutorial: Processing Eye-Tracking Data with PyNeon\n",
"\n",
"## Step 1: Loading Sample Data\n",
"\n",
"First, we'll load sample eye-tracking data provided by PyNeon."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"from pyneon import NeonRecording, get_sample_data\n",
"from pyneon.preprocess import *\n",
"\n",
"# Load the sample recording\n",
"recording_dir = get_sample_data(\"OfficeWalk\") / \"Timeseries Data\" / \"walk1-e116e606\"\n",
"recording = NeonRecording(recording_dir)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 2: Constructing Event Times\n",
"\n",
"We'll create a list of event times from 0 to 100 seconds at intervals of 0.1 seconds. These events will serve as reference points for creating epochs."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" t_ref t_before t_after description\n",
"0 1.725032e+18 100000000.0 500000000.0 test_event\n",
"1 1.725032e+18 100000000.0 500000000.0 test_event\n",
"2 1.725032e+18 100000000.0 500000000.0 test_event\n",
"3 1.725032e+18 100000000.0 500000000.0 test_event\n",
"4 1.725032e+18 100000000.0 500000000.0 test_event\n"
]
}
],
"source": [
"# Create a list of event times from 0 to 100 seconds at 0.1-second intervals\n",
"tlist = np.arange(0, 100, 0.1)\n",
"global_ref_time = recording.start_time\n",
"\n",
"# Construct event times DataFrame\n",
"event_times = construct_event_times(\n",
" t_refs=tlist,\n",
" t_before=0.1, # 0.1 seconds before the event\n",
" t_after=0.5, # 0.5 seconds after the event\n",
" description=\"test_event\",\n",
" global_t_ref=global_ref_time,\n",
" time_unit=\"s\", # Specify that t_refs are in seconds\n",
")\n",
"\n",
"# Display the first few event times\n",
"print(event_times.head())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 3: Verifying Event Intervals\n",
"\n",
"Check the average interval between events to confirm they are correctly spaced."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Average interval between events: 100000000.0 nanoseconds\n"
]
}
],
"source": [
"# Calculate the average difference between subsequent event times\n",
"average_interval = np.mean(np.diff(event_times[\"t_ref\"]))\n",
"\n",
"print(f\"Average interval between events: {average_interval} nanoseconds\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This confirms that events are spaced 0.1 seconds (100,000,000 nanoseconds) apart.\n",
"\n",
"## Step 4: Creating Epochs from the Data\n",
"\n",
"Use the create_epoch function to create epochs from the gaze data based on the event times."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# Create epochs from the gaze data\n",
"epochs_df, annotated_data = create_epoch(recording.gaze.data, event_times)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"epoch id 29\n",
"t_ref 1725032224427000064\n",
"t_before 100000000.0\n",
"t_after 500000000.0\n",
"description test_event\n",
"epoch data timestamp [ns] gaze x [px] gaze y [p...\n",
"Name: 0, dtype: object\n"
]
}
],
"source": [
"print(epochs_df.iloc[0])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Every row in the epochs_df file has information about the epoch as well as the data assigned to this epoch. "
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"timestamp [ns] 1725032224852161732\n",
"gaze x [px] 1067.486\n",
"gaze y [px] 620.856\n",
"worn True\n",
"fixation id 1\n",
"blink id <NA>\n",
"azimuth [deg] 16.21303\n",
"elevation [deg] -0.748998\n",
"time [s] 0.0\n",
"epoch id 34\n",
"description test_event\n",
"t_rel -74838272.0\n",
"Name: 0, dtype: object\n"
]
}
],
"source": [
"print(annotated_data.iloc[0])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"On the other hand, annotated data has the information about the current epoch appended at the end.\n",
"\n",
"Alternatively, an epoch object can also be created without an event_times object but rather the info needed to create one"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [],
"source": [
"epochs_df, annotated_data = create_epoch(\n",
" recording.gaze.data,\n",
" times_df=None,\n",
" t_refs=tlist,\n",
" t_before=0.1,\n",
" t_after=0.5,\n",
" global_t_ref=global_ref_time,\n",
" time_unit=\"s\",\n",
" description=\"test_event\",\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This object is equivalent to the ones created before"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 5: Initializing the Epoch Class\n",
"\n",
"Initialize the Epoch class with the gaze data and event times."
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"# Initialize the Epoch object\n",
"\n",
"epochs = Epoch(recording.gaze.data, event_times)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 6: Converting Epochs to NumPy Array\n",
"\n",
"Convert the epochs into a NumPy array, specifying the columns of interest"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"NaN values were found in the data.\n",
"Column IDs: ['gaze x [px]', 'gaze y [px]']\n",
"Time relative to reference (s): [-0.1 -0.09 -0.08 -0.07 -0.06 -0.05 -0.04 -0.03 -0.02 -0.01 0. 0.01\n",
" 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1 0.11 0.12 0.13\n",
" 0.14 0.15 0.16 0.17 0.18 0.19 0.2 0.21 0.22 0.23 0.24 0.25\n",
" 0.26 0.27 0.28 0.29 0.3 0.31 0.32 0.33 0.34 0.35 0.36 0.37\n",
" 0.38 0.39 0.4 0.41 0.42 0.43 0.44 0.45 0.46 0.47 0.48 0.49\n",
" 0.5 ]\n",
"Shape of epochs array: (955, 61, 2)\n"
]
}
],
"source": [
"# Convert epochs to NumPy array, selecting specific columns\n",
"ep_np, info = epochs.to_numpy(columns=[\"gaze x [px]\", \"gaze y [px]\"])\n",
"\n",
"# Display information about the epochs\n",
"print(\"Column IDs:\", info[\"column_ids\"])\n",
"print(\"Time relative to reference (s):\", info[\"t_rel\"] * 1e-9)\n",
"print(\"Shape of epochs array:\", ep_np.shape)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Column IDs: The data channels extracted.\n",
"Times: The common time grid for all epochs.\n",
"Shape: Indicates there are 1000 epochs, each with 61 time points and 2 data channels.\n",
"\n",
"## Step 7: Averaging Across Epochs\n",
"\n",
"Compute the average across all epochs to get the mean time-series."
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Shape after averaging across epochs: (61, 2)\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"C:\\Users\\jan-gabriel.hartel\\AppData\\Local\\Temp\\ipykernel_12180\\2544218633.py:2: RuntimeWarning: Mean of empty slice\n",
" integrated_epochs = np.nanmean(ep_np, axis=0)\n"
]
}
],
"source": [
"# Average across epochs (resulting in a 2D array)\n",
"integrated_epochs = np.nanmean(ep_np, axis=0)\n",
"print(\"Shape after averaging across epochs:\", integrated_epochs.shape)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The resulting array has 61 time points and 2 channels.\n",
"\n",
"## Step 8: Averaging Over Time\n",
"\n",
"Further, average over time to get a single value per channel."
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Averaged values over time: [784.02903257 539.72164082]\n"
]
}
],
"source": [
"# Average over time (resulting in a 1D array)\n",
"integrate_in_time = np.nanmean(integrated_epochs, axis=0)\n",
"print(\"Averaged values over time:\", integrate_in_time)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"his gives the overall mean for each data channel.\n",
"\n",
"## Conclusion\n",
"\n",
"In this tutorial, we've demonstrated how to:\n",
"\n",
"- Load sample eye-tracking data using PyNeon.\n",
"- Construct event times for epoching the data.\n",
"- Create epochs from continuous gaze data.\n",
"- Convert epochs into a NumPy array for analysis.\n",
"- Perform averaging across epochs and over time.\n",
"\n",
"These steps are essential for preprocessing eye-tracking data and can be extended for more advanced analyses."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "pyneon",
"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.5"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
2 changes: 1 addition & 1 deletion docs/_sources/tutorials/export_to_bids.ipynb.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
"version": "3.12.6"
}
},
"nbformat": 4,
Expand Down
Loading

0 comments on commit fffa5d7

Please sign in to comment.