diff --git a/func/Module_SA_label_v2.py b/func/Module_SA_label_v2.py index 93a0d78..769e74e 100644 --- a/func/Module_SA_label_v2.py +++ b/func/Module_SA_label_v2.py @@ -553,7 +553,7 @@ class DataFrameModel(QAbstractTableModel): return QColor(255, 0, 0) else: # 返回黑色 - return QColor(0, 0, 0) + return QColor(0, 0, 0) except Exception as e: return None @@ -652,7 +652,7 @@ class MainWindow_SA_label(QMainWindow): self.display_columns_name_origin = ["事件编号", "事件类型", "起始时间(s)", "终止时间(s)"] self.header_mapping_origin = dict(zip(self.display_columns_origin, self.display_columns_name_origin)) - self.display_columns_revised = ["Index", "correct_EventsType", "score", "correct_Start", + self.display_columns_revised = ["Index", "correct_EventsType", "score", "correct_Start", "correct_End"] self.display_columns_name_revised = ["事件编号", "修正事件类型", "标签类型", "起始时间(s)", "终止时间(s)"] @@ -696,7 +696,6 @@ class MainWindow_SA_label(QMainWindow): self.ui.label_sampno.setText(f"编号:{sampID}") - # 初始化画框 self.fig = plt.figure(figsize=(12, 9), dpi=100) self.canvas = FigureCanvasQTAgg(self.fig) @@ -707,7 +706,6 @@ class MainWindow_SA_label(QMainWindow): self.figToolbar.cid_mouse_move = self.canvas.mpl_connect('motion_notify_event', self.on_motion) self.figToolbar.cid_wheel = self.canvas.mpl_connect('scroll_event', self.__slot_wheel_move__) - self.ui.verticalLayout_canvas.addWidget(self.canvas) self.ui.verticalLayout_canvas.addWidget(self.figToolbar) @@ -798,6 +796,7 @@ class MainWindow_SA_label(QMainWindow): self.ui.pushButton_next_half.clicked.connect(self.__slot_btn_move__) self.ui.pushButton_jump_to.clicked.connect(self.__slot_btn_move__) self.ui.pushButton_confirmLabel.clicked.connect(self.__slot_btn_confirmLabel__) + self.ui.pushButton_reset_event.clicked.connect(self.__reset_event__) # 输入防抖 self.debounce_timer1 = QTimer() @@ -846,20 +845,18 @@ class MainWindow_SA_label(QMainWindow): self.ui.pushButton_best_fit.setShortcut( QCoreApplication.translate("MainWindow", Params.SA_LABEL_BTN_BEST_FIT_SHORTCUT_KEY)) self.ui.pushButton_quick_remark_input_littleChange.setShortcut( - QCoreApplication.translate("MainWindow", Params. SA_LABEL_BTN_LITTLE_CHANGED_SHORTCUT_KEY) + QCoreApplication.translate("MainWindow", Params.SA_LABEL_BTN_LITTLE_CHANGED_SHORTCUT_KEY) ) self.ui.pushButton_quick_remark_input_changeOnMiddle.setShortcut( - QCoreApplication.translate("MainWindow", Params. SA_LABEL_BTN_CHANGED_ON_MIDDLE_SHORTCUT_KEY) + QCoreApplication.translate("MainWindow", Params.SA_LABEL_BTN_CHANGED_ON_MIDDLE_SHORTCUT_KEY) ) self.ui.pushButton_quick_remark_input_noNormalRespBetweenArtifact.setShortcut( - ).setShortcut( - QCoreApplication.translate("MainWindow", Params. SA_LABEL_BTN_BETWEEN_ARTIFACT_SHORTCUT_KEY) + QCoreApplication.translate("MainWindow", Params.SA_LABEL_BTN_BETWEEN_ARTIFACT_SHORTCUT_KEY) ) self.ui.pushButton_quick_remark_input_lowSignalNoiseRatio.setShortcut( - QCoreApplication.translate("MainWindow", Params. SA_LABEL_BTN_LOW_SNR_SHORTCUT_KEY) + QCoreApplication.translate("MainWindow", Params.SA_LABEL_BTN_LOW_SNR_SHORTCUT_KEY) ) - def load_data_to_table(self): try: self.data_model_origin = DataFrameModel(self.data.df_origin, self.display_columns_origin, @@ -932,16 +929,19 @@ class MainWindow_SA_label(QMainWindow): keep_xlim = False else: return - print(index, event_index) + # print(index, event_index) # 表格移动到指定行 - row_list = self.data_model_revised._showdata[self.data_model_revised._showdata["Index"] == event_index].index.tolist() + row_list = self.data_model_revised._showdata[ + self.data_model_revised._showdata["Index"] == event_index].index.tolist() if row_list: row = row_list[0] model_index = self.data_model_revised.index(row, 0) - self.ui.tableView_label_revised.scrollTo(model_index, self.ui.tableView_label_revised.ScrollHint.PositionAtCenter) + self.ui.tableView_label_revised.scrollTo(model_index, + self.ui.tableView_label_revised.ScrollHint.PositionAtCenter) # 显示事件信息 - row_list = self.data_model_origin._showdata[self.data_model_origin._showdata["Index"] == event_index].index.tolist() + row_list = self.data_model_origin._showdata[ + self.data_model_origin._showdata["Index"] == event_index].index.tolist() if row_list: row = row_list[0] @@ -1117,7 +1117,7 @@ class MainWindow_SA_label(QMainWindow): new_start = int(x_press) new_end = round(int(x_press) + dx) if sum(self.data.event_index_revised[ - max(0, new_start - 1):min(new_end + 1, self.config["SignalSecond"])]) != 0: + max(0, new_start - 1):min(new_end + 1, self.config["SignalSecond"])]) != 0: # 与已有事件重叠,删除创建的矩形框 self.selected_event_rect.remove() self.selected_event_rect = None @@ -1171,15 +1171,14 @@ class MainWindow_SA_label(QMainWindow): # 点击了空白区域 elif event_row is None: - self.selected_event_rect.set_alpha(0.2) + self.__reset_rect__() self.selected_event_info = None self.selected_event_rect = None self.__clear_event_info__() elif self.selected_event_info["Index"] != event_row["Index"]: # TODO 弹窗提醒是否切换 - if self.selected_event_rect is not None: - self.selected_event_rect.set_alpha(0.2) + self.__reset_rect__() self.selected_event_info = event_row.copy() self.selected_event_rect = self.event_ploy_collection[self.selected_event_info["Index"]] self.selected_event_rect.set_alpha(0.4) @@ -1223,6 +1222,21 @@ class MainWindow_SA_label(QMainWindow): self.canvas.setCursor(QCursor(Qt.CursorShape.ArrowCursor)) self.canvas.draw_idle() + def __reset_rect__(self): + if self.selected_event_info is not None and self.selected_event_rect is not None: + self.selected_event_rect.set_alpha(0.2) + x_rect = self.selected_event_rect.get_x() + width = self.selected_event_rect.get_width() + + event_left = self.selected_event_info["correct_Start"] if self.selected_event_info["isLabeled"] != -1 else \ + self.selected_event_info["Start"] + event_right = self.selected_event_info["correct_End"] if self.selected_event_info["isLabeled"] != -1 else \ + self.selected_event_info["End"] + if x_rect != event_left or width != (event_right - event_left): + self.selected_event_rect.set_x(event_left) + self.selected_event_rect.set_width(event_right - event_left) + self.canvas.draw_idle() + @overrides def closeEvent(self, event): reply = QMessageBox.question(self, '确认', '确认退出吗?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) @@ -1260,7 +1274,6 @@ class MainWindow_SA_label(QMainWindow): else: event.ignore() - def __save_revise_df__(self): try: # 过滤掉Index大于origin的行中score为3的行 @@ -1510,8 +1523,8 @@ class MainWindow_SA_label(QMainWindow): # 检查是否已有事件重叠 overlapping_indices = set(self.data.event_index_revised[ - max(0, event_info["correct_Start"] - 1):min(event_info["correct_End"] + 1, - self.config["SignalSecond"])]) + max(0, event_info["correct_Start"] - 1):min(event_info["correct_End"] + 1, + self.config["SignalSecond"])]) overlapping_indices.discard(event_info["Index"]) # 去除自身 overlapping_indices.discard(0) # 去除空白区域标记 if len(overlapping_indices) > 0: @@ -1597,19 +1610,22 @@ class MainWindow_SA_label(QMainWindow): self.event_ploy_collection[new_event["Index"]] = self.selected_event_rect self.show_selected_event(int(new_event["Index"])) - def reset_event(self, event_index): + def __reset_event__(self): """ 从df_origin中重置事件信息到df_revised, df_origin只有df_revised的部分列,剩余的列恢复默认值 """ if self.data is None or self.data.df_revised is None: raise ValueError("Data or df_revised is not initialized.") - index = self.data.df_revised[self.data.df_revised["Index"] == event_index].index - if index < 1 or index > len(self.data.df_revised): - raise IndexError("Index out of bounds for df_revised.") + event_index = self.selected_event_info["Index"] + + if event_index < 1 or event_index > len(self.data.df_origin): + PublicFunc.msgbox_output(self, "只能重置原始事件,无法重置新建事件!", Constants.MSGBOX_TYPE_WARNING) + PublicFunc.text_output(self.ui, "只能重置原始事件,无法重置新建事件!", Constants.TIPS_TYPE_ERROR) + return # 获取原始事件信息 - original_event_info = self.data.df_origin[self.data.df_origin["Index"] == index].copy() + original_event_info = self.data.df_origin[self.data.df_origin["Index"] == event_index].copy() original_event_info["isLabeled"] = -1 # 重置为未标记状态 original_event_info["correct_EventsType"] = "" # 重置为None original_event_info["score"] = -1 # 重置为None @@ -1617,23 +1633,42 @@ class MainWindow_SA_label(QMainWindow): original_event_info["correct_End"] = -1 # 重置为原始终止时间 original_event_info["remark"] = "" # 重置备注为None # 检查是否有重叠 - if sum(self.data.event_index_revised[ - max(0, original_event_info["Start"] - 1):min(original_event_info["End"] + 1, - self.config["SignalSecond"])]) != original_event_info[ - "Index"]: + # 检查是否已有事件重叠 + + overlapping_indices = set(self.data.event_index_revised[ + max(0, original_event_info["Start"].values[0] - 1):min( + original_event_info["End"].values[0] + 1, + self.config["SignalSecond"])]) + overlapping_indices.discard(event_index) # 去除自身 + overlapping_indices.discard(0) # 去除空白区域标记 + if len(overlapping_indices) > 0: PublicFunc.msgbox_output(self, "重置事件与已有事件重叠,无法重置!", Constants.MSGBOX_TYPE_WARNING) PublicFunc.text_output(self.ui, "重置事件与已有事件重叠,无法重置!", Constants.TIPS_TYPE_ERROR) return # 更新事件索引映射 - self.data.event_index_revised[original_event_info["Start"]:original_event_info["End"]] = original_event_info[ - "Index"] + # 先去除原始事件索引映射 + self.data.event_index_revised[self.data.event_index_revised == event_index] = 0 + # 再添加新的事件索引映射 + self.data.event_index_revised[original_event_info["Start"].values[0]:original_event_info["End"].values[0]] = event_index # 重置事件信息到df_revised - self.data.df_revised[self.data.df_revised["Index"] == index] = original_event_info + self.data.df_revised[self.data.df_revised["Index"] == event_index] = original_event_info self.data_model_revised.update_all(self.data.df_revised) + # 更新rect + if event_index in self.event_ploy_collection: + if self.event_ploy_collection[event_index] is not None: + self.event_ploy_collection[event_index].remove() + + color = self.color_cycle[self.data.event_type_to_value[original_event_info["Event type"].values[0]]] + self.selected_event_rect = self.ax5.axvspan(original_event_info["Start"].values[0], + original_event_info["End"].values[0], color=color, + alpha=0.4) + self.event_ploy_collection[event_index] = self.selected_event_rect + self.canvas.draw_idle() + def __slot_btn_input__(self): PublicFunc.__disableAllButton__(self, ButtonState) @@ -1786,7 +1821,6 @@ class MainWindow_SA_label(QMainWindow): PublicFunc.text_output(self.ui, f"滚轮移动 {offset} 秒", Constants.TIPS_TYPE_INFO) self.__jump_to__by_time__(self.config["WindowStartSecond"], offset) - def __slot_btn_quick_remark__(self): sender = self.sender() @@ -1899,7 +1933,7 @@ class MainWindow_SA_label(QMainWindow): start = 0 if start < 0 else start plt_.plot(linspace(start, end, (end - start) * plot_freq), self.data.channel[channel][ - start * plot_freq:end * plot_freq], label=channel, + start * plot_freq:end * plot_freq], label=channel, color=self.color_cycle[0]) if label_list is not None: for j in event_code: @@ -1970,7 +2004,6 @@ class CustomNavigationToolbar(NavigationToolbar2QT): self._actions['pan'].setShortcut( QCoreApplication.translate("MainWindow", Params.SA_LABEL_BTN_PAN_MODE_SHORTCUT_KEY)) - def drag_pan(self, event): """Callback for dragging in pan/zoom mode.""" for ax in self._pan_info.axes: