diff --git a/func/Module_label_check.py b/func/Module_label_check.py index 962c031..0a7cbf2 100644 --- a/func/Module_label_check.py +++ b/func/Module_label_check.py @@ -9,7 +9,7 @@ from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication, QTableWidg 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 numpy import append, delete, arange, setdiff1d from overrides import overrides from pandas import read_csv, DataFrame from scipy.signal import find_peaks @@ -818,6 +818,7 @@ class MainWindow_label_check(QMainWindow): height=Config["FindPeaks"]["MinHeight"], distance=Config["FindPeaks"]["MinInterval"]) peaks_idx = peaks_idx + int(rect_left) + peaks_idx = setdiff1d(peaks_idx, self.data.corrected_peak) if len(peaks_idx) != 0: PublicFunc.text_output(self.ui, f"{Constants.LABEL_CHECK_ADD_POINTS_SUCCESSFULLY}{peaks_idx}", Constants.TIPS_TYPE_INFO) diff --git a/func/Module_resp_quality_label.py b/func/Module_resp_quality_label.py new file mode 100644 index 0000000..38d21b7 --- /dev/null +++ b/func/Module_resp_quality_label.py @@ -0,0 +1,1552 @@ +from gc import collect +from pathlib import Path +from traceback import format_exc + +import matplotlib.pyplot as plt +from PySide6.QtCore import QCoreApplication +from PySide6.QtGui import QAction, QFont +from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication, QTableWidget, QTableWidgetItem +from matplotlib import gridspec, patches +from matplotlib.backends.backend_qt import NavigationToolbar2QT +from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg +from numpy import array, full, int64, append, zeros, where, arange, float64, nan, place, delete, setdiff1d +from overrides import overrides +from pandas import read_csv, DataFrame +from scipy.signal import find_peaks, resample +from yaml import dump, load, FullLoader + +from func.utils.PublicFunc import PublicFunc +from func.utils.Constants import Constants, ConfigParams +from func.Filters.Preprocessing import Butterworth_for_BCG_PreProcess, Butterworth_for_ECG_PreProcess +from func.utils.Result import Result +from func.utils.resp_quality_label import pre_process, get_slice, evaluate_quality +from func.utils.resp_quality_label_filter import get_bandpass_bcgsignal + +from ui.MainWindow.MainWindow_resp_quality_label import Ui_MainWindow_resp_quality_label +from ui.setting.resp_quality_label_input_setting import Ui_MainWindow_resp_quality_label_input_setting + + +Config = { + +} + +ButtonState = { + "Default": { + "pushButton_input_setting": True, + "pushButton_input_and_calculate_peaks": True, + "pushButton_calculate_peaks": False, + "pushButton_calculate_peaks_save": False, + "pushButton_input_data_and_label": True, + "pushButton_autoqualitylabel_recalculate": False, + "pushButton_refilter_orgBcg": False, + "pushButton_valid": False, + "pushButton_invalid": False, + "pushButton_reset": False, + "pushButton_prev": False, + "pushButton_next": False, + "pushButton_save": False + }, + "Current": { + "pushButton_input_setting": True, + "pushButton_input_and_calculate_peaks": True, + "pushButton_calculate_peaks": False, + "pushButton_calculate_peaks_save": False, + "pushButton_input_data_and_label": True, + "pushButton_autoqualitylabel_recalculate": False, + "pushButton_refilter_orgBcg": False, + "pushButton_valid": False, + "pushButton_invalid": False, + "pushButton_reset": False, + "pushButton_prev": False, + "pushButton_next": False, + "pushButton_save": False + } +} + + +class SettingWindow(QMainWindow): + + def __init__(self, root_path, sampID): + super(SettingWindow, self).__init__() + self.ui = Ui_MainWindow_resp_quality_label_input_setting() + self.ui.setupUi(self) + + self.root_path = root_path + self.sampID = sampID + + self.config = None + self.__read_config__() + + self.ui.spinBox_input_freq_signal_OrgBCG.valueChanged.connect(self.__update_ui__) + self.ui.spinBox_input_freq_signal_Tho.valueChanged.connect(self.__update_ui__) + self.ui.pushButton_confirm.clicked.connect(self.__write_config__) + self.ui.pushButton_cancel.clicked.connect(self.__rollback_config__) + self.ui.pushButton_cancel.clicked.connect(self.close) + + def __read_config__(self): + if not Path(ConfigParams.RESP_QUALITY_LABEL_CONFIG_FILE_PATH).exists(): + with open(ConfigParams.RESP_QUALITY_LABEL_CONFIG_FILE_PATH, "w") as f: + dump(ConfigParams.RESP_QUALITY_LABEL_CONFIG_NEW_CONTENT, f) + + with open(ConfigParams.RESP_QUALITY_LABEL_CONFIG_FILE_PATH, "r") as f: + file_config = load(f.read(), Loader=FullLoader) + Config.update(file_config) + self.config = file_config + + Config.update({ + "Path": { + "Input_OrgBCG": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + Path(str(self.sampID)))), + "Input_Tho": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + Path(str(self.sampID)))), + "Input_Artifact": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + Path(str(self.sampID)))), + "Save_Resp_quality_label": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + Path(str(self.sampID)))), + "Save_Tho_peak": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + Path(str(self.sampID)))) + }, + "CurrentPartNum": 1, + "DataPartNum": 0, + "CurrentOrgBCGIndex": 0, + "CurrentThoIndex": 0 + }) + + # 数据回显 + self.ui.spinBox_input_freq_signal_OrgBCG.setValue(Config["InputConfig"]["OrgBCGFreq"]) + self.ui.spinBox_input_freq_signal_Tho.setValue(Config["InputConfig"]["ThoFreq"]) + self.ui.plainTextEdit_file_path_input_signal_OrgBCG.setPlainText(Config["Path"]["Input_OrgBCG"]) + self.ui.plainTextEdit_file_path_input_signal_Tho.setPlainText(Config["Path"]["Input_Tho"]) + self.ui.plainTextEdit_file_path_input_artifact.setPlainText(Config["Path"]["Input_Artifact"]) + self.ui.plainTextEdit_file_path_save_Resp_quality_label.setPlainText(Config["Path"]["Save_Resp_quality_label"]) + self.ui.plainTextEdit_file_path_save_Tho_peak.setPlainText(Config["Path"]["Save_Tho_peak"]) + + def __write_config__(self): + # 从界面写入配置 + Config["InputConfig"]["OrgBCGFreq"] = self.ui.spinBox_input_freq_signal_OrgBCG.value() + Config["InputConfig"]["ThoFreq"] = self.ui.spinBox_input_freq_signal_Tho.value() + Config["Path"]["Input_OrgBCG"] = self.ui.plainTextEdit_file_path_input_signal_OrgBCG.toPlainText() + Config["Path"]["Input_Tho"] = self.ui.plainTextEdit_file_path_input_signal_Tho.toPlainText() + Config["Path"]["Input_Artifact"] = self.ui.plainTextEdit_file_path_input_artifact.toPlainText() + Config["Path"]["Save_Resp_quality_label"] = self.ui.plainTextEdit_file_path_save_Resp_quality_label.toPlainText() + Config["Path"]["Save_Tho_peak"] = self.ui.plainTextEdit_file_path_save_Tho_peak.toPlainText() + + # 保存配置到文件 + self.config["InputConfig"]["OrgBCGFreq"] = self.ui.spinBox_input_freq_signal_OrgBCG.value() + self.config["InputConfig"]["ThoFreq"] = self.ui.spinBox_input_freq_signal_Tho.value() + + with open(ConfigParams.RESP_QUALITY_LABEL_CONFIG_FILE_PATH, "w") as f: + dump(self.config, f) + + self.close() + + def __rollback_config__(self): + self.__read_config__() + + def __update_ui__(self): + self.ui.plainTextEdit_file_path_input_signal_OrgBCG.setPlainText( + str((Path(self.root_path) / + ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + Path(str(self.sampID)) / + Path(ConfigParams.ORGBCG_SYNC + + str(self.ui.spinBox_input_freq_signal_OrgBCG.value()) + + ConfigParams.ENDSWITH_TXT)))) + self.ui.plainTextEdit_file_path_input_signal_Tho.setPlainText( + str((Path(self.root_path) / + ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + Path(str(self.sampID)) / + Path(ConfigParams.THO_SYNC + + str(self.ui.spinBox_input_freq_signal_Tho.value()) + + ConfigParams.ENDSWITH_TXT)))) + + +class MainWindow_resp_quality_label(QMainWindow): + + def __init__(self): + super(MainWindow_resp_quality_label, self).__init__() + self.ui = Ui_MainWindow_resp_quality_label() + self.ui.setupUi(self) + + self.mode = None + self.root_path = None + self.sampID = None + + self.data = None + + self.setting = None + + # 初始化进度条 + self.progressbar = None + PublicFunc.add_progressbar(self) + + #初始化画框 + self.fig = None + self.canvas = None + self.figToolbar = None + self.gs = None + self.ax0 = None + self.ax1 = None + self.fig_spectrum = None + self.canvas_spectrum = None + self.figToolbar_spectrum = None + self.gs_spectrum = None + self.ax0_spectrum = None + self.ax1_spectrum = None + self.is_left_button_pressed = None + self.is_right_button_pressed = None + + self.tho_peak_point = None + + self.cid1 = None + self.cid2 = None + + self.msgBox = QMessageBox() + self.msgBox.setWindowTitle(Constants.MAINWINDOW_MSGBOX_TITLE) + + @overrides + def show(self, root_path, sampID): + super().show() + self.root_path = root_path + self.sampID = sampID + + self.setting = SettingWindow(root_path, sampID) + + # 初始化画框 + self.fig = plt.figure(figsize=(12, 9), dpi=100) + self.canvas = FigureCanvasQTAgg(self.fig) + self.figToolbar = CustomNavigationToolbar(self.canvas, self) + self.figToolbar.action_Label_Multiple.setEnabled(False) + 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_Multiple_mode) + self.ui.verticalLayout_canvas.addWidget(self.canvas) + self.ui.verticalLayout_canvas.addWidget(self.figToolbar) + self.gs = gridspec.GridSpec(2, 1, height_ratios=[1, 1]) + self.fig.subplots_adjust(top=0.98, bottom=0.05, right=0.98, left=0.1, hspace=0.1, wspace=0) + self.ax0 = self.fig.add_subplot(self.gs[0]) + self.ax0.grid(True) + self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax1 = self.fig.add_subplot(self.gs[1]) + self.ax1.grid(True) + self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + + # 初始化频谱画框 + self.fig_spectrum = plt.figure(figsize=(12, 9), dpi=100) + self.canvas_spectrum = FigureCanvasQTAgg(self.fig_spectrum) + self.figToolbar_spectrum = NavigationToolbar2QT(self.canvas_spectrum) + self.figToolbar_spectrum.setStyleSheet(Constants.RESP_QUALITY_LABEL_FIGTOOLBAR_SPECTRUM_STYLESHEET) + for action in self.figToolbar_spectrum._actions.values(): + action.setEnabled(False) + for action in self.figToolbar_spectrum.actions(): + if action.text() == "Subplots" or action.text() == "Customize": + self.figToolbar_spectrum.removeAction(action) + self.ui.verticalLayout_spectrum_display.addWidget(self.canvas_spectrum) + self.ui.verticalLayout_spectrum_display.addWidget(self.figToolbar_spectrum) + self.gs_spectrum = gridspec.GridSpec(2, 1, height_ratios=[1, 1]) + self.fig_spectrum.subplots_adjust(top=0.95, bottom=0.05, right=0.98, left=0.1, hspace=0.2, wspace=0) + self.ax0_spectrum = self.fig_spectrum.add_subplot(self.gs_spectrum[0]) + self.ax0_spectrum.grid(True) + self.ax0_spectrum.set_title(Constants.RESP_QUALITY_LABEL_SPECTRUM_BDR_TITLE, fontsize=8) + self.ax1_spectrum = self.fig_spectrum.add_subplot(self.gs_spectrum[1]) + self.ax1_spectrum.grid(True) + self.ax1_spectrum.set_title(Constants.RESP_QUALITY_LABEL_SPECTRUM_THO_TITLE, fontsize=8) + + PublicFunc.__resetAllButton__(self, ButtonState) + + self.ui.doubleSpinBox_quality_threshold1.setValue(Config["Threshold"]["Low"]) + self.ui.doubleSpinBox_quality_threshold2.setValue(Config["Threshold"]["High"]) + self.ui.doubleSpinBox_findpeaks_min_interval.setValue(Config["FindPeaks"]["MinInterval"]) + self.ui.doubleSpinBox_findpeaks_min_height.setValue(Config["FindPeaks"]["MinHeight"]) + self.ui.doubleSpinBox_fillterMode_custom_low.setValue(Config["Filter"]["BandPassLow"]) + self.ui.doubleSpinBox_fillterMode_custom_high.setValue(Config["Filter"]["BandPassHigh"]) + + self.ui.tableWidget_labeled.setHorizontalHeaderLabels(['信号片段', '质量类型']) + self.ui.tableWidget_tobelabeled.setHorizontalHeaderLabels(['信号片段', '质量类型']) + self.ui.tableWidget_labeled.setEditTriggers(QTableWidget.NoEditTriggers) + self.ui.tableWidget_tobelabeled.setEditTriggers(QTableWidget.NoEditTriggers) + self.ui.tableWidget_labeled.horizontalHeader().setStretchLastSection(True) + self.ui.tableWidget_tobelabeled.horizontalHeader().setStretchLastSection(True) + + self.ui.pushButton_input_setting.clicked.connect(self.setting.show) + self.ui.pushButton_input_and_calculate_peaks.clicked.connect(self.__slot_btn_input_and_calculate_peaks__) + self.ui.pushButton_calculate_peaks.clicked.connect(self.__slot_btn_calculate_peaks__) + self.ui.pushButton_calculate_peaks_save.clicked.connect(self.__slot_btn_save_calculate_peak__) + self.ui.pushButton_input_and_label.clicked.connect(self.__slot_btn_input_and_label__) + self.ui.pushButton_autoqualitylabel_recalculate.clicked.connect(self.__slot_btn_autoqualitylabel_recalculate__) + self.ui.pushButton_refilter_orgBcg.clicked.connect(self.__slot_btn_refilter_orgBcg__) + self.ui.pushButton_prev.clicked.connect(self.__slot_btn_move__) + self.ui.pushButton_next.clicked.connect(self.__slot_btn_move__) + self.ui.tableWidget_labeled.cellDoubleClicked.connect(self.__slot_tableWidget_on_cell_double_clicked__) + self.ui.tableWidget_tobelabeled.cellDoubleClicked.connect(self.__slot_tableWidget_on_cell_double_clicked__) + self.ui.pushButton_valid.clicked.connect(self.__slot_btn_label__) + self.ui.pushButton_invalid.clicked.connect(self.__slot_btn_label__) + self.ui.pushButton_reset.clicked.connect(self.__slot_btn_label__) + self.ui.pushButton_save.clicked.connect(self.__slot_btn_save__) + + self.ui.lineEdit_filter_labeled.textChanged.connect(self.__slot_lineEdit_filter__) + self.ui.lineEdit_filter_tobelabeled.textChanged.connect(self.__slot_lineEdit_filter__) + self.ui.doubleSpinBox_quality_threshold1.valueChanged.connect(self.update_config) + self.ui.doubleSpinBox_quality_threshold2.valueChanged.connect(self.update_config) + self.ui.doubleSpinBox_findpeaks_min_interval.valueChanged.connect(self.update_config) + self.ui.doubleSpinBox_findpeaks_min_height.valueChanged.connect(self.update_config) + self.ui.doubleSpinBox_fillterMode_custom_low.valueChanged.connect(self.update_config) + self.ui.doubleSpinBox_fillterMode_custom_high.valueChanged.connect(self.update_config) + + @overrides + def closeEvent(self, event): + reply = QMessageBox.question(self, '确认', '确认退出吗?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) + if reply == QMessageBox.Yes: + + PublicFunc.__disableAllButton__(self, ButtonState) + + PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg(Constants.SHUTTING_DOWN)) + QApplication.processEvents() + + # 清空画框 + del self.tho_peak_point + if self.ax0 is not None: + self.ax0.clear() + if self.ax1 is not None: + self.ax1.clear() + if self.ax0_spectrum is not None: + self.ax0_spectrum.clear() + if self.ax1_spectrum is not None: + self.ax1_spectrum.clear() + + # 释放资源 + del self.data + self.fig.clf() + plt.close(self.fig) + self.deleteLater() + collect() + self.canvas = None + event.accept() + else: + event.ignore() + + def __reset__(self): + ButtonState["Current"].update(ButtonState["Default"].copy()) + + def __plot__(self): + # 清空画框 + self.reset_axes() + + sender = self.sender() + + if sender == self.ui.pushButton_calculate_peaks: + try: + self.ax1.plot(self.data.Tho_Processed, + label=Constants.RESP_QUALITY_LABEL_PLOT_LABEL_THO, color=Constants.PLOT_COLOR_BLUE) + self.tho_peak_point, = self.ax1.plot(self.data.Tho_peak, self.data.Tho_peak_y, 'ro', + label=Constants.RESP_QUALITY_LABEL_PLOT_LABEL_THO_PEAKS) + self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT) + self.canvas.draw() + except Exception as e: + return Result().failure(info=Constants.DRAW_FAILURE + "\n" + format_exc()) + return Result().success(info=Constants.DRAW_FINISHED) + elif (sender == self.ui.pushButton_input_and_label or + sender == self.ui.pushButton_refilter_orgBcg or + sender == self.ui.pushButton_prev or + sender == self.ui.pushButton_next or + sender == self.ui.tableWidget_labeled or + sender == self.ui.tableWidget_tobelabeled): + try: + if Config["CurrentPartNum"] != Config["DataPartNum"]: + begin_OrgBCG = Config["CurrentOrgBCGIndex"] + end_OrgBCG = (Config["CurrentOrgBCGIndex"] + ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["OrgBCGUseFreq"])) + begin_Tho = Config["CurrentThoIndex"] + end_Tho = (Config["CurrentThoIndex"] + ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])) + else: + begin_OrgBCG = Config["CurrentOrgBCGIndex"] + end_OrgBCG = len(self.data.OrgBCG_Processed) + begin_Tho = Config["CurrentThoIndex"] + end_Tho = len(self.data.Tho_Processed) + + if self.ui.radioButton_orgBcg_fillterMode_preset.isChecked(): + mode = "preset" + elif self.ui.radioButton_orgBcg_fillterMode_custom.isChecked(): + mode = "custom" + else: + raise ValueError("模式不存在") + BDR, band_low, band_high, bcg_spectrum, bcg_freq, tho_spectrum, tho_freq = ( + self.data.preprocess_getBDR(self.data.OrgBCG_Processed[begin_OrgBCG:end_OrgBCG], + self.data.Tho_Processed[begin_Tho:end_Tho], mode)) + # 绘制数据 + self.ax0.plot(arange(begin_OrgBCG, end_OrgBCG), BDR, + label=Constants.RESP_QUALITY_LABEL_PLOT_LABEL_ORGBCG, + color=Constants.PLOT_COLOR_BLUE) + self.ax1.plot(arange(begin_Tho, end_Tho), self.data.Tho_Processed[begin_Tho:end_Tho], + label=Constants.RESP_QUALITY_LABEL_PLOT_LABEL_THO, + color=Constants.PLOT_COLOR_BLUE) + self.tho_peak_point, = self.ax1.plot( + [value for value in self.data.Tho_peak if begin_Tho <= value <= end_Tho], + [self.data.Tho_peak_y[x] for x in + [index for index, value in enumerate(self.data.Tho_peak) if begin_Tho <= value <= end_Tho]], 'ro', + label=Constants.RESP_QUALITY_LABEL_PLOT_LABEL_THO_PEAKS) + self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) + self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT) + # 绘制体动 + mask = self.data.artifact_mask[begin_OrgBCG: end_OrgBCG] == 1 + mask = (BDR * mask).astype(float64) + place(mask, mask == 0, nan) + self.ax0.plot(arange(begin_OrgBCG, end_OrgBCG), mask, + label=f"{Constants.RESP_QUALITY_LABEL_PLOT_LABEL_ARTIFACT}", + color=Constants.PLOT_COLOR_PINK, linestyle="-") + # 绘制频谱 + self.ax0_spectrum.plot(bcg_freq, bcg_spectrum, + label=Constants.RESP_QUALITY_LABEL_SPECTRUM_ORGBCG_LABEL, + color=Constants.PLOT_COLOR_BLUE) + self.ax0_spectrum.axvline(x=band_low, + label=Constants.RESP_QUALITY_LABEL_SPECTRUM_BDR_LABEL, + color=Constants.PLOT_COLOR_ORANGE, + linestyle='--') + self.ax0_spectrum.axvline(x=band_high, + color=Constants.PLOT_COLOR_ORANGE, + linestyle='--') + self.ax1_spectrum.plot(tho_freq, tho_spectrum, + label=Constants.RESP_QUALITY_LABEL_SPECTRUM_THO_LABEL, + color=Constants.PLOT_COLOR_BLUE) + self.ax0_spectrum.legend(loc=Constants.PLOT_UPPER_RIGHT) + self.ax1_spectrum.legend(loc=Constants.PLOT_UPPER_RIGHT) + + self.canvas.draw() + self.canvas_spectrum.draw() + self.cid1 = self.ax0.callbacks.connect('xlim_changed', self.on_xlim_changed) + self.cid2 = self.ax1.callbacks.connect('xlim_changed', self.on_xlim_changed) + except Exception as e: + return Result().failure(info=Constants.DRAW_FAILURE + "\n" + format_exc()) + return Result().success(info=Constants.DRAW_FINISHED) + else: + self.canvas.draw() + self.ax0.autoscale(False) + self.ax1.autoscale(False) + return Result().failure(info=Constants.DRAW_FAILURE) + + def __redraw_peaks__(self): + try: + if Config["CurrentPartNum"] != Config["DataPartNum"]: + begin_Tho = Config["CurrentThoIndex"] + end_Tho = (Config["CurrentThoIndex"] + ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])) + elif Config["CurrentPartNum"] == Config["DataPartNum"]: + begin_Tho = Config["CurrentThoIndex"] + end_Tho = len(self.data.Tho_Processed) + + self.tho_peak_point.remove() + self.tho_peak_point, = self.ax1.plot( + [value for value in self.data.Tho_peak if begin_Tho <= value <= end_Tho], + [self.data.Tho_peak_y[x] for x in + [index for index, value in enumerate(self.data.Tho_peak) if begin_Tho <= value <= end_Tho]], 'ro', + label=Constants.RESP_QUALITY_LABEL_PLOT_LABEL_THO_PEAKS) + + self.ax1.autoscale(False) + self.canvas.draw() + return Result().success(info=Constants.DRAW_FINISHED) + except Exception as e: + self.canvas.draw() + self.ax0.autoscale(False) + self.ax1.autoscale(False) + return Result().failure(info=Constants.DRAW_FAILURE) + + def update_tableWidget(self): + label_list = { + "已标注": + where((self.data.resp_quality_label == Constants.RESP_QUALITY_LABEL_A_QUALITY) | + (self.data.resp_quality_label == Constants.RESP_QUALITY_LABEL_B_QUALITY))[0] + 1, + "未标注": + where(self.data.resp_quality_label == Constants.RESP_QUALITY_LABEL_C_QUALITY)[0] + 1 + } + self.ui.tableWidget_labeled.setRowCount( + label_list["已标注"].__len__()) + self.ui.tableWidget_tobelabeled.setRowCount( + label_list["未标注"].__len__()) + for label_name, label in label_list.items(): + if label_name == "已标注": + tableWidget = self.ui.tableWidget_labeled + elif label_name == "未标注": + tableWidget = self.ui.tableWidget_tobelabeled + else: + raise ValueError("label_name不存在") + for row, value in enumerate(label): + item = QTableWidgetItem(str(value).strip()) + tableWidget.setItem(row, 0, item) + item = QTableWidgetItem(Constants.RESP_QUALITY_LABEL_KEY_VALUE[self.data.resp_quality_label[value - 1]]) + tableWidget.setItem(row, 1, item) + self.ui.tableWidget_labeled.verticalScrollBar().setValue(self.ui.tableWidget_labeled.verticalScrollBar().maximum()) + self.ui.tableWidget_tobelabeled.verticalScrollBar().setValue(self.ui.tableWidget_tobelabeled.verticalScrollBar().maximum()) + + def update_info(self): + try: + self.ui.lineEdit_current_part_num.setText("{} / {}".format(Config["CurrentPartNum"], Config["DataPartNum"])) + self.ui.lineEdit_current_part_label.setText( + str(Constants.RESP_QUALITY_LABEL_KEY_VALUE[self.data.resp_quality_label[Config["CurrentPartNum"] - 1]])) + except Exception as e: + return Result().failure(info=Constants.UPDATE_FAILURE + + Constants.FAILURE_REASON["Update_Info_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.UPDATE_FINISHED) + + def __slot_btn_input_and_calculate_peaks__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + + self.reset_axes() + self.canvas.draw() + + self.data = Data() + + # 导入数据 + PublicFunc.progressbar_update(self, 1, 3, Constants.INPUTTING_DATA, 0) + result = self.data.open_file_calculate_peaks() + if not result.status: + PublicFunc.text_output(self.ui, "(1/3)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(1/3)" + result.info, Constants.TIPS_TYPE_INFO) + + # 重采样 + PublicFunc.progressbar_update(self, 2, 3, Constants.RESAMPLING_DATA, 40) + result = self.data.resample_tho() + if not result.status: + PublicFunc.text_output(self.ui, "(2/3)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(2/3)" + result.info, Constants.TIPS_TYPE_INFO) + + # 数据预处理 + PublicFunc.progressbar_update(self, 3, 3, Constants.PREPROCESSING_DATA, 70) + result = self.data.preprocess_tho() + if not result.status: + PublicFunc.text_output(self.ui, "(3/3)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(3/3)" + result.info, Constants.TIPS_TYPE_INFO) + + self.__reset__() + ButtonState["Current"]["pushButton_input_setting"] = True + ButtonState["Current"]["pushButton_input_and_calculate_peaks"] = True + ButtonState["Current"]["pushButton_calculate_peaks"] = True + ButtonState["Current"]["pushButton_calculate_peaks_save"] = True + ButtonState["Current"]["pushButton_input_data_and_label"] = True + ButtonState["Current"]["pushButton_autoqualitylabel_recalculate"] = False + ButtonState["Current"]["pushButton_refilter_orgBcg"]: False + ButtonState["Current"]["pushButton_valid"] = False + ButtonState["Current"]["pushButton_invalid"] = False + ButtonState["Current"]["pushButton_reset"] = False + ButtonState["Current"]["pushButton_prev"] = False + ButtonState["Current"]["pushButton_next"] = False + ButtonState["Current"]["pushButton_save"] = False + for action in self.figToolbar._actions.values(): + action.setEnabled(True) + self.figToolbar.action_Label_Multiple.setEnabled(False) + + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_calculate_peaks__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + + self.reset_axes() + self.canvas.draw() + + # 计算峰值 + PublicFunc.progressbar_update(self, 1, 2, Constants.RESP_QUALITY_LABEL_CALCULATING_PEAK, 0) + result = self.data.calculate_tho_peak() + if not result.status: + PublicFunc.text_output(self.ui, "(1/2)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(1/2)" + result.info, Constants.TIPS_TYPE_INFO) + + # 绘图 + PublicFunc.progressbar_update(self, 2, 2, Constants.DRAWING_DATA, 50) + result = self.__plot__() + if not result.status: + PublicFunc.text_output(self.ui, "(2/2)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(2/2)" + result.info, Constants.TIPS_TYPE_INFO) + + ButtonState["Current"]["pushButton_input_setting"] = True + ButtonState["Current"]["pushButton_input_and_calculate_peaks"] = True + ButtonState["Current"]["pushButton_calculate_peaks"] = True + ButtonState["Current"]["pushButton_calculate_peaks_save"] = True + ButtonState["Current"]["pushButton_input_data_and_label"] = True + ButtonState["Current"]["pushButton_autoqualitylabel_recalculate"] = False + ButtonState["Current"]["pushButton_refilter_orgBcg"]: False + ButtonState["Current"]["pushButton_valid"] = False + ButtonState["Current"]["pushButton_invalid"] = False + ButtonState["Current"]["pushButton_reset"] = False + ButtonState["Current"]["pushButton_prev"] = False + ButtonState["Current"]["pushButton_next"] = False + ButtonState["Current"]["pushButton_save"] = False + + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_save_calculate_peak__(self): + reply = QMessageBox.question(self, Constants.QUESTION_TITLE, + Constants.QUESTION_CONTENT + Config["Path"]["Save_Tho_peak"], + QMessageBox.Yes | QMessageBox.No, + QMessageBox.Yes) + if reply == QMessageBox.Yes: + PublicFunc.__disableAllButton__(self, ButtonState) + + # 保存 + PublicFunc.progressbar_update(self, 1, 1, Constants.SAVING_DATA, 0) + result = self.data.save_tho_peak() + if not result.status: + PublicFunc.text_output(self.ui, "(1/1)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(1/1)" + result.info, Constants.TIPS_TYPE_INFO) + + PublicFunc.msgbox_output(self, result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_input_and_label__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + + self.reset_axes() + self.canvas.draw() + + self.data = Data() + + # 导入数据 + PublicFunc.progressbar_update(self, 1, 6, Constants.INPUTTING_DATA, 0) + result = self.data.open_file_label() + if not result.status: + PublicFunc.text_output(self.ui, "(1/6)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(1/6)" + result.info, Constants.TIPS_TYPE_INFO) + + # 获取标签存档 + PublicFunc.progressbar_update(self, 2, 6, Constants.LOADING_ARCHIVE, 30) + result = self.data.get_archive_resp_quality() + if not result.status: + PublicFunc.text_output(self.ui, "(2/6)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(2/6)" + result.info, Constants.TIPS_TYPE_INFO) + + # 获取峰值存档 + PublicFunc.progressbar_update(self, 3, 6, Constants.LOADING_ARCHIVE, 30) + result = self.data.get_archive_tho_peak() + if not result.status: + PublicFunc.text_output(self.ui, "(3/6)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(3/6)" + result.info, Constants.TIPS_TYPE_INFO) + + # 重采样 + PublicFunc.progressbar_update(self, 4, 6, Constants.RESAMPLING_DATA, 40) + result = self.data.resample_tho_and_OrgBCG() + if not result.status: + PublicFunc.text_output(self.ui, "(4/6)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(4/6)" + result.info, Constants.TIPS_TYPE_INFO) + + # 数据预处理 + PublicFunc.progressbar_update(self, 5, 6, Constants.PREPROCESSING_DATA, 70) + result = self.data.preprocess_tho_and_OrgBCG() + if not result.status: + PublicFunc.text_output(self.ui, "(5/6)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(5/6)" + result.info, Constants.TIPS_TYPE_INFO) + + # 绘图 + PublicFunc.progressbar_update(self, 6, 6, Constants.DRAWING_DATA, 90) + self.ax0.autoscale(True) + self.ax1.autoscale(True) + self.ax1.relim() + self.ax1.autoscale_view() + result = self.__plot__() + self.ax0.autoscale(False) + self.ax1.autoscale(False) + if not result.status: + PublicFunc.text_output(self.ui, "(6/6)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(6/6)" + result.info, Constants.TIPS_TYPE_INFO) + + Config["CurrentPartNum"] = 1 + self.update_info() + self.update_tableWidget() + self.__reset__() + ButtonState["Current"]["pushButton_input_setting"] = False + ButtonState["Current"]["pushButton_input_and_calculate_peaks"] = False + ButtonState["Current"]["pushButton_calculate_peaks"] = False + ButtonState["Current"]["pushButton_calculate_peaks_save"] = False + ButtonState["Current"]["pushButton_input_data_and_label"] = False + ButtonState["Current"]["pushButton_autoqualitylabel_recalculate"] = True + ButtonState["Current"]["pushButton_refilter_orgBcg"] = True + ButtonState["Current"]["pushButton_valid"] = True + ButtonState["Current"]["pushButton_invalid"] = True + ButtonState["Current"]["pushButton_reset"] = True + ButtonState["Current"]["pushButton_prev"] = True + ButtonState["Current"]["pushButton_next"] = True + ButtonState["Current"]["pushButton_save"] = True + for action in self.figToolbar._actions.values(): + action.setEnabled(True) + for action in self.figToolbar_spectrum._actions.values(): + action.setEnabled(True) + self.figToolbar.action_Label_Multiple.setEnabled(True) + + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_autoqualitylabel_recalculate__(self): + reply = QMessageBox.question(self, '确认', Constants.RESP_QUALITY_LABEL_CHECK_ARGS_QUESTION_CONTENT, + QMessageBox.Yes | QMessageBox.No, QMessageBox.No) + if reply == QMessageBox.Yes: + if self.check_autolabel_args() is False: + PublicFunc.msgbox_output(self, Constants.RESP_QUALITY_LABEL_AUTOLABEL_ARGS_ERROR, Constants.MSGBOX_TYPE_ERROR) + return + + try: + # 确定带体动的片段 + artifact_indices = [] + for i in range(0, len(self.data.Artifact_a)): + if i + 3 < len(self.data.Artifact_a): # 防止索引越界 + index0 = self.data.Artifact_a[i + 2] // (Config["InputConfig"]["OrgBCGUseFreq"] * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC) # 第三行(索引+2) + index1 = self.data.Artifact_a[i + 3] // (Config["InputConfig"]["OrgBCGUseFreq"] * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC) # 第四行(索引+3) + if index0 == index1: + artifact_indices.append(index0) + else: + artifact_indices.append(index0) + artifact_indices.append(index1) + artifact_indices = list(dict.fromkeys(artifact_indices)) + for seg_idx in range(1, Config["DataPartNum"] - 1): + # 数据切片预处理 + BCG = pre_process( + get_slice( + self.data.OrgBCG_Processed, seg_idx, ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC, Config["InputConfig"]["OrgBCGUseFreq"]), Config["InputConfig"]["OrgBCGUseFreq"], ConfigParams.RESP_QUALITY_LABEL_PREPROCESS_FC) + THO = pre_process( + get_slice( + self.data.Tho_Processed, seg_idx, ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC, Config["InputConfig"]["ThoUseFreq"]), Config["InputConfig"]["ThoUseFreq"], ConfigParams.RESP_QUALITY_LABEL_PREPROCESS_FC) + + # 质量评估 + # 有体动:1 无体动:0 + artifact_flag = 1 if (seg_idx - 1) in artifact_indices else 0 + + quality = evaluate_quality( + BCG, THO, Config["InputConfig"]["OrgBCGUseFreq"], Config["InputConfig"]["ThoUseFreq"] + , artifact_flag, [float(Config["Threshold"]["Low"]), float(Config["Threshold"]["High"])] + ) + self.data.resp_quality_label[seg_idx - 1] = quality + + self.update_tableWidget() + result = self.update_info() + if not result.status: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, Constants.OPERATION_FINISHED, Constants.TIPS_TYPE_INFO) + PublicFunc.msgbox_output(self, Constants.OPERATION_FINISHED, Constants.MSGBOX_TYPE_INFO) + except Exception as e: + PublicFunc.text_output(self.ui, Constants.OPERATION_FAILURE, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, Constants.OPERATION_FAILURE, Constants.MSGBOX_TYPE_ERROR) + + def __slot_btn_refilter_orgBcg__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + if len(self.data.OrgBCG_Processed) == 0: + Result().failure(info=Constants.RESAMPLE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + return + + if self.ui.radioButton_orgBcg_fillterMode_custom.isChecked(): + if self.check_filter_args() is False: + PublicFunc.msgbox_output(self, Constants.RESP_QUALITY_LABEL_CUSTOM_FILTER_ARGS_ERROR, Constants.MSGBOX_TYPE_ERROR) + return + result = self.__plot__() + if not result.status: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_INFO) + + def __slot_btn_move__(self): + sender = self.sender() + + if sender == self.ui.pushButton_prev: + if self.check_filter_args() is False: + PublicFunc.msgbox_output(self, Constants.RESP_QUALITY_LABEL_CUSTOM_FILTER_ARGS_ERROR, Constants.MSGBOX_TYPE_ERROR) + return + if Config["CurrentPartNum"] == 1: + PublicFunc.text_output(self.ui, Constants.RESP_QUALITY_LABEL_VIEWING_THE_FIRST_PART, Constants.MSGBOX_TYPE_INFO) + PublicFunc.msgbox_output(self, Constants.RESP_QUALITY_LABEL_VIEWING_THE_FIRST_PART, Constants.MSGBOX_TYPE_INFO) + return + Config["CurrentPartNum"] = Config["CurrentPartNum"] - 1 + Config["CurrentOrgBCGIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["OrgBCGUseFreq"])) + Config["CurrentThoIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])) + result = self.__plot__() + if not result.status: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_INFO) + result = self.update_info() + if not result.status: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, Constants.RESP_QUALITY_LABEL_PREV_PART + str(Config["CurrentPartNum"]), + Constants.TIPS_TYPE_INFO) + elif sender == self.ui.pushButton_next: + if self.check_filter_args() is False: + PublicFunc.msgbox_output(self, Constants.RESP_QUALITY_LABEL_CUSTOM_FILTER_ARGS_ERROR, Constants.MSGBOX_TYPE_ERROR) + return + if Config["CurrentPartNum"] == Config["DataPartNum"]: + PublicFunc.text_output(self.ui, Constants.RESP_QUALITY_LABEL_VIEWING_THE_LAST_PART, Constants.MSGBOX_TYPE_INFO) + PublicFunc.msgbox_output(self, Constants.RESP_QUALITY_LABEL_VIEWING_THE_LAST_PART, Constants.MSGBOX_TYPE_INFO) + return + Config["CurrentPartNum"] = Config["CurrentPartNum"] + 1 + Config["CurrentOrgBCGIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["OrgBCGUseFreq"])) + Config["CurrentThoIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])) + result = self.__plot__() + if not result.status: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_INFO) + result = self.update_info() + if not result.status: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, Constants.RESP_QUALITY_LABEL_NEXT_PART + str(Config["CurrentPartNum"]), + Constants.TIPS_TYPE_INFO) + else: + raise ValueError("发射信号不存在") + + def __slot_tableWidget_on_cell_double_clicked__(self, row, column): + sender = self.sender() + + if self.check_filter_args() is False: + PublicFunc.msgbox_output(self, Constants.RESP_QUALITY_LABEL_CUSTOM_FILTER_ARGS_ERROR, Constants.MSGBOX_TYPE_ERROR) + return + if sender == self.ui.tableWidget_labeled: + Config["CurrentPartNum"] = int( + self.ui.tableWidget_labeled.item(row, 0).text()) + Config["CurrentOrgBCGIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["OrgBCGUseFreq"])) + Config["CurrentThoIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])) + elif sender == self.ui.tableWidget_tobelabeled: + Config["CurrentPartNum"] = int( + self.ui.tableWidget_tobelabeled.item(row, 0).text()) + Config["CurrentOrgBCGIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["OrgBCGUseFreq"])) + Config["CurrentThoIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])) + else: + raise ValueError("发射信号不存在") + result = self.__plot__() + if not result.status: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_INFO) + result = self.update_info() + if not result.status: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, Constants.RESP_QUALITY_LABEL_JUMP + str(Config["CurrentPartNum"]), + Constants.TIPS_TYPE_INFO) + + def __slot_btn_label__(self): + sender = self.sender() + + if sender == self.ui.pushButton_valid: + self.data.resp_quality_label[Config["CurrentPartNum"] - 1] = 1 + elif sender == self.ui.pushButton_invalid: + self.data.resp_quality_label[Config["CurrentPartNum"] - 1] = 0 + elif sender == self.ui.pushButton_reset: + self.data.resp_quality_label[Config["CurrentPartNum"] - 1] = -1 + else: + raise ValueError("发射信号不存在") + result = self.data.save_resp_quality_label() + self.update_tableWidget() + if not result.status: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, str(Config["CurrentPartNum"]) + + Constants.RESP_QUALITY_LABEL_LABEL_SUCCESSFULLY + + "," + Constants.RESP_QUALITY_LABEL_LABEL_TYPE + + Constants.RESP_QUALITY_LABEL_KEY_VALUE[self.data.resp_quality_label[Config["CurrentPartNum"] - 1]], + Constants.TIPS_TYPE_INFO) + + def __slot_btn_save__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + + # 保存 + PublicFunc.progressbar_update(self, 1, 2, Constants.SAVING_DATA + ConfigParams.RESP_QUALITY_LABEL, 0) + result = self.data.save_resp_quality_label() + if not result.status: + PublicFunc.text_output(self.ui, "(1/2)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(1/2)" + result.info, Constants.TIPS_TYPE_INFO) + + PublicFunc.progressbar_update(self, 2, 2, Constants.SAVING_DATA + ConfigParams.THO_PEAK, 50) + result = self.data.save_tho_peak() + if not result.status: + PublicFunc.text_output(self.ui, "(2/2)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(2/2)" + result.info, Constants.TIPS_TYPE_INFO) + + PublicFunc.msgbox_output(self, Constants.SAVE_FINISHED, Constants.TIPS_TYPE_INFO) + PublicFunc.finish_operation(self, ButtonState) + + def __slot_lineEdit_filter__(self, filter_text): + sender = self.sender() + + if sender == self.ui.lineEdit_filter_labeled: + for row in range(self.ui.tableWidget_labeled.rowCount()): + match = False + for col in range(self.ui.tableWidget_labeled.columnCount()): + item = self.ui.tableWidget_labeled.item(row, col) + if filter_text.lower() in item.text().lower(): + match = True + break + self.ui.tableWidget_labeled.setRowHidden(row, not match) + elif sender == self.ui.lineEdit_filter_tobelabeled: + for row in range(self.ui.tableWidget_tobelabeled.rowCount()): + match = False + for col in range(self.ui.tableWidget_tobelabeled.columnCount()): + item = self.ui.tableWidget_tobelabeled.item(row, col) + if filter_text.lower() in item.text().lower(): + match = True + break + self.ui.tableWidget_tobelabeled.setRowHidden(row, not match) + else: + raise ValueError("发生信号不存在") + + def reset_axes(self): + if self.ax0 is not None: + self.ax0.clear() + self.ax0.grid(True) + self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + if self.ax1 is not None: + self.ax1.clear() + self.ax1.grid(True) + self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + if self.ax0_spectrum is not None: + self.ax0_spectrum.clear() + self.ax0_spectrum.grid(True) + self.ax0_spectrum.set_title(Constants.RESP_QUALITY_LABEL_SPECTRUM_BDR_TITLE, fontsize=8) + if self.ax1_spectrum is not None: + self.ax1_spectrum.clear() + self.ax1_spectrum.grid(True) + self.ax1_spectrum.set_title(Constants.RESP_QUALITY_LABEL_SPECTRUM_THO_TITLE, fontsize=8) + + def check_filter_args(self): + if (float(Config["Filter"]["BandPassLow"]) >= float(Config["Filter"]["BandPassHigh"])): + return False + return True + + def check_autolabel_args(self): + if (float(Config["Threshold"]["Low"]) >= float(Config["Threshold"]["High"])): + return False + return True + + def on_xlim_changed(self, ax): + # 获取触发事件的轴 + if ax == self.ax0: + # 获取第一个子图的X轴范围 + xlim1 = self.ax0.get_xlim() + # 计算对应的第二个子图的X轴范围 + ratio = (int(Config["InputConfig"]["ThoUseFreq"]) / + int(Config["InputConfig"]["OrgBCGUseFreq"])) # 信号B的样本点数与信号A的样本点数的比例 + xlim2 = (xlim1[0] * ratio, xlim1[1] * ratio) + + # 禁用事件监听 + self.ax0.callbacks.disconnect(self.cid2) + # 设置第二个子图的X轴范围 + self.ax1.set_xlim(xlim2) + # 重新启用事件监听 + self.cid2 = self.ax1.callbacks.connect('xlim_changed', self.on_xlim_changed) + + elif ax == self.ax1: + # 获取第二个子图的X轴范围 + xlim2 = self.ax1.get_xlim() + # 计算对应的第一个子图的X轴范围 + ratio = (int(Config["InputConfig"]["OrgBCGUseFreq"]) / + int(Config["InputConfig"]["ThoUseFreq"])) # 信号A的样本点数与信号B的样本点数的比例 + xlim1 = (xlim2[0] * ratio, xlim2[1] * ratio) + + # 禁用事件监听 + self.ax0.callbacks.disconnect(self.cid1) + # 设置第一个子图的X轴范围 + self.ax0.set_xlim(xlim1) + # 重新启用事件监听 + self.cid1 = self.ax0.callbacks.connect('xlim_changed', self.on_xlim_changed) + + def update_config(self): + Config["Threshold"]["Low"] = self.ui.doubleSpinBox_quality_threshold1.value() + Config["Threshold"]["High"] = self.ui.doubleSpinBox_quality_threshold2.value() + Config["FindPeaks"]["MinInterval"] = self.ui.doubleSpinBox_findpeaks_min_interval.value() + Config["FindPeaks"]["MinHeight"] = self.ui.doubleSpinBox_findpeaks_min_height.value() + Config["Filter"]["BandPassLow"] = self.ui.doubleSpinBox_fillterMode_custom_low.value() + Config["Filter"]["BandPassHigh"] = self.ui.doubleSpinBox_fillterMode_custom_high.value() + + def toggle_home(self): + if Config["CurrentPartNum"] is None: + self.ax1.autoscale(True) + self.ax1.relim() + self.ax1.autoscale_view() + self.canvas.draw() + self.ax1.autoscale(False) + + def toggle_changeLabel_Multiple_mode(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_ax1 is not 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 < Config["CurrentThoIndex"]: + rect_left = Config["CurrentThoIndex"] + elif rect_left >= (Config["CurrentThoIndex"] + ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])): + rect_left = 0 + rect_right = 0 + if (rect_right >= Config["CurrentThoIndex"] + ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])): + rect_right = (Config["CurrentThoIndex"] + ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"]) - 1) + elif rect_right < Config["CurrentThoIndex"]: + rect_left = 0 + rect_right = 0 + selected_area_for_add_points = self.data.Tho_Processed[int(rect_left):int(rect_right)] + peaks_idx, _ = find_peaks(selected_area_for_add_points, + height=float(Config["FindPeaks"]["MinHeight"]), + distance=float(Config["FindPeaks"]["MinInterval"])) + peaks_idx = peaks_idx + int(rect_left) + peaks_idx = setdiff1d(peaks_idx, self.data.Tho_peak) + if len(peaks_idx) != 0: + PublicFunc.text_output(self.ui, + f"{Constants.RESP_QUALITY_LABEL_ADD_POINTS_SUCCESSFULLY}{peaks_idx}", + Constants.TIPS_TYPE_INFO) + else: + PublicFunc.text_output(self.ui, + Constants.RESP_QUALITY_LABEL_NO_POINT_IN_THE_INTERVAL, + Constants.TIPS_TYPE_INFO) + self.data.Tho_peak = append(self.data.Tho_peak, peaks_idx) + self.data.Tho_peak_y = append(self.data.Tho_peak_y, self.data.Tho_Processed[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.Tho_peak - rect_left + right_label2_to_delete = self.data.Tho_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.RESP_QUALITY_LABEL_REMOVE_POINTS_SUCCESSFULLY}{self.data.Tho_peak[left_label2_to_delete_idx:right_label2_to_delete_idx]}", + Constants.TIPS_TYPE_INFO) + else: + PublicFunc.text_output(self.ui, + Constants.RESP_QUALITY_LABEL_NO_POINT_IN_THE_INTERVAL, + Constants.TIPS_TYPE_INFO) + self.data.Tho_peak = delete(self.data.Tho_peak, + arange(left_label2_to_delete_idx, right_label2_to_delete_idx)) + self.data.Tho_peak_y = delete(self.data.Tho_peak_y, arange(left_label2_to_delete_idx, right_label2_to_delete_idx)) + self.__redraw_peaks__() + self.data.Tho_peak.sort() + self.data.Tho_peak_y = [self.data.Tho_Processed[x] for x in self.data.Tho_peak] + self.figToolbar.rect_start_x = None + self.figToolbar.rect_end_x = None + + result = self.data.save_tho_peak() + if not result.status: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_INFO) + + # 移除矩形patch + if self.figToolbar.rect_patch_ax1 is not 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_ax1 is None: + if self.is_left_button_pressed: + self.figToolbar.rect_patch_ax1 = patches.Rectangle((0, 0), 1, 1, fill=True, + alpha=ConfigParams.RESP_QUALITY_LABEL_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.RESP_QUALITY_LABEL_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 = self.ax1.get_ylim()[0] - 1000 + rect_up = self.ax1.get_ylim()[1] + 1000 + 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(): + + def __init__(self): + self.OrgBCG = None + self.Tho = None + self.OrgBCG_Processed = None + self.Tho_Processed = None + self.Tho_peak = None + self.resp_quality_label = None + self.Artifact_a = None + self.Tho_peak_y = None + + self.artifact_number = array([]).astype(int64) + self.artifact_type = array([]).astype(int64) + self.artifact_mask = array([]).astype(int64) + + def open_file_calculate_peaks(self): + if Path(Config["Path"]["Input_OrgBCG"]).is_file(): + Config["Path"]["Input_OrgBCG"] = str(Path(Config["Path"]["Input_OrgBCG"]).parent) + if Path(Config["Path"]["Input_Tho"]).is_file(): + Config["Path"]["Input_Tho"] = str(Path(Config["Path"]["Input_Tho"]).parent) + if Path(Config["Path"]["Input_Artifact"]).is_file(): + Config["Path"]["Input_Artifact"] = str(Path(Config["Path"]["Input_Artifact"]).parent) + if Path(Config["Path"]["Save_Resp_quality_label"]).is_file(): + Config["Path"]["Save_Resp_quality_label"] = str(Path(Config["Path"]["Save_Resp_quality_label"]).parent) + if Path(Config["Path"]["Save_Tho_peak"]).is_file(): + Config["Path"]["Save_Tho_peak"] = str(Path(Config["Path"]["Save_Tho_peak"]).parent) + + result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], ConfigParams.THO_SYNC) + if result.status: + Config["Path"]["Input_Tho"] = result.data["path"] + Config["InputConfig"]["ThoFreq"] = result.data["freq"] + else: + return result + + Config["Path"]["Save_Tho_peak"] = str( + Path(Config["Path"]["Save_Tho_peak"]) / Path(ConfigParams.THO_PEAK + str(Config["InputConfig"]["ThoUseFreq"]) + ConfigParams.ENDSWITH_TXT)) + + try: + self.Tho = read_csv(Config["Path"]["Input_Tho"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + except Exception as e: + return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Open_Data_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.INPUT_FINISHED) + + def resample_tho(self): + if self.Tho is None: + Result().failure(info=Constants.RESAMPLE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + + try: + if Config["InputConfig"]["ThoFreq"] != Config["InputConfig"]["ThoUseFreq"]: + self.Tho = resample(self.Tho, + int(len(self.Tho) * + (Config["InputConfig"]["ThoUseFreq"] / Config["InputConfig"]["ThoFreq"]))) + else: + return Result().success(info=Constants.RESAMPLE_NO_NEED) + except Exception as e: + Result().failure(info=Constants.RESAMPLE_FAILURE + + Constants.FAILURE_REASON["Resample_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.RESAMPLE_FINISHED) + + def preprocess_tho(self): + if self.Tho is None: + return Result().failure(info=Constants.PREPROCESS_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + + try: + self.Tho_Processed = pre_process(self.Tho, Config["InputConfig"]["ThoUseFreq"], ConfigParams.RESP_QUALITY_LABEL_PREPROCESS_FC) + except Exception as e: + return Result().failure(info=Constants.PREPROCESS_FAILURE + + Constants.FAILURE_REASON["Preprocess_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.PREPROCESS_FINISHED) + + def calculate_tho_peak(self): + if self.Tho_Processed is None: + return Result().failure(info=Constants.RESP_QUALITY_LABEL_CALCULATE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + + try: + self.Tho_peak, _ = find_peaks(self.Tho_Processed, + height=float(Config["FindPeaks"]["MinHeight"]), + distance=float(Config["FindPeaks"]["MinInterval"])) + self.Tho_peak_y = [self.Tho_Processed[x] for x in (self.Tho_peak)] + except Exception as e: + return Result().failure(info=Constants.RESP_QUALITY_LABEL_CALCULATE_FAILURE + + Constants.FAILURE_REASON["Calculate_Peak_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.RESP_QUALITY_LABEL_CALCULATE_FINISHED) + + def save_tho_peak(self): + if (not Path(Config["Path"]["Save_Tho_peak"]).parent.exists()) or (not Path(Config["Path"]["Save_Tho_peak"]).parent.is_dir()): + Path(Config["Path"]["Save_Tho_peak"]).parent.mkdir(parents=True, exist_ok=True) + + if self.Tho_peak is None: + + return Result().failure(info=ConfigParams.THO_PEAK + Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + + try: + DataFrame(self.Tho_peak).to_csv(Path(Config["Path"]["Save_Tho_peak"]), mode='w', index=False, header=False) + except Exception as e: + return Result().failure(info=ConfigParams.THO_PEAK + Constants.SAVE_FAILURE + + Constants.FAILURE_REASON["Save_Exception"] + "\n" + format_exc()) + + return Result().success(info=ConfigParams.THO_PEAK + Constants.SAVE_FINISHED) + + def open_file_label(self): + if Path(Config["Path"]["Input_OrgBCG"]).is_file(): + Config["Path"]["Input_OrgBCG"] = str(Path(Config["Path"]["Input_OrgBCG"]).parent) + if Path(Config["Path"]["Input_Tho"]).is_file(): + Config["Path"]["Input_Tho"] = str(Path(Config["Path"]["Input_Tho"]).parent) + if Path(Config["Path"]["Input_Artifact"]).is_file(): + Config["Path"]["Input_Artifact"] = str(Path(Config["Path"]["Input_Artifact"]).parent) + if Path(Config["Path"]["Save_Resp_quality_label"]).is_file(): + Config["Path"]["Save_Resp_quality_label"] = str(Path(Config["Path"]["Save_Resp_quality_label"]).parent) + if Path(Config["Path"]["Save_Tho_peak"]).is_file(): + Config["Path"]["Save_Tho_peak"] = str(Path(Config["Path"]["Save_Tho_peak"]).parent) + + result = PublicFunc.examine_file(Config["Path"]["Input_OrgBCG"], ConfigParams.ORGBCG_SYNC) + if result.status: + Config["Path"]["Input_OrgBCG"] = result.data["path"] + Config["InputConfig"]["OrgBCGFreq"] = result.data["freq"] + else: + return result + + result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], ConfigParams.THO_SYNC) + if result.status: + Config["Path"]["Input_Tho"] = result.data["path"] + Config["InputConfig"]["ThoFreq"] = result.data["freq"] + else: + return result + + Config["Path"]["Input_Artifact"] = str( + Path(Config["Path"]["Input_Artifact"]) / Path(ConfigParams.ARTIFACT_A + ConfigParams.ENDSWITH_TXT)) + Config["Path"]["Save_Resp_quality_label"] = str( + Path(Config["Path"]["Save_Resp_quality_label"]) / Path( + ConfigParams.RESP_QUALITY_LABEL + ConfigParams.ENDSWITH_TXT)) + Config["Path"]["Save_Tho_peak"] = str( + Path(Config["Path"]["Save_Tho_peak"]) / Path( + ConfigParams.THO_PEAK + str(Config["InputConfig"]["ThoUseFreq"]) + ConfigParams.ENDSWITH_TXT)) + + try: + self.OrgBCG = read_csv(Config["Path"]["Input_OrgBCG"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + self.Tho = read_csv(Config["Path"]["Input_Tho"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + self.Artifact_a = read_csv(Config["Path"]["Input_Artifact"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + except Exception as e: + return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Open_Data_Exception"] + "\n" + format_exc()) + + try: + Config["DataPartNum"] = len(self.OrgBCG) // (ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + Config["InputConfig"]["OrgBCGFreq"]) + 1 + if Config["DataPartNum"] == 0: + return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Data_Length_Not_Correct"]) + except Exception as e: + return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Open_Data_Exception"] + "\n" + format_exc()) + + try: + # 检查体动标签正确性,长度 + PublicFunc.examine_artifact(self.Artifact_a) + # 定义绘制体动所需要的数组 + artifact_start = array([]) + artifact_start = artifact_start.astype(int64) + artifact_end = array([]) + artifact_end = artifact_end.astype(int64) + for i in range(0, len(self.Artifact_a), 4): + self.artifact_number = append(self.artifact_number, self.Artifact_a[i]) + for i in range(1, len(self.Artifact_a), 4): + self.artifact_type = append(self.artifact_type, self.Artifact_a[i]) + for i in range(2, len(self.Artifact_a), 4): + artifact_start = append(artifact_start, self.Artifact_a[i]) + for i in range(3, len(self.Artifact_a), 4): + artifact_end = append(artifact_end, self.Artifact_a[i]) + self.artifact_mask = zeros(len(self.OrgBCG)) + for i in range(0, len(self.artifact_number)): + self.artifact_mask[artifact_start[i]: artifact_end[i] + 1] = 1 + except Exception as e: + return Result().failure(info=Constants.INPUT_FAILURE + + Constants.FAILURE_REASON["Get_Artifact_Format_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.INPUT_FINISHED) + + def get_archive_resp_quality(self): + if not Path(Config["Path"]["Save_Resp_quality_label"]).exists(): + self.resp_quality_label = full(Config["DataPartNum"], -1) + return Result().success(info=ConfigParams.RESP_QUALITY_LABEL + ":" + Constants.ARCHIVE_NOT_EXIST) + else: + self.resp_quality_label = read_csv(Config["Path"]["Save_Resp_quality_label"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + return Result().success(info=ConfigParams.RESP_QUALITY_LABEL + ":" + Constants.ARCHIVE_EXIST) + + def get_archive_tho_peak(self): + if not Path(Config["Path"]["Save_Tho_peak"]).exists(): + self.Tho_peak = array([]).astype(int) + self.Tho_peak_y = array([]).astype(int) + return Result().success(info=ConfigParams.RESP_QUALITY_LABEL + ":" + Constants.ARCHIVE_NOT_EXIST) + else: + self.Tho_peak = read_csv(Config["Path"]["Save_Tho_peak"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + + return Result().success(info=ConfigParams.THO_PEAK + ":" + Constants.ARCHIVE_EXIST) + + def resample_tho_and_OrgBCG(self): + if (self.OrgBCG is None) or (self.Tho is None): + Result().failure(info=Constants.RESAMPLE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + + try: + if ((Config["InputConfig"]["OrgBCGFreq"] != Config["InputConfig"]["OrgBCGUseFreq"]) + or (Config["InputConfig"]["ThoFreq"] != Config["InputConfig"]["ThoUseFreq"])): + + if Config["InputConfig"]["OrgBCGFreq"] != Config["InputConfig"]["OrgBCGUseFreq"]: + self.OrgBCG = resample(self.OrgBCG, + int(len(self.OrgBCG) * + (Config["InputConfig"]["OrgBCGUseFreq"] / Config["InputConfig"]["OrgBCGFreq"]))) + if Config["InputConfig"]["ThoFreq"] != Config["InputConfig"]["ThoUseFreq"]: + self.Tho = resample(self.Tho, + int(len(self.Tho) * + (Config["InputConfig"]["ThoUseFreq"] / Config["InputConfig"]["ThoFreq"]))) + else: + return Result().success(info=Constants.RESAMPLE_NO_NEED) + except Exception as e: + Result().failure(info=Constants.RESAMPLE_FAILURE + + Constants.FAILURE_REASON["Resample_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.RESAMPLE_FINISHED) + + def preprocess_tho_and_OrgBCG(self): + if (self.OrgBCG is None) or (self.Tho is None): + return Result().failure(info=Constants.PREPROCESS_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + + try: + self.OrgBCG_Processed = self.OrgBCG.copy() + self.Tho_Processed = pre_process(self.Tho, Config["InputConfig"]["ThoUseFreq"], ConfigParams.RESP_QUALITY_LABEL_PREPROCESS_FC) + self.Tho_peak_y = [self.Tho_Processed[x] for x in (self.Tho_peak)] + except Exception as e: + return Result().failure(info=Constants.PREPROCESS_FAILURE + + Constants.FAILURE_REASON["Preprocess_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.PREPROCESS_FINISHED) + + def preprocess_getBDR(self, orgBcg_slice, THO_slice, mode): + orgBcg = pre_process(orgBcg_slice, int(Config["InputConfig"]["OrgBCGUseFreq"]), + ConfigParams.RESP_QUALITY_LABEL_PREPROCESS_FC) + if mode == "preset": + BDR, band_low, band_high, bcg_spectrum, bcg_freq, tho_spectrum, tho_freq = ( + get_bandpass_bcgsignal(orgBcg, THO_slice, int(Config["InputConfig"]["OrgBCGUseFreq"]), + int(Config["InputConfig"]["ThoUseFreq"]), use_custom_band=False)) + elif mode == "custom": + BDR, band_low, band_high, bcg_spectrum, bcg_freq, tho_spectrum, tho_freq = ( + get_bandpass_bcgsignal(orgBcg, THO_slice, int(Config["InputConfig"]["OrgBCGUseFreq"]), + int(Config["InputConfig"]["ThoUseFreq"]), + use_custom_band=True, + low_cutoff=float(Config["Filter"]["BandPassLow"]), + high_cutoff=float(Config["Filter"]["BandPassHigh"]))) + else: + raise ValueError("模式不存在") + return BDR, band_low, band_high, bcg_spectrum, bcg_freq, tho_spectrum, tho_freq + + def save_resp_quality_label(self): + if (not Path(Config["Path"]["Save_Resp_quality_label"]).parent.exists()) or (not Path(Config["Path"]["Save_Resp_quality_label"]).parent.is_dir()): + Path(Config["Path"]["Save_Resp_quality_label"]).parent.mkdir(parents=True, exist_ok=True) + + if self.resp_quality_label is None: + + return Result().failure(info=ConfigParams.RESP_QUALITY_LABEL + Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + + try: + DataFrame(self.resp_quality_label).to_csv(Path(Config["Path"]["Save_Resp_quality_label"]), mode='w', index=False, header=False) + except Exception as e: + return Result().failure(info=ConfigParams.RESP_QUALITY_LABEL + Constants.SAVE_FAILURE + + Constants.FAILURE_REASON["Save_Exception"] + "\n" + format_exc()) + + return Result().success(info=ConfigParams.RESP_QUALITY_LABEL + Constants.SAVE_FINISHED) + + +class CustomNavigationToolbar(NavigationToolbar2QT): + + def __init__(self, canvas, parent): + super().__init__(canvas, parent) + # 初始化画框工具栏 + self.action_Label_Multiple = QAction(Constants.RESP_QUALITY_LABEL_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.RESP_QUALITY_LABEL_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_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/utils/ConfigParams.py b/func/utils/ConfigParams.py index 04582c6..404ada5 100644 --- a/func/utils/ConfigParams.py +++ b/func/utils/ConfigParams.py @@ -275,6 +275,7 @@ class ConfigParams: } } RESP_QUALITY_LABEL_PREPROCESS_FC: int = 1 + RESP_QUALITY_LABEL_PARTS_TIME_SEC: int = 30 RESP_QUALITY_LABEL_LABEL_TRANSPARENCY: float = 0.2 RESP_QUALITY_LABEL_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY: str = "Z" @@ -341,7 +342,7 @@ class ConfigParams: RESP_QUALITY_LABEL_INPUT_XINXIAO_DEFAULT_FS: int = 1000 RESP_QUALITY_LABEL_INPUT_THO_DEFAULT_FS: int = 200 - RESP_QUALITY_LABEL_PARTS_TIME_SEC: int = 30 + RESP_QUALITY_LABEL_THRESHOLD1_DEFAULT: float = 0.65 diff --git a/func/utils/Constants.py b/func/utils/Constants.py index ad4749a..f8a2a0e 100644 --- a/func/utils/Constants.py +++ b/func/utils/Constants.py @@ -103,7 +103,7 @@ class Constants: "Method_Not_Exist": "(检测方法不存在)", "Data_Length_not_Correct": "(orgBcg和BCG长度不匹配)", "Artifact_Format_Not_Correct": "(体动长度或格式不正确)", - "Get_Artifact_Format_Exception": "(获取体动长度或格式异常)", + "Data_Length_Not_Correct": "(信号长度不正确)", "Open_Data_Exception": "(打开数据异常)", "Process_Exception": "(处理异常)", @@ -132,6 +132,7 @@ class Constants: "Get_File_and_Freq_Excepetion": "(检查文件是否存在并获取其数据采样率异常)", "Update_tableWidget_Exception": "(更新表格异常)", "Update_Info_Exception": "(更新信息异常)", + "Get_Artifact_Format_Exception": "(获取体动长度或格式异常)", "Label_Format_Exception": "(获取标签格式异常)", "Calculate_Peak_Exception": "(计算峰值异常)", @@ -389,11 +390,45 @@ class Constants: RESP_QUALITY_LABEL_PLOT_LABEL_ARTIFACT: str = "Artifact" RESP_QUALITY_LABEL_SPECTRUM_BDR_TITLE: str = "Spectrum of BDR_sync by filter OrgBCG_Sync" RESP_QUALITY_LABEL_SPECTRUM_THO_TITLE: str = "Spectrum of THO_sync after preprocess" - RESP_QUALITY_LABEL_SPECTRUM_ORGBCG_LABEL: str = "orgBcg" + RESP_QUALITY_LABEL_SPECTRUM_ORGBCG_LABEL: str = "OrgBCG" RESP_QUALITY_LABEL_SPECTRUM_BDR_LABEL: str = "BDR" - RESP_QUALITY_LABEL_SPECTRUM_THO_LABEL: str = "THO" - + RESP_QUALITY_LABEL_SPECTRUM_THO_LABEL: str = "Tho" + RESP_QUALITY_LABEL_VIEWING_THE_FIRST_PART: str = "你正在查看第1段信号" + RESP_QUALITY_LABEL_VIEWING_THE_LAST_PART: str = "你正在查看最后1段信号" + RESP_QUALITY_LABEL_PREV_PART: str = "上一个片段,index " + RESP_QUALITY_LABEL_NEXT_PART: str = "下一个片段,index " + RESP_QUALITY_LABEL_JUMP: str = "跳转到片段,index " + RESP_QUALITY_LABEL_LABEL_SUCCESSFULLY: str = "片段标注成功" + RESP_QUALITY_LABEL_LABEL_TYPE: str = "标注类型为:" + RESP_QUALITY_LABEL_ADD_POINTS_SUCCESSFULLY: str = "成功新增点,横坐标:" + RESP_QUALITY_LABEL_REMOVE_POINTS_SUCCESSFULLY: str = "成功删除点,横坐标:" + RESP_QUALITY_LABEL_NO_POINT_IN_THE_INTERVAL: str = "所选区间内无新增或删除点" + RESP_QUALITY_LABEL_CUSTOM_FILTER_ARGS_ERROR: str = "OrgBCG带通滤波频率设置范围应为数字,范围是0~1" + RESP_QUALITY_LABEL_AUTOLABEL_ARGS_ERROR: str = "人工标注阈值设置范围应为数字,范围是0~1" + RESP_QUALITY_LABEL_CHECK_ARGS_QUESTION_CONTENT: str = "你确定要执行此操作吗,请确保参数输入正确" RESP_QUALITY_LABEL_ACTION_LABEL_MULTIPLE_NAME: str = f"批量更改标签({ConfigParams.RESP_QUALITY_LABEL_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY})" + RESP_QUALITY_LABEL_A_QUALITY: int = 1 + RESP_QUALITY_LABEL_B_QUALITY: int = 0 + RESP_QUALITY_LABEL_C_QUALITY: int = -1 + RESP_QUALITY_LABEL_KEY_VALUE = { + 1: "Good", + 0: "Bad", + -1: "None" + } + RESP_QUALITY_LABEL_FIGTOOLBAR_SPECTRUM_STYLESHEET: str = """ + QToolBar { + border: 1px; + spacing: 2px; /* 设置工具栏按钮之间的间距 */ + } + QToolButton { + height: 20px; /* 设置工具栏按钮的高度 */ + width: 20px; /* 设置工具栏按钮的宽度 */ + font-size: 8px; /* 设置按钮文字大小 */ + } + QToolButton::menu-button { + width: 0px; /* 隐藏下拉菜单按钮 */ + } + """ # 睡眠呼吸暂停事件标注 SA_LABEL_JUMP: str = "跳转到事件" @@ -483,52 +518,6 @@ class Constants: background-color: yellow; /* 鼠标悬停时的背景颜色 */ }""" - - # 呼吸可用性及间期标注 - RESP_QUALITY_LABEL_FILES_NOT_FOUND: str = f"无法找到{ConfigParams.RESP_QUALITY_LABEL_INPUT_XINXIAO_FILENAME}{ConfigParams.ENDSWITH_TXT}或{ConfigParams.RESP_QUALITY_LABEL_INPUT_THO_FILENAME}{ConfigParams.ENDSWITH_TXT}或{ConfigParams.RESP_QUALITY_LABEL_INPUT_ARTIFACT_FILENAME}{ConfigParams.ENDSWITH_TXT},无法执行<呼吸可用性及间期标注>" - RESP_QUALITY_LABEL_FILES_FOUND: str = f"找到{ConfigParams.RESP_QUALITY_LABEL_INPUT_XINXIAO_FILENAME}{ConfigParams.ENDSWITH_TXT}和{ConfigParams.RESP_QUALITY_LABEL_INPUT_THO_FILENAME}{ConfigParams.ENDSWITH_TXT}和{ConfigParams.RESP_QUALITY_LABEL_INPUT_ARTIFACT_FILENAME}{ConfigParams.ENDSWITH_TXT}" - RESP_QUALITY_LABEL_HISTORICAL_SAVE1_FOUND: str = f"找到历史存档文件{ConfigParams.RESP_QUALITY_LABEL_SAVE_RESP_QUALITY_LABNEL_FILENAME}{ConfigParams.ENDSWITH_TXT},已成功读取" - RESP_QUALITY_LABEL_HISTORICAL_SAVE2_FOUND: str = f"找到历史存档文件{ConfigParams.RESP_QUALITY_LABEL_SAVE_THO_PEAK_FILENAME}{ConfigParams.ENDSWITH_TXT},已成功读取" - RESP_QUALITY_LABEL_INPUT_SIGNAL_FAILURE: str = "导入信号失败,请检查信号长度" - RESP_QUALITY_LABEL_INPUT_SUCCESSFULLY: str = "导入数据成功" - RESP_QUALITY_LABEL_PREPROCESS_SUCCESSFULLY: str = "导入数据成功" - RESP_QUALITY_LABEL_INPUT_ARTIFACT_FAILURE_FORMAT: str = "导入体动失败,请检查体动标签格式" - RESP_QUALITY_LABEL_INPUT_ARTIFACT_FAILURE_LENGTH: str = "导入体动失败,请检查体动长度是否为4的倍数" - - RESP_QUALITY_LABEL_VIEWING_THE_FIRST_PART: str = "你正在查看第1段信号" - RESP_QUALITY_LABEL_VIEWING_THE_LAST_PART: str = "你正在查看最后1段信号" - RESP_QUALITY_LABEL_CUSTOM_NAVIGATIONTOOLBAR_WIDGET_NAME: str = "MainWindow" - RESP_QUALITY_LABEL_BUTTON_PRESS_EVENT: str = "button_press_event" - RESP_QUALITY_LABEL_BUTTON_RELEASE_EVENT: str = "button_release_event" - RESP_QUALITY_LABEL_MOTION_NOTIFY_EVENT: str = "motion_notify_event" - RESP_QUALITY_LABEL_ADD_POINTS_SUCCESSFULLY: str = "成功新增点,横坐标:" - RESP_QUALITY_LABEL_REMOVE_POINTS_SUCCESSFULLY: str = "成功删除点,横坐标:" - RESP_QUALITY_LABEL_NO_POINT_IN_THE_INTERVAL: str = "所选区间内无新增或删除点" - RESP_QUALITY_LABEL_SAVE_PEAKS_SUCCESSFULLY: str = "保存峰值成功" - RESP_QUALITY_LABEL_DATA_NOT_FOUND: str = "数据未导入" - RESP_QUALITY_LABEL_LABEL_SUCCESSFULLY: str = "片段标注并保存成功" - RESP_QUALITY_LABEL_RESET_SUCCESSFULLY: str = "片段重置并保存成功" - RESP_QUALITY_LABEL_PLOT_LABEL_VLINE: str = "vline" - RESP_QUALITY_LABEL_PLOT_LABEL_HLINE: str = "hline" - RESP_QUALITY_LABEL_A_QUALITY: int = 1 - RESP_QUALITY_LABEL_B_QUALITY: int = 0 - RESP_QUALITY_LABEL_C_QUALITY: int = -1 - RESP_QUALITY_LABEL_LABELED: str = "已标注" - RESP_QUALITY_LABEL_TOBELABELED: str = "未标注" - - RESP_QUALITY_LABEL_CUSTOM_FILTER_ARGS_ERROR: str = "orgBcg带通滤波频率设置范围应为数字,范围是0~1" - RESP_QUALITY_LABEL_AUTOLABEL_ARGS_ERROR: str = "人工标注阈值设置范围应为数字,范围是0~1" - RESP_QUALITY_LABEL_CHECK_ARGS_QUESTION_CONTENT: str = "你确定要执行此操作吗,请确保参数输入正确" - RESP_QUALITY_LABEL_KEY_VALUE = { - 1: "Good", - 0: "Bad", - -1: "None" - } - - - - - # 禁止实例化 def __new__(cls): raise TypeError("Constants class cannot be instantiated") diff --git a/ui/MainWindow/MainWindow_resp_quality_label.py b/ui/MainWindow/MainWindow_resp_quality_label.py index 4367465..146c77c 100644 --- a/ui/MainWindow/MainWindow_resp_quality_label.py +++ b/ui/MainWindow/MainWindow_resp_quality_label.py @@ -94,13 +94,13 @@ class Ui_MainWindow_resp_quality_label(object): self.gridLayout_5.addWidget(self.pushButton_calculate_peaks_save, 2, 0, 1, 1) - self.pushButton_input_data_and_label = QPushButton(self.groupBox_left) - self.pushButton_input_data_and_label.setObjectName(u"pushButton_input_data_and_label") - sizePolicy.setHeightForWidth(self.pushButton_input_data_and_label.sizePolicy().hasHeightForWidth()) - self.pushButton_input_data_and_label.setSizePolicy(sizePolicy) - self.pushButton_input_data_and_label.setFont(font1) + self.pushButton_input_and_label = QPushButton(self.groupBox_left) + self.pushButton_input_and_label.setObjectName(u"pushButton_input_and_label") + sizePolicy.setHeightForWidth(self.pushButton_input_and_label.sizePolicy().hasHeightForWidth()) + self.pushButton_input_and_label.setSizePolicy(sizePolicy) + self.pushButton_input_and_label.setFont(font1) - self.gridLayout_5.addWidget(self.pushButton_input_data_and_label, 0, 1, 3, 1) + self.gridLayout_5.addWidget(self.pushButton_input_and_label, 0, 1, 3, 1) self.verticalLayout_2.addLayout(self.gridLayout_5) @@ -135,14 +135,16 @@ class Ui_MainWindow_resp_quality_label(object): self.doubleSpinBox_quality_threshold1 = QDoubleSpinBox(self.groupBox_autoqualitylabel_options) self.doubleSpinBox_quality_threshold1.setObjectName(u"doubleSpinBox_quality_threshold1") self.doubleSpinBox_quality_threshold1.setFont(font1) - self.doubleSpinBox_quality_threshold1.setMaximum(10000.000000000000000) + self.doubleSpinBox_quality_threshold1.setMaximum(1.000000000000000) + self.doubleSpinBox_quality_threshold1.setSingleStep(0.100000000000000) self.gridLayout_3.addWidget(self.doubleSpinBox_quality_threshold1, 0, 1, 1, 1) self.doubleSpinBox_quality_threshold2 = QDoubleSpinBox(self.groupBox_autoqualitylabel_options) self.doubleSpinBox_quality_threshold2.setObjectName(u"doubleSpinBox_quality_threshold2") self.doubleSpinBox_quality_threshold2.setFont(font1) - self.doubleSpinBox_quality_threshold2.setMaximum(10000.000000000000000) + self.doubleSpinBox_quality_threshold2.setMaximum(1.000000000000000) + self.doubleSpinBox_quality_threshold2.setSingleStep(0.100000000000000) self.gridLayout_3.addWidget(self.doubleSpinBox_quality_threshold2, 1, 1, 1, 1) @@ -201,14 +203,16 @@ class Ui_MainWindow_resp_quality_label(object): self.doubleSpinBox_fillterMode_custom_low = QDoubleSpinBox(self.groupBox_threshold_setting) self.doubleSpinBox_fillterMode_custom_low.setObjectName(u"doubleSpinBox_fillterMode_custom_low") self.doubleSpinBox_fillterMode_custom_low.setFont(font1) - self.doubleSpinBox_fillterMode_custom_low.setMaximum(10000.000000000000000) + self.doubleSpinBox_fillterMode_custom_low.setMaximum(1.000000000000000) + self.doubleSpinBox_fillterMode_custom_low.setSingleStep(0.100000000000000) self.gridLayout_6.addWidget(self.doubleSpinBox_fillterMode_custom_low, 3, 1, 1, 1) self.doubleSpinBox_fillterMode_custom_high = QDoubleSpinBox(self.groupBox_threshold_setting) self.doubleSpinBox_fillterMode_custom_high.setObjectName(u"doubleSpinBox_fillterMode_custom_high") self.doubleSpinBox_fillterMode_custom_high.setFont(font1) - self.doubleSpinBox_fillterMode_custom_high.setMaximum(10000.000000000000000) + self.doubleSpinBox_fillterMode_custom_high.setMaximum(1.000000000000000) + self.doubleSpinBox_fillterMode_custom_high.setSingleStep(0.100000000000000) self.gridLayout_6.addWidget(self.doubleSpinBox_fillterMode_custom_high, 3, 3, 1, 1) @@ -229,6 +233,7 @@ class Ui_MainWindow_resp_quality_label(object): self.radioButton_orgBcg_fillterMode_preset = QRadioButton(self.groupBox_threshold_setting) self.radioButton_orgBcg_fillterMode_preset.setObjectName(u"radioButton_orgBcg_fillterMode_preset") self.radioButton_orgBcg_fillterMode_preset.setFont(font1) + self.radioButton_orgBcg_fillterMode_preset.setChecked(True) self.gridLayout_6.addWidget(self.radioButton_orgBcg_fillterMode_preset, 0, 0, 1, 1) @@ -471,7 +476,7 @@ class Ui_MainWindow_resp_quality_label(object): self.pushButton_calculate_peaks.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u8ba1\u7b97\u5cf0\u503c\u5e76\u7ed8\u5236", None)) self.pushButton_input_and_calculate_peaks.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u5bfc\u5165\u5e76\u7b97\u6cd5\u5b9a\u4f4d\u5cf0\u503c", None)) self.pushButton_calculate_peaks_save.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u4fdd\u5b58\u5cf0\u503c\u7ed3\u679c", None)) - self.pushButton_input_data_and_label.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u5bfc\u5165\u5e76\u5f00\u59cb\u6807\u6ce8", None)) + self.pushButton_input_and_label.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u5bfc\u5165\u5e76\u5f00\u59cb\u6807\u6ce8", None)) self.groupBox_autoqualitylabel_options.setTitle(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u4eba\u5de5\u6807\u6ce8\u9608\u503c\u8bbe\u7f6e", None)) self.label_6.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"threshold[1]", None)) self.label_5.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"threshold[0]", None)) diff --git a/ui/MainWindow/MainWindow_resp_quality_label.ui b/ui/MainWindow/MainWindow_resp_quality_label.ui index a0213a7..c65e326 100644 --- a/ui/MainWindow/MainWindow_resp_quality_label.ui +++ b/ui/MainWindow/MainWindow_resp_quality_label.ui @@ -122,7 +122,7 @@ - + 0 @@ -204,7 +204,10 @@ - 10000.000000000000000 + 1.000000000000000 + + + 0.100000000000000 @@ -216,7 +219,10 @@ - 10000.000000000000000 + 1.000000000000000 + + + 0.100000000000000 @@ -324,7 +330,10 @@ - 10000.000000000000000 + 1.000000000000000 + + + 0.100000000000000 @@ -336,7 +345,10 @@ - 10000.000000000000000 + 1.000000000000000 + + + 0.100000000000000 @@ -380,6 +392,9 @@ 预设 + + true + diff --git a/ui/setting/resp_quality_label_input_setting.py b/ui/setting/resp_quality_label_input_setting.py index b8f4b5d..fc6b9b3 100644 --- a/ui/setting/resp_quality_label_input_setting.py +++ b/ui/setting/resp_quality_label_input_setting.py @@ -100,10 +100,10 @@ class Ui_MainWindow_resp_quality_label_input_setting(object): self.verticalLayout_3.addLayout(self.horizontalLayout_3) - self.plainTextEdit_file_path_input_Tho = QPlainTextEdit(self.groupBox_file_path_input_Tho) - self.plainTextEdit_file_path_input_Tho.setObjectName(u"plainTextEdit_file_path_input_Tho") + self.plainTextEdit_file_path_input_signal_Tho = QPlainTextEdit(self.groupBox_file_path_input_Tho) + self.plainTextEdit_file_path_input_signal_Tho.setObjectName(u"plainTextEdit_file_path_input_signal_Tho") - self.verticalLayout_3.addWidget(self.plainTextEdit_file_path_input_Tho) + self.verticalLayout_3.addWidget(self.plainTextEdit_file_path_input_signal_Tho) self.verticalLayout_3.setStretch(0, 1) self.verticalLayout_3.setStretch(1, 2) @@ -181,8 +181,8 @@ class Ui_MainWindow_resp_quality_label_input_setting(object): self.plainTextEdit_file_path_input_signal_OrgBCG.setPlaceholderText(QCoreApplication.translate("MainWindow_resp_quality_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None)) self.groupBox_file_path_input_Tho.setTitle(QCoreApplication.translate("MainWindow_resp_quality_label_input_setting", u"\u540c\u6b65\u540e\u7684Effort Tho\u8def\u5f84", None)) self.label_3.setText(QCoreApplication.translate("MainWindow_resp_quality_label_input_setting", u"\u91c7\u6837\u7387(Hz)\uff1a", None)) - self.plainTextEdit_file_path_input_Tho.setPlainText("") - self.plainTextEdit_file_path_input_Tho.setPlaceholderText(QCoreApplication.translate("MainWindow_resp_quality_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None)) + self.plainTextEdit_file_path_input_signal_Tho.setPlainText("") + self.plainTextEdit_file_path_input_signal_Tho.setPlaceholderText(QCoreApplication.translate("MainWindow_resp_quality_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None)) self.groupBox_file_path_input_artifact.setTitle(QCoreApplication.translate("MainWindow_resp_quality_label_input_setting", u"\u4f53\u52a8Artifact_a\u8def\u5f84", None)) self.plainTextEdit_file_path_input_artifact.setPlainText("") self.plainTextEdit_file_path_input_artifact.setPlaceholderText(QCoreApplication.translate("MainWindow_resp_quality_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None)) diff --git a/ui/setting/resp_quality_label_input_setting.ui b/ui/setting/resp_quality_label_input_setting.ui index cb34972..9b91416 100644 --- a/ui/setting/resp_quality_label_input_setting.ui +++ b/ui/setting/resp_quality_label_input_setting.ui @@ -126,7 +126,7 @@ - +