diff --git a/spikeinterface_gui/controller.py b/spikeinterface_gui/controller.py index dd5b9d5d..d73d288b 100644 --- a/spikeinterface_gui/controller.py +++ b/spikeinterface_gui/controller.py @@ -902,6 +902,27 @@ def make_manual_merge_if_possible(self, merge_unit_ids): print(f"Merged unit group: {[str(u) for u in merge_unit_ids]}") return True + + def remove_units_from_merge_if_possible(self, merge_unit_ids): + """ + Check if selected units are in a merge group. If they are, remove them. + """ + if not self.curation: + return False + + merges = self.curation_data["merges"] + for i, merge in enumerate(merges): + if set(merge_unit_ids).issubset(set(merge['unit_ids'])): + merge_ids_with_removed_ids = list(set(merge['unit_ids']).difference(set(merge_unit_ids))) + if len(merge_ids_with_removed_ids) > 1: + merges[i]['unit_ids'] = merge_ids_with_removed_ids + return True + else: + return False + + return False + + def make_manual_split_if_possible(self, unit_id): """ Check if the a unit_id can be split into a new split in the curation_data. diff --git a/spikeinterface_gui/unitlistview.py b/spikeinterface_gui/unitlistview.py index ef6a6958..23800964 100644 --- a/spikeinterface_gui/unitlistview.py +++ b/spikeinterface_gui/unitlistview.py @@ -20,16 +20,6 @@ def __init__(self, controller=None, parent=None, backend="qt"): ## common ## - def show_all(self): - self.controller.set_visible_unit_ids(self.controller.unit_ids) - self.notify_unit_visibility_changed() - self.refresh() - - def hide_all(self): - self.controller.set_all_unit_visibility_off() - self.notify_unit_visibility_changed() - self.refresh() - def get_selected_unit_ids(self): if self.backend == 'qt': return self._qt_get_selected_unit_ids() @@ -88,10 +78,6 @@ def _qt_make_layout(self): self.column_order = None self.menu = QT.QMenu() - act = self.menu.addAction('Show all') - act.triggered.connect(self.show_all) - act = self.menu.addAction('Hide all') - act.triggered.connect(self.hide_all) self.shortcut_only_previous = QT.QShortcut(self.qt_widget) self.shortcut_only_previous.setKey(QT.QKeySequence(QT.CTRL | QT.Key_Up)) @@ -106,6 +92,8 @@ def _qt_make_layout(self): act.triggered.connect(self._qt_delete_unit) act = self.menu.addAction('Merge selected') act.triggered.connect(self._qt_merge_selected) + act = self.menu.addAction('Remove from merge') + act.triggered.connect(self._qt_remove_from_merge) self.shortcut_delete = QT.QShortcut(self.qt_widget) self.shortcut_delete.setKey(QT.QKeySequence("ctrl+d")) self.shortcut_delete.activated.connect(self._qt_on_delete_shortcut) @@ -156,11 +144,17 @@ def _qt_refresh_visibility_items(self): from .myqt import QT self.table.itemChanged.disconnect(self._qt_on_item_changed) + + visible_unit_ids = self.controller.get_visible_unit_ids() + + view_target_unit_id = visible_unit_ids[0] + target_item = self.items_visibility[view_target_unit_id] + self.table.scrollToItem(target_item, QT.QAbstractItemView.PositionAtCenter) for unit_id in self.controller.unit_ids: item = self.items_visibility[unit_id] item.setCheckState(QT.Qt.Unchecked) - for unit_id in self.controller.get_visible_unit_ids(): + for unit_id in visible_unit_ids: item = self.items_visibility[unit_id] item.setCheckState(QT.Qt.Checked) self._qt_refresh_color_icons() @@ -435,9 +429,19 @@ def _qt_merge_selected(self): "merged, or split already." ) return - self.notify_manual_curation_updated() - + else: + self.notify_manual_curation_updated() + def _qt_remove_from_merge(self): + merge_unit_ids = self.get_selected_unit_ids() + success = self.controller.remove_units_from_merge_if_possible(merge_unit_ids) + if not success: + self.warning( + "Could not remove units from a merge. Ensure all selected units are in a merge group, and that you are not leaving zero or one units in the merge group." + ) + return + else: + self.notify_manual_curation_updated() ## panel zone ## def _panel_make_layout(self): @@ -526,35 +530,19 @@ def _panel_make_layout(self): column_callbacks={"visible": self._panel_on_visible_checkbox_toggled}, ) - self.select_all_button = pn.widgets.Button(name="Select All", button_type="default") - self.unselect_all_button = pn.widgets.Button(name="Unselect All", button_type="default") self.refresh_button = pn.widgets.Button(name="↻", button_type="default") - button_list = [ - self.select_all_button, - self.unselect_all_button, - ] + button_list = [] if self.controller.curation: self.delete_button = pn.widgets.Button(name="Delete", button_type="default") self.merge_button = pn.widgets.Button(name="Merge", button_type="default") - # self.hide_noise = pn.widgets.Toggle(name="Show/Hide Noise", button_type="default") - - # if "quality" in self.label_definitions: - # self.show_only = pn.widgets.Select( - # name="Show only", - # options=["all"] + list(self.label_definitions["quality"]['label_options']), - # sizing_mode="stretch_width", - # ) - # else: - # self.show_only = None - - # self.hide_noise.param.watch(self._panel_on_hide_noise, 'value') - # self.show_only.param.watch(self._panel_on_show_only, 'value') + self.unmerge_button = pn.widgets.Button(name="Unmerge", button_type="default") button_list.extend( [ self.delete_button, self.merge_button, + self.unmerge_button, ] ) @@ -596,14 +584,12 @@ def _panel_make_layout(self): self.layout.append(shortcuts_component) self.table.tabulator.on_edit(self._panel_on_edit) - - self.select_all_button.on_click(self._panel_select_all) - self.unselect_all_button.on_click(self._panel_unselect_all) self.refresh_button.on_click(self._panel_refresh_click) if self.controller.curation: self.delete_button.on_click(self._panel_delete_unit_callback) self.merge_button.on_click(self._panel_merge_units_callback) + self.unmerge_button.on_click(self._panel_remove_from_merge_callback) def _panel_refresh_click(self, event): self.table.reset() @@ -658,14 +644,6 @@ def _panel_refresh_header(self): txt = f"All units: {n1} - visible: {n2} - selected: {n3}" self.info_text.object = txt - def _panel_select_all(self, event): - self.show_all() - self.notifier.notify_active_view_updated() - - def _panel_unselect_all(self, event): - self.hide_all() - self.notifier.notify_active_view_updated() - def _panel_delete_unit_callback(self, event): self._panel_delete_unit() self.notifier.notify_active_view_updated() @@ -674,6 +652,10 @@ def _panel_merge_units_callback(self, event): self._panel_merge_units() self.notifier.notify_active_view_updated() + def _panel_remove_from_merge_callback(self, event): + self._panel_remove_from_merge() + self.notifier.notify_active_view_updated() + def _panel_on_visible_checkbox_toggled(self, row): # print("checkbox toggled on row", row) unit_ids = self.table.value.index.values @@ -759,6 +741,18 @@ def _panel_merge_units(self): self.notify_manual_curation_updated() self.refresh() + def _panel_remove_from_merge(self): + merge_unit_ids = self.get_selected_unit_ids() + success = self.controller.remove_units_from_merge_if_possible(merge_unit_ids) + if not success: + self.warning( + "Could not remove units from a merge. Ensure all selected units are in a merge " + "group, and that you are not leaving zero or one units in the merge group." + ) + return + self.notify_manual_curation_updated() + self.refresh() + def _panel_handle_shortcut(self, event): if self.is_view_active(): selected_unit_ids = self._panel_get_selected_unit_ids()