Axon Binary Format (ABF) data conversion#
Convert intracellular electrophysiology recorded in Axon Binary Format (ABF) to NWB using
AxonIntracellularInterface.
One interface instance corresponds to one channel: one electrode’s recording in one ABF file. You tell it
which recorded channel is the response and how it was clamped (the arguments are explained below). Combine
several channels in a converter for a dual-patch or multi-file recording (see below).
Install NeuroConv with the additional dependencies necessary for reading Axon Binary Format (ABF) data.
pip install "neuroconv[abf]"
>>> from neuroconv.datainterfaces import AxonIntracellularInterface
>>>
>>> file_path = f"{ECEPHY_DATA_PATH}/axon/File_axon_5.abf"
>>> interface = AxonIntracellularInterface(
... file_path=file_path,
... response_channel_name="_Ipatch", # the recorded channel
... mode="current_clamp", # voltage_clamp | current_clamp | izero
... stimulus_command="Cmd 0", # optional: reconstruct the stimulus from this command channel
... )
>>>
>>> # Extract what metadata we can from the source files (session_start_time is read from the ABF file)
>>> metadata = interface.get_metadata()
>>> # Add subject information (required for DANDI upload)
>>> metadata["Subject"] = dict(subject_id="subject1", species="Mus musculus", sex="M", age="P30D")
>>>
>>> nwbfile_path = f"{path_to_save_nwbfile}" # This should be something like: "./saved_file.nwb"
>>> interface.run_conversion(nwbfile_path=nwbfile_path, metadata=metadata)
The interface does not guess which recorded channel is the cell and which is an auxiliary monitor, so the recording is described explicitly through the constructor arguments:
response_channel_name(required): the recorded analog-to-digital converter channel for the electrode’s response, given as the channel name (for example"_Ipatch"or"IN0") or its integer index.mode(required): the clamp mode, one of"voltage_clamp","current_clamp"or"izero". This selects the NWB series type (VoltageClampSeries,CurrentClampSeriesorIZeroClampSeries).The stimulus (optional) comes from one of two mutually-exclusive sources:
stimulus_command, a digital-to-analog converter command channel (for example"Cmd 0") whose waveform is reconstructed from the protocol (ABF version 2 only); orstimulus_channel_name, a recorded monitor channel holding the actual delivered signal (works for ABF v1 and v2).izerotakes no stimulus.
To find out the names of the channels and commands, neuroconv provides two utility methods:
>>> from neuroconv.datainterfaces import AxonIntracellularInterface
>>>
>>> file_path = f"{ECEPHY_DATA_PATH}/axon/File_axon_5.abf"
>>>
>>> # The recorded channels: the options for `response_channel_name` and `stimulus_channel_name`.
>>> channel_names = AxonIntracellularInterface.get_channel_names(file_path=file_path)
>>>
>>> # The command channels: the options for `stimulus_command` (an empty list for ABF v1, which has no protocol).
>>> command_names = AxonIntracellularInterface.get_command_names(file_path=file_path)
What these names are and where they come from:
The channel names are the recorded analog-to-digital (ADC) channels, the signals the amplifier digitized (the cell’s response and any monitor outputs). neuroconv reads them from the ABF header, exactly as the acquisition software (Clampex) stored them; these are the values you give to
response_channel_name(and tostimulus_channel_nameif you are using one of the recorded channels as a monitor).The command names are the digital-to-analog (DAC) command channels from the protocol, the waveforms the amplifier was told to deliver. neuroconv reads them from the protocol’s DAC table, so they exist only in ABF version 2 files (version 1 has no protocol section, hence the empty list); these are the values you give to
stimulus_command.
A channel or command whose stored name is blank falls back to ch{index} / cmd{index}, so every one is
always addressable by a non-empty name.
The interface writes one continuous PatchClampSeries per electrode and records each sweep through the NWB
IntracellularRecordings table.
Combining channels and files with the converter#
A single AxonIntracellularInterface writes one channel’s per-sweep recordings rows but not the upper icephys
hierarchy tables, because those can only be built once the full set of channels and files is known.
AxonIntracellularConverter
combines several interfaces and builds that hierarchy over them: the SimultaneousRecordings (channels
recorded together) and SequentialRecordings (one per run, carrying the stimulus type) tables, and the
two optional grouping levels above them. You give it one interface per channel: a single cell is the
one-interface case; pass one per electrode for a dual-patch recording (the channels of each sweep grouped
into one simultaneous recording), or one per file for a multi-file experiment (each run becomes its own
sequential recording, the runs placed on a single timeline from each file’s header start time, which requires
ABF version 2).
You build the two upper grouping levels by labeling each interface through its repetition and condition
arguments. Runs sharing a repetition label are grouped into one Repetitions entry (repeated trials of the
same protocol), and repetitions sharing a condition label are grouped into one ExperimentalConditions
entry (the experimental condition, for example a drug wash-in versus control). Both are optional: pass neither and
the converter stops at the sequential level; pass condition alone and each run becomes its own repetition
before being grouped by condition.
The example below combines two channels recorded in one file.
>>> from neuroconv.datainterfaces import AxonIntracellularInterface
>>> from neuroconv.converters import AxonIntracellularConverter
>>>
>>> # One interface per channel; here two electrodes recorded in the same file.
>>> current_clamp = AxonIntracellularInterface(
... file_path=f"{ECEPHY_DATA_PATH}/axon/File_axon_6.abf",
... response_channel_name="_Ipatch",
... mode="current_clamp",
... )
>>> voltage_clamp = AxonIntracellularInterface(
... file_path=f"{ECEPHY_DATA_PATH}/axon/File_axon_6.abf",
... response_channel_name="IN1",
... mode="voltage_clamp",
... )
>>> converter = AxonIntracellularConverter(data_interfaces=[current_clamp, voltage_clamp])
>>>
>>> # The converter groups the two channels of each sweep into the icephys tables.
>>> metadata = converter.get_metadata()
>>> metadata["Subject"] = dict(subject_id="subject1", species="Mus musculus", sex="M", age="P30D")
>>>
>>> nwbfile_path = f"{path_to_save_nwbfile}" # This should be something like: "./saved_file.nwb"
>>> converter.run_conversion(nwbfile_path=nwbfile_path, metadata=metadata, overwrite=True)
Legacy AbfInterface#
Note
AbfInterface is legacy and will be deprecated. Prefer AxonIntracellularInterface above for new
conversions; it writes one continuous series per electrode and records each sweep through the NWB
intracellular recordings table.
Convert ABF intracellular electrophysiology data to NWB using AbfInterface.
>>> from neuroconv.datainterfaces import AbfInterface
>>>
>>> # Metadata info
>>> icephys_metadata = {
... "cell_id": "20220818001",
... "slice_id": "20220818001",
... "targeted_layer": "L2-3(medial)",
... "inferred_layer": "",
... "recording_sessions": [
... {
... "abf_file_name": "File_axon_5.abf",
... "stimulus_type": "long_square",
... "icephys_experiment_type": "voltage_clamp"
... }
... ]
... }
>>>
>>> # Instantiate data interface
>>> interface = AbfInterface(
... file_paths=[f"{ECEPHY_DATA_PATH}/axon/File_axon_5.abf"],
... icephys_metadata=icephys_metadata
... )
>>>
>>> # Get metadata from source data and modify any values you want
>>> metadata = interface.get_metadata()
>>> metadata['NWBFile'].update(
... identifier="ID1234",
... session_description="Intracellular electrophysiology experiment.",
... lab="my lab name", # <-- optional
... institution="My University", # <-- optional
... experimenter=["John Doe", "Jane Doe"], # <-- optional
... )
>>> metadata["Subject"] = dict(
... subject_id="subject_ID123",
... species="Mus musculus",
... sex="M",
... date_of_birth="2022-03-15T00:00:00"
... )
>>>
>>> # Run conversion
>>> interface.run_conversion(nwbfile_path=output_folder / "single_abf_conversion.nwb", metadata=metadata)
If you have multiple ABF files for the same experiment, one file per recording stimulus type, you can organize a multi-file conversion as such:
>>> from neuroconv.datainterfaces import AbfInterface
>>>
>>> # Metadata info
>>> icephys_metadata = {
... "cell_id": "20220818001",
... "slice_id": "20220818001",
... "targeted_layer": "L2-3(medial)",
... "inferred_layer": "",
... "recording_sessions": [
... {
... "abf_file_name": "File_axon_5.abf",
... "stimulus_type": "long_square",
... "icephys_experiment_type": "voltage_clamp"
... },
... {
... "abf_file_name": "File_axon_6.abf",
... "stimulus_type": "short_square",
... "icephys_experiment_type": "voltage_clamp"
... }
... ]
... }
>>>
>>> # Instantiate data interface
>>> interface = AbfInterface(
... file_paths=[
... f"{ECEPHY_DATA_PATH}/axon/File_axon_5.abf",
... f"{ECEPHY_DATA_PATH}/axon/File_axon_6.abf",
... ],
... icephys_metadata=icephys_metadata
... )
>>>
>>> # Get metadata from source data and modify any values you want
>>> metadata = interface.get_metadata()
>>> metadata['NWBFile'].update(
... identifier="ID1234",
... session_description="Intracellular electrophysiology experiment.",
... lab="my lab name", # <-- optional
... institution="My University", # <-- optional
... experimenter=["John Doe", "Jane Doe"], # <-- optional
... )
>>> metadata["Subject"] = dict(
... subject_id="subject_ID123",
... species="Mus musculus",
... sex="M",
... date_of_birth="2022-03-15T00:00:00"
... )
>>>
>>> # Run conversion
>>> interface.run_conversion(nwbfile_path=output_folder / "multiple_abf_conversion.nwb", metadata=metadata)