CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pyedflib

Python library for reading and writing EDF+/BDF+ files used for storing biomedical signal data

Pending
Overview
Eval results
Files

edf-writing.mddocs/

EDF File Writing

Interface for creating and writing EDF, EDF+, BDF, and BDF+ files with comprehensive header configuration, signal data writing, and annotation support. The EdfWriter class provides Python-friendly methods with automatic resource management and validation.

Capabilities

File Creation and Management

Create new EDF files with specified channel count and file type, with automatic resource management through context managers.

class EdfWriter:
    def __init__(self, file_name: str, n_channels: int, file_type: int = FILETYPE_EDFPLUS):
        """
        Initialize EDF writer for new file.
        
        Parameters:
        - file_name: str, output file path
        - n_channels: int, number of signal channels
        - file_type: int, file format (FILETYPE_EDF, FILETYPE_EDFPLUS, FILETYPE_BDF, FILETYPE_BDFPLUS)
        """

    def __enter__(self) -> EdfWriter:
        """Context manager entry."""

    def __exit__(self, exc_type, exc_val, exc_tb):
        """Context manager exit with automatic file closure."""

    def close(self):
        """Close file and finalize writing."""

    def update_header(self):
        """Update file header with current settings."""

Usage example:

# Using context manager (recommended)
with pyedflib.EdfWriter('output.edf', 2, pyedflib.FILETYPE_EDFPLUS) as f:
    # Configure and write data
    f.setSignalHeaders(signal_headers)
    f.writeSamples(data)

# Manual management
f = pyedflib.EdfWriter('output.edf', 2)
try:
    f.setSignalHeaders(signal_headers)
    f.writeSamples(data)
finally:
    f.close()

Header Configuration

Set file-level and signal-level header information including patient data, recording details, and signal parameters.

def setHeader(self, fileHeader: Dict):
    """
    Set file header from dictionary.
    
    Parameters:
    - fileHeader: dict, complete file header information
    """

def setSignalHeader(self, edfsignal: int, channel_info: Dict):
    """
    Set header for specific signal channel.
    
    Parameters:
    - edfsignal: int, channel number (0-based)
    - channel_info: dict, signal configuration
    """

def setSignalHeaders(self, signalHeaders: List[Dict]):
    """
    Set headers for all signal channels.
    
    Parameters:
    - signalHeaders: List[dict], list of signal configurations
    """

Usage example:

# Create signal headers
signal_headers = [
    {
        'label': 'EEG Fp1',
        'dimension': 'uV', 
        'sample_frequency': 256,
        'physical_min': -500.0,
        'physical_max': 500.0,
        'digital_min': -32768,
        'digital_max': 32767,
        'transducer': 'AgAgCl electrodes',
        'prefilter': 'HP:0.1Hz LP:70Hz'
    },
    {
        'label': 'EEG Fp2',
        'dimension': 'uV',
        'sample_frequency': 256,
        'physical_min': -500.0,
        'physical_max': 500.0,
        'digital_min': -32768,
        'digital_max': 32767,
        'transducer': 'AgAgCl electrodes', 
        'prefilter': 'HP:0.1Hz LP:70Hz'
    }
]

with pyedflib.EdfWriter('eeg.edf', 2) as f:
    f.setSignalHeaders(signal_headers)

Patient Information

Set patient demographics and identification information.

def setPatientName(self, patient_name: str):
    """Set patient name."""

def setPatientCode(self, patient_code: str):
    """Set patient identification code."""

def setPatientAdditional(self, patient_additional: str):
    """Set additional patient information."""

def setSex(self, sex: int):
    """
    Set patient sex.
    
    Parameters:
    - sex: int, patient sex (0=female, 1=male)
    """

def setBirthdate(self, birthdate: Union[str, date]):
    """
    Set patient birthdate.
    
    Parameters:
    - birthdate: str or date, birthdate in YYYY-MM-DD format or date object
    """

Recording Information

Set recording session metadata and technical details.

def setTechnician(self, technician: str):
    """Set technician name."""

def setRecordingAdditional(self, recording_additional: str):
    """Set additional recording information."""

def setEquipment(self, equipment: str):
    """Set recording equipment information."""

def setAdmincode(self, admincode: str):
    """Set administration code."""

def setStartdatetime(self, recording_start_time: Union[datetime, str]):
    """
    Set recording start date and time.
    
    Parameters:
    - recording_start_time: datetime or str, start time
    """

def setDatarecordDuration(self, record_duration: Union[float, int]):
    """
    Set data record duration in seconds.
    
    Parameters:
    - record_duration: float or int, duration per data record
    """

def set_number_of_annotation_signals(self, number_of_annotations: int):
    """
    Set number of annotation signals.
    
    Parameters:
    - number_of_annotations: int, annotation signal count
    """

Signal Configuration

Configure individual signal channel properties including sampling rates, calibration, and metadata.

def setSamplefrequency(self, edfsignal: int, samplefrequency: Union[int, float]):
    """
    Set sampling frequency for signal.
    
    Parameters:
    - edfsignal: int, channel number
    - samplefrequency: int or float, sample rate in Hz
    """

def setPhysicalMaximum(self, edfsignal: int, physical_maximum: Union[int, float]):
    """
    Set physical maximum value for signal.
    
    Parameters:
    - edfsignal: int, channel number
    - physical_maximum: int or float, maximum physical value
    """

def setPhysicalMinimum(self, edfsignal: int, physical_minimum: Union[int, float]):
    """
    Set physical minimum value for signal.
    
    Parameters:
    - edfsignal: int, channel number  
    - physical_minimum: int or float, minimum physical value
    """

def setDigitalMaximum(self, edfsignal: int, digital_maximum: int):
    """
    Set digital maximum value for signal.
    
    Parameters:
    - edfsignal: int, channel number
    - digital_maximum: int, maximum digital value
    """

def setDigitalMinimum(self, edfsignal: int, digital_minimum: int):
    """
    Set digital minimum value for signal.
    
    Parameters:
    - edfsignal: int, channel number
    - digital_minimum: int, minimum digital value  
    """

def setLabel(self, edfsignal: int, label: str):
    """
    Set signal label.
    
    Parameters:
    - edfsignal: int, channel number
    - label: str, signal label/name
    """

def setPhysicalDimension(self, edfsignal: int, physical_dimension: str):
    """
    Set physical dimension (units) for signal.
    
    Parameters:
    - edfsignal: int, channel number
    - physical_dimension: str, units (e.g., 'uV', 'mV')
    """

def setTransducer(self, edfsignal: int, transducer: str):
    """
    Set transducer information for signal.
    
    Parameters:
    - edfsignal: int, channel number
    - transducer: str, transducer description
    """

def setPrefilter(self, edfsignal: int, prefilter: str):
    """
    Set prefilter information for signal.
    
    Parameters:
    - edfsignal: int, channel number
    - prefilter: str, prefilter description
    """

Data Writing

Write signal data to the file with support for different data types and writing modes.

def writeSamples(self, data_list: Union[List[np.ndarray], np.ndarray], digital: bool = False):
    """
    Write signal samples to file.
    
    Parameters:
    - data_list: List[numpy.ndarray] or numpy.ndarray, signal data for each channel
    - digital: bool, whether data contains digital values (True) or physical values (False)
    """

def writePhysicalSamples(self, data: np.ndarray) -> int:
    """
    Write physical samples for all channels.
    
    Parameters:
    - data: numpy.ndarray, physical sample values
    
    Returns:
    int: Number of samples written
    """

def writeDigitalSamples(self, data: np.ndarray) -> int:
    """
    Write digital samples for all channels.
    
    Parameters:
    - data: numpy.ndarray, digital sample values
    
    Returns:
    int: Number of samples written
    """

def writeDigitalShortSamples(self, data: np.ndarray) -> int:
    """
    Write digital short samples for all channels.
    
    Parameters:
    - data: numpy.ndarray, digital short sample values
    
    Returns:
    int: Number of samples written
    """

def blockWritePhysicalSamples(self, data: np.ndarray) -> int:
    """
    Block write physical samples.
    
    Parameters:
    - data: numpy.ndarray, physical sample data
    
    Returns:
    int: Number of samples written
    """

def blockWriteDigitalSamples(self, data: np.ndarray) -> int:
    """
    Block write digital samples.
    
    Parameters:
    - data: numpy.ndarray, digital sample data
    
    Returns:
    int: Number of samples written
    """

def blockWriteDigitalShortSamples(self, data: np.ndarray) -> int:
    """
    Block write digital short samples.
    
    Parameters:
    - data: numpy.ndarray, digital short sample data
    
    Returns:
    int: Number of samples written
    """

Usage example:

import numpy as np

# Generate sample data (1000 samples at 256 Hz for 2 channels)
data_ch1 = np.random.normal(0, 100, 1000)  # EEG-like signal in uV
data_ch2 = np.random.normal(0, 100, 1000)

with pyedflib.EdfWriter('sample.edf', 2) as f:
    f.setSignalHeaders(signal_headers)
    
    # Write as list of arrays (recommended)
    f.writeSamples([data_ch1, data_ch2])
    
    # Or write as 2D array (channels x samples)
    data_2d = np.array([data_ch1, data_ch2])
    f.writeSamples(data_2d)

Annotation Writing

Add annotations (events, markers) to EDF+ and BDF+ files with timing and description information.

def writeAnnotation(self, onset_in_seconds: Union[int, float], 
                   duration_in_seconds: Union[int, float], 
                   description: str, str_format: str = 'utf8'):
    """
    Write annotation to file.
    
    Parameters:
    - onset_in_seconds: int or float, annotation start time in seconds
    - duration_in_seconds: int or float, annotation duration in seconds
    - description: str, annotation text description
    - str_format: str, text encoding ('utf8' or 'latin1')
    """

Usage example:

with pyedflib.EdfWriter('annotated.edf', 2, pyedflib.FILETYPE_EDFPLUS) as f:
    f.setSignalHeaders(signal_headers)
    f.writeSamples([data_ch1, data_ch2])
    
    # Add annotations
    f.writeAnnotation(10.0, 0.0, "Stimulus onset")
    f.writeAnnotation(15.5, 2.0, "Patient movement")  
    f.writeAnnotation(30.0, 0.0, "End of trial")

Utility Methods

Helper methods for configuration and validation.

def get_smp_per_record(self, ch_idx: int) -> int:
    """
    Get samples per record for channel.
    
    Parameters:
    - ch_idx: int, channel index
    
    Returns:
    int: Samples per data record
    """

Complete Writing Example

import pyedflib
import numpy as np
from datetime import datetime

# Create sample EEG data
n_channels = 4
n_samples = 2560  # 10 seconds at 256 Hz
sample_rate = 256

# Generate realistic EEG-like signals
channels = ['EEG Fp1', 'EEG Fp2', 'EEG C3', 'EEG C4']
data = []
for i in range(n_channels):
    # Mix of sine waves with noise to simulate EEG
    t = np.linspace(0, 10, n_samples)
    signal = (np.sin(2*np.pi*10*t) * 50 +  # 10 Hz alpha-like
              np.sin(2*np.pi*4*t) * 30 +   # 4 Hz theta-like  
              np.random.normal(0, 20, n_samples))  # noise
    data.append(signal)

# Create signal headers
signal_headers = []
for i, label in enumerate(channels):
    signal_headers.append({
        'label': label,
        'dimension': 'uV',
        'sample_frequency': sample_rate,
        'physical_min': -500.0,
        'physical_max': 500.0,
        'digital_min': -32768,
        'digital_max': 32767,
        'transducer': 'AgAgCl electrodes',
        'prefilter': 'HP:0.1Hz LP:70Hz'
    })

# Create file header
file_header = {
    'technician': 'Dr. Smith',
    'recording_additional': 'EEG sleep study',
    'patientname': 'Patient001',
    'patient_additional': 'Age 25',
    'patientcode': 'P001',
    'equipment': 'EEG System v2.1',
    'admincode': 'ADMIN001',
    'sex': 'M',
    'startdate': datetime.now(),
    'birthdate': '1998-01-15'
}

# Write EDF file
with pyedflib.EdfWriter('complete_example.edf', n_channels, pyedflib.FILETYPE_EDFPLUS) as f:
    # Set headers
    f.setHeader(file_header)
    f.setSignalHeaders(signal_headers)
    
    # Write data
    f.writeSamples(data)
    
    # Add annotations
    f.writeAnnotation(2.0, 0.0, "Eyes closed")
    f.writeAnnotation(5.0, 1.0, "Sleep spindle")
    f.writeAnnotation(8.0, 0.0, "Eyes open")

print("EDF file created successfully!")

Constants

# File type constants
FILETYPE_EDF: int        # Standard EDF format
FILETYPE_EDFPLUS: int    # EDF+ format with annotations  
FILETYPE_BDF: int        # BDF format (24-bit)
FILETYPE_BDFPLUS: int    # BDF+ format with annotations

Install with Tessl CLI

npx tessl i tessl/pypi-pyedflib

docs

edf-reading.md

edf-writing.md

high-level-functions.md

index.md

low-level-interface.md

tile.json