From b4c4e124f808819eb4e95202f9305365eedcc142 Mon Sep 17 00:00:00 2001 From: Yorusora Date: Tue, 6 May 2025 13:40:35 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E7=B2=BE=E7=AE=80=E9=83=A8=E5=88=86?= =?UTF-8?q?=E5=85=AC=E5=85=B1=E4=BB=A3=E7=A0=81=E5=88=B0PublicFunc.py?= =?UTF-8?q?=E4=B8=AD=202=E3=80=81=E5=AE=8C=E6=88=90=E4=BA=86<=E4=BA=BA?= =?UTF-8?q?=E5=B7=A5=E7=BA=A0=E6=AD=A3>=E7=9A=84=E6=89=80=E6=9C=89?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Filters/Preprocessing.py | 8 + func/Module_detect_Jpeak.py | 33 +- func/Module_detect_Rpeak.py | 35 +- func/Module_label_check.py | 734 ++++++++++++++++++++- func/Module_mainwindow.py | 4 +- func/Module_preprocess.py | 31 +- func/utils/ConfigParams.py | 31 +- func/utils/Constants.py | 69 +- func/utils/PublicFunc.py | 13 +- ui/MainWindow/MainWindow_artifact_label.py | 6 + ui/MainWindow/MainWindow_artifact_label.ui | 18 + ui/MainWindow/MainWindow_label_check.py | 23 +- ui/MainWindow/MainWindow_label_check.ui | 31 +- 13 files changed, 858 insertions(+), 178 deletions(-) diff --git a/func/Filters/Preprocessing.py b/func/Filters/Preprocessing.py index 1da8c0e..2e2f255 100644 --- a/func/Filters/Preprocessing.py +++ b/func/Filters/Preprocessing.py @@ -54,3 +54,11 @@ def Butterworth_for_BCG_PreProcess(data, sample_rate, type, low_cut=0.0, high_cu return sosfiltfilt(sos, array(data)) else: # 警告,滤波器类型必须有 raise ValueError("Please choose a type of fliter") + +def data_preprocess_for_label_check(data, n, f1, f2, fs): + + f1 = f1 / (fs / 2.0) + f2 = f2 / (fs / 2.0) + b, a = butter(n, [f1, f2], btype="bandpass") + data = array(filtfilt(b, a, data)) + return data \ No newline at end of file diff --git a/func/Module_detect_Jpeak.py b/func/Module_detect_Jpeak.py index 405523c..5f6db59 100644 --- a/func/Module_detect_Jpeak.py +++ b/func/Module_detect_Jpeak.py @@ -290,12 +290,11 @@ class MainWindow_detect_Jpeak(QMainWindow): # 清空模型列表 self.ui.comboBox_model.clear() - PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(1/2)" + Constants.DETECT_JPEAK_LOADING_MODEL)) - self.progressbar.setValue(0) - QApplication.processEvents() + self.data = Data() + self.model = Model() # 寻找模型 - self.model = Model() + PublicFunc.progressbar_update(self, 1, 2, Constants.DETECT_JPEAK_LOADING_MODEL, 0) status, info = self.model.seek_model() if not status: PublicFunc.text_output(self.ui, "(1/2)" + info, Constants.TIPS_TYPE_ERROR) @@ -306,12 +305,8 @@ class MainWindow_detect_Jpeak(QMainWindow): PublicFunc.text_output(self.ui, "(1/2)" + info, Constants.TIPS_TYPE_INFO) self.update_ui_comboBox_model(self.model.model_list) - PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(2/2)" + Constants.INPUTTING_DATA)) - self.progressbar.setValue(10) - QApplication.processEvents() - # 导入数据 - self.data = Data() + PublicFunc.progressbar_update(self, 2, 2, Constants.INPUTTING_DATA, 10) status, info = self.data.open_file() if not status: PublicFunc.text_output(self.ui, "(2/2)" + info, Constants.TIPS_TYPE_ERROR) @@ -328,11 +323,8 @@ class MainWindow_detect_Jpeak(QMainWindow): PublicFunc.__disableAllButton__(self, ButtonState) - PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(1/3)" + Constants.DETECT_JPEAK_PROCESSING_DATA)) - self.progressbar.setValue(0) - QApplication.processEvents() - # 数据预处理 + PublicFunc.progressbar_update(self, 1, 3, Constants.DETECT_JPEAK_PROCESSING_DATA, 0) status, info = self.data.preprocess() if not status: PublicFunc.text_output(self.ui, "(1/3)" + info, Constants.TIPS_TYPE_ERROR) @@ -342,11 +334,8 @@ class MainWindow_detect_Jpeak(QMainWindow): else: PublicFunc.text_output(self.ui, "(1/3)" + info, Constants.TIPS_TYPE_INFO) - PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(2/3)" + Constants.DETECT_JPEAK_PREDICTING_PEAK)) - self.progressbar.setValue(10) - QApplication.processEvents() - # 预测峰值 + PublicFunc.progressbar_update(self, 2, 3, Constants.DETECT_JPEAK_PREDICTING_PEAK, 10) self.model.selected_model = Config["DetectMethod"] status, info = self.data.predict_Jpeak(self.model) if not status: @@ -364,11 +353,8 @@ class MainWindow_detect_Jpeak(QMainWindow): PublicFunc.text_output(self.ui, Constants.DETECT_JPEAK_PEAK_AMOUNT + str(len(self.data.peak)), Constants.TIPS_TYPE_INFO) - PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(3/3)" + Constants.DRAWING_DATA)) - self.progressbar.setValue(70) - QApplication.processEvents() - # 绘图 + PublicFunc.progressbar_update(self, 3, 3, Constants.DRAWING_DATA, 70) status, info = self.__plot__() if not status: PublicFunc.text_output(self.ui, "(3/3)" + info, Constants.TIPS_TYPE_ERROR) @@ -390,11 +376,8 @@ class MainWindow_detect_Jpeak(QMainWindow): if reply == QMessageBox.Yes: PublicFunc.__disableAllButton__(self, ButtonState) - PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(1/1)" + Constants.SAVING_DATA)) - self.progressbar.setValue(0) - QApplication.processEvents() - # 保存 + PublicFunc.progressbar_update(self, 1, 1, Constants.SAVING_DATA, 0) # status, info = self.data.save() total_rows = len(DataFrame(self.data.peak.reshape(-1))) chunk_size = ConfigParams.DETECT_JPEAK_SAVE_CHUNK_SIZE diff --git a/func/Module_detect_Rpeak.py b/func/Module_detect_Rpeak.py index 772159e..8071279 100644 --- a/func/Module_detect_Rpeak.py +++ b/func/Module_detect_Rpeak.py @@ -273,11 +273,12 @@ class MainWindow_detect_Rpeak(QMainWindow): PublicFunc.__disableAllButton__(self, ButtonState) # 清空画框 - if self.line_data and self.point_peak and self.line_interval: + if self.line_data and self.point_peak and self.line_interval and self.point_RRIV: try: self.line_data.remove() self.point_peak.remove() self.line_interval.remove() + self.point_RRIV.remove() except ValueError: pass self.canvas.draw() @@ -285,11 +286,11 @@ class MainWindow_detect_Rpeak(QMainWindow): # 清空方法列表 self.ui.comboBox_method.clear() - PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(1/2)" + Constants.DETECT_RPEAK_LOADING_METHOD)) - self.progressbar.setValue(0) - QApplication.processEvents() + self.data = Data() # 寻找方法 + PublicFunc.progressbar_update(self, 1, 2, Constants.DETECT_RPEAK_LOADING_METHOD, 0) + # TODO:获取检测方法的解耦 method_list = get_method() if len(method_list) == 0 or method_list is None: status = False @@ -306,12 +307,8 @@ class MainWindow_detect_Rpeak(QMainWindow): PublicFunc.text_output(self.ui, "(1/2)" + info, Constants.TIPS_TYPE_INFO) self.update_ui_comboBox_method(method_list) - PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(2/2)" + Constants.INPUTTING_DATA)) - self.progressbar.setValue(10) - QApplication.processEvents() - # 导入数据 - self.data = Data() + PublicFunc.progressbar_update(self, 2, 2, Constants.INPUTTING_DATA, 10) status, info = self.data.open_file() if not status: PublicFunc.text_output(self.ui, "(2/2)" + info, Constants.TIPS_TYPE_ERROR) @@ -328,11 +325,8 @@ class MainWindow_detect_Rpeak(QMainWindow): PublicFunc.__disableAllButton__(self, ButtonState) - PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(1/3)" + Constants.DETECT_RPEAK_PROCESSING_DATA)) - self.progressbar.setValue(0) - QApplication.processEvents() - # 数据预处理 + PublicFunc.progressbar_update(self, 1, 3, Constants.DETECT_RPEAK_PROCESSING_DATA, 0) status, info = self.data.preprocess() if not status: PublicFunc.text_output(self.ui, "(1/3)" + info, Constants.TIPS_TYPE_ERROR) @@ -342,11 +336,8 @@ class MainWindow_detect_Rpeak(QMainWindow): else: PublicFunc.text_output(self.ui, "(1/3)" + info, Constants.TIPS_TYPE_INFO) - PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(2/3)" + Constants.DETECT_RPEAK_PREDICTING_PEAK)) - self.progressbar.setValue(10) - QApplication.processEvents() - # 预测峰值 + PublicFunc.progressbar_update(self, 2, 3, Constants.DETECT_RPEAK_PREDICTING_PEAK, 10) status, info = self.data.predict_Rpeak() if not status: PublicFunc.text_output(self.ui, "(2/3)" + info, Constants.TIPS_TYPE_ERROR) @@ -363,11 +354,8 @@ class MainWindow_detect_Rpeak(QMainWindow): PublicFunc.text_output(self.ui, Constants.DETECT_RPEAK_PEAK_AMOUNT + str(len(self.data.peak)), Constants.TIPS_TYPE_INFO) - PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(3/3)" + Constants.DRAWING_DATA)) - self.progressbar.setValue(70) - QApplication.processEvents() - # 绘图 + PublicFunc.progressbar_update(self, 3, 3, Constants.DRAWING_DATA, 70) status, info = self.__plot__() if not status: PublicFunc.text_output(self.ui, "(3/3)" + info, Constants.TIPS_TYPE_ERROR) @@ -389,11 +377,8 @@ class MainWindow_detect_Rpeak(QMainWindow): if reply == QMessageBox.Yes: PublicFunc.__disableAllButton__(self, ButtonState) - PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(1/1)" + Constants.SAVING_DATA)) - self.progressbar.setValue(0) - QApplication.processEvents() - # 保存 + PublicFunc.progressbar_update(self, 1, 1, Constants.SAVING_DATA, 0) # status, info = self.data.save() total_rows = len(DataFrame(self.data.peak.reshape(-1))) chunk_size = ConfigParams.DETECT_RPEAK_SAVE_CHUNK_SIZE diff --git a/func/Module_label_check.py b/func/Module_label_check.py index 50b9047..d62c66d 100644 --- a/func/Module_label_check.py +++ b/func/Module_label_check.py @@ -2,17 +2,21 @@ from gc import collect from pathlib import Path import matplotlib.pyplot as plt -from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication -from matplotlib import gridspec +from PySide6.QtCore import QTimer, QCoreApplication +from PySide6.QtGui import QAction, QFont +from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication, QTableWidgetItem, QTableWidget +from matplotlib import gridspec, patches from matplotlib.backends.backend_qt import NavigationToolbar2QT from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg +from numpy import append, delete, arange from overrides import overrides from pandas import read_csv, DataFrame -from scipy.signal import resample +from scipy.signal import find_peaks from yaml import dump, load, FullLoader from func.utils.PublicFunc import PublicFunc from func.utils.Constants import Constants, ConfigParams +from func.Filters.Preprocessing import data_preprocess_for_label_check from ui.MainWindow.MainWindow_label_check import Ui_MainWindow_label_check from ui.setting.label_check_input_setting import Ui_MainWindow_label_check_input_setting @@ -109,7 +113,7 @@ class SettingWindow(QMainWindow): "Mode": self.mode }) else: - raise ValueError + raise ValueError("模式不存在") # 数据回显 self.ui.spinBox_input_freq_signal.setValue(Config["InputConfig"]["Freq"]) @@ -125,7 +129,7 @@ class SettingWindow(QMainWindow): self.ui.doubleSpinBox_bandPassLow.setValue(Config["Filter"]["ECGBandPassLow"]) self.ui.doubleSpinBox_bandPassHigh.setValue(Config["Filter"]["ECGBandPassHigh"]) else: - raise ValueError + raise ValueError("模式不存在") def __write_config__(self): @@ -143,7 +147,7 @@ class SettingWindow(QMainWindow): Config["Filter"]["ECGBandPassLow"] = self.ui.doubleSpinBox_bandPassLow.value() Config["Filter"]["ECGBandPassHigh"] = self.ui.doubleSpinBox_bandPassHigh.value() else: - raise ValueError + raise ValueError("模式不存在") # 保存配置到文件 self.config["InputConfig"]["Freq"] = self.ui.spinBox_input_freq_signal.value() @@ -176,7 +180,7 @@ class SettingWindow(QMainWindow): str(self.ui.spinBox_input_freq_signal.value()) + ConfigParams.ENDSWITH_TXT)))) else: - raise ValueError + raise ValueError("模式不存在") class MainWindow_label_check(QMainWindow): @@ -192,8 +196,6 @@ class MainWindow_label_check(QMainWindow): self.sampID = None self.data = None - self.original_peak = None - self.corrected_peak = None self.setting = None @@ -208,11 +210,28 @@ class MainWindow_label_check(QMainWindow): self.gs = None self.ax0 = None self.ax1 = None + self.is_left_button_pressed = None + self.is_right_button_pressed = None self.line_processed_data_1 = None self.line_processed_data_2 = None self.point_peak_original = None self.point_peak_corrected = None + self.annotation_tableWidget = None + + # 初始化自动播放定时器 + self.autoplay_xlim_start = None + self.autoplay_xlim_end = None + self.timer_autoplay = QTimer() + self.timer_autoplay.timeout.connect(self.autoplay_move_xlim) + Config.update({ + "AutoplayArgs": { + "AutoplayMode": "pause", + "MoveLength": int(self.ui.label_moveLength_preset_1.text()), + "MaxRange": int(self.ui.label_maxRange_preset_1.text()), + "MoveSpeed": int(self.ui.label_moveSpeed_preset_1.text()) + } + }) self.msgBox = QMessageBox() self.msgBox.setWindowTitle(Constants.MAINWINDOW_MSGBOX_TITLE) @@ -230,10 +249,14 @@ class MainWindow_label_check(QMainWindow): # 初始化画框 self.fig = plt.figure(figsize=(12, 9), dpi=100) self.canvas = FigureCanvasQTAgg(self.fig) - self.figToolbar = NavigationToolbar2QT(self.canvas) + self.figToolbar = CustomNavigationToolbar(self.canvas, self) + for action in self.figToolbar._actions.values(): + action.setEnabled(False) for action in self.figToolbar.actions(): if action.text() == "Subplots" or action.text() == "Customize": self.figToolbar.removeAction(action) + self.figToolbar._actions['home'].triggered.connect(self.toggle_home) + self.figToolbar.action_Label_Multiple.triggered.connect(self.toggle_changeLabel) self.ui.verticalLayout_canvas.addWidget(self.canvas) self.ui.verticalLayout_canvas.addWidget(self.figToolbar) self.gs = gridspec.GridSpec(2, 1, height_ratios=[1, 1]) @@ -242,17 +265,42 @@ class MainWindow_label_check(QMainWindow): self.ax0.grid(True) self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) self.ax0.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) - self.ax1 = self.fig.add_subplot(self.gs[1]) + self.ax1 = self.fig.add_subplot(self.gs[1], sharex=self.ax0, sharey=self.ax0) self.ax1.grid(True) self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) PublicFunc.__resetAllButton__(self, ButtonState) self.ui.label_mode.setText(self.mode) + self.ui.doubleSpinBox_findpeaks_min_interval.setValue(Config["FindPeaks"]["MinInterval"]) + self.ui.doubleSpinBox_findpeaks_min_height.setValue(Config["FindPeaks"]["MinHeight"]) + self.ui.spinBox_moveLength.setValue(Config["CustomAutoplayArgs"]["MoveLength"]) + self.ui.spinBox_maxRange.setValue(Config["CustomAutoplayArgs"]["MaxRange"]) + self.ui.spinBox_moveSpeed.setValue(Config["CustomAutoplayArgs"]["MoveSpeed"]) - # self.ui.pushButton_input.clicked.connect(self.__slot_btn_input__) + self.ui.tableWidget_peak_original.setHorizontalHeaderLabels(['Original']) + self.ui.tableWidget_peak_corrected.setHorizontalHeaderLabels(['Corrected']) + self.ui.tableWidget_peak_original.setEditTriggers(QTableWidget.NoEditTriggers) + self.ui.tableWidget_peak_corrected.setEditTriggers(QTableWidget.NoEditTriggers) + self.ui.tableWidget_peak_original.horizontalHeader().setStretchLastSection(True) + self.ui.tableWidget_peak_corrected.horizontalHeader().setStretchLastSection(True) + + self.ui.pushButton_input.clicked.connect(self.__slot_btn_input__) self.ui.pushButton_input_setting.clicked.connect(self.setting.show) - # self.ui.pushButton_save.clicked.connect(self.__slot_btn_save__) + self.ui.pushButton_save.clicked.connect(self.__slot_btn_save__) + self.ui.pushButton_prev_move.clicked.connect(self.__slot_btn_move__) + self.ui.pushButton_pause.clicked.connect(self.__slot_btn_move__) + self.ui.pushButton_next_move.clicked.connect(self.__slot_btn_move__) + self.ui.radioButton_move_preset_1.toggled.connect(self.__change_autoplay_args__) + self.ui.radioButton_move_preset_2.toggled.connect(self.__change_autoplay_args__) + self.ui.radioButton_move_preset_3.toggled.connect(self.__change_autoplay_args__) + self.ui.radioButton_move_custom.toggled.connect(self.__change_autoplay_args__) + self.ui.tableWidget_peak_original.cellDoubleClicked.connect( + self.__slot_tableWidget_on_cell_double_clicked__) + self.ui.tableWidget_peak_corrected.cellDoubleClicked.connect( + self.__slot_tableWidget_on_cell_double_clicked__) + + self.ui.doubleSpinBox_findpeaks_min_interval.editingFinished.connect(self.__update_config__) self.ui.doubleSpinBox_findpeaks_min_height.editingFinished.connect(self.__update_config__) self.ui.spinBox_moveLength.editingFinished.connect(self.__update_config__) @@ -304,18 +352,13 @@ class MainWindow_label_check(QMainWindow): sender = self.sender() if sender == self.ui.pushButton_input: - # self.point_RRIV, = self.ax0.plot(self.data.peak[2:], self.data.RRIV, - # 'r.', - # label=Constants.DETECT_RPEAK_PLOT_LABEL_RRIV) - # self.line_data, = self.ax1.plot(self.data.processed_data, - # color=Constants.PLOT_COLOR_BLUE, - # label=Constants.DETECT_RPEAK_PLOT_LABEL_ECG) - # self.point_peak, = self.ax1.plot(self.data.peak, self.data.processed_data[self.data.peak], - # 'r*', - # label=Constants.DETECT_RPEAK_PLOT_LABEL_R_PEAKS) - # self.line_interval, = self.ax1.plot(self.data.interval, - # color=Constants.PLOT_COLOR_GREEN, - # label=Constants.DETECT_RPEAK_PLOT_LABEL_INTERVAL) + self.ui.spinBox_data_length.setValue(len(self.data.processed_data)) + self.line_processed_data_1, = self.ax0.plot(self.data.processed_data, + label=Constants.LABEL_CHECK_PLOT_LABEL_SIGNAL, + color=Constants.PLOT_COLOR_BLUE) + self.line_processed_data_2, = self.ax1.plot(self.data.processed_data, + label=Constants.LABEL_CHECK_PLOT_LABEL_SIGNAL, + color=Constants.PLOT_COLOR_BLUE) self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT) status = True @@ -325,6 +368,54 @@ class MainWindow_label_check(QMainWindow): info = Constants.DRAWING_FAILURE self.canvas.draw() + self.ax0.autoscale(False) + self.ax1.autoscale(False) + return status, info + + def __plot_peaks__(self): + + try: + self.point_peak_original, = self.ax0.plot(self.data.original_peak, self.data.original_peak_y, 'ro', + label=Constants.LABEL_CHECK_PLOT_LABEL_PEAK_ORIGINAL) + self.point_peak_corrected, = self.ax1.plot(self.data.corrected_peak, self.data.corrected_peak_y, 'ro', + label=Constants.LABEL_CHECK_PLOT_LABEL_PEAK_CORRECTED) + self.ax1.callbacks.connect('xlim_changed', lambda ax: self.on_xlim_change(ax)) + self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) + self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT) + except Exception as e: + return False, Constants.DRAWING_FAILURE + + self.canvas.draw() + return True, Constants.DRAWING_FINISHED + + def __redraw_peaks__(self): + + self.point_peak_corrected.remove() + self.point_peak_corrected, = self.ax1.plot(self.data.corrected_peak, self.data.corrected_peak_y, 'ro', + label=Constants.LABEL_CHECK_PLOT_LABEL_PEAK_CORRECTED) + self.canvas.draw() + + def __update_tableWidget_and_info__(self): + + if self.data.original_peak is None or self.data.corrected_peak is None: + return False, Constants.LABEL_CHECK_FAILURE_REASON["Peak_Not_Exist"] + + try: + self.ui.tableWidget_peak_original.setRowCount(len(self.data.original_peak)) + self.ui.spinBox_peak_length_original.setValue(len(self.data.original_peak)) + for row, value in enumerate(self.data.original_peak): + item = QTableWidgetItem(str(value).strip()) + self.ui.tableWidget_peak_original.setItem(row, 0, item) + self.ui.tableWidget_peak_corrected.setRowCount(len(self.data.corrected_peak)) + self.ui.spinBox_peak_length_corrected.setValue(len(self.data.corrected_peak)) + for row, value in enumerate(self.data.corrected_peak): + item = QTableWidgetItem(str(value).strip()) + self.ui.tableWidget_peak_corrected.setItem(row, 0, item) + status = True + info = Constants.UPDATING_FINISHED + except Exception: + status = False + info = Constants.UPDATING_FAILURE return status, info def __update_config__(self): @@ -335,6 +426,459 @@ class MainWindow_label_check(QMainWindow): Config["CustomAutoplayArgs"]["MaxRange"] = self.ui.spinBox_maxRange.value() Config["CustomAutoplayArgs"]["MoveSpeed"] = self.ui.spinBox_moveSpeed.value() + def __slot_btn_input__(self): + + PublicFunc.__disableAllButton__(self, ButtonState) + + # 清空画框 + if self.line_processed_data_1 and self.line_processed_data_2 and self.point_peak_original and self.point_peak_corrected: + try: + self.line_processed_data_1.remove() + self.line_processed_data_2.remove() + self.point_peak_original.remove() + self.point_peak_corrected.remove() + except ValueError: + pass + self.canvas.draw() + + self.data = Data() + + # 导入数据 + PublicFunc.progressbar_update(self, 1, 6, Constants.INPUTTING_DATA, 0) + status, info = self.data.open_file() + if not status: + PublicFunc.text_output(self.ui, "(1/6)" + info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(1/6)" + info, Constants.TIPS_TYPE_INFO) + + # 获取存档 + PublicFunc.progressbar_update(self, 2, 6, Constants.LABEL_CHECK_LOADING_ARCHIVE, 20) + status, info = self.data.get_archive() + if not status: + PublicFunc.text_output(self.ui, "(2/6)" + info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(2/6)" + info, Constants.TIPS_TYPE_INFO) + + # 数据预处理 + PublicFunc.progressbar_update(self, 3, 6, Constants.LABEL_CHECK_PROCESSING_DATA, 30) + status, info = self.data.preprocess() + if not status: + PublicFunc.text_output(self.ui, "(3/6)" + info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(3/6)" + info, Constants.TIPS_TYPE_INFO) + + # 更新表格 + PublicFunc.progressbar_update(self, 4, 6, Constants.UPDATING_TABLEWIDGET_AND_INFO, 50) + status, info = self.__update_tableWidget_and_info__() + if not status: + PublicFunc.text_output(self.ui, "(4/6)" + info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(4/6)" + info, Constants.TIPS_TYPE_INFO) + + # 绘图 + PublicFunc.progressbar_update(self, 5, 6, Constants.DRAWING_DATA, 60) + status, info = self.__plot__() + if not status: + PublicFunc.text_output(self.ui, "(5/6)" + info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(5/6)" + info, Constants.TIPS_TYPE_INFO) + + # 绘点 + PublicFunc.progressbar_update(self, 6, 6, Constants.DRAWING_DATA, 80) + status, info = self.__plot_peaks__() + if not status: + PublicFunc.text_output(self.ui, "(6/6)" + info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(6/6)" + info, Constants.TIPS_TYPE_INFO) + + MainWindow_label_check.__reset__() + self.canvas.mpl_connect("motion_notify_event", self.on_motion) + self.figToolbar.action_Label_Multiple.setEnabled(True) + for action in self.figToolbar._actions.values(): + action.setEnabled(True) + ButtonState["Current"]["pushButton_input"] = False + ButtonState["Current"]["pushButton_input_setting"] = False + ButtonState["Current"]["pushButton_prev_move"] = True + ButtonState["Current"]["pushButton_next_move"] = True + ButtonState["Current"]["pushButton_pause"] = True + ButtonState["Current"]["pushButton_save"] = True + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_save__(self): + + reply = QMessageBox.question(self, Constants.QUESTION_TITLE, + Constants.QUESTION_CONTENT + Config["Path"]["Save"], + QMessageBox.Yes | QMessageBox.No, + QMessageBox.Yes) + if reply == QMessageBox.Yes: + PublicFunc.__disableAllButton__(self, ButtonState) + + # 保存 + PublicFunc.progressbar_update(self, 1, 1, Constants.SAVING_DATA, 0) + # status, info = self.data.save() + total_rows = len(DataFrame(self.data.corrected_peak.reshape(-1))) + chunk_size = ConfigParams.LABEL_CHECK_SAVE_CHUNK_SIZE + with open(Config["Path"]["Save"], 'w') as f: + for start in range(0, total_rows, chunk_size): + end = min(start + chunk_size, total_rows) + chunk = DataFrame(self.data.corrected_peak.reshape(-1)).iloc[start:end] + status, info = self.data.save(chunk) + progress = int((end / total_rows) * 100) + self.progressbar.setValue(progress) + QApplication.processEvents() + + if not status: + PublicFunc.text_output(self.ui, "(1/1)" + info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(1/1)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.msgbox_output(self, info, Constants.TIPS_TYPE_INFO) + + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_move__(self): + + if self.data is None: + return + + sender = self.sender() + + if sender == self.ui.pushButton_prev_move: + Config["AutoplayArgs"]["AutoplayMode"] = "prev" + self.autoplay_xlim_start = int(self.ax0.get_xlim()[1] - Config["AutoplayArgs"]["MaxRange"]) + self.autoplay_xlim_end = int(self.ax0.get_xlim()[1]) + if self.autoplay_xlim_end > len(self.data.processed_data): + self.autoplay_xlim_start = int(len(self.data.processed_data) - Config["AutoplayArgs"]["MaxRange"]) + self.autoplay_xlim_end = int(len(self.data.processed_data)) + self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end) + self.canvas.draw() + self.timer_autoplay.start(Config["AutoplayArgs"]["MoveSpeed"]) + PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_PREV_MOVE, Constants.TIPS_TYPE_INFO) + elif sender == self.ui.pushButton_next_move: + Config["AutoplayArgs"]["AutoplayMode"] = "next" + self.autoplay_xlim_start = int(self.ax0.get_xlim()[0]) + self.autoplay_xlim_end = int(self.ax0.get_xlim()[0] + Config["AutoplayArgs"]["MaxRange"]) + if self.autoplay_xlim_start < 0: + self.autoplay_xlim_start = 0 + self.autoplay_xlim_end = 0 + Config["AutoplayArgs"]["MaxRange"] + self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end) + self.canvas.draw() + self.timer_autoplay.start(Config["AutoplayArgs"]["MoveSpeed"]) + PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_NEXT_MOVE, Constants.TIPS_TYPE_INFO) + elif sender == self.ui.pushButton_pause: + Config["AutoplayArgs"]["AutoplayMode"] = "pause" + self.timer_autoplay.stop() + PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_PAUSE, Constants.TIPS_TYPE_INFO) + + def __change_autoplay_args__(self): + + sender = self.sender() + + if sender == self.ui.radioButton_move_preset_1 and self.ui.radioButton_move_preset_1.isChecked(): + Config["AutoplayArgs"]["MoveLength"] = int(self.ui.label_moveLength_preset_1.text()) + Config["AutoplayArgs"]["MaxRange"] = int(self.ui.label_maxRange_preset_1.text()) + Config["AutoplayArgs"]["MoveSpeed"] = int(self.ui.label_moveSpeed_preset_1.text()) + PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_SWITCH_PRESET_1, Constants.TIPS_TYPE_INFO) + elif sender == self.ui.radioButton_move_preset_2 and self.ui.radioButton_move_preset_2.isChecked(): + Config["AutoplayArgs"]["MoveLength"] = int(self.ui.label_moveLength_preset_2.text()) + Config["AutoplayArgs"]["MaxRange"] = int(self.ui.label_maxRange_preset_2.text()) + Config["AutoplayArgs"]["MoveSpeed"] = int(self.ui.label_moveSpeed_preset_2.text()) + PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_SWITCH_PRESET_2, Constants.TIPS_TYPE_INFO) + elif sender == self.ui.radioButton_move_preset_3 and self.ui.radioButton_move_preset_3.isChecked(): + Config["AutoplayArgs"]["MoveLength"] = int(self.ui.label_moveLength_preset_3.text()) + Config["AutoplayArgs"]["MaxRange"] = int(self.ui.label_maxRange_preset_3.text()) + Config["AutoplayArgs"]["MoveSpeed"] = int(self.ui.label_moveSpeed_preset_3.text()) + PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_SWITCH_PRESET_3, Constants.TIPS_TYPE_INFO) + elif sender == self.ui.radioButton_move_custom and self.ui.radioButton_move_custom.isChecked(): + Config["AutoplayArgs"]["MoveLength"] = int(self.ui.spinBox_moveLength.value()) + Config["AutoplayArgs"]["MaxRange"] = int(self.ui.spinBox_maxRange.value()) + Config["AutoplayArgs"]["MoveSpeed"] = int(self.ui.spinBox_moveSpeed.value()) + PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_SWITCH_CUSTOM, Constants.TIPS_TYPE_INFO) + if Config["AutoplayArgs"]["AutoplayMode"] == "next": + self.autoplay_xlim_start = int(self.ax0.get_xlim()[0]) + self.autoplay_xlim_end = int(self.ax0.get_xlim()[0] + Config["AutoplayArgs"]["MaxRange"]) + if self.autoplay_xlim_start < 0: + self.autoplay_xlim_start = 0 + self.autoplay_xlim_end = 0 + Config["AutoplayArgs"]["MaxRange"] + self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end) + self.timer_autoplay.start(Config["AutoplayArgs"]["MoveSpeed"]) + elif Config["AutoplayArgs"]["AutoplayMode"] == "prev": + self.autoplay_xlim_start = int(self.ax0.get_xlim()[1] - Config["AutoplayArgs"]["MaxRange"]) + self.autoplay_xlim_end = int(self.ax0.get_xlim()[1]) + if self.autoplay_xlim_end > len(self.data.processed_data): + self.autoplay_xlim_start = int(self.data.processed_data) - Config["AutoplayArgs"]["MaxRange"] + self.autoplay_xlim_end = int(self.data.processed_data) + self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end) + self.timer_autoplay.start(Config["AutoplayArgs"]["MoveSpeed"]) + elif Config["AutoplayArgs"]["AutoplayMode"] == "pause": + self.timer_autoplay.stop() + + def __slot_tableWidget_on_cell_double_clicked__(self, row, col): + + if Config["AutoplayArgs"]["AutoplayMode"] != "pause": + self.ui.pushButton_pause.click() + + sender = self.sender() + + if sender == self.ui.tableWidget_peak_original: + x = float(self.ui.tableWidget_peak_original.item(row, col).text()) + elif sender == self.ui.tableWidget_peak_corrected: + x = float(self.ui.tableWidget_peak_corrected.item(row, col).text()) + else: + raise ValueError("表格跳转参数不存在") + self.ax0.set_xlim(x - 5000, x + 5000) + self.annotation_tableWidget = self.ax0.annotate(f'x={int(x)}', xy=(int(x), self.ax0.get_ylim()[0]), + xytext=(int(x), self.ax0.get_ylim()[0] + (self.ax0.get_ylim()[1] - self.ax0.get_ylim()[0]) * 0.1), + arrowprops=dict(facecolor=Constants.PLOT_COLOR_BLACK, shrink=0.1)) + self.canvas.draw() + PublicFunc.text_output(self.ui, f"{Constants.LABEL_CHECK_JUMP_X_INDEX}{str(int(x))}", Constants.TIPS_TYPE_INFO) + + def on_xlim_change(self, event_ax): + + try: + if self.annotation_tableWidget: + self.annotation_tableWidget.remove() + except AttributeError: + pass + self.annotation_tableWidget = None + + def autoplay_move_xlim(self): + + if Config["AutoplayArgs"]["AutoplayMode"] == "prev" and self.autoplay_xlim_start < 0: + Config["AutoplayArgs"]["AutoplayMode"] = "pause" + self.timer_autoplay.stop() + elif Config["AutoplayArgs"]["AutoplayMode"] == "next" and self.autoplay_xlim_end > len(self.data.processed_data): + Config["AutoplayArgs"]["AutoplayMode"] = "pause" + self.timer_autoplay.stop() + else: + if Config["AutoplayArgs"]["AutoplayMode"] == "next": + self.autoplay_xlim_start += Config["AutoplayArgs"]["MoveLength"] + self.autoplay_xlim_end += Config["AutoplayArgs"]["MoveLength"] + elif Config["AutoplayArgs"]["AutoplayMode"] == "prev": + self.autoplay_xlim_start -= Config["AutoplayArgs"]["MoveLength"] + self.autoplay_xlim_end -= Config["AutoplayArgs"]["MoveLength"] + self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end) + self.canvas.draw() + + def on_motion(self, event): + + if event.inaxes and self.ui.checkBox_show_reference_line.isChecked(): + # Clear previous reference lines and temporary points + for line in self.ax0.lines[1:]: + if (line.get_label() == "vline" or + line.get_label() == "hline"): + line.remove() + for line in self.ax1.lines[1:]: + if (line.get_label() == "vline" or + line.get_label() == "hline"): + line.remove() + + # Draw vertical and horizontal reference lines + self.ax0.axvline(event.xdata, color=Constants.PLOT_COLOR_GRAY, linestyle='--', label="vline") + self.ax0.axhline(event.ydata, color=Constants.PLOT_COLOR_GRAY, linestyle='--', label="hline") + self.ax1.axvline(event.xdata, color=Constants.PLOT_COLOR_GRAY, linestyle='--', label="vline") + self.ax1.axhline(event.ydata, color=Constants.PLOT_COLOR_GRAY, linestyle='--', label="hline") + + self.canvas.draw() + + def toggle_home(self): + + if Config["AutoplayArgs"]["AutoplayMode"] != "pause": + self.ui.pushButton_pause.click() + self.ax0.autoscale(True) + self.ax1.autoscale(True) + self.ax1.relim() + self.ax1.autoscale_view() + self.canvas.draw() + self.ax0.autoscale(False) + self.ax1.autoscale(False) + PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_RECOVER_SCALE, Constants.TIPS_TYPE_INFO) + + def toggle_changeLabel(self, state): + + if state: + self.deactivate_figToolbar_buttons() + self.figToolbar.action_Label_Multiple.setChecked(True) + self.figToolbar.cid_mouse_press = self.canvas.mpl_connect( + "button_press_event", self.on_click) + self.figToolbar.cid_mouse_release = self.canvas.mpl_connect( + "button_release_event", self.on_release) + self.figToolbar.cid_mouse_hold = self.canvas.mpl_connect( + "motion_notify_event", self.on_hold) + else: + if self.figToolbar.cid_mouse_press is not None: + self.canvas.mpl_disconnect(self.figToolbar.cid_mouse_press) + self.figToolbar.cid_mouse_press = None + if self.figToolbar.cid_mouse_release is not None: + self.canvas.mpl_disconnect(self.figToolbar.cid_mouse_release) + self.figToolbar.cid_mouse_release = None + if self.figToolbar.cid_mouse_hold: + self.canvas.mpl_disconnect(self.figToolbar.cid_mouse_hold) + self.figToolbar.cid_mouse_hold = None + + def deactivate_figToolbar_buttons(self): + + for action in self.figToolbar._actions.values(): + if action.isChecked() == True: + if action == self.figToolbar._actions['pan']: + self.figToolbar.pan() + if action == self.figToolbar._actions['zoom']: + self.figToolbar.zoom() + + def on_click(self, event): + + if self.figToolbar.action_Label_Multiple.isChecked(): + if event.button == 1 or event.button == 3: # 左键或右键 + if event.button == 1: + self.is_left_button_pressed = True + elif event.button == 3: + self.is_right_button_pressed = True + self.figToolbar.rect_start_x = event.xdata + # 如果矩形patch已存在,先移除 + if self.figToolbar.rect_patch_ax0 is not None and self.figToolbar.rect_patch_ax1 is not None: + self.figToolbar.rect_patch_ax0.remove() + self.figToolbar.rect_patch_ax0 = None + self.figToolbar.rect_patch_ax1.remove() + self.figToolbar.rect_patch_ax1 = None + self.canvas.draw() + + def on_release(self, event): + + if self.figToolbar.action_Label_Multiple.isChecked(): + if self.figToolbar.rect_start_x is not None: + self.figToolbar.rect_end_x = event.xdata + if self.figToolbar.rect_start_x is not None and self.figToolbar.rect_end_x is not None: + if self.figToolbar.rect_start_x < self.figToolbar.rect_end_x: + rect_left = self.figToolbar.rect_start_x + rect_right = self.figToolbar.rect_end_x + elif self.figToolbar.rect_start_x > self.figToolbar.rect_end_x: + rect_left = self.figToolbar.rect_end_x + rect_right = self.figToolbar.rect_start_x + else: + rect_left = self.figToolbar.rect_start_x + rect_right = self.figToolbar.rect_start_x + else: + rect_left = self.figToolbar.rect_start_x + rect_right = self.figToolbar.rect_start_x + if event.button == 1 and self.is_left_button_pressed: + self.is_left_button_pressed = False + if rect_left < 0: + rect_left = 0 + elif rect_left >= len(self.data.processed_data): + rect_left = 0 + rect_right = 0 + if rect_right >= len(self.data.processed_data): + rect_right = len(self.data.processed_data) - 1 + elif rect_right < 0: + rect_left = 0 + rect_right = 0 + selected_area_for_add_points = self.data.processed_data[int(rect_left):int(rect_right)] + peaks_idx, _ = find_peaks(selected_area_for_add_points, + height=Config["FindPeaks"]["MinHeight"], + distance=Config["FindPeaks"]["MinInterval"]) + peaks_idx = peaks_idx + int(rect_left) + if len(peaks_idx) != 0: + PublicFunc.text_output(self.ui, f"{Constants.LABEL_CHECK_ADD_POINTS_SUCCESSFULLY}{peaks_idx}", + Constants.TIPS_TYPE_INFO) + else: + PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_NO_POINT_IN_THE_INTERVAL, + Constants.TIPS_TYPE_INFO) + self.data.corrected_peak = append(self.data.corrected_peak, peaks_idx) + self.data.corrected_peak_y = append(self.data.corrected_peak_y, self.data.processed_data[peaks_idx]) + self.__redraw_peaks__() + elif event.button == 3 and self.is_right_button_pressed: + self.is_right_button_pressed = False + left_label2_to_delete = self.data.corrected_peak - rect_left + right_label2_to_delete = self.data.corrected_peak - rect_right + left_label2_to_delete_idx = len(left_label2_to_delete[left_label2_to_delete < 0]) + right_label2_to_delete_idx = len(right_label2_to_delete[right_label2_to_delete < 0]) + if left_label2_to_delete_idx != right_label2_to_delete_idx: + PublicFunc.text_output(self.ui, f"{Constants.LABEL_CHECK_REMOVE_POINTS_SUCCESSFULLY}{self.data.corrected_peak[left_label2_to_delete_idx:right_label2_to_delete_idx]}", + Constants.TIPS_TYPE_INFO) + else: + PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_NO_POINT_IN_THE_INTERVAL, + Constants.TIPS_TYPE_INFO) + self.data.corrected_peak = delete(self.data.corrected_peak, arange(left_label2_to_delete_idx, right_label2_to_delete_idx)) + self.data.corrected_peak_y = delete(self.data.corrected_peak_y, arange(left_label2_to_delete_idx, right_label2_to_delete_idx)) + self.__redraw_peaks__() + self.figToolbar.rect_start_x = None + self.figToolbar.rect_end_x = None + self.data.corrected_peak.sort() + self.data.corrected_peak_y = [self.data.processed_data[x] for x in self.data.corrected_peak] + self.__update_tableWidget_and_info__() + DataFrame(self.data.corrected_peak).to_csv(self.data.file_path_save, + index=False, header=False) + # 移除矩形patch + if self.figToolbar.rect_patch_ax0 is not None and self.figToolbar.rect_patch_ax1 is not None: + self.figToolbar.rect_patch_ax0.remove() + self.figToolbar.rect_patch_ax0 = None + self.figToolbar.rect_patch_ax1.remove() + self.figToolbar.rect_patch_ax1 = None + self.canvas.draw() + + def on_hold(self, event): + + if self.figToolbar.rect_start_x is not None and event.xdata is not None: + self.figToolbar.rect_end_x = event.xdata + + # 如果矩形patch不存在,则创建一个新的 + if self.figToolbar.rect_patch_ax0 is None: + if self.is_left_button_pressed: + self.figToolbar.rect_patch_ax0 = patches.Rectangle((0, 0), 1, 1, fill=True, + alpha=ConfigParams.LABEL_CHECK_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_PINK) + elif self.is_right_button_pressed: + self.figToolbar.rect_patch_ax0 = patches.Rectangle((0, 0), 1, 1, fill=True, + alpha=ConfigParams.LABEL_CHECK_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_RED) + self.ax0.add_patch(self.figToolbar.rect_patch_ax0) + + # 如果矩形patch不存在,则创建一个新的 + if self.figToolbar.rect_patch_ax1 is None: + if self.is_left_button_pressed: + self.figToolbar.rect_patch_ax1 = patches.Rectangle((0, 0), 1, 1, fill=True, + alpha=ConfigParams.LABEL_CHECK_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_PINK) + elif self.is_right_button_pressed: + self.figToolbar.rect_patch_ax1 = patches.Rectangle((0, 0), 1, 1, fill=True, + alpha=ConfigParams.LABEL_CHECK_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_RED) + self.ax1.add_patch(self.figToolbar.rect_patch_ax1) + + # 更新矩形patch的位置和大小 + x_start = self.figToolbar.rect_start_x + x_end = self.figToolbar.rect_end_x + rect_down = min(self.ax0.get_ylim()[0], self.ax1.get_ylim()[0]) - 1000 + rect_up = max(self.ax0.get_ylim()[1], self.ax1.get_ylim()[1]) + 1000 + self.figToolbar.rect_patch_ax0.set_xy((min(x_start, x_end), rect_down)) + self.figToolbar.rect_patch_ax0.set_width(abs(x_end - x_start)) + self.figToolbar.rect_patch_ax0.set_height(rect_up - rect_down) + self.figToolbar.rect_patch_ax1.set_xy((min(x_start, x_end), rect_down)) + self.figToolbar.rect_patch_ax1.set_width(abs(x_end - x_start)) + self.figToolbar.rect_patch_ax1.set_height(rect_up - rect_down) + + self.canvas.draw() + class Data: @@ -345,4 +889,142 @@ class Data: self.raw_data = None self.processed_data = None - self.peak = None \ No newline at end of file + self.original_peak = None + self.original_peak_y = None + self.corrected_peak = None + self.corrected_peak_y = None + + def open_file(self): + + if (not Path(Config["Path"]["Input_Signal"]).exists()) or (not Path(Config["Path"]["Input_Peak"]).exists()): + return False, Constants.INPUT_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Data_Path_Not_Exist"] + + try: + self.raw_data = read_csv(self.file_path_input_signal, + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + self.original_peak = read_csv(self.file_path_input_peak, + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + except Exception: + return False, Constants.INPUT_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Read_Data_Exception"] + + return True, Constants.INPUT_FINISHED + + def get_archive(self): + + if not Path(Config["Path"]["Save"]).exists(): + self.corrected_peak = self.original_peak + return True, Constants.LABEL_CHECK_ARCHIVE_NOT_EXIST + else: + self.corrected_peak = read_csv(self.file_path_save, + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + return True, Constants.LABEL_CHECK_ARCHIVE_EXIST + + def preprocess(self): + + if self.raw_data is None: + return False, Constants.LABEL_CHECK_PROCESS_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Raw_Data_Not_Exist"] + + try: + if Config["Mode"] == "BCG": + self.processed_data = data_preprocess_for_label_check(self.raw_data, + Config["Filter"]["BCGBandPassOrder"], + Config["Filter"]["BCGBandPassLow"], + Config["Filter"]["BCGBandPassHigh"], + Config["InputConfig"]["Freq"]) + elif Config["Mode"] == "ECG": + self.processed_data = data_preprocess_for_label_check(self.raw_data, + Config["Filter"]["ECGBandPassOrder"], + Config["Filter"]["ECGBandPassLow"], + Config["Filter"]["ECGBandPassHigh"], + Config["InputConfig"]["Freq"]) + else: + raise ValueError("模式不存在") + self.original_peak_y = [self.processed_data[x] for x in self.original_peak] + self.corrected_peak_y = [self.processed_data[x] for x in self.corrected_peak] + except Exception: + return False, Constants.LABEL_CHECK_PROCESS_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Filter_Exception"] + + return True, Constants.LABEL_CHECK_PROCESS_FINISHED + + def save(self, chunk): + + if self.corrected_peak is None: + return False, Constants.SAVING_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Peak_Not_Exist"] + + try: + # DataFrame(self.corrected_peak.reshape(-1)).to_csv(self.file_path_save, + # index=False, + # header=False) + chunk.to_csv(self.file_path_save, mode='a', index=False, header=False) + except Exception: + return False, Constants.SAVING_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Save_Exception"] + + return True, Constants.SAVING_FINISHED + + +class CustomNavigationToolbar(NavigationToolbar2QT): + + + def __init__(self, canvas, parent): + super().__init__(canvas, parent) + # 初始化画框工具栏 + self.action_Label_Multiple = QAction(Constants.LABEL_CHECK_ACTION_LABEL_MULTIPLE_NAME, self) + self.action_Label_Multiple.setFont(QFont(ConfigParams.FONT, 14)) + self.action_Label_Multiple.setCheckable(True) + self.action_Label_Multiple.setShortcut(QCoreApplication.translate( + "MainWindow", + ConfigParams.LABEL_CHECK_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY)) + self.insertAction(self._actions['pan'], self.action_Label_Multiple) + + self._actions['pan'].setShortcut(QCoreApplication.translate( + "MainWindow", + ConfigParams.ACTION_PAN_SHORTCUT_KEY)) + self._actions['zoom'].setShortcut(QCoreApplication.translate( + "MainWindow", + ConfigParams.ACTION_ZOOM_SHORTCUT_KEY)) + + # 用于存储事件连接ID + self.cid_mouse_press = None + self.cid_mouse_release = None + self.cid_mouse_hold = None + + # 初始化矩形选择区域 + self.rect_start_x = None + self.rect_end_x = None + self.rect_patch_ax0 = None # 用于绘制矩形的patch + self.rect_patch_ax1 = None # 用于绘制矩形的patch + + + def home(self, *args): + + pass + + + def zoom(self, *args): + + super().zoom(*args) + self.deactivate_figToorbar_changeLabel_mode() + + + def pan(self, *args): + + super().pan(*args) + self.deactivate_figToorbar_changeLabel_mode() + + + def deactivate_figToorbar_changeLabel_mode(self): + + if self.action_Label_Multiple.isChecked(): + self.action_Label_Multiple.setChecked(False) + if self.cid_mouse_press is not None: + self.canvas.mpl_disconnect(self.cid_mouse_press) + self.cid_mouse_press = None + if self.cid_mouse_release is not None: + self.canvas.mpl_disconnect(self.cid_mouse_release) + self.cid_mouse_release = None + if self.cid_mouse_hold is not None: + self.canvas.mpl_disconnect(self.cid_mouse_hold) + self.cid_mouse_hold = None \ No newline at end of file diff --git a/func/Module_mainwindow.py b/func/Module_mainwindow.py index 72ddc6c..a9db44a 100644 --- a/func/Module_mainwindow.py +++ b/func/Module_mainwindow.py @@ -4,12 +4,14 @@ from PySide6.QtWidgets import QMainWindow, QMessageBox, QFileDialog from matplotlib import use from yaml import dump, load, FullLoader + from func.utils.PublicFunc import PublicFunc from ui.MainWindow.MainWindow_menu import Ui_Signal_Label from func.Module_preprocess import MainWindow_preprocess from func.Module_detect_Jpeak import MainWindow_detect_Jpeak from func.Module_detect_Rpeak import MainWindow_detect_Rpeak +from func.Module_label_check import MainWindow_label_check from func.utils.Constants import Constants, ConfigParams @@ -115,7 +117,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): def __slot_btn_label_check__(self): - self.label_check = MainWindow_detect_Rpeak() + self.label_check = MainWindow_label_check() sender = self.sender() root_path = self.ui.plainTextEdit_root_path.toPlainText() diff --git a/func/Module_preprocess.py b/func/Module_preprocess.py index 22bec8c..f04d911 100644 --- a/func/Module_preprocess.py +++ b/func/Module_preprocess.py @@ -100,7 +100,7 @@ class SettingWindow(QMainWindow): "Mode": self.mode }) else: - raise ValueError + raise ValueError("模式不存在") # 数据回显 self.ui.spinBox_input_freq.setValue(Config["InputConfig"]["Freq"]) @@ -162,7 +162,7 @@ class SettingWindow(QMainWindow): str(self.ui.spinBox_output_freq.value()) + ConfigParams.ENDSWITH_TXT)))) else: - raise ValueError + raise ValueError("模式不存在") class MainWindow_preprocess(QMainWindow): @@ -235,7 +235,7 @@ class MainWindow_preprocess(QMainWindow): self.ui.doubleSpinBox_bandPassLow.setValue(Config["Filter"]["ECGBandPassLow"]) self.ui.doubleSpinBox_bandPassHigh.setValue(Config["Filter"]["ECGBandPassHigh"]) else: - raise ValueError + raise ValueError("模式不存在") self.ui.pushButton_input.clicked.connect(self.__slot_btn_input__) self.ui.pushButton_input_setting.clicked.connect(self.setting.show) @@ -314,7 +314,7 @@ class MainWindow_preprocess(QMainWindow): Config["Filter"]["ECGBandPassLow"] = self.ui.doubleSpinBox_bandPassLow.value() Config["Filter"]["ECGBandPassHigh"] = self.ui.doubleSpinBox_bandPassHigh.value() else: - raise ValueError + raise ValueError("模式不存在") def __slot_btn_input__(self): @@ -329,12 +329,10 @@ class MainWindow_preprocess(QMainWindow): pass self.canvas.draw() - PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(1/1)" + Constants.INPUTTING_DATA)) - self.progressbar.setValue(0) - QApplication.processEvents() + self.data = Data() # 导入数据 - self.data = Data() + PublicFunc.progressbar_update(self, 1, 1, Constants.INPUTTING_DATA, 0) status, info = self.data.open_file() if not status: PublicFunc.text_output(self.ui, "(1/1)" + info, Constants.TIPS_TYPE_ERROR) @@ -351,11 +349,8 @@ class MainWindow_preprocess(QMainWindow): PublicFunc.__disableAllButton__(self, ButtonState) - PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(1/2)" + Constants.PREPROCESS_PROCESSING_DATA)) - self.progressbar.setValue(0) - QApplication.processEvents() - # 数据预处理 + PublicFunc.progressbar_update(self, 1, 2, Constants.PREPROCESS_PROCESSING_DATA, 0) status, info = self.data.preprocess() if not status: PublicFunc.text_output(self.ui, "(1/2)" + info, Constants.TIPS_TYPE_ERROR) @@ -365,11 +360,8 @@ class MainWindow_preprocess(QMainWindow): else: PublicFunc.text_output(self.ui, "(1/2)" + info, Constants.TIPS_TYPE_INFO) - PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(2/2)" + Constants.DRAWING_DATA)) - self.progressbar.setValue(50) - QApplication.processEvents() - # 绘图 + PublicFunc.progressbar_update(self, 2, 2, Constants.DRAWING_DATA, 50) status, info = self.__plot__() if not status: PublicFunc.text_output(self.ui, "(2/2)" + info, Constants.TIPS_TYPE_ERROR) @@ -391,11 +383,8 @@ class MainWindow_preprocess(QMainWindow): if reply == QMessageBox.Yes: PublicFunc.__disableAllButton__(self, ButtonState) - PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(1/1)" + Constants.SAVING_DATA)) - self.progressbar.setValue(0) - QApplication.processEvents() - # 保存 + PublicFunc.progressbar_update(self, 1, 1, Constants.SAVING_DATA, 0) # status, info = self.data.save() total_rows = len(DataFrame(self.data.processed_data.reshape(-1))) chunk_size = ConfigParams.PREPROCESS_SAVE_CHUNK_SIZE @@ -467,7 +456,7 @@ class Data: order=Config["Filter"]["ECGBandPassOrder"], sample_rate=Config["OutputConfig"]["Freq"]) else: - raise ValueError + raise ValueError("模式不存在") except Exception: return False, Constants.PREPROCESS_PROCESS_FAILURE + Constants.PREPROCESS_FAILURE_REASON["Filter_Exception"] diff --git a/func/utils/ConfigParams.py b/func/utils/ConfigParams.py index d1c7ead..92bc7bf 100644 --- a/func/utils/ConfigParams.py +++ b/func/utils/ConfigParams.py @@ -124,6 +124,8 @@ class ConfigParams: LABEL_CHECK_INPUT_RPEAK_FILENAME: str = "final_Rpeak" LABEL_CHECK_SAVE_RPEAK_FILENAME: str = "final_Rpeak_corrected" LABEL_CHECK_SAVE_CHUNK_SIZE: int = 100 + LABEL_CHECK_LABEL_TRANSPARENCY: float = 0.2 + LABEL_CHECK_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY: str = "Z" # 体动标注 @@ -156,35 +158,6 @@ class ConfigParams: APPROXIMATELY_ALIGN_BUTTERHIGHPASSFREQ_DEFAULT: float = 0.70 APPROXIMATELY_ALIGN_APPLYFREQ_DEFAULT: float = 5 - # 人工纠正 - LABEL_CHECK_INPUT_BCG_FILENAME: str = "DSbcg_sig_" - LABEL_CHECK_INPUT_JPEAK_FILENAME: str = "JPeak_revise" - LABEL_CHECK_SAVE_JPEAK_FILENAME: str = "JPeak_revise_corrected" - LABEL_CHECK_INPUT_ECG_FILENAME: str = "ECG_filter_" - LABEL_CHECK_INPUT_RPEAK_FILENAME: str = "final_Rpeak" - LABEL_CHECK_SAVE_RPEAK_FILENAME: str = "final_Rpeak_corrected" - - LABEL_CHECK_INPUT_DEFAULT_FS: int = 1000 - - LABEL_CHECK_DATA1_FILTER_ORDER_DEFAULT: int = 2 - LABEL_CHECK_DATA1_BANDPASS_LOW_DEFAULT: int = 2 - LABEL_CHECK_DATA1_BANDPASS_HIGH_DEFAULT: int = 10 - LABEL_CHECK_DATA2_FILTER_ORDER_DEFAULT: int = 2 - LABEL_CHECK_DATA2_BANDPASS_LOW_DEFAULT: int = 2 - LABEL_CHECK_DATA2_BANDPASS_HIGH_DEFAULT: int = 15 - LABEL_CHECK_FINDPEAKS_MIN_INTERVAL_DEFAULT: int = 1000 - LABEL_CHECK_FINDPEAKS_MIN_HEIGHT_DEFAULT: int = 0.5 - LABEL_CHECK_MOVELENGTH_DEFAULT: int = 15000 - LABEL_CHECK_MAXRANGE_DEFAULT: int = 60000 - LABEL_CHECK_MOVESPEED_DEFAULT: int = 1000 - - LABEL_CHECK_FILTER: str = "bandpass" - - LABEL_CHECK_LABEL_TRANSPARENCY: float = 0.2 - - LABEL_CHECK_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY: str = "Z" - - # 体动打标 ARTIFACT_LABEL_INPUT_BCG_FILENAME: str = "BCG_sync_" ARTIFACT_LABEL_INPUT_XINXIAO_FILENAME: str = "orgBcg_sync_" diff --git a/func/utils/Constants.py b/func/utils/Constants.py index 389ce9b..dc67c9c 100644 --- a/func/utils/Constants.py +++ b/func/utils/Constants.py @@ -19,6 +19,10 @@ class Constants: DRAWING_FINISHED: str = "绘制完成" DRAWING_FAILURE: str = "绘制失败" + UPDATING_TABLEWIDGET_AND_INFO: str = "正在更新表格和信息" + UPDATING_FINISHED: str = "更新完成" + UPDATING_FAILURE: str = "更新失败" + SAVING_DATA: str = "正在保存数据" SAVING_FINISHED: str = "保存完成" SAVING_FAILURE: str = "保存失败" @@ -158,22 +162,38 @@ class Constants: LABEL_CHECK_PROCESS_FINISHED: str = "处理完成" LABEL_CHECK_PROCESS_FAILURE: str = "处理失败" + LABEL_CHECK_LOADING_ARCHIVE: str = "正在获取历史存档" + LABEL_CHECK_ARCHIVE_EXIST: str = "找到历史存档,成功读取" + LABEL_CHECK_ARCHIVE_NOT_EXIST: str = "未找到历史存档,创建新存档" + LABEL_CHECK_FAILURE_REASON = { "Data_Path_Not_Exist": "(数据路径不存在)", "Read_Data_Exception": "(读取数据异常)", - "Method_Not_Exist": "(检测方法不存在)", - "Read_Method_Exception": "(读取方法异常)", - "Predict_Exception": "(峰值预测异常)", "Raw_Data_Not_Exist": "(原始数据不存在)", "Filter_Exception": "(滤波器异常)", "Processed_Data_Not_Exist": "(处理后数据不存在)", - "Peak_Not_Exist": "(预测的峰值不存在)", + "Peak_Not_Exist": "(峰值不存在)", "Save_Exception": "(保存异常)" } - LABEL_CHECK_PLOT_LABEL_BCG: str = "Data_Processed" + LABEL_CHECK_PLOT_LABEL_SIGNAL: str = "Data_Processed" LABEL_CHECK_PLOT_LABEL_PEAK_ORIGINAL: str = "Peaks_Original" LABEL_CHECK_PLOT_LABEL_PEAK_CORRECTED: str = "Peaks_Corrected" + LABEL_CHECK_PREV_MOVE: str = "向前移动" + LABEL_CHECK_NEXT_MOVE: str = "向后移动" + LABEL_CHECK_PAUSE: str = "暂停移动" + LABEL_CHECK_SWITCH_PRESET_1: str = "变更为预设1" + LABEL_CHECK_SWITCH_PRESET_2: str = "变更为预设2" + LABEL_CHECK_SWITCH_PRESET_3: str = "变更为预设3" + LABEL_CHECK_SWITCH_CUSTOM: str = "变更为自定义,请注意,自定义的参数未经校验,过大或过小的参数可能导致程序异常" + LABEL_CHECK_JUMP_X_INDEX: str = "跳转到x坐标: " + LABEL_CHECK_RECOVER_SCALE: str = "尺度恢复" + LABEL_CHECK_ADD_POINTS_SUCCESSFULLY: str = "成功新增点,横坐标:" + LABEL_CHECK_REMOVE_POINTS_SUCCESSFULLY: str = "成功删除点,横坐标:" + LABEL_CHECK_NO_POINT_IN_THE_INTERVAL: str = "所选区间内无新增或删除点" + LABEL_CHECK_ACTION_LABEL_MULTIPLE_NAME: str = f"批量更改标签({ConfigParams.LABEL_CHECK_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY})" + + # 体动标注 @@ -198,45 +218,6 @@ class Constants: APPROXIMATELY_ALIGN_RUNNING: str = "开始执行任务<数据粗同步>" APPROXIMATELY_RECORD_NOT_FOUND: str = "没有保存记录" - # 人工纠正 - LABEL_CHECK_FILES_BCG_NOT_FOUND: str = f"无法找到{ConfigParams.LABEL_CHECK_INPUT_BCG_FILENAME}{ConfigParams.ENDSWITH_TXT}或{ConfigParams.LABEL_CHECK_INPUT_JPEAK_FILENAME}{ConfigParams.ENDSWITH_TXT},无法执行" - LABEL_CHECK_FILES_BCG_FOUND: str = f"找到{ConfigParams.LABEL_CHECK_INPUT_BCG_FILENAME}{ConfigParams.ENDSWITH_TXT}和{ConfigParams.LABEL_CHECK_INPUT_JPEAK_FILENAME}{ConfigParams.ENDSWITH_TXT}" - LABEL_CHECK_FILES_ECG_NOT_FOUND: str = f"无法找到{ConfigParams.LABEL_CHECK_INPUT_ECG_FILENAME}{ConfigParams.ENDSWITH_TXT}或{ConfigParams.LABEL_CHECK_INPUT_RPEAK_FILENAME}{ConfigParams.ENDSWITH_TXT},无法执行" - LABEL_CHECK_FILES_ECG_FOUND: str = f"找到{ConfigParams.LABEL_CHECK_INPUT_ECG_FILENAME}{ConfigParams.ENDSWITH_TXT}和{ConfigParams.LABEL_CHECK_INPUT_RPEAK_FILENAME}{ConfigParams.ENDSWITH_TXT}" - LABEL_CHECK_HISTORICAL_SAVE_FOUND: str = f"找到历史存档文件{ConfigParams.LABEL_CHECK_SAVE_JPEAK_FILENAME}{ConfigParams.ENDSWITH_TXT}或{ConfigParams.LABEL_CHECK_SAVE_RPEAK_FILENAME}{ConfigParams.ENDSWITH_TXT},已成功读取" - - LABEL_CHECK_RUNNING: str = "开始执行任务<人工纠正>" - LABEL_CHECK_BCG_MODE: str = "BCG_MODE" - LABEL_CHECK_ECG_MODE: str = "ECG_MODE" - LABEL_CHECK_PLOT_LABEL_DATA1: str = "Data 1" - LABEL_CHECK_PLOT_LABEL_DATA2: str = "Data 2" - LABEL_CHECK_PLOT_LABEL_LABEL1: str = "Label 1" - LABEL_CHECK_PLOT_LABEL_LABEL2: str = "Label 2" - LABEL_CHECK_PLOT_LABEL_VLINE: str = "vline" - LABEL_CHECK_PLOT_LABEL_HLINE: str = "hline" - LABEL_CHECK_AUTOPLAY_LEFT: str = "LEFT" - LABEL_CHECK_AUTOPLAY_PAUSE: str = "PAUSE" - LABEL_CHECK_AUTOPLAY_RIGHT: str = "RIGHT" - LABEL_CHECK_AUTOPLAY_LEFT_INFO: str = "开始自动播放-向左" - LABEL_CHECK_AUTOPLAY_PAUSE_INFO: str = "暂停自动播放" - LABEL_CHECK_AUTOPLAY_RIGHT_INFO: str = "开始自动播放-向右" - LABEL_CHECK_AUTOPLAY_PRESET1_INFO: str = "切换到自动播放-预设1" - LABEL_CHECK_AUTOPLAY_PRESET2_INFO: str = "切换到自动播放-预设2" - LABEL_CHECK_AUTOPLAY_PRESET3_INFO: str = "切换到自动播放-预设3" - LABEL_CHECK_AUTOPLAY_PRESET_CUSTOM_INFO: str = "切换到自动播放-自定义" - LABEL_CHECK_AUTOPLAY_PRESET_CUSTOM_WARNING: str = "自定义的输入参数未做任何检查,请斟酌输入参数,否则可能会导致程序异常" - LABEL_CHECK_JUMP_X_INDEX: str = "跳转到x坐标: " - LABEL_CHECK_RECOVER_SCALE: str = "尺度恢复" - LABEL_CHECK_BUTTON_PRESS_EVENT: str = "button_press_event" - LABEL_CHECK_BUTTON_RELEASE_EVENT: str = "button_release_event" - LABEL_CHECK_MOTION_NOTIFY_EVENT: str = "motion_notify_event" - LABEL_CHECK_ADD_POINTS_SUCCESSFULLY: str = "成功新增点,横坐标:" - LABEL_CHECK_REMOVE_POINTS_SUCCESSFULLY: str = "成功删除点,横坐标:" - LABEL_CHECK_NO_POINT_IN_THE_INTERVAL: str = "所选区间内无新增或删除点" - LABEL_CHECK_CUSTOM_NAVIGATIONTOOLBAR_WIDGET_NAME: str = "MainWindow" - LABEL_CHECK_ACTION_LABEL_MULTIPLE_NAME: str = f"批量更改标签({ConfigParams.LABEL_CHECK_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY})" - - # 体动打标 ARTIFACT_LABEL_FILES_NOT_FOUND: str = f"无法找到{ConfigParams.ARTIFACT_LABEL_INPUT_BCG_FILENAME}{ConfigParams.ENDSWITH_TXT}或{ConfigParams.ARTIFACT_LABEL_INPUT_XINXIAO_FILENAME}{ConfigParams.ENDSWITH_TXT},无法执行<体动标注>" ARTIFACT_LABEL_FILES_FOUND: str = f"找到{ConfigParams.ARTIFACT_LABEL_INPUT_BCG_FILENAME}{ConfigParams.ENDSWITH_TXT}和{ConfigParams.ARTIFACT_LABEL_INPUT_XINXIAO_FILENAME}{ConfigParams.ENDSWITH_TXT}" diff --git a/func/utils/PublicFunc.py b/func/utils/PublicFunc.py index fe23f4c..651ab43 100644 --- a/func/utils/PublicFunc.py +++ b/func/utils/PublicFunc.py @@ -154,4 +154,15 @@ class PublicFunc: mainWindow.progressbar.setValue(100) QApplication.processEvents() - PublicFunc.__enableAllButton__(mainWindow, buttonState) \ No newline at end of file + PublicFunc.__enableAllButton__(mainWindow, buttonState) + + @staticmethod + def progressbar_update(mainWindow, current: int, total: int, msg: str, progressbarState: int): + + if current > total: + raise ValueError("当前进度值大于总进度值") + if progressbarState < 0 or progressbarState > 100: + raise ValueError("进度条值的范围应该在[0, 100]") + PublicFunc.statusbar_show_msg(mainWindow, PublicFunc.format_status_msg(f"({str(current)}/{str(total)}){msg}")) + mainWindow.progressbar.setValue(progressbarState) + QApplication.processEvents() \ No newline at end of file diff --git a/ui/MainWindow/MainWindow_artifact_label.py b/ui/MainWindow/MainWindow_artifact_label.py index 62bdaa6..b2e25ee 100644 --- a/ui/MainWindow/MainWindow_artifact_label.py +++ b/ui/MainWindow/MainWindow_artifact_label.py @@ -250,6 +250,8 @@ class Ui_MainWindow_artifact_label(object): self.spinBox_moveLength.setObjectName(u"spinBox_moveLength") self.spinBox_moveLength.setFont(font1) self.spinBox_moveLength.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_moveLength.setMinimum(1000) + self.spinBox_moveLength.setMaximum(100000) self.gridLayout_3.addWidget(self.spinBox_moveLength, 4, 1, 1, 1) @@ -290,6 +292,8 @@ class Ui_MainWindow_artifact_label(object): self.spinBox_maxRange.setObjectName(u"spinBox_maxRange") self.spinBox_maxRange.setFont(font1) self.spinBox_maxRange.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_maxRange.setMinimum(1000) + self.spinBox_maxRange.setMaximum(100000) self.gridLayout_3.addWidget(self.spinBox_maxRange, 4, 2, 1, 1) @@ -304,6 +308,8 @@ class Ui_MainWindow_artifact_label(object): self.spinBox_moveSpeed.setObjectName(u"spinBox_moveSpeed") self.spinBox_moveSpeed.setFont(font1) self.spinBox_moveSpeed.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_moveSpeed.setMinimum(100) + self.spinBox_moveSpeed.setMaximum(10000) self.gridLayout_3.addWidget(self.spinBox_moveSpeed, 4, 3, 1, 1) diff --git a/ui/MainWindow/MainWindow_artifact_label.ui b/ui/MainWindow/MainWindow_artifact_label.ui index b978175..9814a36 100644 --- a/ui/MainWindow/MainWindow_artifact_label.ui +++ b/ui/MainWindow/MainWindow_artifact_label.ui @@ -422,6 +422,12 @@ QAbstractSpinBox::ButtonSymbols::NoButtons + + 1000 + + + 100000 + @@ -503,6 +509,12 @@ QAbstractSpinBox::ButtonSymbols::NoButtons + + 1000 + + + 100000 + @@ -530,6 +542,12 @@ QAbstractSpinBox::ButtonSymbols::NoButtons + + 100 + + + 10000 + diff --git a/ui/MainWindow/MainWindow_label_check.py b/ui/MainWindow/MainWindow_label_check.py index 1a51486..a55d8e8 100644 --- a/ui/MainWindow/MainWindow_label_check.py +++ b/ui/MainWindow/MainWindow_label_check.py @@ -209,6 +209,8 @@ class Ui_MainWindow_label_check(object): self.spinBox_moveLength.setObjectName(u"spinBox_moveLength") self.spinBox_moveLength.setFont(font1) self.spinBox_moveLength.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_moveLength.setMinimum(1000) + self.spinBox_moveLength.setMaximum(100000) self.gridLayout_3.addWidget(self.spinBox_moveLength, 4, 1, 1, 1) @@ -249,6 +251,8 @@ class Ui_MainWindow_label_check(object): self.spinBox_maxRange.setObjectName(u"spinBox_maxRange") self.spinBox_maxRange.setFont(font1) self.spinBox_maxRange.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_maxRange.setMinimum(1000) + self.spinBox_maxRange.setMaximum(100000) self.gridLayout_3.addWidget(self.spinBox_maxRange, 4, 2, 1, 1) @@ -263,6 +267,9 @@ class Ui_MainWindow_label_check(object): self.spinBox_moveSpeed.setObjectName(u"spinBox_moveSpeed") self.spinBox_moveSpeed.setFont(font1) self.spinBox_moveSpeed.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_moveSpeed.setMinimum(100) + self.spinBox_moveSpeed.setMaximum(10000) + self.spinBox_moveSpeed.setValue(100) self.gridLayout_3.addWidget(self.spinBox_moveSpeed, 4, 3, 1, 1) @@ -344,11 +351,11 @@ class Ui_MainWindow_label_check(object): self.horizontalLayout_3 = QHBoxLayout() self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") - self.checkBox = QCheckBox(self.groupBox_left) - self.checkBox.setObjectName(u"checkBox") - self.checkBox.setFont(font1) + self.checkBox_show_reference_line = QCheckBox(self.groupBox_left) + self.checkBox_show_reference_line.setObjectName(u"checkBox_show_reference_line") + self.checkBox_show_reference_line.setFont(font1) - self.horizontalLayout_3.addWidget(self.checkBox) + self.horizontalLayout_3.addWidget(self.checkBox_show_reference_line) self.pushButton_save = QPushButton(self.groupBox_left) self.pushButton_save.setObjectName(u"pushButton_save") @@ -440,14 +447,20 @@ class Ui_MainWindow_label_check(object): self.gridLayout_4.addWidget(self.spinBox_peak_length_corrected, 3, 1, 1, 1) self.tableWidget_peak_original = QTableWidget(self.groupBox_right) + if (self.tableWidget_peak_original.columnCount() < 1): + self.tableWidget_peak_original.setColumnCount(1) self.tableWidget_peak_original.setObjectName(u"tableWidget_peak_original") self.tableWidget_peak_original.setFont(font1) + self.tableWidget_peak_original.setColumnCount(1) self.gridLayout_4.addWidget(self.tableWidget_peak_original, 4, 0, 1, 1) self.tableWidget_peak_corrected = QTableWidget(self.groupBox_right) + if (self.tableWidget_peak_corrected.columnCount() < 1): + self.tableWidget_peak_corrected.setColumnCount(1) self.tableWidget_peak_corrected.setObjectName(u"tableWidget_peak_corrected") self.tableWidget_peak_corrected.setFont(font1) + self.tableWidget_peak_corrected.setColumnCount(1) self.gridLayout_4.addWidget(self.tableWidget_peak_corrected, 4, 1, 1, 1) @@ -507,7 +520,7 @@ class Ui_MainWindow_label_check(object): self.label_7.setText(QCoreApplication.translate("MainWindow_label_check", u"\u79fb\u52a8\u8ddd\u79bb", None)) self.label_6.setText(QCoreApplication.translate("MainWindow_label_check", u"\u6700\u5927\u8303\u56f4", None)) self.label_8.setText(QCoreApplication.translate("MainWindow_label_check", u"\u79fb\u52a8\u95f4\u9694(ms)", None)) - self.checkBox.setText(QCoreApplication.translate("MainWindow_label_check", u"\u7ed8\u5236\u53c2\u8003\u7ebf", None)) + self.checkBox_show_reference_line.setText(QCoreApplication.translate("MainWindow_label_check", u"\u7ed8\u5236\u53c2\u8003\u7ebf", None)) self.pushButton_save.setText(QCoreApplication.translate("MainWindow_label_check", u"\u5bfc\u51fa\u6807\u7b7e", None)) self.groupBox_4.setTitle(QCoreApplication.translate("MainWindow_label_check", u"\u65e5\u5fd7", None)) self.groupBox_right.setTitle(QCoreApplication.translate("MainWindow_label_check", u"\u5cf0\u503c\u5750\u6807\u548c\u4fe1\u606f", None)) diff --git a/ui/MainWindow/MainWindow_label_check.ui b/ui/MainWindow/MainWindow_label_check.ui index b96017d..3f1bba6 100644 --- a/ui/MainWindow/MainWindow_label_check.ui +++ b/ui/MainWindow/MainWindow_label_check.ui @@ -348,6 +348,12 @@ QAbstractSpinBox::ButtonSymbols::NoButtons + + 1000 + + + 100000 + @@ -429,6 +435,12 @@ QAbstractSpinBox::ButtonSymbols::NoButtons + + 1000 + + + 100000 + @@ -456,6 +468,15 @@ QAbstractSpinBox::ButtonSymbols::NoButtons + + 100 + + + 10000 + + + 100 + @@ -587,7 +608,7 @@ - + 12 @@ -756,6 +777,10 @@ 12 + + 1 + + @@ -765,6 +790,10 @@ 12 + + 1 + +