anon-iclr-submission/benchname-bug-localization huggingface dataset:
Repository: spikeinterface/spikeinterface
Issue: Mismatch in sw.plot_timeseries

Hi all,

when we use a multishank probe, we observe a mismatch between the probe mapping and the order in which the channels are plotted using sw.plot_timeseries when the boolean "order_channel_by_depth=True".
The Y axis of the plot does not have the channels organized based on their depth position. However, when we use a linear probe we dont have this issue.
Any suggestions?



Changed files:
spikeinterface/widgets/timeseries.py, spikeinterface/widgets/tests/test_widgets.py

diff --git a/spikeinterface/widgets/tests/test_widgets.py b/spikeinterface/widgets/tests/test_widgets.py
index fb83a8dd..295c9f0e 100644
--- a/spikeinterface/widgets/tests/test_widgets.py
+++ b/spikeinterface/widgets/tests/test_widgets.py
@@ -197,10 +197,10 @@ if __name__ == '__main__':
     mytest = TestWidgets()
     mytest.setUp()
     
-    # mytest.test_plot_timeseries()
+    mytest.test_plot_timeseries()
     
     # mytest.test_plot_unit_waveforms()
     # mytest.test_plot_unit_templates()
-    mytest.test_plot_unit_templates()
+    # mytest.test_plot_unit_templates()
 
     plt.show()
diff --git a/spikeinterface/widgets/timeseries.py b/spikeinterface/widgets/timeseries.py
index a039f7c5..14f0070a 100644
--- a/spikeinterface/widgets/timeseries.py
+++ b/spikeinterface/widgets/timeseries.py
@@ -204,6 +204,9 @@ def _get_trace_list(recordings, channel_ids, time_range, segment_index, order=No
     time_range = frame_range / fs
     times = np.arange(frame_range[0], frame_range[1]) / fs
 
+    if order is not None:
+        channel_ids = np.array(channel_ids)[order]
+
     list_traces = []
     for rec_name, rec in recordings.items():
         traces = rec.get_traces(
@@ -215,8 +218,6 @@ def _get_trace_list(recordings, channel_ids, time_range, segment_index, order=No
 
         if order is not None:
             traces = traces[:, order]
-            channel_ids = np.asarray(channel_ids)[order]
-
         list_traces.append(traces)
-    
+
     return times, list_traces, frame_range, channel_ids
\\ No newline at end of file
Repository: spikeinterface/spikeinterface
Issue: Error in recording.py if chunk_size is greater than number of frames in recording

Getting an error in `spikeinterace/core/recording.py` setting up a unit test for a small recording because the number of frames is less than the chunk size. In lines 36-38:

```
        length = recording.get_num_frames(segment_index)
        random_starts = np.random.RandomState(seed=seed).randint(0,
                                                                 length - chunk_size, size=num_chunks_per_segment)
```
if `length <=chunk_size`, then an error is thrown.

Changed files:
spikeinterface/core/recording_tools.py

diff --git a/spikeinterface/core/recording_tools.py b/spikeinterface/core/recording_tools.py
index 65a21a6d..93eaed0f 100644
--- a/spikeinterface/core/recording_tools.py
+++ b/spikeinterface/core/recording_tools.py
@@ -27,15 +27,20 @@ def get_random_data_chunks(recording, return_scaled=False, num_chunks_per_segmen
     chunk_list: np.array
         Array of concatenate chunks per segment
     """
-    # TODO: if segment have differents length make another sampling that dependant on the lneght of the segment
-    # Should be done by chnaging kwargs with total_num_chunks=XXX and total_duration=YYYY
-    # And randomize the number of chunk per segment wieighted by segment duration
+    # TODO: if segment have differents length make another sampling that dependant on the length of the segment
+    # Should be done by changing kwargs with total_num_chunks=XXX and total_duration=YYYY
+    # And randomize the number of chunk per segment weighted by segment duration
+
+    # check chunk size    
+    for segment_index in range(recording.get_num_segments()):
+        assert chunk_size < recording.get_num_samples(segment_index), (f"chunk_size is greater than the number "
+                                                                        f"of samples for segment index {segment_index}. "
+                                                                        f"Use a smaller chunk_size!")
 
     chunk_list = []
     for segment_index in range(recording.get_num_segments()):
         length = recording.get_num_frames(segment_index)
-        random_starts = np.random.RandomState(seed=seed).randint(0,
-                                                                 length - chunk_size, size=num_chunks_per_segment)
+        random_starts = np.random.RandomState(seed=seed).randint(0, length - chunk_size, size=num_chunks_per_segment)
         for start_frame in random_starts:
             chunk = recording.get_traces(start_frame=start_frame,
                                          end_frame=start_frame + chunk_size,
Repository: spikeinterface/spikeinterface
Issue: Another issue with PhySortingExtractor

Hi,

we enocunter anothe issue with PhySortingExtractor.
Once we run the extractor after curation in Phy we noticed the following:

"get_unit_ids" in spikeinterface is giving us the  index of the units shown in "si_unit_id" of the ClusterView (Phy GUI).
However, the spike trains information are stored under the index "id" of the ClusterView (Phy GUI). 
Since the "id" and the "si_unit_id" of the ClusterView (Phy GUI) often do not match (especially after merging or splitting during manual curation), this creates issues when extracting the timestamps of the spikes (and even the waveforms) when using "get_unit_ids" to iterate through the id of the unit after manual curation.

I hope this is clear, otherwise I am happy to give more details.

Changed files:
spikeinterface/extractors/phykilosortextractors.py

diff --git a/spikeinterface/extractors/phykilosortextractors.py b/spikeinterface/extractors/phykilosortextractors.py
index 865ce9a0..2106ac7d 100644
--- a/spikeinterface/extractors/phykilosortextractors.py
+++ b/spikeinterface/extractors/phykilosortextractors.py
@@ -96,6 +96,26 @@ class BasePhyKilosortSortingExtractor(BaseSorting):
 
         if 'si_unit_id' in cluster_info.columns:
             unit_ids = cluster_info["si_unit_id"].values
+
+            if np.all(np.isnan(unit_ids)):
+                max_si_unit_id = -1
+            else:
+                max_si_unit_id = int(np.nanmax(unit_ids))
+
+            # update spike cluster values
+            spike_clusters_new = np.zeros_like(spike_clusters)
+            for i, (phy_id, si_id) in enumerate(zip(cluster_info["cluster_id"].values,
+                                                    cluster_info["si_unit_id"].values)):
+                if np.isnan(si_id):
+                    max_si_unit_id += 1
+                    new_si_id = int(max_si_unit_id)
+                else:
+                    new_si_id = si_id
+                unit_ids[i] = new_si_id
+
+                spike_clusters_new[spike_clusters == phy_id] = new_si_id
+            unit_ids = unit_ids.astype(int)
+            spike_clusters = spike_clusters_new
             del cluster_info["si_unit_id"]
         else:
             unit_ids = cluster_info["cluster_id"].values
Repository: spikeinterface/spikeinterface
Issue: Loading sync channel using read_openephys

Hey guys, appreciate all of your terrific work!
I am using OE to record NPX and also save the sync channel - #385. I am trying to load the sync channel using read_openephys (in spikeinterface.extractors). When I use:
`new_recording = se.read_openephys(path_to_recording_file, stream_name="Record Node 101#Neuropix-PXI-100.ProbeA-AP", load_sync_channel=True)` 
I get the following error: "set_probe(inplace=True) must have all channel indices"

Changed files:
src/spikeinterface/extractors/neoextractors/openephys.py

diff --git a/src/spikeinterface/extractors/neoextractors/openephys.py b/src/spikeinterface/extractors/neoextractors/openephys.py
index e1a6598f..a7af1078 100644
--- a/src/spikeinterface/extractors/neoextractors/openephys.py
+++ b/src/spikeinterface/extractors/neoextractors/openephys.py
@@ -149,8 +149,8 @@ class OpenEphysBinaryRecordingExtractor(NeoBaseRecordingExtractor):
         else:
             exp_id = exp_ids[block_index]
 
-        # do not load probe for NIDQ stream
-        if "NI-DAQmx" not in stream_name:
+        # do not load probe for NIDQ stream or if load_sync_channel is True
+        if "NI-DAQmx" not in stream_name and not load_sync_channel:
             settings_file = self.neo_reader.folder_structure[record_node]["experiments"][exp_id]["settings_file"]
 
             if Path(settings_file).is_file():
Repository: spikeinterface/spikeinterface
Issue: a small bug in generate_erroneous_sorting

[generate_erroneous_sorting](https://github.com/SpikeInterface/spikeinterface/blob/4bdf86eb86a399989a2461ebdefa0f1a5624bc62/examples/modules_gallery/comparison/generate_erroneous_sorting.py#L61)

This line should be `units_err[82] = st82` instead of `units_err[81] = st82`



Changed files:
examples/modules_gallery/comparison/generate_erroneous_sorting.py

diff --git a/examples/modules_gallery/comparison/generate_erroneous_sorting.py b/examples/modules_gallery/comparison/generate_erroneous_sorting.py
index 7aa1b5d7..731f82ff 100644
--- a/examples/modules_gallery/comparison/generate_erroneous_sorting.py
+++ b/examples/modules_gallery/comparison/generate_erroneous_sorting.py
@@ -12,6 +12,27 @@ import spikeinterface.comparison as sc
 import spikeinterface.widgets as sw
 
 def generate_erroneous_sorting():
+    """
+    Generate an erroneous spike sorting for illustration purposes.
+
+    This function creates a toy example recording and true sorting using the
+    `toy_example` function. It then introduces
+    various errors in the true sorting to create an erroneous sorting.
+
+    The specific types of errors are:
+
+    * Units 1 and 2 are perfect and have no errors.
+    * Units 3, 4, and 10 have medium to low agreement with the true sorting.
+    * Units 5 and 6 are over-merged, meaning that they contain spikes from multiple true units.
+    * Unit 7 is over-split, meaning that it contains spikes from a true unit that has been split into two parts.
+    * Unit 8 is redundant and appears 3 times in the erroneous sorting.
+    * Unit 9 is completely missing from the erroneous sorting.
+    * Units 15, 16, and 17 do not exist in the true sorting, but are included in the erroneous sorting.
+
+    Returns:
+        A tuple containing the true sorting and the erroneous sorting in that order
+    """
+    
     rec, sorting_true = se.toy_example(num_channels=4, num_units=10, duration=10, seed=10, num_segments=1)
 
     # artificially remap to one based
@@ -58,7 +79,7 @@ def generate_erroneous_sorting():
     st82 = np.sort(np.random.choice(st8, size=int(st8.size*0.55), replace=False))
     units_err[80] = st80
     units_err[81] = st81
-    units_err[81] = st82
+    units_err[82] = st82
 
     # unit 9 is missing
Repository: spikeinterface/spikeinterface
Issue: Issue with order_channels_by_depth

I have attempted several ways to use the 'detect_bad_channels' function from spikeinterface.preprocessing, however....I get an error "IndexError: arrays used as indices must be of integer (or boolean) type" which is evoked within the subfunction 'order_channels_by_depth'. 

The error occurs during this step: **locations = locations[channel_inds, :]**

Investigating this further, I realized that the 'channel_ids' variable is intended to be a vector of integer values corresponding to the channels, but (at least in my case) the 'channel_ids' variable is a vector full of strings. As a first pass, I changed the error-causing line to:

#converting the string variables to integers and making the indices pythonic
**locations[[int(x)-1 for x in channel_inds], :]**  

Following this change, I ran detect_bad_channels and was pleased that it worked, but a "warning" emerged: 

#the code for detection
bad_channel_ids, channel_labels = spikeinterface.preprocessing.detect_bad_channels(reader_filtered)

#warning label
**UserWarning: nperseg = 244 is greater than input length  = 32, using nperseg = 32
  warnings.warn('nperseg = {0:d} is greater than input length '**

The 'input length = 32' was concerning and leads me to believe (because I am working with a 32-channel shank) that the data is being read in a transposed fashion, but I cannot be sure?

As another 'workaround', I tried multiple times to set the channel ids to integer values because I dont want to be working with a modified version of spikeinterface functions, but the object file does not allow for this. 

For clarity on this issue....I am using a 32-channel neuronexus probe and recording using TDT, and importing into spikeinterface using read_tdt.

Thanks


Changed files:
spikeinterface/core/recording_tools.py, spikeinterface/core/base.py

diff --git a/spikeinterface/core/base.py b/spikeinterface/core/base.py
index 0293ea48..44755080 100644
--- a/spikeinterface/core/base.py
+++ b/spikeinterface/core/base.py
@@ -96,7 +96,7 @@ class BaseExtractor:
             if prefer_slice:
                 indices = slice(None)
             else:
-                indices = self._main_ids
+                indices = np.arange(len(self._main_ids))
         else:
             _main_ids = self._main_ids.tolist()
             indices = np.array([_main_ids.index(id) for id in ids], dtype=int)
diff --git a/spikeinterface/core/recording_tools.py b/spikeinterface/core/recording_tools.py
index 3a155e3e..c5c1ba67 100644
--- a/spikeinterface/core/recording_tools.py
+++ b/spikeinterface/core/recording_tools.py
@@ -223,7 +223,7 @@ def order_channels_by_depth(recording, channel_ids=None, dimensions=('x', 'y')):
     """
     locations = recording.get_channel_locations()
     ndim = locations.shape[1]
-    channel_inds = recording.ids_to_indices(channel_ids)
+    channel_inds = recording.ids_to_indices(ids=channel_ids, prefer_slice=True)
     locations = locations[channel_inds, :]
 
     if isinstance(dimensions, str):