Python package for reading, writing, and processing physiologic signals and annotations in WFDB format.
npx @tessl/cli install tessl/pypi-wfdb@4.3.00
# WFDB Python Package
1
2
A comprehensive Python-native package for reading, writing, processing, and plotting physiologic signals and annotations based on the Waveform Database (WFDB) specifications. This package provides complete tooling for biomedical signal analysis, including integration with NumPy, SciPy, Pandas, and Matplotlib for the Python scientific ecosystem.
3
4
## Package Information
5
6
- **Package Name**: wfdb
7
- **Language**: Python
8
- **Installation**: `pip install wfdb`
9
- **Documentation**: https://wfdb.readthedocs.io/
10
- **Repository**: https://github.com/MIT-LCP/wfdb-python
11
12
## Core Imports
13
14
```python
15
import wfdb
16
```
17
18
Common patterns for specific functionality:
19
20
```python
21
# Core I/O operations
22
from wfdb import rdrecord, rdann, wrsamp, wrann
23
24
# Signal processing (must use module path)
25
import wfdb.processing
26
# Then use: wfdb.processing.xqrs_detect, wfdb.processing.find_peaks
27
28
# Plotting
29
from wfdb.plot import plot_wfdb, plot_items
30
31
# Format conversion (must use module path)
32
import wfdb.io.convert
33
# Then use: wfdb.io.convert.read_edf, wfdb.io.convert.wfdb_to_mat
34
```
35
36
## Basic Usage
37
38
```python
39
import wfdb
40
import numpy as np
41
42
# Read a WFDB record from PhysioNet
43
record = wfdb.rdrecord('100', pn_dir='mitdb')
44
print(f"Record: {record.record_name}")
45
print(f"Signals: {record.sig_name}")
46
print(f"Length: {record.sig_len} samples at {record.fs} Hz")
47
48
# Read annotations
49
annotation = wfdb.rdann('100', 'atr', pn_dir='mitdb')
50
print(f"Found {len(annotation.sample)} annotations")
51
52
# Plot the first 3600 samples (10 seconds at 360 Hz)
53
wfdb.plot_wfdb(record=record, annotation=annotation,
54
time_units='seconds', title='ECG Record 100')
55
56
# Detect QRS complexes
57
qrs_inds = wfdb.processing.xqrs_detect(record.p_signal[:, 0], fs=record.fs)
58
print(f"Detected {len(qrs_inds)} QRS complexes")
59
60
# Calculate heart rate
61
hr = wfdb.processing.compute_hr(record.sig_len, qrs_inds, record.fs)
62
print(f"Mean heart rate: {np.mean(hr):.1f} BPM")
63
```
64
65
## Architecture
66
67
The WFDB package is organized into four main modules that handle different aspects of physiological signal processing:
68
69
- **I/O Module**: Core data structures (Record, MultiRecord, Annotation) and functions for reading/writing WFDB files, database access, and data source management
70
- **Processing Module**: Signal processing algorithms including resampling, filtering, peak detection, QRS detection, and heart rate analysis
71
- **Plotting Module**: Visualization tools for signals and annotations with matplotlib integration
72
- **Conversion Module**: Format conversion utilities for EDF, MATLAB, CSV, WAV, and other common biomedical data formats
73
74
This modular design enables efficient handling of large-scale physiological databases while maintaining compatibility with the original WFDB specifications and PhysioNet infrastructure.
75
76
## Capabilities
77
78
### I/O Operations
79
80
Core functionality for reading and writing WFDB records and annotations, including database access and data source management.
81
82
```python { .api }
83
def rdrecord(record_name: str, sampfrom: int = 0, sampto: Union[int, str] = None,
84
channels: List[int] = None, physical: bool = True,
85
pn_dir: str = None) -> Union[Record, MultiRecord]: ...
86
87
def rdann(record_name: str, extension: str, sampfrom: int = 0,
88
sampto: Union[int, str] = 'end', pn_dir: str = None) -> Annotation: ...
89
90
def wrsamp(record_name: str, fs: float, units: List[str], sig_name: List[str],
91
p_signal: np.ndarray = None, **kwargs) -> None: ...
92
93
def sampfreq(record_name: str, pn_dir: str = None) -> float: ...
94
95
def signame(record_name: str, pn_dir: str = None, sig_nums: List[int] = []) -> List[str]: ...
96
97
def wfdbdesc(record_name: str, pn_dir: str = None) -> List[str]: ...
98
99
def wfdbtime(record_name: str, input_times: Union[List, np.ndarray], pn_dir: str = None) -> List[str]: ...
100
101
def show_ann_labels() -> None: ...
102
103
def show_ann_classes() -> None: ...
104
105
def mrgann(record_name: str, extensions: List[str], pn_dir: str = None) -> None: ...
106
107
def dl_files(db: str, dl_dir: str, files: List[str], keep_subdirs: bool = True, overwrite: bool = False) -> None: ...
108
109
def get_dbs() -> List[str]: ...
110
111
def get_record_list(db_dir: str, records: str = "all") -> List[str]: ...
112
113
def set_db_index_url(db_index_url: str = None) -> None: ...
114
115
def show_data_sources() -> None: ...
116
117
def add_data_source(data_source: DataSource) -> None: ...
118
119
def remove_data_source(name: str) -> None: ...
120
121
def reset_data_sources() -> None: ...
122
123
class Record:
124
record_name: str
125
n_sig: int
126
fs: float
127
sig_len: int
128
p_signal: np.ndarray
129
sig_name: List[str]
130
units: List[str]
131
132
class Annotation:
133
record_name: str
134
sample: np.ndarray
135
symbol: List[str]
136
fs: float
137
```
138
139
[I/O Operations](./io-operations.md)
140
141
### Signal Processing
142
143
Comprehensive signal processing tools including resampling, filtering, peak detection, QRS detection, and heart rate analysis.
144
145
```python { .api }
146
def xqrs_detect(sig: np.ndarray, fs: float, sampfrom: int = 0, sampto: str = "end",
147
conf: str = None, learn: bool = True, verbose: bool = True) -> np.ndarray: ...
148
149
def gqrs_detect(sig: np.ndarray, fs: float, **kwargs) -> np.ndarray: ...
150
151
def find_peaks(sig: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: ...
152
153
def compute_hr(sig_len: int, qrs_inds: np.ndarray, fs: float) -> np.ndarray: ...
154
155
def resample_sig(x: np.ndarray, fs: float, fs_target: float) -> Tuple[np.ndarray, np.ndarray]: ...
156
157
class XQRS:
158
def detect(self, sig: np.ndarray, verbose: bool = False) -> np.ndarray: ...
159
```
160
161
[Signal Processing](./signal-processing.md)
162
163
### Plotting and Visualization
164
165
Tools for plotting physiological signals and annotations with customizable styling and multiple display options.
166
167
```python { .api }
168
def plot_wfdb(record: Record = None, annotation: Annotation = None,
169
plot_sym: bool = False, time_units: str = 'seconds', **kwargs) -> None: ...
170
171
def plot_items(signal: np.ndarray = None, ann_samp: List[int] = None,
172
fs: float = None, time_units: str = "samples", **kwargs) -> None: ...
173
174
def plot_all_records(records: List[str], annotation: List[str] = None,
175
**kwargs) -> None: ...
176
```
177
178
[Plotting](./plotting.md)
179
180
### Format Conversion
181
182
Utilities for converting between WFDB and other common biomedical data formats including EDF, MATLAB, CSV, and WAV.
183
184
```python { .api }
185
def read_edf(file_name: str, pn_dir: str = None, **kwargs) -> Record: ...
186
187
def wfdb_to_edf(record_name: str, pn_dir: str = None, **kwargs) -> None: ...
188
189
def wfdb_to_mat(record_name: str, pn_dir: str = None, **kwargs) -> None: ...
190
191
def csv_to_wfdb(file_name: str, fs: float, units: List[str],
192
sig_name: List[str], **kwargs) -> None: ...
193
```
194
195
[Format Conversion](./format-conversion.md)
196
197
## Types
198
199
```python { .api }
200
class Record:
201
"""Single-segment WFDB record representation."""
202
record_name: str
203
n_sig: int
204
fs: float
205
sig_len: int
206
p_signal: np.ndarray # Physical signal values (MxN array)
207
d_signal: np.ndarray # Digital signal values (MxN array)
208
sig_name: List[str] # Signal names for each channel
209
units: List[str] # Units for each channel
210
comments: List[str] # Header comments
211
base_time: datetime.time
212
base_date: datetime.date
213
214
def wrsamp(self, expanded: bool = False, write_dir: str = "") -> None: ...
215
def to_dataframe(self) -> pd.DataFrame: ...
216
217
class MultiRecord:
218
"""Multi-segment WFDB record representation."""
219
segments: List[Union[Record, None]]
220
layout: str # "fixed" or "variable"
221
seg_name: List[str]
222
seg_len: List[int]
223
224
def multi_to_single(self, physical: bool, return_res: int = 64) -> Record: ...
225
226
class Annotation:
227
"""WFDB annotation representation."""
228
record_name: str
229
extension: str
230
sample: np.ndarray # Annotation sample locations
231
symbol: List[str] # Annotation symbols
232
fs: float # Sampling frequency
233
aux_note: List[str] # Auxiliary notes
234
235
def wrann(self, write_fs: bool = False, write_dir: str = "") -> None: ...
236
237
class DataSource:
238
"""Data source configuration."""
239
name: str
240
ds_type: DataSourceType # LOCAL or HTTP
241
uri: str
242
243
class XQRS:
244
"""Configurable QRS detector."""
245
def detect(self, sig: np.ndarray, verbose: bool = False) -> np.ndarray: ...
246
247
DataSourceType = Literal["LOCAL", "HTTP"]
248
```