Skip to content

Cluster–channel mismatch in Phy after QC with SpikeInterface #4255

@wenxin8023

Description

@wenxin8023

Hi, I’m spike-sorting 128-channel Intan recordings from a flexible probe using Kilosort4 and running quality metrics with SpikeInterface. I generated the probe layout and channel mapping using probeinterface, attached it to the recording, and exported the results to Phy.

However, in Phy I found that the cluster–channel mapping is inconsistent with original mapping(See the screenshots below, using the cluster with the highest firing rate as an example):

Before QC:
Image

After QC:
Image

I suspect this may be related to the device_channel_indices, channel ordering, or how the probe is attached, but I am not sure what the correct procedure is.

Below is the exact code used for probe construction, channel mapping, attaching the probe, waveform extraction, and exporting:

import spikeinterface.core as si
import spikeinterface.extractors as se
import probeinterface as pi
import numpy as np
from spikeinterface.qualitymetrics import (
    compute_snrs,
    compute_firing_rates,
    compute_isi_violations,
    compute_quality_metrics,
)

recording = se.read_intan('E:/Desktop/flexible electrode/LL NO 170/acute-m03-stratium/acute-m03-striatum-3_251209_152340.rhd', stream_id='0')
sorting = se.read_phy('E:/Desktop/flexible electrode/LL NO 170/acute-m03-striatum/kilosort4')

import probeinterface as pi

num_ch = 128


x = np.zeros(num_ch)
y = 776 + np.arange(num_ch) * (1500 / 128)
positions = np.column_stack((x, y))

ks_map = np.array([
    73,77,74,82,83,81,90,88,102,104,108,110,117,109,118,114,75,79,
    76,80,78,87,89,84,101,107,113,103,115,111,116,112,71,69,72,70,
    86,85,91,92,99,100,105,106,119,121,120,122,67,65,68,66,93,64,
    94,95,98,96,97,127,123,125,124,126,15,13,16,18,23,17,20,24,43,40,
    39,46,47,45,48,50,11,9,12,10,14,19,25,26,37,38,49,44,51,53,52,54,
    7,5,8,6,22,21,27,28,35,36,41,42,55,57,56,58,3,1,4,2,29,0,30,31,
    34,32,33,63,59,61,60,62
])
ks_map_str = np.array([f"A-{i:03d}" for i in ks_map])
recording = recording.select_channels(ks_map_str)

probe = pi.Probe(ndim=2, si_units="um")
probe.set_contacts(
    positions=positions[ks_map],
    shapes="circle",
    shape_params={"radius": 5}
)
probe.set_device_channel_indices(np.arange(128))

recording = recording.set_probe(probe)
print(probe)obe(probe)
print(probe)

recording_signed = si.unsigned_to_signed(recording)
recording_f = si.bandpass_filter(recording_signed, freq_min=300, freq_max=6000)
print(recording_f)
recording_cmr = si.common_reference(recording_f, reference="global", operator="median")
print(recording_cmr)

analyzer = si.create_sorting_analyzer(sorting=sorting, recording=recording_cmr, format="memory")
analyzer.compute("random_spikes", method="uniform", max_spikes_per_unit=600, seed=2205)
analyzer.compute("waveforms", ms_before=1.3, ms_after=2.6, n_jobs=2)
analyzer.compute("templates", operators=["average", "median", "std"])
analyzer.compute("noise_levels")
analyzer.compute("principal_components", n_components=3, mode="by_channel_global", whiten=True)

metrics = compute_quality_metrics(
    analyzer,
    metric_names=["snr", "isi_violation",  "firing_rate", "presence_ratio", "amplitude_cutoff", "d_prime", "isolation_distance", "l_ratio"],
    extension_params = {
        "isi_violation":{"isi_threshold_ms":2.0}
    }
)
from spikeinterface.exporters import export_to_phy
export_to_phy(sorting_analyzer=analyzer, output_folder='E:/Desktop/flexible electrode/LL NO 170/acute-m03-striatum/phy_with_metrics')

Is there anything obviously wrong in my code, especially in how I construct the probe, assign device_channel_indices, or attach the probe to the recording? I’m not sure whether the mismatch in Phy is caused by incorrect channel ordering or by the way I applied the probe mapping.

Any suggestions would be greatly appreciated!

Metadata

Metadata

Assignees

No one assigned

    Labels

    exportersRelated to exporters module

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions