Skip to content

Ephys Data Module

The ephys_data module provides tools for analyzing electrophysiology data, including spike trains, local field potentials (LFPs), and EMG signals.

Modules

ephys_data.py

Core class for loading and analyzing electrophysiology data.

visualize.py

Functions for visualizing neural data, including raster plots and firing rate heatmaps.

lfp_processing.py

Tools for extracting and processing LFP data from raw recordings.

BAKS.py

Implementation of Bayesian Adaptive Kernel Smoother for firing rate estimation.

Basic Usage

from utils.ephys_data.ephys_data import ephys_data

# Initialize with data directory
data = ephys_data(data_dir='/path/to/data')

# Load basic data
data.get_unit_descriptors()  # Get unit information
data.get_spikes()           # Extract spike data

# Calculating firing rates and LFPs needs additional parameters
# If not set, the module will use default values
# See `Default Parameters` section for details

# data.firing_rate_params = { ... }
# or
# data.firing_rate_params = data.default_firing_params

# data.stft_params = { ... }
# or
# data.lfp_params = data.default_lfp_params

data.get_firing_rates()     # Calculate firing rates
data.get_lfps()            # Extract LFP data

# Same for STFT calculation
data.stft_params = { ... }
data.get_stft()            # Calculate spectrograms

Key Features

Spike and Firing Rate Analysis

# Access spike data
spikes = data.spikes       # List of spike arrays per taste
firing = data.firing_array # 4D array of firing rates

LFP Analysis

# Access LFP data
lfps = data.lfp_array     # Raw LFP data
stft = data.stft_array    # Complex Spectrograms
amplitude = data.amplitude_array # STFT Amplitude (power)
phase = data.phase_array  # STFT Phase

Region-Based Analysis

# Get units by brain region
data.get_region_units()
region_spikes = data.return_region_spikes('region_name')
region_firing = data.get_region_firing('region_name')

# Get LFPs by region
region_lfps, region_names = data.return_region_lfps()

Laser Condition Analysis

# Check for laser trials
data.check_laser()

# Separate data by laser condition
data.separate_laser_data()  # Separates spikes, firing rates, and LFPs

# Access separated data
on_spikes = data.on_spikes
off_spikes = data.off_spikes
on_firing = data.on_firing
off_firing = data.off_firing

Trial Information

# Get trial information
data.get_trial_info_frame()

# Sequester trials by condition
data.sequester_trial_inds()
data.get_sequestered_spikes()
data.get_sequestered_firing()

Palatability Analysis

# Calculate palatability correlations
data.calc_palatability()

# Access results
pal_df = data.pal_df       # Palatability rankings
pal_array = data.pal_array # Palatability correlations

Example Workflows

Ephys Data Processing

from utils.ephys_data.ephys_data import ephys_data
import numpy as np
import matplotlib.pyplot as plt

# Load data
data = ephys_data(data_dir='/path/to/data')

# Get basic information
data.get_unit_descriptors()
data.get_spikes()
data.get_firing_rates()
data.get_lfps()

# Analyze by brain region
data.get_region_units()
print(f"Available regions: {data.region_names}")

# Get spikes for a specific region
region_spikes = data.return_region_spikes('GC')  # Gustatory cortex example

# Analyze laser conditions (if applicable)
data.check_laser()
if data.laser_exists:
    data.separate_laser_data()
    # Compare firing rates between conditions
    plt.figure(figsize=(12, 6))
    plt.subplot(1, 2, 1)
    plt.title('Laser OFF')
    plt.imshow(np.mean(data.off_firing[0], axis=0), aspect='auto', cmap='viridis')
    plt.subplot(1, 2, 2)
    plt.title('Laser ON')
    plt.imshow(np.mean(data.on_firing[0], axis=0), aspect='auto', cmap='viridis')
    plt.tight_layout()
    plt.show()

