Module 0: Python Bootcamp for EEG Analysis Workbook
Welcome to your Python programming journey in neuroscience! This interactive workbook contains exercises designed to test your understanding of Python concepts in the context of EEG data analysis. Complete the exercises digitally or on paper, then implement your solutions in your Python environment.
How to use this workbook:
• Click the checkboxes to mark your answers
• Fill in the blanks with appropriate Python code
• Write complete solutions in the provided spaces
• Test all your answers in your Python IDE or Jupyter notebook
• Check your work with the answer key at the end
Topic 2: Python with Neuroscience Examples
Complete the following code to organize EEG channels by brain region:
# Define channel counts for each brain region
frontal_count = # Fp1, Fp2, F3, F4
parietal_count = 4
temporal_count = # T3, T4, T5, T6
occipital_count = 2 # O1, O2
# Create lists of channel names
frontal_channels = ['Fp1', 'Fp2', , ]
temporal_channels = [ , 'T4', 'T5', ]
# Combine all channels into one list
all_channels = frontal_channels + + temporal_channels +
# Calculate total number of channels
total_channels = (all_channels)
print(f"Total EEG channels: { }")
Question: What function would you use to find how many times 'Fp1' appears in all_channels?
Complete this function to calculate EEG recording parameters:
def calculate_eeg_params(sampling_rate, duration_seconds, num_channels):
# Calculate samples per channel
samples_per_channel = *
# Calculate total data points
total_points = samples_per_channel *
# Calculate Nyquist frequency
nyquist_freq = / 2
# File size in MB (4 bytes per sample)
file_size_mb = (total_points * 4) / ( * 1024)
return {
'samples_per_channel': samples_per_channel,
'total_points': total_points,
'nyquist_frequency': nyquist_freq,
'file_size_mb': file_size_mb
}
# Test with 256 Hz, 10 seconds, 32 channels
result = calculate_eeg_params( , , )
True or False:
Topic 3: NumPy for EEG Data
Fill in the blanks to create and manipulate EEG data arrays:
import numpy as np
# Create time array for 5 seconds at 250 Hz
sampling_rate = 250
duration = 5
time = np. (0, duration, )
# Create 8-channel EEG data array with random noise
num_channels = 8
num_samples = len(time)
eeg_data = np.random. ((num_channels, num_samples))
# Add 10 Hz sine wave to channel 0
frequency = 10
amplitude = 50 # microvolts
eeg_data[0, :] += amplitude * np. (2 * np. * frequency * time)
# Extract data from channels 2 to 5
subset = eeg_data[ : , :]
# Calculate mean across all channels (axis=?)
channel_means = np.mean(eeg_data, axis= )
Match the NumPy functions with their EEG applications:
1. np.fft.fft()
2. np.std()
3. np.correlate()
4. np.concatenate()
A. Calculate signal variance
B. Frequency analysis
C. Combine multiple recordings
D. Find signal relationships
Match numbers to letters: 1-___, 2-___, 3-___, 4-___
Complete the epoch extraction function:
def extract_epoch(eeg_data, event_sample, pre_samples, post_samples):
"""Extract a single epoch around an event"""
# Calculate start and end indices
start_idx = event_sample -
end_idx = event_sample +
# Check boundaries
if start_idx < 0 or end_idx > eeg_data.shape[ ]:
return None
# Extract epoch (all channels, time window)
epoch = eeg_data[ , start_idx: ]
return epoch
# Convert time to samples: 200ms = ? samples at 250 Hz
pre_time_ms = 200
pre_samples = int(pre_time_ms * / )
Remember: samples = time_in_seconds × sampling_rate
Select all correct statements about epoching:
Topic 4: Pandas for EEG Data
Complete the code to analyze an EEG experiment's behavioral data:
import pandas as pd
# Create event log DataFrame
events_dict = {
'timestamp': [1.2, 2.5, 3.8, 5.1, 6.4],
'event_type': ['stimulus', 'response', 'stimulus', 'response', 'stimulus'],
'reaction_time': [None, 1.3, None, 1.3, None],
'accuracy': [None, 1, None, 0, None]
}
df = pd. (events_dict)
# Filter only response events
responses = df[df['event_type'] == ]
# Calculate mean reaction time (exclude None values)
mean_rt = responses['reaction_time']. ()
# Count accurate responses
accurate_count = responses['accuracy']. ()
# Group by event type and count
event_counts = df. ('event_type').size()
Which Pandas method would you use for each task?
| Task |
Method |
| Remove rows with missing reaction times |
|
| Sort events by timestamp |
|
| Save DataFrame to CSV |
|
Complete this code to organize EEG frequency band data:
# Define frequency bands
bands = {
'delta': (0.5, 4),
'theta': ( , ),
'alpha': (8, 13),
'beta': ( , 30),
'gamma': (30, )
}
# Create DataFrame for power values
power_data = {
'subject': ['S01', 'S01', 'S02', 'S02'],
'channel': ['Fz', 'Cz', 'Fz', 'Cz'],
'alpha_power': [12.5, 15.3, 10.2, 14.8],
'beta_power': [8.3, 7.9, 9.1, 8.5]
}
df_power = pd.DataFrame(power_data)
# Calculate mean power per subject
subject_means = df_power.groupby( )[['alpha_power', 'beta_power']]. ()
# Find subject with highest alpha power
max_alpha_subject = df_power.loc[df_power['alpha_power']. (), 'subject']. ()
What's the correct way to create a MultiIndex DataFrame for channels × frequency bands?
Topic 5: Matplotlib for EEG Visualization
Complete the code to create a multi-channel EEG plot:
import matplotlib.pyplot as plt
def plot_eeg(data, channel_names, sampling_rate):
n_channels = data.shape[0]
n_samples = data.shape[1]
time = np.arange(n_samples) /
# Create figure and axis
fig, = plt.subplots(figsize=(12, 8))
# Plot each channel with offset
for i in range(n_channels):
offset = i * 100 # microvolts spacing
plt. (time, data[i, :] + offset, 'b-', linewidth=0.5)
# Add channel label
plt. (0, offset, channel_names[i], fontsize=8)
# Set labels
plt.xlabel( )
plt.ylabel('Channel')
plt.title('Multi-channel EEG')
# Add grid
plt. (True, alpha=0.3)
plt.tight_layout()
plt.show()
Match the matplotlib functions with their purpose:
| Function |
Purpose Options |
| plt.specgram() |
|
| plt.axvline() |
|
| plt.colorbar() |
|
Choose the correct parameters for EEG spectrogram visualization:
# Create spectrogram
plt.figure(figsize=(10, 6))
Pxx, freqs, bins, im = plt.specgram(
signal,
NFFT= , # Window size (power of 2)
Fs= , # Sampling frequency
noverlap= , # Overlap between windows
cmap=' ' # Colormap
)
# Limit frequency range for EEG
plt.ylim([0, ]) # Typical EEG range in Hz
# Add colorbar
cbar = plt.colorbar()
cbar.set_label(' ')
For a 256 Hz EEG signal, which NFFT value is most appropriate?
What overlap percentage typically provides good time-frequency resolution?
Final Project: Complete EEG Analysis Pipeline
Complete this comprehensive EEG analysis class by filling in the missing parts:
class EEGAnalyzer:
def __init__(self, data, channels, fs):
self.data = data # numpy array (channels × samples)
self.channels = channels # list of channel names
self.fs = fs # sampling rate
def get_time_array(self):
"""Return time array in seconds"""
n_samples = self.data.shape[ ]
return np.arange(n_samples) / self.
def filter_data(self, low_freq, high_freq):
"""Apply bandpass filter"""
from scipy import signal
# Design Butterworth filter
nyquist = self.fs /
low = low_freq / nyquist
high = high_freq / nyquist
b, a = signal. (4, [low, high], btype='band')
# Apply filter to each channel
filtered = np.zeros_like(self.data)
for ch in range(self.data.shape[0]):
filtered[ch, :] = signal. (b, a, self.data[ch, :])
return filtered
def calculate_band_power(self, band_name):
"""Calculate power in specific frequency band"""
bands = {
'delta': (0.5, 4),
'theta': (4, 8),
'alpha': (8, 13),
'beta': (13, 30),
'gamma': (30, 50)
}
low, high = bands[ ]
# Filter data to band
band_data = self.filter_data( , )
# Calculate power (variance of filtered signal)
power = np. (band_data, axis=1)
return power
Select the correct filter design considerations:
Answer these questions about the EEG analysis pipeline:
- What order should these processing steps typically follow?
- For a 30-minute EEG recording at 500 Hz with 64 channels, calculate the uncompressed file size:
- Write the NumPy code to calculate the correlation between two EEG channels:
- What sampling rate would you need for gamma band activity up to 80 Hz?
Minimum: Hz
Recommended: Hz
Answer Key
Use this section to check your answers after completing all exercises.
Exercise 1: frontal_count = 4, temporal_count = 4, 'F3', 'F4', 'T3', 'T6',
parietal_channels, occipital_channels, len, total_channels
Multiple choice: all_channels.count('Fp1')
Exercise 2: sampling_rate, duration_seconds, num_channels, sampling_rate, 1024,
256, 10, 32
True/False: F, T, T
Exercise 3: linspace, sampling_rate * duration, randn, sin, pi, 2, 5, 1
Matching: 1-B, 2-A, 3-D, 4-C
Exercise 4: pre_samples, post_samples, 1, :, end_idx, 250, 1000
Checkboxes: 1st, 3rd, and 4th statements are correct
Exercise 5: DataFrame, 'response', mean, sum, groupby
Methods: dropna(), sort_values(), to_csv()
Exercise 6: 4, 8, 13, 50, 'subject', mean, idxmax, iloc[0]
Multiple choice: pd.MultiIndex.from_product([channels, bands])
Exercise 7: sampling_rate, ax, plot, text, 'Time (s)', grid
Functions: specgram - Create a spectrogram, axvline - Draw vertical line,
colorbar - Add color scale
Exercise 8: 256, sampling_rate, 128, 'viridis' or 'jet', 50, 'Power (dB/Hz)'
Multiple choice: 256 (NFFT), 50% (overlap)
Exercise 9: 1, fs, 2, butter, filtfilt, band_name, low, high, var
Checkboxes: 1st and 3rd statements are correct
Exercise 10:
1. Artifact removal → Filtering → Epoching → Analysis
2. 30 min × 60 s/min × 500 Hz × 64 channels × 4 bytes = 230.4 MB
3. correlation = np.corrcoef(channel1, channel2)[0, 1]
4. Minimum: 160 Hz, Recommended: 250-500 Hz
Congratulations! 🎉
You've completed the Module 0 workbook. Make sure to implement all these exercises in your Python environment and experiment with different parameters. This hands-on practice is essential for mastering EEG analysis programming!
Next step: Move on to Module 1 - Signal Processing Fundamentals