A comprehensive Python library for representing electrophysiology data with support for reading and writing a wide range of neurophysiology file formats.
—
Fundamental data containers and objects for representing all types of electrophysiology data. Neo's hierarchical design organizes data into containers (Block, Segment, Group) that hold data objects (signals, spikes, events) with rich metadata and dimensional consistency.
Top-level organizational structures that group related electrophysiology data.
class Block:
"""
Main container for entire experiments or recording sessions.
A Block represents the top level grouping of data and is not necessarily
temporally homogeneous, in contrast to Segment.
"""
def __init__(self, name=None, description=None, file_origin=None,
file_datetime=None, rec_datetime=None, index=None,
**annotations): ...
# Container relationships
segments: list[Segment] # Temporal divisions of the experiment
groups: list[Group] # Logical groupings across segments
# Methods
def filter(self, **kwargs): ... # Filter contained objects by properties
def merge(self, other): ... # Merge with another Block
class Segment:
"""
Container for temporally related data objects.
A Segment represents a time period within an experiment, typically
corresponding to a trial, stimulus presentation, or recording epoch.
"""
def __init__(self, name=None, description=None, **annotations): ...
# Data object containers
analogsignals: list[AnalogSignal] # Continuous signals
irregularlysampledsignals: list[IrregularlySampledSignal] # Non-uniform sampling
spiketrains: list[SpikeTrain] # Spike timing data
events: list[Event] # Point events
epochs: list[Epoch] # Time intervals
imagesequences: list[ImageSequence] # Image data sequences
# Methods
def filter(self, **kwargs): ... # Filter contained objects
t_start: pq.Quantity # Segment start time
t_stop: pq.Quantity # Segment stop time
class Group:
"""
Logical grouping container for related data objects.
Groups organize related objects across segments, typically representing
electrode arrays, tetrodes, or other logical recording arrangements.
"""
def __init__(self, name=None, description=None, **annotations): ...
# Data object containers (same as Segment)
analogsignals: list[AnalogSignal]
spiketrains: list[SpikeTrain]
events: list[Event]
epochs: list[Epoch]Continuous data representations for analog recordings.
class AnalogSignal:
"""
Regularly sampled continuous analog signals with physical units.
Represents multi-channel continuous data like LFP, EEG, voltage clamp
recordings, or any uniformly sampled analog measurements.
Note: The 'copy' parameter is deprecated and will be removed in Neo 0.15.0.
Only copy=None is accepted; any other value raises ValueError.
"""
def __init__(self, signal, units=None, dtype=None, copy=None,
t_start=0*pq.s, sampling_rate=None, sampling_period=None,
name=None, file_origin=None, description=None,
array_annotations=None, **annotations): ...
# Properties
shape: tuple # (n_samples, n_channels)
sampling_rate: pq.Quantity # Hz, kHz, etc.
sampling_period: pq.Quantity # s, ms, etc.
t_start: pq.Quantity # Start time
t_stop: pq.Quantity # End time
duration: pq.Quantity # Total duration
times: pq.Quantity # Time array for each sample
# Methods
def time_slice(self, t_start, t_stop): ... # Extract time window
def time_index(self, t): ... # Get array index for time
def time_shift(self, t_shift): ... # Shift signal to new start time
def downsample(self, downsampling_factor, **kwargs): ... # Downsample signal data
def resample(self, sample_count, **kwargs): ... # Resample to fixed sample count
def rectify(self, **kwargs): ... # Rectify by taking absolute value
def concatenate(self, *signals, overwrite=False, padding=False): ... # Concatenate signals
def splice(self, signal, copy=False): ... # Replace part of signal
def channel_index_to_channel_id(self, index): ... # Channel mapping
def merge(self, other): ... # Combine signals
class IrregularlySampledSignal:
"""
Irregularly sampled continuous analog signals.
For data with non-uniform sampling intervals, where each sample
has an associated timestamp.
"""
def __init__(self, times, signal, units=None, time_units=None,
dtype=None, copy=None, name=None, file_origin=None, description=None,
array_annotations=None, **annotations): ...
# Properties
times: pq.Quantity # Sample timestamps
shape: tuple # (n_samples, n_channels)
t_start: pq.Quantity # First timestamp
t_stop: pq.Quantity # Last timestamp
# Methods
def time_slice(self, t_start, t_stop): ...
def merge(self, other): ...
class ChannelView:
"""
View into specific channels of multi-channel signals.
Provides a way to work with subsets of channels from AnalogSignal
or IrregularlySampledSignal objects without copying data.
"""
def __init__(self, obj, index): ...
# Properties inherit from parent signal
# Methods delegate to parent signalDiscrete event data and time interval representations.
class Event:
"""
Time-stamped discrete events with labels and annotations.
Represents point events like stimulus onsets, behavioral markers,
or detected events with associated metadata.
"""
def __init__(self, times, labels=None, units=None, name=None,
description=None, **annotations): ...
# Properties
times: pq.Quantity # Event timestamps
labels: np.ndarray # String labels for each event
size: int # Number of events
# Methods
def time_slice(self, t_start, t_stop): ...
def merge(self, other): ...
class Epoch:
"""
Time intervals with duration and labels.
Represents periods of time like stimulus presentations, behavioral
states, or analysis windows with start times and durations.
"""
def __init__(self, times, durations, labels=None, units=None,
name=None, description=None, **annotations): ...
# Properties
times: pq.Quantity # Start times
durations: pq.Quantity # Duration of each epoch
labels: np.ndarray # String labels
size: int # Number of epochs
# Methods
def time_slice(self, t_start, t_stop): ...
def merge(self, other): ...Specialized containers for action potential timing data.
class SpikeTrain:
"""
Sequence of action potential timestamps with metadata.
Represents spike timing data from single units or multi-unit
activity with support for waveforms and spike classifications.
"""
def __init__(self, times, t_stop, units=None, dtype=None, copy=None,
sampling_rate=1.0*pq.Hz, t_start=0.0*pq.s, waveforms=None,
left_sweep=None, name=None, file_origin=None, description=None,
array_annotations=None, **annotations): ...
# Properties
times: pq.Quantity # Spike timestamps
t_start: pq.Quantum # Recording start time
t_stop: pq.Quantity # Recording stop time
duration: pq.Quantity # Total recording duration
size: int # Number of spikes
waveforms: pq.Quantity # Spike waveform data (optional)
sampling_rate: pq.Quantity # Waveform sampling rate
left_sweep: pq.Quantity # Pre-spike waveform duration
# Methods
def time_slice(self, t_start, t_stop): ... # Extract time window
def merge(self, other): ... # Combine spike trains
def isi(self): ... # Inter-spike intervals
def cv(self): ... # Coefficient of variationSupport for image sequences and regions of interest.
class ImageSequence:
"""
Sequences of 2D images with timing information.
For optical imaging data, calcium imaging, or other image-based
measurements with temporal sequences.
"""
def __init__(self, image_data, units=None, dtype=None, copy=True,
t_start=0*pq.s, sampling_rate=None, sampling_period=None,
spatial_scale=None, name=None, description=None,
**annotations): ...
# Properties
shape: tuple # (n_frames, height, width, [channels])
sampling_rate: pq.Quantity # Frame rate
spatial_scale: pq.Quantity # Spatial resolution
times: pq.Quantity # Frame timestamps
# Methods
def time_slice(self, t_start, t_stop): ...
class RectangularRegionOfInterest:
"""Rectangular region of interest definition."""
def __init__(self, x, y, width, height, **annotations): ...
class CircularRegionOfInterest:
"""Circular region of interest definition."""
def __init__(self, x, y, radius, **annotations): ...
class PolygonRegionOfInterest:
"""Polygon-shaped region of interest definition."""
def __init__(self, x, y, **annotations): ...Query and filtering system for data objects.
class FilterCondition:
"""Abstract base class for filter conditions."""
class Equals:
"""Equality filter condition for data properties."""
def __init__(self, value): ...
class IsNot:
"""Inequality filter condition."""
def __init__(self, value): ...
class LessThan:
"""Less-than filter condition."""
def __init__(self, value): ...
class GreaterThan:
"""Greater-than filter condition."""
def __init__(self, value): ...
class IsIn:
"""Membership test filter condition."""
def __init__(self, values): ...
class InRange:
"""Range-based filter condition."""
def __init__(self, min_val, max_val): ...import neo
import numpy as np
import quantities as pq
# Create hierarchical structure
block = neo.Block(name="Experiment 1", experimenter="Dr. Smith")
segment = neo.Segment(name="Trial 1", trial_id=1)
block.segments.append(segment)
# Add continuous signals
signal_data = np.random.randn(1000, 4) * pq.mV
analog_signal = neo.AnalogSignal(
signal_data,
sampling_rate=1*pq.kHz,
t_start=0*pq.s,
name="LFP",
channel_names=['Ch1', 'Ch2', 'Ch3', 'Ch4']
)
segment.analogsignals.append(analog_signal)
# Add spike data
spike_times = np.array([0.1, 0.3, 0.7, 1.2]) * pq.s
spike_train = neo.SpikeTrain(
spike_times,
t_start=0*pq.s,
t_stop=2*pq.s,
name="Unit 1"
)
segment.spiketrains.append(spike_train)
# Add events
event_times = np.array([0.5, 1.0, 1.5]) * pq.s
events = neo.Event(
event_times,
labels=['stimulus_on', 'response', 'stimulus_off']
)
segment.events.append(events)# Time slicing
signal_slice = analog_signal.time_slice(0.1*pq.s, 0.5*pq.s)
# Channel selection
channel_view = neo.ChannelView(analog_signal, [0, 2]) # Channels 1 and 3
# Access properties
print(f"Shape: {analog_signal.shape}")
print(f"Sampling rate: {analog_signal.sampling_rate}")
print(f"Duration: {analog_signal.duration}")
print(f"Times shape: {analog_signal.times.shape}")from neo.core.filters import Equals, GreaterThan
# Filter spike trains by name
unit1_trains = segment.filter(name=Equals("Unit 1"), objects="SpikeTrain")
# Filter events by time
late_events = segment.filter(times=GreaterThan(1.0*pq.s), objects="Event")
# Complex filtering
fast_spikes = segment.filter(
name=Equals("Unit 1"),
size=GreaterThan(10),
objects="SpikeTrain"
)# Base quantity types from quantities package
Signal = np.ndarray * pq.Quantity # Multidimensional array with units
Time = pq.Quantity # Time values (s, ms, μs, etc.)
Rate = pq.Quantity # Frequencies (Hz, kHz, MHz, etc.)
Voltage = pq.Quantity # Electrical potential (V, mV, μV, etc.)
# Container types
BlockList = list[Block] # List of Block objects
SegmentList = list[Segment] # List of Segment objects
GroupList = list[Group] # List of Group objects
# Data object types
AnalogSignalList = list[AnalogSignal] # List of AnalogSignal objects
SpikeTrainList = list[SpikeTrain] # List of SpikeTrain objects
EventList = list[Event] # List of Event objects
EpochList = list[Epoch] # List of Epoch objects
# Metadata types
Annotations = dict[str, Any] # Arbitrary key-value metadata
ChannelNames = list[str] # Channel identification strings
Labels = np.ndarray # String labels for events/epochsInstall with Tessl CLI
npx tessl i tessl/pypi-neo