From 6f8cb7a7fa38ffd10601a0683adcb6adba927ab9 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Mon, 24 Nov 2025 14:42:59 -0500 Subject: [PATCH 1/7] Add github action to codespell main on push and PRs --- .github/workflows/codespell.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/codespell.yml diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml new file mode 100644 index 00000000..b2316674 --- /dev/null +++ b/.github/workflows/codespell.yml @@ -0,0 +1,25 @@ +# Codespell configuration is within pyproject.toml +--- +name: Codespell + +on: + push: + branches: [main] + pull_request: + branches: [main] + +permissions: + contents: read + +jobs: + codespell: + name: Check for spelling errors + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Annotate locations with typos + uses: codespell-project/codespell-problem-matcher@v1 + - name: Codespell + uses: codespell-project/actions-codespell@v2 From fc5f9d4644e624b8fdfd23523b9e33cd41303b87 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Mon, 24 Nov 2025 14:42:59 -0500 Subject: [PATCH 2/7] Add rudimentary codespell config --- pyproject.toml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index acfa121a..c1dbda00 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,3 +62,10 @@ docs = [ "sphinx>=5.0", "sphinx_rtd_theme", ] + +[tool.codespell] +# Ref: https://github.com/codespell-project/codespell#using-a-config-file +skip = '.git*,pyproject.toml' +check-hidden = true +# ignore-regex = '' +ignore-words-list = 'nd,gaus' From adb8fcee462856a78fe471e6a7f88acca5ac0550 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Mon, 24 Nov 2025 14:44:50 -0500 Subject: [PATCH 3/7] [DATALAD RUNCMD] run codespell throughout fixing typos automagically (but ignoring overall fail due to ambigous ones) === Do not change lines below === { "chain": [], "cmd": "codespell -w || :", "exit": 0, "extra_inputs": [], "inputs": [], "outputs": [], "pwd": "." } ^^^ Do not change lines above ^^^ --- TODO.md | 2 +- docs/source/views.rst | 2 +- spikeinterface_gui/backend_panel.py | 4 ++-- spikeinterface_gui/backend_qt.py | 6 +++--- spikeinterface_gui/controller.py | 4 ++-- spikeinterface_gui/ndscatterview.py | 6 +++--- spikeinterface_gui/probeview.py | 2 +- spikeinterface_gui/spikelistview.py | 2 +- spikeinterface_gui/tests/testingtools.py | 6 +++--- spikeinterface_gui/utils_panel.py | 2 +- spikeinterface_gui/utils_qt.py | 2 +- spikeinterface_gui/view_base.py | 8 ++++---- 12 files changed, 23 insertions(+), 23 deletions(-) diff --git a/TODO.md b/TODO.md index 8fdc7e05..2674b3ce 100644 --- a/TODO.md +++ b/TODO.md @@ -25,7 +25,7 @@ - [ ] global settings (e.g. color options, layout) - [x] unit list - [x] more columns to panel unit list - - [x] add settings to select colums + - [x] add settings to select columns - [x] add sparsity and channel id - [x] visible only when clicking on select column - [x] make x-axis scrollable diff --git a/docs/source/views.rst b/docs/source/views.rst index 7bfd4c26..e29fc03c 100644 --- a/docs/source/views.rst +++ b/docs/source/views.rst @@ -12,7 +12,7 @@ Controls ~~~~~~~~ - **left click** : select single unit - **ctrl + left click** : add unit to selection -- **mouse drag from within circle** : change channel visibilty and unit visibility on other views +- **mouse drag from within circle** : change channel visibility and unit visibility on other views - **mouse drag from "diamond"** : change channel / unit radii size Screenshots diff --git a/spikeinterface_gui/backend_panel.py b/spikeinterface_gui/backend_panel.py index 0844dd1b..d54e4760 100644 --- a/spikeinterface_gui/backend_panel.py +++ b/spikeinterface_gui/backend_panel.py @@ -207,7 +207,7 @@ def __init__(self, controller, layout_dict=None, user_settings=None): self.make_views(user_settings) self.create_main_layout() - # refresh all views wihtout notiying + # refresh all views without notiying self.controller.signal_handler.deactivate() self.controller.signal_handler.activate() @@ -281,7 +281,7 @@ def create_main_layout(self): layout_zone = {} for zone, view_names in preset.items(): - # keep only instanciated views + # keep only instantiated views view_names = [view_name for view_name in view_names if view_name in self.view_layouts.keys()] if len(view_names) == 0: diff --git a/spikeinterface_gui/backend_qt.py b/spikeinterface_gui/backend_qt.py index c5b18393..aae12884 100644 --- a/spikeinterface_gui/backend_qt.py +++ b/spikeinterface_gui/backend_qt.py @@ -48,7 +48,7 @@ def notify_unit_color_changed(self): self.unit_color_changed.emit() -# Used by controler to handle/callback signals +# Used by controller to handle/callback signals class SignalHandler(QT.QObject): def __init__(self, controller, parent=None): QT.QObject.__init__(self, parent=parent) @@ -165,13 +165,13 @@ def __init__(self, controller, parent=None, layout_dict=None, user_settings=None self.make_views(user_settings) self.create_main_layout() - # refresh all views wihtout notiying + # refresh all views without notiying self.controller.signal_handler.deactivate() for view in self.views.values(): # refresh do not work because view are not yet visible at init view._refresh() self.controller.signal_handler.activate() - # TODO sam : all veiws are always refreshed at the moment so this is useless. + # TODO sam : all views are always refreshed at the moment so this is useless. # uncommen this when ViewBase.is_view_visible() work correctly # for view_name, dock in self.docks.items(): # dock.visibilityChanged.connect(self.views[view_name].refresh) diff --git a/spikeinterface_gui/controller.py b/spikeinterface_gui/controller.py index 8d78a715..cb89be87 100644 --- a/spikeinterface_gui/controller.py +++ b/spikeinterface_gui/controller.py @@ -66,7 +66,7 @@ def __init__(self, analyzer=None, backend="qt", parent=None, verbose=False, save self.main_settings = _default_main_settings.copy() self.num_channels = self.analyzer.get_num_channels() - # this now private and shoudl be acess using function + # this now private and should be access using function self._visible_unit_ids = [self.unit_ids[0]] # sparsity @@ -552,7 +552,7 @@ def get_visible_unit_ids(self): return self._visible_unit_ids def get_visible_unit_indices(self): - """Get list of indicies of visible units""" + """Get list of indices of visible units""" unit_ids = list(self.unit_ids) visible_unit_indices = [unit_ids.index(u) for u in self._visible_unit_ids] return visible_unit_indices diff --git a/spikeinterface_gui/ndscatterview.py b/spikeinterface_gui/ndscatterview.py index 65e71e9d..53c98728 100644 --- a/spikeinterface_gui/ndscatterview.py +++ b/spikeinterface_gui/ndscatterview.py @@ -280,7 +280,7 @@ def _qt_refresh(self, update_components=True, update_colors=True): self.update_selected_components() #ndscatter - # TODO sam: I have the feeling taht it is a bit slow + # TODO sam: I have the feeling that it is a bit slow self.scatter.clear() # scatter_x, scatter_y, spike_indices, selected_scatter_x, selected_scatter_y = self.get_plotting_data(concatenated=True) @@ -367,7 +367,7 @@ def _qt_on_lasso_finished(self, points, shift_held=False): vertices = np.array(points) self._lasso_vertices.append(vertices) - # inside lasso and visibles + # inside lasso and visible ind_visibles, = np.nonzero(np.isin(self.random_spikes_indices, self.controller.get_indices_spike_visible())) projected = self.apply_dot(self.data[ind_visibles, :]) inside = inside_poly(projected, vertices) @@ -550,7 +550,7 @@ def _on_panel_selection_geometry(self, event): else: self._lasso_vertices = [polygon] - # inside lasso and visibles + # inside lasso and visible ind_visibles, = np.nonzero(np.isin(self.random_spikes_indices, self.controller.get_indices_spike_visible())) inds = self.random_spikes_indices[ind_visibles[selected]] self.controller.set_indices_spike_selected(inds) diff --git a/spikeinterface_gui/probeview.py b/spikeinterface_gui/probeview.py index 29099645..3f3c73f2 100644 --- a/spikeinterface_gui/probeview.py +++ b/spikeinterface_gui/probeview.py @@ -713,6 +713,6 @@ def circle_from_roi(roi): ### Controls - **left click** : select single unit - **ctrl + left click** : add unit to selection -- **mouse drag from within circle** : change channel visibilty and unit visibility on other views +- **mouse drag from within circle** : change channel visibility and unit visibility on other views - **mouse drag from "diamond"** : change channel / unit radii size """ diff --git a/spikeinterface_gui/spikelistview.py b/spikeinterface_gui/spikelistview.py index 2e5510f1..548010cf 100644 --- a/spikeinterface_gui/spikelistview.py +++ b/spikeinterface_gui/spikelistview.py @@ -224,7 +224,7 @@ def _qt_on_spike_selection_changed(self): visible_inds = self.controller.get_indices_spike_visible() row_selected, = np.nonzero(np.isin(visible_inds, selected_inds)) - if row_selected.size>100:#otherwise this is verry slow + if row_selected.size>100:#otherwise this is very slow row_selected = row_selected[:10] # change selection diff --git a/spikeinterface_gui/tests/testingtools.py b/spikeinterface_gui/tests/testingtools.py index de29f8e9..44e7ee5f 100644 --- a/spikeinterface_gui/tests/testingtools.py +++ b/spikeinterface_gui/tests/testingtools.py @@ -44,7 +44,7 @@ def make_analyzer_folder(test_folder, case="small", unit_dtype="str"): job_kwargs = dict(n_jobs=-1, progress_bar=True, chunk_duration="1s") recordings = [] - sortings = [] + sorting = [] probes = [] for i in range(num_probe): recording, sorting = si.generate_ground_truth_recording( @@ -75,7 +75,7 @@ def make_analyzer_folder(test_folder, case="small", unit_dtype="str"): recording = recording.set_probe(probe) recordings.append(recording) - sortings.append(sorting) + sorting.append(sorting) probes.append(probe.copy()) if 'split' in case: @@ -105,7 +105,7 @@ def make_analyzer_folder(test_folder, case="small", unit_dtype="str"): count += n recording = recording.set_probegroup(probegroup) - sorting = si.aggregate_units(sortings) + sorting = si.aggregate_units(sorting) sorting = sorting.rename_units(sorting.unit_ids.astype(unit_dtype)) diff --git a/spikeinterface_gui/utils_panel.py b/spikeinterface_gui/utils_panel.py index 7b5ba94b..0ed6a316 100644 --- a/spikeinterface_gui/utils_panel.py +++ b/spikeinterface_gui/utils_panel.py @@ -234,7 +234,7 @@ def is_position_inside(self, x, y, skip_other_positions=None, skip_distance=5): """ Check if the given position (x, y) is inside the circle. If skip_other_positions is provided, check if the position is close to any of them - usinf the skip_distance. + using the skip_distance. """ # Check if position is inside the circle distance = np.sqrt((x - self.center[0]) ** 2 + (y - self.center[1]) ** 2) diff --git a/spikeinterface_gui/utils_qt.py b/spikeinterface_gui/utils_qt.py index ddfc9ccd..0d1f5d56 100644 --- a/spikeinterface_gui/utils_qt.py +++ b/spikeinterface_gui/utils_qt.py @@ -38,7 +38,7 @@ def add_stretch_to_qtoolbar(tb): - # add an expending widget + a seprator + # add an expending widget + a separator empty = QT.QWidget() empty.setSizePolicy(QT.QSizePolicy.Expanding, QT.QSizePolicy.Preferred) tb.addWidget(empty) diff --git a/spikeinterface_gui/view_base.py b/spikeinterface_gui/view_base.py index c2828c21..a6c5b111 100644 --- a/spikeinterface_gui/view_base.py +++ b/spikeinterface_gui/view_base.py @@ -78,7 +78,7 @@ def notify_unit_color_changed(self): def on_settings_changed(self, *params): # what to do when one settings is changed # optionally views can implement custom method - # but the general case is to refesh + # but the general case is to refresh if self.backend == "qt" and hasattr(self, "_qt_on_settings_changed"): return self._qt_on_settings_changed() elif self.backend == "panel" and hasattr(self, "_panel_on_settings_changed"): @@ -178,7 +178,7 @@ def get_unit_color(self, unit_id): html_color = matplotlib.colors.rgb2hex(color, keep_alpha=True) return html_color - # Default behavior for all views : this can be changed view by view for perfs reaons + # Default behavior for all views : this can be changed view by view for perfs reasons def on_spike_selection_changed(self): if not self.is_view_visible(): return @@ -252,7 +252,7 @@ def _qt_on_spike_selection_changed(self): pass def _qt_on_unit_visibility_changed(self): - # most veiw need a refresh + # most view need a refresh self.refresh() def _qt_on_channel_visibility_changed(self): @@ -312,7 +312,7 @@ def _panel_on_spike_selection_changed(self): pass def _panel_on_unit_visibility_changed(self): - # most veiw need a refresh + # most view need a refresh self.refresh() def _panel_on_channel_visibility_changed(self): From 585baaf50b1fed0d560ffe71877e35a5e7ff70ed Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Mon, 24 Nov 2025 14:45:22 -0500 Subject: [PATCH 4/7] [DATALAD RUNCMD] chore: run codespell throughout fixing a few typos interactively === Do not change lines below === { "chain": [], "cmd": "codespell -w -i 3 -C 4", "exit": 0, "extra_inputs": [], "inputs": [], "outputs": [], "pwd": "." } ^^^ Do not change lines above ^^^ --- spikeinterface_gui/__init__.py | 2 +- spikeinterface_gui/ndscatterview.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spikeinterface_gui/__init__.py b/spikeinterface_gui/__init__.py index 90764da3..367d75ca 100644 --- a/spikeinterface_gui/__init__.py +++ b/spikeinterface_gui/__init__.py @@ -1,7 +1,7 @@ """ Some design notes: * controller is a layer between spikeinterface objects and every view - * every view can notify some signals to other view that are centralized bu the controller + * every view can notify some signals to other view that are centralized by the controller * views have settings * views have 2 implementations : qt (legacy) and panel (for the web) They need to implement the make_layout and the refresh for each backends (qt, panel). diff --git a/spikeinterface_gui/ndscatterview.py b/spikeinterface_gui/ndscatterview.py index 53c98728..7c0c5b8d 100644 --- a/spikeinterface_gui/ndscatterview.py +++ b/spikeinterface_gui/ndscatterview.py @@ -38,7 +38,7 @@ def __init__(self, controller=None, parent=None, backend="qt"): self.selected_comp = np.ones((ndim), dtype='bool') self.projection = self.get_one_random_projection() - #estimate limts + #estimate limits data = self.data if data.shape[0] > 1000: inds = np.random.choice(data.shape[0], 1000, replace=False) @@ -297,7 +297,7 @@ def _qt_refresh(self, update_components=True, update_colors=True): self.scatter_select.setData(selected_scatter_x, selected_scatter_y) - # TODO sam : kepp the old implementation in mind + # TODO sam : keep the old implementation in mind # for unit_index, unit_id in enumerate(self.controller.unit_ids): # if not self.controller.get_unit_visibility(unit_id): # continue From a6a33ce83b686c79d3b24a5eb4c7baa0409abd13 Mon Sep 17 00:00:00 2001 From: Alessio Buccino Date: Fri, 6 Mar 2026 10:24:58 -0800 Subject: [PATCH 5/7] fix: exclude 'sortings' and remove old TODO --- .github/workflows/codespell.yml | 2 + TODO.md | 57 ------------------------ spikeinterface_gui/tests/testingtools.py | 6 +-- 3 files changed, 5 insertions(+), 60 deletions(-) delete mode 100644 TODO.md diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index b2316674..fb0d517a 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -23,3 +23,5 @@ jobs: uses: codespell-project/codespell-problem-matcher@v1 - name: Codespell uses: codespell-project/actions-codespell@v2 + with: + ignore_words_list: sortings diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 2674b3ce..00000000 --- a/TODO.md +++ /dev/null @@ -1,57 +0,0 @@ -# TODO - -### Sam -- [ ] remove compute -- [x] QT settings not more dialog -- [ ] remove custom docker -- [x] simple layout description -- [ ] unit list with depth - - -### Alessio -- [x] handle similarity default compute -- [x] spike list + spike selection -- [x] curation view -- [x] add settings / more columns to panel unit list -- [x] unitlist: fix merge and delete with sorters -- [ ] implement default color toggle button - - - - -### Panel Views -- [ ] general - - [x] fix settings cards - - [ ] global settings (e.g. color options, layout) -- [x] unit list - - [x] more columns to panel unit list - - [x] add settings to select columns - - [x] add sparsity and channel id - - [x] visible only when clicking on select column - - [x] make x-axis scrollable -- [ ] probe - - [x] fix pan to move circles - - [ ] add option to resize circles -- [ ] spike list - - [x] add unit color - - [x] fix segment index - - [x] fix spike selection -- [x] curation -- [x] merge -- [x] waveform - - [x] zoom on wheel - - [x] flatten mode -- [x] trace - - [x] fix multi-segment selection - - [x] zoom on wheel - - [x] fix spike at init -- [ ] spike amplitudes - - [x] add selection - - [ ] add option to scatter decimate -- [ ] NDscatter - - [x] fix limits - - [ ] add selection - -### Discussion -* panel.param or Pydantic? -* plotly / bokeh? diff --git a/spikeinterface_gui/tests/testingtools.py b/spikeinterface_gui/tests/testingtools.py index 44e7ee5f..de29f8e9 100644 --- a/spikeinterface_gui/tests/testingtools.py +++ b/spikeinterface_gui/tests/testingtools.py @@ -44,7 +44,7 @@ def make_analyzer_folder(test_folder, case="small", unit_dtype="str"): job_kwargs = dict(n_jobs=-1, progress_bar=True, chunk_duration="1s") recordings = [] - sorting = [] + sortings = [] probes = [] for i in range(num_probe): recording, sorting = si.generate_ground_truth_recording( @@ -75,7 +75,7 @@ def make_analyzer_folder(test_folder, case="small", unit_dtype="str"): recording = recording.set_probe(probe) recordings.append(recording) - sorting.append(sorting) + sortings.append(sorting) probes.append(probe.copy()) if 'split' in case: @@ -105,7 +105,7 @@ def make_analyzer_folder(test_folder, case="small", unit_dtype="str"): count += n recording = recording.set_probegroup(probegroup) - sorting = si.aggregate_units(sorting) + sorting = si.aggregate_units(sortings) sorting = sorting.rename_units(sorting.unit_ids.astype(unit_dtype)) From 84c3190281b225416dc095585776f903e035fd33 Mon Sep 17 00:00:00 2001 From: Alessio Buccino Date: Fri, 6 Mar 2026 10:31:09 -0800 Subject: [PATCH 6/7] fix: ignore 'trough' --- .github/workflows/codespell.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index fb0d517a..cfa7f987 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -24,4 +24,4 @@ jobs: - name: Codespell uses: codespell-project/actions-codespell@v2 with: - ignore_words_list: sortings + ignore_words_list: sortings,trough From 3c52530b31c8d4c7c33e27952b7024bf2e4e4846 Mon Sep 17 00:00:00 2001 From: Alessio Buccino Date: Fri, 6 Mar 2026 20:57:31 +0100 Subject: [PATCH 7/7] Apply suggestion from @alejoe91 --- spikeinterface_gui/spikelistview.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spikeinterface_gui/spikelistview.py b/spikeinterface_gui/spikelistview.py index 548010cf..29881da0 100644 --- a/spikeinterface_gui/spikelistview.py +++ b/spikeinterface_gui/spikelistview.py @@ -224,7 +224,7 @@ def _qt_on_spike_selection_changed(self): visible_inds = self.controller.get_indices_spike_visible() row_selected, = np.nonzero(np.isin(visible_inds, selected_inds)) - if row_selected.size>100:#otherwise this is very slow + if row_selected.size > 100: #otherwise this is very slow row_selected = row_selected[:10] # change selection