Skip to main content
Ctrl+K

NeuroConv documentation

  • User Guide
  • Conversion Gallery
  • How To Guides
  • Developer Guide
  • API
  • GitHub
  • User Guide
  • Conversion Gallery
  • How To Guides
  • Developer Guide
  • API
  • GitHub

Section Navigation

Contents:

  • Setting Probes on Recording Interfaces
  • How to Annotate Extracellular Electrophysiology Data
  • How to Link Sorted Data to Electrodes
  • Converting Video Formats with FFmpeg for DANDI Upload
  • Adding Multiple Sorting Interfaces
  • How To Guides
  • How to Link Sorted Data to Electrodes

How to Link Sorted Data to Electrodes#

When converting spike sorting results to NWB format, it is essential to preserve the relationship between sorted units and the recording electrodes that detected them. This linkage ensures that each unit inherits all electrode-level metadata stored in the electrodes table of the NWB file.

For this linkage to be useful, the electrodes table itself must be well annotated, including accurate information on brain area, anatomical coordinates, electrode geometry, and any probe-specific metadata. Without this detail, the benefits of unit-electrode linking are severely limited. For guidance on electrode table annotation, see How to Annotate Extracellular Electrophysiology Data.

Why Link Units to Electrodes?#

Proper electrode linking allows each unit to be formally connected to all the metadata describing its recording site. This enables both spatial and anatomical localization of units which is critical for accurate interpretation and reproducibility:

Spatial Analysis

With well-annotated electrode positions (e.g., rel_x, rel_y, rel_z), future users of the NWBFile can determine where units lie within the probe, perform laminar analyses, assess depth-dependent firing properties, and investigate spatial organization such as receptive field gradients or clustering patterns across channels.

Anatomical Analysis

Registering the probe’s position in the brain allows anatomical features such as brain area, subregion, or cortical layer to be associated with electrodes and, by extension, with linked units. As an example, Liu et al. (2022) demonstrated how depth-resolved recordings across hippocampal layers reveal distinct current source density and local field potential signatures of sharp wave-ripples. This type of interpretation is only possible when recording channel locations are known and correctly linked to sorted units.

Quality Control and Traceability

Linking units to electrode metadata ensures full traceability from spike sorting results back to the raw recording channels. This allows you to inspect waveforms, review spike detection events, and confirm that units are spatially plausible (e.g., waveforms localized to nearby electrodes). Such verification helps detect sorting errors, identify artifacts, and maintain reproducibility by making the sorting process transparent and auditable.

Accessing Electrode Metadata from Units#

Once units are properly linked to electrodes and the electrodes table is well annotated, you can programmatically retrieve electrode-level metadata for any unit in your NWB file.

from pynwb import read_nwb

nwbfile = read_nwb("output.nwb")

# View all units as a DataFrame
units_df = nwbfile.units.to_dataframe()
print(units_df)

# Access electrode information for each unit
for unit_index in range(len(nwbfile.units)):
    unit_id = nwbfile.units.id[unit_index]
    electrode_refs = nwbfile.units.electrodes[unit_index]
    electrode_indices = list(electrode_refs.index)

    # Get electrode properties for this unit
    unit_electrodes = nwbfile.electrodes[electrode_indices]
    print(f"Unit {unit_id}:")
    print(f"  - Electrode indices: {electrode_indices}")
    print(f"  - Locations: {unit_electrodes['location']}")
    print(f"  - Groups: {unit_electrodes['group_name']}")
    print(f"  - X positions: {unit_electrodes['rel_x']}")
    print(f"  - Y positions: {unit_electrodes['rel_y']}")

Single Recording and Sorting Interface#

For most spike sorting workflows, you have one recording interface and one sorting interface that need to be linked together. The SortedRecordingConverter handles this by requiring an explicit mapping between unit IDs and their associated channel IDs.

Using Intan Recording Data#

This example demonstrates linking data from an Intan recording system with Kilosort sorting results:

from neuroconv.converters import SortedRecordingConverter
from neuroconv.datainterfaces import (
    IntanRecordingInterface,
    KiloSortSortingInterface
)

# Initialize interfaces
recording_interface = IntanRecordingInterface(
    file_path="path/to/intan_data.rhd"
)
sorting_interface = KiloSortSortingInterface(
    folder_path="path/to/kilosort_output"
)

Examine the available channel and unit IDs:

# Access channel IDs from the recording
print(recording_interface.channel_ids)
# Example output: ['A-000', 'A-001', 'A-002', 'A-003', ...]

# Access unit IDs from the sorting
print(sorting_interface.unit_ids)
# Example output: ['0', '1', '2', '3', ...]

Create the mapping between units and channels. This mapping specifies which recording channels were used to detect each sorted unit:

unit_ids_to_channel_ids = {
    "0": ["A-000", "A-001", "A-002"],    # Unit 0 detected on 3 channels
    "1": ["A-003", "A-004"],             # Unit 1 detected on 2 channels
    "2": ["A-005", "A-006", "A-007"],    # Unit 2 detected on 3 channels
    "3": ["A-008"],                      # Unit 3 detected on 1 channel
    # ... continue for all units
}

Note

Every unit from the sorting interface must have a corresponding channel mapping. The channel IDs must exactly match those from the recording interface.

Create the converter and run the conversion:

converter = SortedRecordingConverter(
    recording_interface=recording_interface,
    sorting_interface=sorting_interface,
    unit_ids_to_channel_ids=unit_ids_to_channel_ids
)

nwbfile = converter.create_nwbfile()
from neuroconv.tools import configure_and_write_nwbfile
configure_and_write_nwbfile(nwbfile=nwbfile, nwbfile_path="path/to/output.nwb")

SpikeGLX Multi-Probe Data#

SpikeGLX recordings often contain data from multiple probes that have been sorted independently. The SortedSpikeGLXConverter enhances the standard SpikeGLXConverterPipe with the ability to preserve sorting metadata and maintain proper unit-to-electrode linkage across all probes.

Interface Names in SpikeGLX: For SpikeGLX data, interface names correspond to recording streams which combine probe and band information (e.g., “imec0.ap” = probe 0 + ap band, “imec1.lf” = probe 1 + lf band). Only AP interfaces can have sorting data associated with them.

Multiple Probes with Independent Sorting#

Example with multiple Neuropixels probes, each sorted independently:

from neuroconv.converters import SpikeGLXConverterPipe, SortedSpikeGLXConverter
from neuroconv.datainterfaces import KiloSortSortingInterface

# Initialize the SpikeGLX converter for all streams
spikeglx_converter = SpikeGLXConverterPipe(
    folder_path="path/to/spikeglx_data"
)

# View available interfaces
print(spikeglx_converter.data_interface_objects.keys())
# Example output: dict_keys(['imec0.ap', 'imec0.lf', 'imec1.ap', 'imec1.lf', 'nidq'])

When working with multiple sorting interfaces, a common challenge arises when different sorters produce units with identical IDs (e.g., both probes generating units “0”, “1”, “2”). The Adding Multiple Sorting Interfaces guide provides comprehensive strategies for handling such scenarios. However, the SortedSpikeGLXConverter automatically resolves these conflicts by generating unique unit names using the pattern {interface_name}_unit_{original_id} (e.g., imec0_ap_unit_0, imec1_ap_unit_0) when conflicts are detected. If unit IDs are already unique across all sorters, the original unit names are preserved.

Create sorting configuration for each sorted probe. Note the channel ID format specific to SpikeGLX:

sorting_configuration = [
    {
        "interface_name": "imec0.ap",
        "sorting_interface": KiloSortSortingInterface(
            folder_path="path/to/imec0_kilosort_output"
        ),
        "unit_ids_to_channel_ids": {
            "0": ["imec0.ap#AP0", "imec0.ap#AP1", "imec0.ap#AP2"],
            "1": ["imec0.ap#AP3", "imec0.ap#AP4"],
            "2": ["imec0.ap#AP5", "imec0.ap#AP6"]
        }
    },
    {
        "interface_name": "imec1.ap",
        "sorting_interface": KiloSortSortingInterface(
            folder_path="path/to/imec1_kilosort_output"
        ),
        "unit_ids_to_channel_ids": {
            "0": ["imec1.ap#AP0", "imec1.ap#AP1"],
            "1": ["imec1.ap#AP2", "imec1.ap#AP3", "imec1.ap#AP4"],
            "2": ["imec1.ap#AP10", "imec1.ap#AP11"]
        }
    }
]

Create the converter and run the conversion:

# Create the sorted converter
converter = SortedSpikeGLXConverter(
    spikeglx_converter=spikeglx_converter,
    sorting_configuration=sorting_configuration
)

# Create NWB file and write to disk
nwbfile = converter.create_nwbfile()
from neuroconv.tools import configure_and_write_nwbfile
configure_and_write_nwbfile(nwbfile=nwbfile, nwbfile_path="path/to/output.nwb")

previous

How to Annotate Extracellular Electrophysiology Data

next

Converting Video Formats with FFmpeg for DANDI Upload

On this page
  • Why Link Units to Electrodes?
    • Accessing Electrode Metadata from Units
  • Single Recording and Sorting Interface
    • Using Intan Recording Data
  • SpikeGLX Multi-Probe Data
    • Multiple Probes with Independent Sorting
Edit on GitHub

This Page

  • Show Source

© Copyright 2022, CatalystNeuro.

Created using Sphinx 8.2.3.

Built with the PyData Sphinx Theme 0.16.1.