# Calculate palatability correlation
data.calc_palatability()
plt.figure(figsize=(10, 6))
plt.imshow(data.pal_array, aspect='auto', cmap='viridis')
plt.colorbar(label='|Palatability Correlation|')
plt.xlabel('Time (bins)')
plt.ylabel('Neuron')
plt.title('Palatability Correlation Over Time')
plt.show()

Visualization

import numpy as np
import matplotlib.pyplot as plt
from utils.ephys_data.visualize import raster, firing_overview

# Create sample spike data (binary array where 1 indicates a spike)
spike_array = np.zeros((10, 100))  # 10 trials, 100 time points
spike_array[2, 20:25] = 1  # Add some spikes
spike_array[5, 40:45] = 1
spike_array[7, 60:65] = 1

# Create a figure and axis
fig, ax = plt.subplots(figsize=(10, 6))

# Generate raster plot
raster(ax, spike_array, marker='|', color='black')
ax.set_xlabel('Time (ms)')
ax.set_ylabel('Trial')
ax.set_title('Example Raster Plot')
plt.show()

# Create sample firing rate data for multiple neurons
# Shape: (neurons, trials, time points)
n_neurons = 4
n_trials = 10
n_timepoints = 100
data = np.random.rand(n_neurons, n_trials, n_timepoints)

# Add some structure to the data
for i in range(n_neurons):
    # Create a peak at different times for each neuron
    peak_time = 20 + i*15
    data[i, :, peak_time-5:peak_time+5] += 2

# Generate firing rate overview
fig, ax = firing_overview(
    data,
    t_vec=np.arange(n_timepoints) * 10,  # 10ms bins
    cmap='viridis',
    cmap_lims='shared',
    subplot_labels=np.arange(n_neurons),
    zscore_bool=True,
    figsize=(12, 10)
)
plt.tight_layout()
plt.show()

LFP Processing

from utils.ephys_data.ephys_data import ephys_data
from utils.ephys_data import lfp_processing
import numpy as np
import matplotlib.pyplot as plt

# Load data using the ephys_data class
data = ephys_data(data_dir='/path/to/data')

# Set LFP parameters (optional - defaults will be used if not set)
data.lfp_params = {
    'freq_bounds': [1, 300],          # Frequency range in Hz
    'sampling_rate': 30000,           # Original sampling rate
    'taste_signal_choice': 'Start',   # Trial alignment
    'fin_sampling_rate': 1000,        # Final sampling rate
    'trial_durations': [2000, 5000]   # Pre/post trial durations in ms
}

# Extract LFPs (handles trial_info_frame internally)
data.extract_lfps()

# Load the extracted LFP data
data.get_lfps()
lfp_data = data.lfp_array  # Shape: (tastes, channels, trials, time)

# Identify good quality trials for a single taste
good_trials_bool = lfp_processing.return_good_lfp_trial_inds(
    data=lfp_data[0],  # First taste, shape: (channels, trials, time)
    MAD_threshold=3    # Number of MADs to use as threshold
)

# Get only the good trials
good_lfp_data = lfp_data[0][:, good_trials_bool, :]

# Plot mean of good trials
plt.figure(figsize=(12, 6))
plt.plot(np.mean(good_lfp_data, axis=(0, 1)), 'b-')
plt.xlabel('Time (ms)')
plt.ylabel('Amplitude')
plt.title('Mean LFP (Good Trials Only)')
plt.show()

Default Parameters

The module comes with sensible defaults for various analyses:

# Default firing rate parameters
default_firing_params = {
    'type': 'conv',
    'step_size': 25,
    'window_size': 250,
    'dt': 1,
    'baks_resolution': 25e-3,
    'baks_dt': 1e-3
}

# Default LFP parameters
default_lfp_params = {
    'freq_bounds': [1,300],
    'sampling_rate': 30000,
    'taste_signal_choice': 'Start',
    'fin_sampling_rate': 1000,
    'trial_durations': [2000,5000]
}

Data Structure

The module expects data organized in a specific way: - HDF5 file containing spike trains and LFP data - JSON info file with experimental parameters - Trial information CSV file

See the main repository documentation for details on data organization.