From b9f9122a6524c045f654997ccaa1f5201ea1f0db Mon Sep 17 00:00:00 2001 From: Yorusora Date: Sat, 10 May 2025 19:45:57 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E5=AE=8C=E6=88=90<=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=B2=97=E5=90=8C=E6=AD=A5>=E7=9A=84=E5=85=A8=E9=83=A8?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=202=E3=80=81=E5=B0=86=E4=B8=9A=E5=8A=A1?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E7=BB=93=E6=9E=9C=E5=B0=81=E8=A3=85=E6=88=90?= =?UTF-8?q?=E4=BA=86=E4=B8=80=E4=B8=AAResult=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_approximately_align.py | 1095 +++++++++++++++++ func/Module_cut_PSG.py | 119 +- func/Module_detect_Jpeak.py | 146 +-- func/Module_detect_Rpeak.py | 140 +-- func/Module_label_check.py | 167 +-- func/Module_mainwindow.py | 9 + func/Module_precisely_align.py | 362 +++--- func/Module_preprocess.py | 108 +- func/utils/ConfigParams.py | 33 +- func/utils/Constants.py | 70 +- func/utils/Result.py | 48 + .../MainWindow_approximately_align.py | 550 +++++++++ .../MainWindow_approximately_align.ui | 803 ++++++++++++ ui/MainWindow/MainWindow_detect_Jpeak.py | 2 +- ui/MainWindow/MainWindow_detect_Jpeak.ui | 2 +- ui/MainWindow/MainWindow_detect_Rpeak.py | 2 +- ui/MainWindow/MainWindow_detect_Rpeak.ui | 2 +- ui/MainWindow/MainWindow_precisely_align.py | 2 +- ui/MainWindow/MainWindow_precisely_align.ui | 2 +- .../approximately_align_input_setting.py | 294 +++++ .../approximately_align_input_setting.ui | 411 +++++++ 数据结构化输入和输出命名规范.md | 3 +- 22 files changed, 3821 insertions(+), 549 deletions(-) create mode 100644 func/Module_approximately_align.py create mode 100644 func/utils/Result.py create mode 100644 ui/MainWindow/MainWindow_approximately_align.py create mode 100644 ui/MainWindow/MainWindow_approximately_align.ui create mode 100644 ui/setting/approximately_align_input_setting.py create mode 100644 ui/setting/approximately_align_input_setting.ui diff --git a/func/Module_approximately_align.py b/func/Module_approximately_align.py new file mode 100644 index 0000000..f48cea7 --- /dev/null +++ b/func/Module_approximately_align.py @@ -0,0 +1,1095 @@ +from gc import collect +from pathlib import Path + +import matplotlib.pyplot as plt +from PySide6.QtGui import QImage, QPixmap +from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication +from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas +from matplotlib.figure import Figure +from numba import prange, njit +from numpy import repeat, convolve, ones, mean, std, empty, int64, sum as np_sum, pad, zeros, array, argmax, linspace, \ + diff +from overrides import overrides +from pandas import read_csv, DataFrame +from scipy.signal import find_peaks, resample, butter, sosfiltfilt +from yaml import dump, load, FullLoader + +from func.utils.PublicFunc import PublicFunc +from func.utils.Constants import Constants, ConfigParams +from func.utils.Result import Result + +from ui.MainWindow.MainWindow_approximately_align import Ui_MainWindow_approximately_align +from ui.setting.approximately_align_input_setting import Ui_MainWindow_approximately_align_input_setting + + +Config = { + +} + +ButtonState = { + "Default": { + "pushButton_input_setting": True, + "pushButton_input": True, + "pushButton_Standardize": False, + "pushButton_CutOff": False, + "pushButton_GetPos": False, + "pushButton_JUMP": False, + "pushButton_EM1": False, + "pushButton_EM10": False, + "pushButton_EM100": False, + "pushButton_EP1": False, + "pushButton_EP10": False, + "pushButton_EP100": False, + "pushButton_save": False + }, + "Current": { + "pushButton_input_setting": True, + "pushButton_input": True, + "pushButton_Standardize": False, + "pushButton_CutOff": False, + "pushButton_GetPos": False, + "pushButton_JUMP": False, + "pushButton_EM1": False, + "pushButton_EM10": False, + "pushButton_EM100": False, + "pushButton_EP1": False, + "pushButton_EP10": False, + "pushButton_EP100": False, + "pushButton_save": False + } +} + + +class SettingWindow(QMainWindow): + + def __init__(self, root_path, sampID): + super(SettingWindow, self).__init__() + self.ui = Ui_MainWindow_approximately_align_input_setting() + self.ui.setupUi(self) + + self.root_path = root_path + self.sampID = sampID + + self.config = None + self.__read_config__() + + self.ui.spinBox_input_orgBcg_freq.valueChanged.connect(self.__update_ui__) + self.ui.spinBox_input_Tho_freq.valueChanged.connect(self.__update_ui__) + self.ui.spinBox_input_Abd_freq.valueChanged.connect(self.__update_ui__) + self.ui.spinBox_bandpassOrder.valueChanged.connect(self.__update_ui__) + self.ui.doubleSpinBox_bandpassLow.valueChanged.connect(self.__update_ui__) + self.ui.doubleSpinBox_bandpassHigh.valueChanged.connect(self.__update_ui__) + self.ui.spinBox_display_freq.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.APPROXIMATELY_ALIGN_CONFIG_FILE_PATH).exists(): + with open(ConfigParams.APPROXIMATELY_ALIGN_CONFIG_FILE_PATH, "w") as f: + dump(ConfigParams.APPROXIMATELY_ALIGN_CONFIG_NEW_CONTENT, f) + + with open(ConfigParams.APPROXIMATELY_ALIGN_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_TEXT / + Path(str(self.sampID)) / Path(ConfigParams.APPROXIMATELY_ALIGN_INPUT_ORGBCG_FILENAME + + str(Config["InputConfig"]["orgBcgFreq"]) + + ConfigParams.ENDSWITH_TXT))), + "Input_Tho": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / + Path(str(self.sampID)) / Path(ConfigParams.APPROXIMATELY_ALIGN_INPUT_THO_FILENAME + + str(Config["InputConfig"]["ThoFreq"]) + + ConfigParams.ENDSWITH_TXT))), + "Input_Abd": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / + Path(str(self.sampID)) / Path(ConfigParams.APPROXIMATELY_ALIGN_INPUT_ABD_FILENAME + + str(Config["InputConfig"]["AbdFreq"]) + + ConfigParams.ENDSWITH_TXT))), + "Save": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / + Path(str(self.sampID)) / Path(ConfigParams.APPROXIMATELY_ALIGN_SAVE_FILENAME + + ConfigParams.ENDSWITH_CSV))) + }, + "orgBcgConfig": {}, + "PSGConfig": {} + }) + + # 数据回显 + self.ui.spinBox_input_orgBcg_freq.setValue(Config["InputConfig"]["orgBcgFreq"]) + self.ui.spinBox_input_Tho_freq.setValue(Config["InputConfig"]["ThoFreq"]) + self.ui.spinBox_input_Abd_freq.setValue(Config["InputConfig"]["AbdFreq"]) + self.ui.spinBox_bandpassOrder.setValue(Config["Filter"]["BandPassOrder"]) + self.ui.doubleSpinBox_bandpassLow.setValue(Config["Filter"]["BandPassLow"]) + self.ui.doubleSpinBox_bandpassHigh.setValue(Config["Filter"]["BandPassHigh"]) + self.ui.spinBox_display_freq.setValue(Config["ApplyFrequency"]) + self.ui.plainTextEdit_file_path_input_orgBcg.setPlainText(Config["Path"]["Input_orgBcg"]) + self.ui.plainTextEdit_file_path_input_Tho.setPlainText(Config["Path"]["Input_Tho"]) + self.ui.plainTextEdit_file_path_input_Abd.setPlainText(Config["Path"]["Input_Abd"]) + self.ui.plainTextEdit_file_path_save.setPlainText(Config["Path"]["Save"]) + + def __write_config__(self): + # 从界面写入配置 + Config["InputConfig"]["orgBcgFreq"] = self.ui.spinBox_input_orgBcg_freq.value() + Config["InputConfig"]["ThoFreq"] = self.ui.spinBox_input_Tho_freq.value() + Config["InputConfig"]["AbdFreq"] = self.ui.spinBox_input_Abd_freq.value() + Config["ApplyFrequency"] = self.ui.spinBox_display_freq.value() + Config["Filter"]["BandPassOrder"] = self.ui.spinBox_bandpassOrder.value() + Config["Filter"]["BandPassLow"] = self.ui.doubleSpinBox_bandpassLow.value() + Config["Filter"]["BandPassHigh"] = self.ui.doubleSpinBox_bandpassHigh.value() + Config["Path"]["Input_orgBcg"] = self.ui.plainTextEdit_file_path_input_orgBcg.toPlainText() + Config["Path"]["Input_Tho"] = self.ui.plainTextEdit_file_path_input_Tho.toPlainText() + Config["Path"]["Input_Abd"] = self.ui.plainTextEdit_file_path_input_Abd.toPlainText() + Config["Path"]["Save"] = self.ui.plainTextEdit_file_path_save.toPlainText() + + # 保存配置到文件 + self.config["InputConfig"]["orgBcgFreq"] = self.ui.spinBox_input_orgBcg_freq.value() + self.config["InputConfig"]["ThoFreq"] = self.ui.spinBox_input_Tho_freq.value() + self.config["InputConfig"]["AbdFreq"] = self.ui.spinBox_input_Abd_freq.value() + self.config["ApplyFrequency"] = self.ui.spinBox_display_freq.value() + self.config["Filter"]["BandPassOrder"] = self.ui.spinBox_bandpassOrder.value() + self.config["Filter"]["BandPassLow"] = self.ui.doubleSpinBox_bandpassLow.value() + self.config["Filter"]["BandPassHigh"] = self.ui.doubleSpinBox_bandpassHigh.value() + + with open(ConfigParams.APPROXIMATELY_ALIGN_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_orgBcg.setPlainText( + str((Path(self.root_path) / + ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + Path(str(self.sampID)) / + Path(ConfigParams.APPROXIMATELY_ALIGN_INPUT_ORGBCG_FILENAME + + str(self.ui.spinBox_input_orgBcg_freq.value()) + + ConfigParams.ENDSWITH_TXT)))) + self.ui.plainTextEdit_file_path_input_Tho.setPlainText( + str((Path(self.root_path) / + ConfigParams.PUBLIC_PATH_PSG_TEXT / + Path(str(self.sampID)) / + Path(ConfigParams.APPROXIMATELY_ALIGN_INPUT_THO_FILENAME + + str(self.ui.spinBox_input_Tho_freq.value()) + + ConfigParams.ENDSWITH_TXT)))) + self.ui.plainTextEdit_file_path_input_Abd.setPlainText( + str((Path(self.root_path) / + ConfigParams.PUBLIC_PATH_PSG_TEXT / + Path(str(self.sampID)) / + Path(ConfigParams.APPROXIMATELY_ALIGN_INPUT_ABD_FILENAME + + str(self.ui.spinBox_input_Abd_freq.value()) + + ConfigParams.ENDSWITH_TXT)))) + self.ui.plainTextEdit_file_path_save.setPlainText( + str((Path(self.root_path) / + ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + Path(str(self.sampID)) / + Path(ConfigParams.APPROXIMATELY_ALIGN_SAVE_FILENAME + + ConfigParams.ENDSWITH_CSV)))) + + +class MainWindow_approximately_align(QMainWindow): + + def __init__(self): + super(MainWindow_approximately_align, self).__init__() + self.ui = Ui_MainWindow_approximately_align() + self.ui.setupUi(self) + + 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.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) + + PublicFunc.__resetAllButton__(self, ButtonState) + + self.ui.groupBox_align_position.setEnabled(False) + + self.ui.pushButton_input.clicked.connect(self.__slot_btn_input__) + self.ui.pushButton_input_setting.clicked.connect(self.setting.show) + self.ui.pushButton_Standardize.clicked.connect(self.__slot_btn_Standardize__) + self.ui.pushButton_CutOff.clicked.connect(self.__slot_btn_CutOff__) + self.ui.pushButton_GetPos.clicked.connect(self.__slot_btn_GetPosition__) + self.ui.pushButton_JUMP.clicked.connect(self.__slot_btn_jump__) + self.ui.pushButton_save.clicked.connect(self.__slot_btn_save__) + self.ui.pushButton_EM1.clicked.connect(self.__EpochChange__) + self.ui.pushButton_EM10.clicked.connect(self.__EpochChange__) + self.ui.pushButton_EM100.clicked.connect(self.__EpochChange__) + self.ui.pushButton_EP1.clicked.connect(self.__EpochChange__) + self.ui.pushButton_EP10.clicked.connect(self.__EpochChange__) + self.ui.pushButton_EP100.clicked.connect(self.__EpochChange__) + self.ui.radioButton_NTHO.clicked.connect(self.__enableAlign__) + self.ui.radioButton_PTHO.clicked.connect(self.__enableAlign__) + self.ui.radioButton_PABD.clicked.connect(self.__enableAlign__) + self.ui.radioButton_NABD.clicked.connect(self.__enableAlign__) + self.ui.radioButton_custom.clicked.connect(self.__enableAlign__) + + @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.data + plt.close() + self.deleteLater() + collect() + self.canvas = None + event.accept() + else: + event.ignore() + + def __reset__(self): + ButtonState["Current"].update(ButtonState["Default"].copy()) + ButtonState["Current"]["pushButton_Standardize"] = True + self.ui.label_Pic.clear() + self.ui.spinBox_PSGPreA.setValue(0) + self.ui.spinBox_PSGPreCut.setValue(0) + self.ui.spinBox_PSGPostCut.setValue(0) + self.ui.spinBox_orgBcgPreA.setValue(0) + self.ui.spinBox_orgBcgPreCut.setValue(0) + self.ui.spinBox_orgBcgPostCut.setValue(0) + self.ui.radioButton_NABD.setChecked(False) + self.ui.radioButton_NTHO.setChecked(False) + self.ui.radioButton_PABD.setChecked(False) + self.ui.radioButton_PTHO.setChecked(False) + self.ui.radioButton_custom.setChecked(False) + self.ui.spinBox_SelectEpoch.setValue(0) + self.ui.spinBox_custom.setValue(0) + self.ui.spinBox_SelectEpoch.setToolTip("") + self.ui.radioButton_PABD.setText("备选3") + self.ui.radioButton_PTHO.setText("备选1") + self.ui.radioButton_NABD.setText("备选4") + self.ui.radioButton_NTHO.setText("备选2") + self.ui.groupBox_align_position.setEnabled(False) + self.ui.spinBox_SelectEpoch.setMinimum(0) + + def __plot__(self, *args, **kwargs): + sender = self.sender() + result, buffer, width, height = None, None, None, None + try: + if sender == self.ui.pushButton_Standardize: + result, buffer, width, height = self.data.DrawPicRawOverview() + elif sender == self.ui.pushButton_CutOff: + result, buffer, width, height = self.data.DrawPicOverviewWithCutOff() + elif sender == self.ui.pushButton_GetPos: + result, buffer, width, height = self.data.DrawPicCorrelate(*args, **kwargs) + elif sender == self.ui.radioButton_NTHO: + result, buffer, width, height = self.data.DrawPicTryAlign() + elif sender == self.ui.radioButton_NABD: + result, buffer, width, height = self.data.DrawPicTryAlign() + elif sender == self.ui.radioButton_PTHO: + result, buffer, width, height = self.data.DrawPicTryAlign() + elif sender == self.ui.radioButton_PABD: + result, buffer, width, height = self.data.DrawPicTryAlign() + elif sender == self.ui.radioButton_custom: + result, buffer, width, height = self.data.DrawPicTryAlign() + elif sender == self.ui.pushButton_JUMP: + result, buffer, width, height = self.data.DrawPicByEpoch(*args, **kwargs) + elif sender == self.ui.pushButton_EM1: + result, buffer, width, height = self.data.DrawPicByEpoch(*args, **kwargs) + elif sender == self.ui.pushButton_EM10: + result, buffer, width, height = self.data.DrawPicByEpoch(*args, **kwargs) + elif sender == self.ui.pushButton_EM100: + result, buffer, width, height = self.data.DrawPicByEpoch(*args, **kwargs) + elif sender == self.ui.pushButton_EP1: + result, buffer, width, height = self.data.DrawPicByEpoch(*args, **kwargs) + elif sender == self.ui.pushButton_EP10: + result, buffer, width, height = self.data.DrawPicByEpoch(*args, **kwargs) + elif sender == self.ui.pushButton_EP100: + result, buffer, width, height = self.data.DrawPicByEpoch(*args, **kwargs) + except Exception: + return Result().failure(info=Constants.DRAWING_FAILURE) + + if result is not None and buffer is not None and width is not None and height is not None: + # 显示到labelPic上 + img = QImage(buffer, width, height, QImage.Format_RGBA8888) + self.ui.label_Pic.setPixmap(QPixmap(img)) + return result + else: + return Result().failure(info=Constants.DRAWING_FAILURE) + + def __slot_btn_input__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + + self.data = Data() + + # 导入数据 + PublicFunc.progressbar_update(self, 1, 3, Constants.INPUTTING_DATA, 0) + result = self.data.open_file() + 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) + + orgBcg_minutes = round(self.data.raw_orgBcg.shape[0] / Config["InputConfig"]["orgBcgFreq"] / 60) + PSG_minutes = round(self.data.raw_Tho.shape[0] / Config["InputConfig"]["ThoFreq"] / 60) + Config.update({ + "orgBcg_minutes": orgBcg_minutes, + "PSG_minutes": PSG_minutes + }) + self.ui.label_orgBcg_length.setText(str(orgBcg_minutes)) + self.ui.label_PSG_length.setText(str(PSG_minutes)) + self.__reset__() + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_save__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + + # 保存对齐信息 + PublicFunc.progressbar_update(self, 1, 1, Constants.SAVING_DATA, 0) + epoch = self.ui.spinBox_SelectEpoch.value() + result = self.data.save(epoch) + 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_Standardize__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + + Config["RawSignal"] = self.ui.checkBox_RawSignal.isChecked() + Config["orgBcgConfig"].update({ + "orgBcgDelBase": self.ui.checkBox_orgBcgDelBase.isChecked(), + "orgBcgZScore": self.ui.checkBox_orgBcgZScore.isChecked() + }) + Config["PSGConfig"].update({ + "PSGDelBase": self.ui.checkBox_PSGDelBase.isChecked(), + "PSGZScore": self.ui.checkBox_PSGZScore.isChecked() + }) + + if Config["RawSignal"]: + # 仅重采样 + PublicFunc.progressbar_update(self, 1, 1, Constants.APPROXIMATELY_ONLY_ALIGN_RESAMPLING, 0) + result = self.data.Standardize_0() + 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) + else: + # 呼吸提取 + PublicFunc.progressbar_update(self, 1, 5, Constants.APPROXIMATELY_RESP_GETTING, 0) + result = self.data.Standardize_1() + if not result.status: + PublicFunc.text_output(self.ui, "(1/5)" + 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/5)" + result.info, Constants.TIPS_TYPE_INFO) + + # 预重采样 + PublicFunc.progressbar_update(self, 2, 5, Constants.APPROXIMATELY_PRE_ALIGN_RESAMPLING, 20) + result = self.data.Standardize_2() + if not result.status: + PublicFunc.text_output(self.ui, "(2/5)" + 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/5)" + result.info, Constants.TIPS_TYPE_INFO) + + # 去基线 + PublicFunc.progressbar_update(self, 3, 5, Constants.APPROXIMATELY_DELETING_BASE, 40) + result = self.data.Standardize_3() + if not result.status: + PublicFunc.text_output(self.ui, "(3/5)" + 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/5)" + result.info, Constants.TIPS_TYPE_INFO) + + # 标准化 + PublicFunc.progressbar_update(self, 4, 5, Constants.APPROXIMATELY_STANDARDIZING, 60) + result = self.data.Standardize_4() + if not result.status: + PublicFunc.text_output(self.ui, "(4/5)" + 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/5)" + result.info, Constants.TIPS_TYPE_INFO) + + # 重采样 + PublicFunc.progressbar_update(self, 5, 5, Constants.APPROXIMATELY_ALIGN_RESAMPLING, 80) + result = self.data.Standardize_5() + if not result.status: + PublicFunc.text_output(self.ui, "(5/5)" + 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/5)" + result.info, Constants.TIPS_TYPE_INFO) + + self.__plot__() + ButtonState["Current"]["pushButton_CutOff"] = True + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_CutOff__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + + Config["orgBcgConfig"].update({"PreA": self.ui.spinBox_orgBcgPreA.value(), + "PreCut": self.ui.spinBox_orgBcgPreCut.value(), + "PostCut": self.ui.spinBox_orgBcgPostCut.value()}) + Config["PSGConfig"].update({"PreA": self.ui.spinBox_PSGPreA.value(), + "PreCut": self.ui.spinBox_PSGPreCut.value(), + "PostCut": self.ui.spinBox_PSGPostCut.value()}) + + PublicFunc.progressbar_update(self, 1, 1, Constants.DRAWING_DATA, 0) + result = self.__plot__() + 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) + + ButtonState["Current"]["pushButton_GetPos"] = True + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_GetPosition__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + + # 计算互相关1/2 + PublicFunc.progressbar_update(self, 1, 4, Constants.APPROXIMATELY_CORRELATION_CALCULATING1, 0) + result1 = self.data.calculate_correlation1() + if not result1.status: + PublicFunc.text_output(self.ui, "(1/4)" + result1.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result1.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(1/4)" + result1.info, Constants.TIPS_TYPE_INFO) + + # 计算互相关2/2 + PublicFunc.progressbar_update(self, 2, 4, Constants.APPROXIMATELY_CORRELATION_CALCULATING2, 25) + result2 = self.data.calculate_correlation2() + if not result2.status: + PublicFunc.text_output(self.ui, "(2/4)" + result2.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result2.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(2/4)" + result2.info, Constants.TIPS_TYPE_INFO) + + # 绘图 + PublicFunc.progressbar_update(self, 3, 4, Constants.DRAWING_DATA, 50) + result = self.__plot__(result1.data["tho_relate"], result1.data["tho_relate2"], result2.data["abd_relate"], result2.data["abd_relate2"]) + if not result.status: + PublicFunc.text_output(self.ui, "(3/4)" + 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/4)" + result.info, Constants.TIPS_TYPE_INFO) + + # 计算最大值位置 + PublicFunc.progressbar_update(self, 4, 4, Constants.APPROXIMATELY_MAXVALUE_POS_CALCULATING, 90) + result = self.data.calculate_maxvalue_pos(result1.data["tho_relate"], result1.data["tho_relate2"], result2.data["abd_relate"], result2.data["abd_relate2"]) + if not result.status: + PublicFunc.text_output(self.ui, "(4/4)" + 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/4)" + result.info, Constants.TIPS_TYPE_INFO) + + self.ui.radioButton_PABD.setText(str(result.data["abd_max"] + result.data["bias"])) + self.ui.radioButton_PTHO.setText(str(result.data["tho_max"] + result.data["bias"])) + self.ui.radioButton_NABD.setText(str(result.data["abd_max2"] + result.data["bias"])) + self.ui.radioButton_NTHO.setText(str(result.data["tho_max2"] + result.data["bias"])) + self.ui.groupBox_align_position.setEnabled(True) + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_jump__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + + epoch = self.ui.spinBox_SelectEpoch.value() + + # 绘图 + PublicFunc.progressbar_update(self, 1, 1, Constants.DRAWING_DATA, 0) + result = self.__plot__(epoch=epoch) + 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.finish_operation(self, ButtonState) + + def __EpochChange__(self): + # 获取当前值 + value = self.ui.spinBox_SelectEpoch.value() + # 判断按键 + if self.sender() == self.ui.pushButton_EM1: + epoch = max(self.ui.spinBox_SelectEpoch.minimum(), value - 1) + elif self.sender() == self.ui.pushButton_EM10: + epoch = max(self.ui.spinBox_SelectEpoch.minimum(), value - 10) + elif self.sender() == self.ui.pushButton_EM100: + epoch = max(self.ui.spinBox_SelectEpoch.minimum(), value - 100) + elif self.sender() == self.ui.pushButton_EP1: + epoch = min(self.ui.spinBox_SelectEpoch.maximum(), value + 1) + elif self.sender() == self.ui.pushButton_EP10: + epoch = min(self.ui.spinBox_SelectEpoch.maximum(), value + 10) + elif self.sender() == self.ui.pushButton_EP100: + epoch = min(self.ui.spinBox_SelectEpoch.maximum(), value + 100) + else: + return + self.ui.spinBox_SelectEpoch.setValue(epoch) + QApplication.processEvents() + self.__slot_btn_jump__() + + def __enableAlign__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + + if self.ui.radioButton_NTHO.isChecked(): + relate = int(self.ui.radioButton_NTHO.text()) + reverse = -1 + elif self.ui.radioButton_PTHO.isChecked(): + relate = int(self.ui.radioButton_PTHO.text()) + reverse = 1 + elif self.ui.radioButton_PABD.isChecked(): + relate = int(self.ui.radioButton_PABD.text()) + reverse = 1 + elif self.ui.radioButton_NABD.isChecked(): + relate = int(self.ui.radioButton_NABD.text()) + reverse = -1 + elif self.ui.radioButton_custom.isChecked(): + relate = int(self.ui.spinBox_custom.value()) + reverse = 1 + else: + return + # 最大相关系数值相对于PSG的位置 + Config.update({"pos": relate}) + # 设置epoch上下限 + Config.update({"orgBcg_reverse": reverse}) + PublicFunc.text_output(self.ui, "相对位置:{}".format(Config["pos"]), Constants.TIPS_TYPE_INFO) + + # 获取epoch + PublicFunc.progressbar_update(self, 1, 2, Constants.APPROXIMATELY_MAXVALUE_POS_CALCULATING, 0) + result3 = self.data.get_epoch() + if not result3.status: + PublicFunc.text_output(self.ui, "(1/2)" + result3.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result3.info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(1/2)" + result3.info, Constants.TIPS_TYPE_INFO) + + # 绘图 + PublicFunc.progressbar_update(self, 2, 2, Constants.DRAWING_DATA, 30) + 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) + + self.ui.spinBox_SelectEpoch.setMinimum(result3.data["epoch_min"]) + self.ui.spinBox_SelectEpoch.setMaximum(result3.data["epoch_max"]) + self.ui.spinBox_SelectEpoch.setValue(result3.data["epoch_min"]) + self.ui.spinBox_SelectEpoch.setToolTip("最小值:{}\n最大值:{}".format(result3.data["epoch_min"], result3.data["epoch_max"])) + self.ui.spinBox_SelectEpoch.setEnabled(True) + ButtonState["Current"]["pushButton_JUMP"] = True + ButtonState["Current"]["pushButton_EM1"] = True + ButtonState["Current"]["pushButton_EM10"] = True + ButtonState["Current"]["pushButton_EM100"] = True + ButtonState["Current"]["pushButton_EP1"] = True + ButtonState["Current"]["pushButton_EP10"] = True + ButtonState["Current"]["pushButton_EP100"] = True + ButtonState["Current"]["pushButton_save"] = True + PublicFunc.finish_operation(self, ButtonState) + + +class Data: + + def __init__(self): + self.raw_orgBcg = None + self.raw_Tho = None + self.raw_Abd = None + self.processed_orgBcg = None + self.processed_Tho = None + self.processed_Abd = None + + def open_file(self): + if ((not Path(Config["Path"]["Input_orgBcg"]).exists()) + or (not Path(Config["Path"]["Input_Tho"]).exists()) + or (not Path(Config["Path"]["Input_Abd"]).exists())): + return Result().failure(info=Constants.INPUT_FAILURE + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON["Data_Path_Not_Exist"]) + + try: + self.raw_orgBcg = read_csv(Config["Path"]["Input_orgBcg"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + self.raw_Tho = read_csv(Config["Path"]["Input_Tho"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + self.raw_Abd = read_csv(Config["Path"]["Input_Abd"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + except Exception: + return Result().failure(info=Constants.INPUT_FAILURE + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON["Read_Data_Exception"]) + + return Result().success(info=Constants.INPUT_FINISHED) + + def save(self, epoch): + try: + pos = Config["pos"] + ApplyFrequency = Config["ApplyFrequency"] + # 保存到csv中 + df = DataFrame({"pos": [pos], "epoch": [epoch], "ApplyFrequency": [ApplyFrequency]}) + df.to_csv(Path(Config["Path"]["Save"]), mode="w", header=True, index=False) + except Exception: + return Result().failure(info=Constants.SAVING_FAILURE + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON["Save_Exception"]) + + return Result().success(info=Constants.SAVING_FINISHED) + + def Standardize_0(self): + # 仅重采样 + if self.raw_orgBcg is None or self.raw_Tho is None or self.raw_Abd is None: + return Result().failure(info=Constants.APPROXIMATELY_ONLY_ALIGN_RESAMPLE_FAILURE + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON["Raw_Data_Not_Exist"]) + try: + self.processed_orgBcg = resample(self.raw_orgBcg, int(Config["orgBcg_minutes"] * 60 * Config["ApplyFrequency"])) + self.processed_Tho = resample(self.raw_Tho, int(Config["PSG_minutes"] * 60 * Config["ApplyFrequency"])) + self.processed_Abd = resample(self.raw_Abd, int(Config["PSG_minutes"] * 60 * Config["ApplyFrequency"])) + except Exception: + return Result().failure(info=Constants.APPROXIMATELY_ONLY_ALIGN_RESAMPLE_FAILURE + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON["Only_Resample_Exception"]) + + return Result().success(info=Constants.APPROXIMATELY_ONLY_ALIGN_RESAMPLE_FINISHED) + + def Standardize_1(self): + # 呼吸提取 + def butter_bandpass_filter(data, lowCut, highCut, fs, order): + low = lowCut / (fs * 0.5) + high = highCut / (fs * 0.5) + sos = butter(order, [low, high], btype="bandpass", output='sos') + return sosfiltfilt(sos, data) + if self.raw_orgBcg is None or self.raw_Tho is None or self.raw_Abd is None: + return Result().failure(info=Constants.APPROXIMATELY_ONLY_ALIGN_RESAMPLE_FAILURE + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON["Raw_Data_Not_Exist"]) + try: + # 滤波 + self.processed_orgBcg = butter_bandpass_filter(self.raw_orgBcg, Config["Filter"]["BandPassLow"], + Config["Filter"]["BandPassHigh"], + Config["InputConfig"]["orgBcgFreq"], + Config["Filter"]["BandPassOrder"]) + self.processed_Tho = butter_bandpass_filter(self.raw_Tho, Config["Filter"]["BandPassLow"], + Config["Filter"]["BandPassHigh"], + Config["InputConfig"]["ThoFreq"], + Config["Filter"]["BandPassOrder"]) + self.processed_Abd = butter_bandpass_filter(self.raw_Abd, Config["Filter"]["BandPassLow"], + Config["Filter"]["BandPassHigh"], + Config["InputConfig"]["AbdFreq"], + Config["Filter"]["BandPassOrder"]) + except Exception: + return Result().failure(info=Constants.APPROXIMATELY_RESP_GET_FAILURE + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON["Resp_Get_Exception"]) + + return Result().success(info=Constants.APPROXIMATELY_RESP_GET_FINISHED) + + def Standardize_2(self): + # 预重采样 + try: + # 如果orgBcg采样率大于PSG采样率,那么orgBcg重采样到PSG采样率 + if Config["InputConfig"]["orgBcgFreq"] > Config["InputConfig"]["ThoFreq"]: + # 用[::]完成 + self.processed_orgBcg = self.processed_orgBcg[::int(Config["InputConfig"]["orgBcgFreq"] / Config["InputConfig"]["ThoFreq"])] + # 如果orgBcg采样率小于PSG采样率,那么orgBcg重采样到PSG采样率 + elif Config["InputConfig"]["orgBcgFreq"] < Config["InputConfig"]["ThoFreq"] < 100: + # 用repeat完成 + self.processed_orgBcg = repeat(self.processed_orgBcg, int(Config["InputConfig"]["ThoFreq"] / Config["InputConfig"]["orgBcgFreq"]), axis=0) + # 修改Config + Config.update({"TempFrequency": Config["InputConfig"]["ThoFreq"]}) + except Exception: + return Result().failure(info=Constants.APPROXIMATELY_PRE_ALIGN_RESAMPLE_FAILURE + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON["Pre_Resample_Exception"]) + + return Result().success(info=Constants.APPROXIMATELY_PRE_ALIGN_RESAMPLE_FINISHED) + + def Standardize_3(self): + # 去基线 + try: + temp_frequency = Config["TempFrequency"] + if Config["PSGConfig"]["PSGDelBase"]: + # 减去四秒钟平均滤波 + self.processed_Tho = self.processed_Tho - convolve(self.processed_Tho, + ones(int(4 * temp_frequency)) / int(4 * temp_frequency), + mode='same') + self.processed_Abd = self.processed_Abd - convolve(self.processed_Abd, + ones(int(4 * temp_frequency)) / int(4 * temp_frequency), + mode='same') + if Config["orgBcgConfig"]["orgBcgDelBase"]: + self.processed_orgBcg = self.processed_orgBcg - convolve(self.processed_orgBcg, + ones(int(4 * temp_frequency)) / int(4 * temp_frequency), + mode='same') + except Exception: + return Result().failure(info=Constants.APPROXIMATELY_DELETE_BASE_FAILURE + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON["Delete_Base_Exception"]) + + return Result().success(info=Constants.APPROXIMATELY_DELETE_BASE_FINISHED) + + def Standardize_4(self): + # 标准化 + try: + # 判断是否标准化 + if Config["PSGConfig"]["PSGZScore"]: + self.processed_Tho = (self.processed_Tho - mean(self.processed_Tho)) / std(self.processed_Tho) + self.processed_Abd = (self.processed_Abd - mean(self.processed_Abd)) / std(self.processed_Abd) + if Config["orgBcgConfig"]["orgBcgZScore"]: + self.processed_orgBcg = (self.processed_orgBcg - mean(self.processed_orgBcg)) / std(self.processed_orgBcg) + except Exception: + return Result().failure(info=Constants.APPROXIMATELY_STANDARDIZE_FAILURE + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON["Standardize_Exception"]) + + return Result().success(info=Constants.APPROXIMATELY_STANDARDIZE_FINISHED) + + def Standardize_5(self): + # 重采样 + try: + # 用[::]完成 + temp_frequency = Config["TempFrequency"] + self.processed_Tho = self.processed_Tho[::int(temp_frequency / Config["ApplyFrequency"])] + self.processed_Abd = self.processed_Abd[::int(temp_frequency / Config["ApplyFrequency"])] + self.processed_orgBcg = self.processed_orgBcg[::int(temp_frequency / Config["ApplyFrequency"])] + except Exception: + return Result().failure(info=Constants.APPROXIMATELY_ALIGN_RESAMPLE_FAILURE + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON["Resample_Exception"]) + + return Result().success(info=Constants.APPROXIMATELY_ALIGN_RESAMPLE_FINISHED) + + def calculate_correlation1(self): + # 计算互相关1/2 + try: + a = self.processed_Tho[Config["PSGConfig"]["PreCut"]:len(self.processed_Tho) - Config["PSGConfig"]["PostCut"]].copy() + v = self.processed_orgBcg[Config["orgBcgConfig"]["PreCut"]:len(self.processed_orgBcg) - Config["orgBcgConfig"]["PostCut"]].copy() + a *= 100 + v *= 100 + a = a.astype(int64) + v = v.astype(int64) + a = pad(a, (len(v) - 1, len(v) - 1), mode='constant') + tho_relate = zeros(len(a) - len(v) - 1, dtype=int64) + len_calc = len(a) - len(v) - 1 + # 将序列分成一百份来计算 + for i in range(100): + tho_relate[i * len_calc // 100:(i + 1) * len_calc // 100] = Data.get_Correlate(a, v, array( + [i * len_calc // 100, (i + 1) * len_calc // 100])) + tho_relate = tho_relate / 10000 + tho_relate2 = - tho_relate + + result = {"tho_relate": tho_relate, "tho_relate2": tho_relate2} + except Exception: + return Result().failure(info=Constants.APPROXIMATELY_CORRELATION_CALCULATE1_FAILURE + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON["Calculate_Correlation1_Exception"]) + + return Result().success(info=Constants.APPROXIMATELY_CORRELATION_CALCULATE1_FINISHED, data=result) + + def calculate_correlation2(self): + # 计算互相关2/2 + try: + a = self.processed_Abd[Config["PSGConfig"]["PreCut"]:len(self.processed_Abd) - Config["PSGConfig"]["PostCut"]].copy() + v = self.processed_orgBcg[Config["orgBcgConfig"]["PreCut"]:len(self.processed_orgBcg) - Config["orgBcgConfig"]["PostCut"]].copy() + a *= 100 + v *= 100 + a = a.astype(int64) + v = v.astype(int64) + a = pad(a, (len(v) - 1, len(v) - 1), mode='constant') + + abd_relate = zeros(len(a) - len(v) - 1, dtype=int64) + len_calc = len(a) - len(v) - 1 + # 将序列分成一百份来计算 + for i in range(100): + abd_relate[i * len_calc // 100:(i + 1) * len_calc // 100] = Data.get_Correlate(a, v, array( + [i * len_calc // 100, (i + 1) * len_calc // 100])) + abd_relate = abd_relate / 10000 + abd_relate2 = - abd_relate + + result = {"abd_relate": abd_relate, "abd_relate2": abd_relate2} + except Exception: + return Result().failure(info=Constants.APPROXIMATELY_CORRELATION_CALCULATE2_FAILURE + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON["Calculate_Correlation2_Exception"]) + + return Result().success(info=Constants.APPROXIMATELY_CORRELATION_CALCULATE2_FINISHED, data=result) + + def calculate_maxvalue_pos(self, tho_relate, tho_relate2, abd_relate, abd_relate2): + # 计算最大值位置 + try: + tho_max = argmax(tho_relate) + tho_max2 = argmax(tho_relate2) + abd_max = argmax(abd_relate) + abd_max2 = argmax(abd_relate2) + pre = Config["PSGConfig"]["PreCut"] + Config["orgBcgConfig"]["PostCut"] + + bias = pre - len(self.processed_orgBcg) + 1 + + result = {"tho_max": tho_max, "tho_max2": tho_max2, "abd_max": abd_max, "abd_max2": abd_max2, "bias": bias} + except Exception: + return Result().failure(info=Constants.APPROXIMATELY_MAXVALUE_POS_CALCULATE_FAILURE + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON["Calculate_Maxvalue_Pos_Exception"]) + + return Result().success(info=Constants.APPROXIMATELY_MAXVALUE_POS_CALCULATE_FINISHED, data=result) + + def get_epoch(self): + # 获取epoch + try: + epoch_min = max(0, Config["pos"] // 30 // Config["ApplyFrequency"] + 1) + epoch_max = min(len(self.processed_Tho) // 30 // Config["ApplyFrequency"] - 1, + (len(self.processed_orgBcg) + Config["pos"]) // 30 // Config["ApplyFrequency"] - 1) + + result = {"epoch_min": epoch_min, "epoch_max": epoch_max} + except Exception: + return Result().failure(info=Constants.APPROXIMATELY_EPOCH_GET_FAILURE + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON["Get_Epoch_Exception"]) + + return Result().success(info=Constants.APPROXIMATELY_EPOCH_GET_FINISHED, data=result) + + def DrawPicRawOverview(self): + try: + fig = Figure(figsize=(12, 10), dpi=100) + canvas = FigureCanvas(fig) + max_x = max(self.processed_Tho.shape[0], self.processed_Abd.shape[0], self.processed_orgBcg.shape[0]) + ax1 = fig.add_subplot(311) + ax1.plot(self.processed_Tho, color='blue') + ax1.set_xlim(0, max_x) + ax1.set_title("THO") + + ax2 = fig.add_subplot(312) + ax2.plot(self.processed_orgBcg, color='blue') + ax2.set_xlim(0, max_x) + ax2.set_title("orgBcg") + + ax3 = fig.add_subplot(313) + ax3.plot(self.processed_Abd, color='blue') + ax3.set_xlim(0, max_x) + ax3.set_title("ABD") + + width, height = fig.figbbox.width, fig.figbbox.height + fig.canvas.draw() + except Exception: + return Result().failure(info=Constants.DRAWING_FAILURE) + # 返回图片以便存到QPixImage + return Result().success(info=Constants.DRAWING_FINISHED), canvas.buffer_rgba(), width, height + + def DrawPicOverviewWithCutOff(self): + try: + fig = Figure(figsize=(12, 10), dpi=100) + canvas = FigureCanvas(fig) + max_x = max(self.processed_Tho.shape[0] + Config["PSGConfig"]["PreA"], + self.processed_orgBcg.shape[0] + Config["orgBcgConfig"]["PreA"]) + min_x = min(Config["PSGConfig"]["PreA"], Config["orgBcgConfig"]["PreA"], 0) + ax1 = fig.add_subplot(311) + ax1.plot( + linspace(Config["PSGConfig"]["PreA"], + len(self.processed_Tho) + Config["PSGConfig"]["PreA"], + len(self.processed_Tho)), self.processed_Tho, color='blue') + # 绘制x = PreCut的线 和 x = PostCut的虚线 + ax1.axvline(x=Config["PSGConfig"]["PreCut"] + Config["PSGConfig"]["PreA"], color='red', + linestyle='--') + ax1.axvline( + x=len(self.processed_Tho) - Config["PSGConfig"]["PostCut"] + Config["PSGConfig"]["PreA"], + color='red', linestyle='--') + + ax1.set_xlim(min_x, max_x) + ax1.set_title("THO") + + ax2 = fig.add_subplot(312) + ax2.plot( + linspace(Config["orgBcgConfig"]["PreA"], len(self.processed_orgBcg) + Config["orgBcgConfig"]["PreA"], + len(self.processed_orgBcg)), self.processed_orgBcg, color='blue') + ax2.axvline(x=Config["orgBcgConfig"]["PreCut"] + Config["orgBcgConfig"]["PreA"], color='red', + linestyle='--') + ax2.axvline(x=len(self.processed_orgBcg) - Config["orgBcgConfig"]["PostCut"] + Config["orgBcgConfig"]["PreA"], + color='red', linestyle='--') + ax2.set_xlim(min_x, max_x) + ax2.set_title("orgBcg") + + ax3 = fig.add_subplot(313) + ax3.plot( + linspace(Config["PSGConfig"]["PreA"], + len(self.processed_Abd) + Config["PSGConfig"]["PreA"], + len(self.processed_Abd)), self.processed_Abd, color='blue') + ax3.axvline(x=Config["PSGConfig"]["PreCut"] + Config["PSGConfig"]["PreA"], color='red', + linestyle='--') + ax3.axvline( + x=len(self.processed_Tho) - Config["PSGConfig"]["PostCut"] + Config["PSGConfig"]["PreA"], + color='red', linestyle='--') + ax3.set_xlim(min_x, max_x) + ax3.set_title("ABD") + + width, height = fig.figbbox.width, fig.figbbox.height + fig.canvas.draw() + except Exception: + return Result().failure(info=Constants.DRAWING_FAILURE) + # 返回图片以便存到QPixImage + return Result().success(info=Constants.DRAWING_FINISHED), canvas.buffer_rgba(), width, height + + def DrawPicCorrelate(self, tho_pxx, tho_nxx, abd_pxx, abd_nxx): + try: + fig = Figure(figsize=(12, 10), dpi=100) + canvas = FigureCanvas(fig) + ax1 = fig.add_subplot(221) + ax1.plot(tho_pxx, color='blue') + ax1.set_title("The Correlation of THO and orgBcg") + + ax2 = fig.add_subplot(222) + ax2.plot(tho_nxx, color='blue') + ax2.set_title("The Correlation of THO and Reverse orgBcg") + + ax3 = fig.add_subplot(223) + ax3.plot(abd_pxx, color='blue') + ax3.set_title("The Correlation of ABD and orgBcg") + + ax4 = fig.add_subplot(224) + ax4.plot(abd_nxx, color='blue') + ax4.set_title("The Correlation of ABD and Reverse orgBcg") + + width, height = fig.figbbox.width, fig.figbbox.height + fig.canvas.draw() + except Exception: + return Result().failure(info=Constants.DRAWING_FAILURE) + # 返回图片以便存到QPixImage + return Result().success(info=Constants.DRAWING_FINISHED), canvas.buffer_rgba(), width, height + + def DrawPicTryAlign(self): + try: + fig = Figure(figsize=(12, 10), dpi=100) + canvas = FigureCanvas(fig) + max_x = max(self.processed_Tho.shape[0], + self.processed_orgBcg.shape[0] + Config["pos"]) + min_x = min(Config["PSGConfig"]["PreA"], Config["orgBcgConfig"]["PreA"] + Config["pos"], 0) + + ax1 = fig.add_subplot(311) + ax1.plot( + linspace(0, len(self.processed_Tho), + len(self.processed_Tho)), self.processed_Tho, color='blue') + # 绘制x = PreCut的线 和 x = PostCut的虚线 + ax1.set_xlim(min_x, max_x) + ax1.set_title("THO") + + ax2 = fig.add_subplot(312) + ax2.plot(linspace(Config["pos"], + len(self.processed_orgBcg) + Config["pos"], + len(self.processed_orgBcg)), self.processed_orgBcg, color='blue') + ax2.set_xlim(min_x, max_x) + ax2.set_title("orgBcg") + + ax3 = fig.add_subplot(313) + ax3.plot( + linspace(0, len(self.processed_Abd), + len(self.processed_Abd)), self.processed_Abd, color='blue') + ax3.set_xlim(min_x, max_x) + ax3.set_title("ABD") + + width, height = fig.figbbox.width, fig.figbbox.height + fig.canvas.draw() + except Exception: + return Result().failure(info=Constants.DRAWING_FAILURE) + # 返回图片以便存到QPixImage + return Result().success(info=Constants.DRAWING_FINISHED), canvas.buffer_rgba(), width, height + + def DrawPicByEpoch(self, epoch): + try: + PSG_SP = epoch * 30 * Config["ApplyFrequency"] + PSG_EP = (epoch + 6) * 30 * Config["ApplyFrequency"] + + orgBcg_SP = PSG_SP - Config["pos"] + orgBcg_EP = PSG_EP - Config["pos"] + + tho_seg = self.processed_Tho[PSG_SP:PSG_EP] + orgBcg_seg = self.processed_orgBcg[orgBcg_SP:orgBcg_EP] * Config["orgBcg_reverse"] + abd_seg = self.processed_Abd[PSG_SP:PSG_EP] + + fig = Figure(figsize=(12, 10), dpi=100) + canvas = FigureCanvas(fig) + # 根据PSG来和绘制 + ax1 = fig.add_subplot(321) + ax1.plot(linspace(PSG_SP, PSG_EP, len(tho_seg)), tho_seg) + tho_peaks, _ = find_peaks(tho_seg, prominence=0, distance=3 * Config["ApplyFrequency"]) + ax1.plot(linspace(PSG_SP, PSG_EP, len(tho_seg))[tho_peaks], tho_seg[tho_peaks], "x") + + ax3 = fig.add_subplot(323) + ax3.plot(linspace(orgBcg_SP, orgBcg_EP, len(orgBcg_seg)), orgBcg_seg) + orgBcg_peaks, _ = find_peaks(orgBcg_seg, prominence=0, distance=3 * Config["ApplyFrequency"]) + ax3.plot(linspace(orgBcg_SP, orgBcg_EP, len(orgBcg_seg))[orgBcg_peaks], orgBcg_seg[orgBcg_peaks], "x") + + ax2 = fig.add_subplot(325) + ax2.plot(linspace(PSG_SP, PSG_EP, len(abd_seg)), abd_seg) + abd_peaks, _ = find_peaks(abd_seg, prominence=0, distance=3 * Config["ApplyFrequency"]) + ax2.plot(linspace(PSG_SP, PSG_EP, len(abd_seg))[abd_peaks], abd_seg[abd_peaks], "x") + + # 绘制间期 + ax4 = fig.add_subplot(322) + ax4.plot(linspace(PSG_SP, PSG_EP, len(diff(tho_peaks).repeat(Config["ApplyFrequency"]))), + diff(tho_peaks).repeat(Config["ApplyFrequency"]), alpha=0.5, label="tho") + ax4.plot(linspace(PSG_SP, PSG_EP, len(diff(orgBcg_peaks).repeat(Config["ApplyFrequency"]))), + diff(orgBcg_peaks).repeat(Config["ApplyFrequency"]), label="resp") + ax4.set_title("tho_interval") + ax4.legend() + ax4.set_ylim((10, 50)) + + ax5 = fig.add_subplot(324) + ax5.plot(linspace(orgBcg_SP, orgBcg_EP, len(diff(tho_peaks).repeat(Config["ApplyFrequency"]))), + diff(tho_peaks).repeat(Config["ApplyFrequency"])) + ax5.plot(linspace(orgBcg_SP, orgBcg_EP, len(diff(orgBcg_peaks).repeat(Config["ApplyFrequency"]))), + diff(orgBcg_peaks).repeat(Config["ApplyFrequency"]), label="resp") + ax5.set_title("resp_interval") + ax5.set_ylim((10, 50)) + + ax6 = fig.add_subplot(326) + ax6.plot(linspace(PSG_SP, PSG_EP, len(diff(abd_peaks).repeat(Config["ApplyFrequency"]))), + diff(abd_peaks).repeat(Config["ApplyFrequency"])) + ax6.plot(linspace(PSG_SP, PSG_EP, len(diff(orgBcg_peaks).repeat(Config["ApplyFrequency"]))), + diff(orgBcg_peaks).repeat(Config["ApplyFrequency"]), label="resp") + ax6.set_title("abd_interval") + ax6.set_ylim((10, 50)) + + width, height = fig.figbbox.width, fig.figbbox.height + fig.canvas.draw() + except Exception: + return Result().failure(info=Constants.DRAWING_FAILURE) + # 返回图片以便存到QPixImage + return Result().success(info=Constants.DRAWING_FINISHED), canvas.buffer_rgba(), width, height + + @staticmethod + @njit("int64[:](int64[:],int64[:], int32[:])", nogil=True, parallel=True) + def get_Correlate(a, v, between): + begin, end = between + if end == 0: + end = len(a) - len(v) - 1 + result = empty(end - begin, dtype=int64) + for i in prange(end - begin): + result[i] = np_sum(a[begin + i: begin + i + len(v)] * v) + return result \ No newline at end of file diff --git a/func/Module_cut_PSG.py b/func/Module_cut_PSG.py index f30d40a..36f708b 100644 --- a/func/Module_cut_PSG.py +++ b/func/Module_cut_PSG.py @@ -11,6 +11,7 @@ from yaml import dump, load, FullLoader from func.utils.PublicFunc import PublicFunc from func.utils.Constants import Constants, ConfigParams +from func.utils.Result import Result from ui.MainWindow.MainWindow_cut_PSG import Ui_MainWindow_cut_PSG @@ -73,19 +74,22 @@ class MainWindow_cut_PSG(QMainWindow): @overrides def closeEvent(self, event): - PublicFunc.__disableAllButton__(self, ButtonState) + 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() + PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg(Constants.SHUTTING_DOWN)) + QApplication.processEvents() - # 释放资源 - del self.data - self.deleteLater() - collect() - event.accept() + # 释放资源 + del self.data + self.deleteLater() + collect() + event.accept() + else: + event.ignore() - @staticmethod - def __reset__(): + def __reset__(self): ButtonState["Current"].update(ButtonState["Default"].copy()) def __read_config__(self): @@ -108,68 +112,73 @@ class MainWindow_cut_PSG(QMainWindow): # 检查文件是否存在并获取其数据采样率 PublicFunc.progressbar_update(self, 1, 5, Constants.CUT_PSG_GETTING_FILE_AND_FREQ, 0) - status, info = self.data.get_file_and_freq() - if not status: - PublicFunc.text_output(self.ui, "(1/5)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.data.get_file_and_freq() + if not result.status: + PublicFunc.text_output(self.ui, "(1/5)" + 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/5)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(1/5)" + result.info, Constants.TIPS_TYPE_INFO) PublicFunc.finish_operation(self, ButtonState) # 导入数据 PublicFunc.progressbar_update(self, 2, 5, Constants.INPUTTING_DATA, 10) - status, info = self.data.open_file() - if not status: - PublicFunc.text_output(self.ui, "(2/5)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.data.open_file() + if not result.status: + PublicFunc.text_output(self.ui, "(2/5)" + 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/5)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(2/5)" + result.info, Constants.TIPS_TYPE_INFO) PublicFunc.finish_operation(self, ButtonState) # 切割数据 PublicFunc.progressbar_update(self, 3, 5, Constants.CUT_PSG_CUTTING_DATA, 40) - status, info = self.data.cut_data() - if not status: - PublicFunc.text_output(self.ui, "(3/5)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.data.cut_data() + if not result.status: + PublicFunc.text_output(self.ui, "(3/5)" + 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/5)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(3/5)" + result.info, Constants.TIPS_TYPE_INFO) PublicFunc.finish_operation(self, ButtonState) # 标签映射 PublicFunc.progressbar_update(self, 4, 5, Constants.CUT_PSG_ALIGNING_LABEL, 60) - status, info = self.data.align_label() - if not status: - PublicFunc.text_output(self.ui, "(4/5)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.data.align_label() + if not result.status: + PublicFunc.text_output(self.ui, "(4/5)" + 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/5)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(4/5)" + result.info, Constants.TIPS_TYPE_INFO) PublicFunc.finish_operation(self, ButtonState) - # 切割数据 + # 保存数据 PublicFunc.progressbar_update(self, 5, 5, Constants.SAVING_DATA, 70) - status, info = self.data.save() - if not status: - PublicFunc.text_output(self.ui, "(5/5)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.data.save() + + if not result.status: + PublicFunc.text_output(self.ui, "(5/5)" + 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/5)" + info, Constants.TIPS_TYPE_INFO) - PublicFunc.msgbox_output(self, info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(5/5)" + result.info, Constants.TIPS_TYPE_INFO) + for key, raw in self.data.raw.items(): + info = "保存{}的长度为{},采样率为{}Hz".format(key, str(len(raw)), str(self.data.freq[key])) + PublicFunc.text_output(self.ui, info, Constants.TIPS_TYPE_INFO) + QApplication.processEvents() + PublicFunc.msgbox_output(self, result.info, Constants.TIPS_TYPE_INFO) PublicFunc.finish_operation(self, ButtonState) @@ -196,20 +205,20 @@ class Data: freq = int(freq_str) self.freq[key] = freq except ValueError: - return False, Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Filename_Format_not_Correct"] + return Result().failure(info=Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Filename_Format_not_Correct"]) for value in self.freq.values(): if value == 0: - return False, Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Filename_Format_not_Correct"] + return Result().failure(info=Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Filename_Format_not_Correct"]) if not any((Config["LabelInput"]["SA Label"] + Config["EndWith"]["SA Label"]) in str(file) for file in Path(Config["Path"]["InputFolder"]).glob('*')): - return False, Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE + Constants.CUT_PSG_FAILURE_REASON["File_not_Exist"] + return Result().failure(info=Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE + Constants.CUT_PSG_FAILURE_REASON["File_not_Exist"]) if not any((Config["StartTime"] + Config["EndWith"]["StartTime"]) in str(file) for file in Path(Config["Path"]["InputFolder"]).glob('*')): - return False, Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE + Constants.CUT_PSG_FAILURE_REASON["File_not_Exist"] + return Result().failure(info=Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE + Constants.CUT_PSG_FAILURE_REASON["File_not_Exist"]) if not Path(Config["Path"]["InputAlignInfo"]).exists(): - return False, Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE + Constants.CUT_PSG_FAILURE_REASON["File_not_Exist"] + return Result().failure(info=Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE + Constants.CUT_PSG_FAILURE_REASON["File_not_Exist"]) except Exception: - return False, Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE + Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE["Get_File_and_Freq_Excepetion"] + return Result().failure(info=Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE + Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE["Get_File_and_Freq_Excepetion"]) - return True, Constants.CUT_PSG_GET_FILE_AND_FREQ_FINISHED + return Result().success(info=Constants.CUT_PSG_GET_FILE_AND_FREQ_FINISHED) def open_file(self): try: @@ -227,9 +236,9 @@ class Data: header=None).to_numpy().reshape(-1) self.alignInfo = literal_eval(self.alignInfo[0]) except Exception: - return False, Constants.INPUT_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Read_Data_Exception"] + return Result().failure(info=Constants.INPUT_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Read_Data_Exception"]) - return True, Constants.INPUT_FINISHED + return Result().success(info=Constants.INPUT_FINISHED) def cut_data(self): try: @@ -245,11 +254,11 @@ class Data: # 切割信号 self.raw[key] = self.raw[key][start_index_cut:end_index_cut] except Exception: - return False, Constants.CUT_PSG_CUT_DATA_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Cut_Data_Length_not_Correct"] + return Result().failure(info=Constants.CUT_PSG_CUT_DATA_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Cut_Data_Length_not_Correct"]) except Exception: - return False, Constants.CUT_PSG_CUT_DATA_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Cut_Data_Exception"] + return Result().failure(info=Constants.CUT_PSG_CUT_DATA_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Cut_Data_Exception"]) - return True, Constants.CUT_PSG_CUT_DATA_FINISHED + return Result().success(info=Constants.CUT_PSG_CUT_DATA_FINISHED) def align_label(self): try: @@ -259,7 +268,7 @@ class Data: self.SALabel["Duration"] = self.SALabel["Duration"].astype(str) self.SALabel["Duration"] = self.SALabel["Duration"].str.replace(r' \(.*?\)', '', regex=True) except Exception: - return False, Constants.CUT_PSG_ALIGN_LABEL_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Align_Label_SALabel_Format_not_Correct"] + return Result().failure(info=Constants.CUT_PSG_ALIGN_LABEL_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Align_Label_SALabel_Format_not_Correct"]) try: # 获取记录开始时间 @@ -280,14 +289,14 @@ class Data: self.SALabel = self.SALabel[self.SALabel["Start"] < ECG_length] self.SALabel.loc[self.SALabel["End"] >= ECG_length, "End"] = ECG_length - 1 except Exception: - return False, Constants.CUT_PSG_ALIGN_LABEL_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Align_Label_Exception"] + return Result().failure(info=Constants.CUT_PSG_ALIGN_LABEL_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Align_Label_Exception"]) - return True, Constants.CUT_PSG_ALIGN_LABEL_FINISHED + return Result().success(info=Constants.CUT_PSG_ALIGN_LABEL_FINISHED) def save(self): for raw in self.raw.values(): if len(raw) == 0: - return False, Constants.SAVING_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Save_Data_not_Exist"] + return Result().failure(info=Constants.SAVING_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Save_Data_not_Exist"]) try: for key, raw in self.raw.items(): @@ -297,9 +306,9 @@ class Data: index=False, encoding="gbk") except Exception: - return False, Constants.SAVING_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Save_Exception"] + return Result().failure(info=Constants.SAVING_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Save_Exception"]) - return True, Constants.SAVING_FINISHED + return Result().success(info=Constants.SAVING_FINISHED) @staticmethod def get_time_to_seconds(time_str): diff --git a/func/Module_detect_Jpeak.py b/func/Module_detect_Jpeak.py index c49358a..0f8fbff 100644 --- a/func/Module_detect_Jpeak.py +++ b/func/Module_detect_Jpeak.py @@ -12,6 +12,7 @@ from yaml import dump, load, FullLoader from func.utils.PublicFunc import PublicFunc from func.utils.Constants import Constants, ConfigParams +from func.utils.Result import Result from func.utils.detect_Jpeak import preprocess, Jpeak_Detection from ui.MainWindow.MainWindow_detect_Jpeak import Ui_MainWindow_detect_Jpeak @@ -190,26 +191,29 @@ class MainWindow_detect_Jpeak(QMainWindow): @overrides def closeEvent(self, event): - PublicFunc.__disableAllButton__(self, ButtonState) + 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() + PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg(Constants.SHUTTING_DOWN)) + QApplication.processEvents() - # 清空画框 - self.ax0.clear() + # 清空画框 + self.ax0.clear() - # 释放资源 - del self.data - del self.model - self.fig.clf() - plt.close(self.fig) - self.deleteLater() - collect() - self.canvas = None - event.accept() + # 释放资源 + del self.data + del self.model + self.fig.clf() + plt.close(self.fig) + self.deleteLater() + collect() + self.canvas = None + event.accept() + else: + event.ignore() - @staticmethod - def __reset__(): + def __reset__(self): ButtonState["Current"].update(ButtonState["Default"].copy()) ButtonState["Current"]["pushButton_view"] = True @@ -230,14 +234,12 @@ class MainWindow_detect_Jpeak(QMainWindow): color=Constants.PLOT_COLOR_ORANGE, label=Constants.DETECT_JPEAK_PLOT_LABEL_INTERVAL) self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) - status = True - info = Constants.DRAWING_FINISHED - else: - status = False - info = Constants.DRAWING_FAILURE - self.canvas.draw() - return status, info + self.canvas.draw() + return Result().success(info=Constants.DRAWING_FINISHED) + else: + self.canvas.draw() + return Result().failure(info=Constants.DRAWING_FAILURE) def __update_config__(self): Config["Filter"]["BandPassLow"] = self.ui.doubleSpinBox_bandPassLow.value() @@ -264,28 +266,28 @@ class MainWindow_detect_Jpeak(QMainWindow): # 寻找模型 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) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.model.seek_model() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(1/2)" + result.info, Constants.TIPS_TYPE_INFO) self.update_ui_comboBox_model(self.model.model_list) # 导入数据 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) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.data.open_file() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(2/2)" + result.info, Constants.TIPS_TYPE_INFO) - MainWindow_detect_Jpeak.__reset__() + self.__reset__() PublicFunc.finish_operation(self, ButtonState) def __slot_btn_view__(self): @@ -293,26 +295,26 @@ class MainWindow_detect_Jpeak(QMainWindow): # 数据预处理 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) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.data.preprocess() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(1/3)" + result.info, Constants.TIPS_TYPE_INFO) # 预测峰值 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: - PublicFunc.text_output(self.ui, "(2/3)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.data.predict_Jpeak(self.model) + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(2/3)" + result.info, Constants.TIPS_TYPE_INFO) PublicFunc.text_output(self.ui, Constants.DETECT_JPEAK_DATA_LENGTH_POINTS + str(len(self.data.raw_data)), Constants.TIPS_TYPE_INFO) PublicFunc.text_output(self.ui, Constants.DETECT_JPEAK_DURATION_MIN + @@ -323,14 +325,14 @@ class MainWindow_detect_Jpeak(QMainWindow): # 绘图 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) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.__plot__() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(3/3)" + result.info, Constants.TIPS_TYPE_INFO) ButtonState["Current"]["pushButton_save"] = True PublicFunc.finish_operation(self, ButtonState) @@ -352,20 +354,20 @@ class MainWindow_detect_Jpeak(QMainWindow): for start in range(0, total_rows, chunk_size): end = min(start + chunk_size, total_rows) chunk = DataFrame(self.data.peak.reshape(-1)).iloc[start:end] - status, info = self.data.save(chunk) + result = 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) + 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)" + info, Constants.TIPS_TYPE_INFO) - PublicFunc.msgbox_output(self, info, Constants.TIPS_TYPE_INFO) + 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 reset_axes(self): @@ -388,20 +390,20 @@ class Data: def open_file(self): if not Path(Config["Path"]["Input"]).exists(): - return False, Constants.INPUT_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Data_Path_Not_Exist"] + return Result().failure(info=Constants.INPUT_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Data_Path_Not_Exist"]) try: self.raw_data = read_csv(Config["Path"]["Input"], encoding=ConfigParams.UTF8_ENCODING, header=None).to_numpy().reshape(-1) except Exception: - return False, Constants.INPUT_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Read_Data_Exception"] + return Result().failure(info=Constants.INPUT_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Read_Data_Exception"]) - return True, Constants.INPUT_FINISHED + return Result().success(info=Constants.INPUT_FINISHED) def preprocess(self): if self.raw_data is None: - return False, Constants.DETECT_JPEAK_PROCESS_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Raw_Data_Not_Exist"] + return Result().failure(info=Constants.DETECT_JPEAK_PROCESS_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Raw_Data_Not_Exist"]) try: self.processed_data = preprocess(self.raw_data, @@ -410,16 +412,16 @@ class Data: Config["Filter"]["BandPassHigh"], Config["AmpValue"]) except Exception: - return False, Constants.DETECT_JPEAK_PROCESS_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Filter_Exception"] + return Result().failure(info=Constants.DETECT_JPEAK_PROCESS_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Filter_Exception"]) - return True, Constants.DETECT_JPEAK_PROCESS_FINISHED + return Result().success(info=Constants.DETECT_JPEAK_PROCESS_FINISHED) def predict_Jpeak(self, model): if not (Path(model.model_folder_path) / Path(model.selected_model)).exists(): - return False, Constants.DETECT_JPEAK_PREDICT_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Model_File_Not_Exist"] + return Result().failure(info=Constants.DETECT_JPEAK_PREDICT_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Model_File_Not_Exist"]) if self.processed_data is None: - return False, Constants.DETECT_JPEAK_PREDICT_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Processed_Data_Not_Exist"] + return Result().failure(info=Constants.DETECT_JPEAK_PREDICT_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Processed_Data_Not_Exist"]) try: self.peak, self.interval = Jpeak_Detection(model.selected_model, @@ -431,20 +433,20 @@ class Data: Config["PeaksValue"], Config["UseCPU"]) except Exception: - return False, Constants.DETECT_JPEAK_PREDICT_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Predict_Exception"] + return Result().failure(info=Constants.DETECT_JPEAK_PREDICT_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Predict_Exception"]) - return True, Constants.DETECT_JPEAK_PREDICT_FINISHED + return Result().success(info=Constants.DETECT_JPEAK_PREDICT_FINISHED) def save(self, chunk): if self.peak is None: - return False, Constants.SAVING_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Peak_Not_Exist"] + return Result().failure(info=Constants.SAVING_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Peak_Not_Exist"]) try: chunk.to_csv(Config["Path"]["Save"], mode='a', index=False, header=False) except Exception: - return False, Constants.SAVING_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Save_Exception"] + return Result().failure(info=Constants.SAVING_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Save_Exception"]) - return True, Constants.SAVING_FINISHED + return Result().success(info=Constants.SAVING_FINISHED) class Model: @@ -457,13 +459,13 @@ class Model: def seek_model(self): if not Path(Config["ModelFolderPath"]).exists(): - return False, Constants.DETECT_JPEAK_LOAD_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Model_Path_Not_Exist"] + return Result().failure(info=Constants.DETECT_JPEAK_LOAD_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Model_Path_Not_Exist"]) try: self.model_list = [file.name for file in Path(Config["ModelFolderPath"]).iterdir() if file.is_file()] if len(self.model_list) == 0: - return False, Constants.DETECT_JPEAK_FAILURE_REASON["Model_File_Not_Exist"] + return Result().failure(info=Constants.DETECT_JPEAK_FAILURE_REASON["Model_File_Not_Exist"]) except Exception: - return False, Constants.DETECT_JPEAK_LOAD_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Read_Model_Exception"] + return Result().failure(info=Constants.DETECT_JPEAK_LOAD_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Read_Model_Exception"]) - return True, Constants.DETECT_JPEAK_LOAD_FINISHED \ No newline at end of file + return Result().success(info=Constants.DETECT_JPEAK_LOAD_FINISHED) \ No newline at end of file diff --git a/func/Module_detect_Rpeak.py b/func/Module_detect_Rpeak.py index 3fee804..b423e0a 100644 --- a/func/Module_detect_Rpeak.py +++ b/func/Module_detect_Rpeak.py @@ -12,6 +12,7 @@ from yaml import dump, load, FullLoader from func.utils.PublicFunc import PublicFunc from func.utils.Constants import Constants, ConfigParams +from func.utils.Result import Result from func.utils.detect_Rpeak import preprocess, Rpeak_Detection, get_method from ui.MainWindow.MainWindow_detect_Rpeak import Ui_MainWindow_detect_Rpeak @@ -183,26 +184,29 @@ class MainWindow_detect_Rpeak(QMainWindow): @overrides def closeEvent(self, event): - PublicFunc.__disableAllButton__(self, ButtonState) + 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() + PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg(Constants.SHUTTING_DOWN)) + QApplication.processEvents() - # 清空画框 - self.ax0.clear() - self.ax1.clear() + # 清空画框 + self.ax0.clear() + self.ax1.clear() - # 释放资源 - del self.data - self.fig.clf() - plt.close(self.fig) - self.deleteLater() - collect() - self.canvas = None - event.accept() + # 释放资源 + del self.data + self.fig.clf() + plt.close(self.fig) + self.deleteLater() + collect() + self.canvas = None + event.accept() + else: + event.ignore() - @staticmethod - def __reset__(): + def __reset__(self): ButtonState["Current"].update(ButtonState["Default"].copy()) ButtonState["Current"]["pushButton_view"] = True @@ -227,14 +231,11 @@ class MainWindow_detect_Rpeak(QMainWindow): label=Constants.DETECT_RPEAK_PLOT_LABEL_INTERVAL) self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT) - status = True - info = Constants.DRAWING_FINISHED + self.canvas.draw() + return Result().success(info=Constants.DRAWING_FINISHED) else: - status = False - info = Constants.DRAWING_FAILURE - - self.canvas.draw() - return status, info + self.canvas.draw() + return Result().failure(info=Constants.DRAWING_FAILURE) def __update_config__(self): Config["Filter"]["BandPassLow"] = self.ui.doubleSpinBox_bandPassLow.value() @@ -259,32 +260,30 @@ class MainWindow_detect_Rpeak(QMainWindow): # TODO:获取检测方法的解耦 method_list = get_method() if len(method_list) == 0 or method_list is None: - status = False - info = Constants.DETECT_RPEAK_LOAD_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Method_Not_Exist"] + result = Result().failure(info=Constants.DETECT_RPEAK_LOAD_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Method_Not_Exist"]) else: - status = True - info = Constants.DETECT_RPEAK_LOAD_FINISHED - if not status: - PublicFunc.text_output(self.ui, "(1/2)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = Result().success(info=Constants.DETECT_RPEAK_LOAD_FINISHED) + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(1/2)" + result.info, Constants.TIPS_TYPE_INFO) self.update_ui_comboBox_method(method_list) # 导入数据 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) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.data.open_file() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(2/2)" + result.info, Constants.TIPS_TYPE_INFO) - MainWindow_detect_Rpeak.__reset__() + self.__reset__() PublicFunc.finish_operation(self, ButtonState) def __slot_btn_view__(self): @@ -292,25 +291,25 @@ class MainWindow_detect_Rpeak(QMainWindow): # 数据预处理 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) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.data.preprocess() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(1/3)" + result.info, Constants.TIPS_TYPE_INFO) # 预测峰值 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) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.data.predict_Rpeak() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(2/3)" + result.info, Constants.TIPS_TYPE_INFO) PublicFunc.text_output(self.ui, Constants.DETECT_RPEAK_DATA_LENGTH_POINTS + str(len(self.data.raw_data)), Constants.TIPS_TYPE_INFO) PublicFunc.text_output(self.ui, Constants.DETECT_RPEAK_DURATION_MIN + @@ -321,14 +320,14 @@ class MainWindow_detect_Rpeak(QMainWindow): # 绘图 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) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.__plot__() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(3/3)" + result.info, Constants.TIPS_TYPE_INFO) ButtonState["Current"]["pushButton_save"] = True PublicFunc.finish_operation(self, ButtonState) @@ -350,20 +349,20 @@ class MainWindow_detect_Rpeak(QMainWindow): for start in range(0, total_rows, chunk_size): end = min(start + chunk_size, total_rows) chunk = DataFrame(self.data.peak.reshape(-1)).iloc[start:end] - status, info = self.data.save(chunk) + result = 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) + 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)" + info, Constants.TIPS_TYPE_INFO) - PublicFunc.msgbox_output(self, info, Constants.TIPS_TYPE_INFO) + 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 reset_axes(self): @@ -391,20 +390,20 @@ class Data: def open_file(self): if not Path(Config["Path"]["Input"]).exists(): - return False, Constants.INPUT_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Data_Path_Not_Exist"] + return Result().failure(info=Constants.INPUT_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Data_Path_Not_Exist"]) try: self.raw_data = read_csv(Config["Path"]["Input"], encoding=ConfigParams.UTF8_ENCODING, header=None).to_numpy().reshape(-1) except Exception: - return False, Constants.INPUT_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Read_Data_Exception"] + return Result().failure(info=Constants.INPUT_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Read_Data_Exception"]) - return True, Constants.INPUT_FINISHED + return Result().success(info=Constants.INPUT_FINISHED) def preprocess(self): if self.raw_data is None: - return False, Constants.DETECT_RPEAK_PROCESS_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Raw_Data_Not_Exist"] + return Result().failure(info=Constants.DETECT_RPEAK_PROCESS_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Raw_Data_Not_Exist"]) try: self.processed_data = preprocess(self.raw_data, @@ -412,13 +411,13 @@ class Data: Config["Filter"]["BandPassLow"], Config["Filter"]["BandPassHigh"]) except Exception: - return False, Constants.DETECT_RPEAK_PROCESS_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Filter_Exception"] + return Result().failure(info=Constants.DETECT_RPEAK_PROCESS_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Filter_Exception"]) - return True, Constants.DETECT_RPEAK_PROCESS_FINISHED + return Result().success(info=Constants.DETECT_RPEAK_PROCESS_FINISHED) def predict_Rpeak(self): if self.processed_data is None: - return False, Constants.DETECT_RPEAK_PREDICT_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Processed_Data_Not_Exist"] + return Result().failure(info=Constants.DETECT_RPEAK_PREDICT_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Processed_Data_Not_Exist"]) try: self.peak, self.interval, self.RRIV = Rpeak_Detection(self.processed_data, @@ -426,17 +425,18 @@ class Data: Config["PeaksValue"], Config["DetectMethod"]) except Exception: - return False, Constants.DETECT_RPEAK_PREDICT_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Predict_Exception"] + return Result().failure(info=Constants.DETECT_RPEAK_PREDICT_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Predict_Exception"]) - return True, Constants.DETECT_RPEAK_PREDICT_FINISHED + return Result().success(info=Constants.DETECT_RPEAK_PREDICT_FINISHED) def save(self, chunk): if self.peak is None: - return False, Constants.SAVING_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Peak_Not_Exist"] + + return Result().failure(info=Constants.SAVING_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Peak_Not_Exist"]) try: chunk.to_csv(Config["Path"]["Save"], mode='a', index=False, header=False) except Exception: - return False, Constants.SAVING_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Save_Exception"] + return Result().failure(info=Constants.SAVING_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Save_Exception"]) - return True, Constants.SAVING_FINISHED \ No newline at end of file + return Result().success(info=Constants.SAVING_FINISHED) \ No newline at end of file diff --git a/func/Module_label_check.py b/func/Module_label_check.py index c9553e8..06b62f5 100644 --- a/func/Module_label_check.py +++ b/func/Module_label_check.py @@ -17,6 +17,7 @@ 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 func.utils.Result import Result 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 @@ -300,29 +301,33 @@ class MainWindow_label_check(QMainWindow): @overrides def closeEvent(self, event): - PublicFunc.__disableAllButton__(self, ButtonState) + reply = QMessageBox.question(self, '确认', '确认退出吗?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) + if reply == QMessageBox.Yes: - PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg(Constants.SHUTTING_DOWN)) - QApplication.processEvents() + PublicFunc.__disableAllButton__(self, ButtonState) - # 清空画框 - del self.point_peak_original - del self.point_peak_corrected - del self.annotation_tableWidget - self.ax0.clear() - self.ax1.clear() + PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg(Constants.SHUTTING_DOWN)) + QApplication.processEvents() - # 释放资源 - del self.data - self.fig.clf() - plt.close(self.fig) - self.deleteLater() - collect() - self.canvas = None - event.accept() + # 清空画框 + del self.point_peak_original + del self.point_peak_corrected + del self.annotation_tableWidget + self.ax0.clear() + self.ax1.clear() - @staticmethod - def __reset__(): + # 释放资源 + 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): @@ -351,16 +356,15 @@ class MainWindow_label_check(QMainWindow): color=Constants.PLOT_COLOR_BLUE) self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT) - status = True - info = Constants.DRAWING_FINISHED + self.canvas.draw() + self.ax0.autoscale(False) + self.ax1.autoscale(False) + return Result().success(info=Constants.DRAWING_FINISHED) else: - status = False - info = Constants.DRAWING_FAILURE - - self.canvas.draw() - self.ax0.autoscale(False) - self.ax1.autoscale(False) - return status, info + self.canvas.draw() + self.ax0.autoscale(False) + self.ax1.autoscale(False) + return Result().failure(info=Constants.DRAWING_FAILURE) def __plot_peaks__(self): try: @@ -372,10 +376,10 @@ class MainWindow_label_check(QMainWindow): self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT) except Exception: - return False, Constants.DRAWING_FAILURE + return Result().failure(info=Constants.DRAWING_FAILURE) self.canvas.draw() - return True, Constants.DRAWING_FINISHED + return Result().success(info=Constants.DRAWING_FINISHED) def __redraw_peaks__(self): self.point_peak_corrected.remove() @@ -398,12 +402,9 @@ class MainWindow_label_check(QMainWindow): 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 + return Result().success(info=Constants.UPDATING_FINISHED) except Exception: - status = False - info = Constants.UPDATING_FAILURE - return status, info + return Result().failure(info=Constants.UPDATING_FAILURE) def __update_config__(self): Config["FindPeaks"]["MinInterval"] = self.ui.doubleSpinBox_findpeaks_min_interval.value() @@ -433,71 +434,71 @@ class MainWindow_label_check(QMainWindow): # 导入数据 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) + result = self.data.open_file() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(1/6)" + result.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) + result = self.data.get_archive() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(2/6)" + result.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) + result = self.data.preprocess() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(3/6)" + result.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) + result = self.__update_tableWidget_and_info__() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(4/6)" + result.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) + result = self.__plot__() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(5/6)" + result.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) + result = self.__plot_peaks__() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(6/6)" + result.info, Constants.TIPS_TYPE_INFO) - MainWindow_label_check.__reset__() + self.__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(): @@ -527,20 +528,20 @@ class MainWindow_label_check(QMainWindow): 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) + result = 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) + 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)" + info, Constants.TIPS_TYPE_INFO) - PublicFunc.msgbox_output(self, info, Constants.TIPS_TYPE_INFO) + 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_move__(self): @@ -875,7 +876,7 @@ class Data: 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"] + return Result().failure(info=Constants.INPUT_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Data_Path_Not_Exist"]) try: self.raw_data = read_csv(Config["Path"]["Input_Signal"], @@ -885,23 +886,23 @@ class Data: 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 Result().failure(info=Constants.INPUT_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Read_Data_Exception"]) - return True, Constants.INPUT_FINISHED + return Result().success(info=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 + return Result().success(info=Constants.LABEL_CHECK_ARCHIVE_NOT_EXIST) else: self.corrected_peak = read_csv(Config["Path"]["Save"], encoding=ConfigParams.UTF8_ENCODING, header=None).to_numpy().reshape(-1) - return True, Constants.LABEL_CHECK_ARCHIVE_EXIST + return Result().success(info=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"] + return Result().failure(info=Constants.LABEL_CHECK_PROCESS_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Raw_Data_Not_Exist"]) try: if Config["Mode"] == "BCG": @@ -921,20 +922,20 @@ class Data: 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 Result().failure(info=Constants.LABEL_CHECK_PROCESS_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Filter_Exception"]) - return True, Constants.LABEL_CHECK_PROCESS_FINISHED + return Result().success(info=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"] + return Result().failure(info=Constants.SAVING_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Peak_Not_Exist"]) try: chunk.to_csv(Config["Path"]["Save"], mode='a', index=False, header=False) except Exception: - return False, Constants.SAVING_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Save_Exception"] + return Result().failure(info=Constants.SAVING_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Save_Exception"]) - return True, Constants.SAVING_FINISHED + return Result().success(info=Constants.SAVING_FINISHED) class CustomNavigationToolbar(NavigationToolbar2QT): diff --git a/func/Module_mainwindow.py b/func/Module_mainwindow.py index 4210251..f49ff8f 100644 --- a/func/Module_mainwindow.py +++ b/func/Module_mainwindow.py @@ -7,6 +7,7 @@ from yaml import dump, load, FullLoader from func.utils.PublicFunc import PublicFunc from ui.MainWindow.MainWindow_menu import Ui_Signal_Label +from func.Module_approximately_align import MainWindow_approximately_align 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 @@ -40,6 +41,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.ui.plainTextEdit_root_path.setPlainText(Config["Path"]["Root"]) self.seek_sampID(Path(Config["Path"]["Root"]) / Path(ConfigParams.PUBLIC_PATH_ORGBCG_TEXT)) + self.approximately_align = None self.preprocess = None self.detect_Jpeak = None self.detect_Rpeak = None @@ -49,6 +51,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): # 绑定槽函数 self.ui.pushButton_open.clicked.connect(self.__slot_btn_open__) + self.ui.pushButton_approximately_align.clicked.connect(self.__slot_btn_approximately_align__) self.ui.pushButton_preprocess_BCG.clicked.connect(self.__slot_btn_preprocess__) self.ui.pushButton_preprocess_ECG.clicked.connect(self.__slot_btn_preprocess__) self.ui.pushButton_detect_Jpeak.clicked.connect(self.__slot_btn_detect_Jpeak__) @@ -87,6 +90,12 @@ class MainWindow(QMainWindow, Ui_Signal_Label): else: PublicFunc.msgbox_output(self, Constants.OPERATION_CANCELED, Constants.MSGBOX_TYPE_INFO) + def __slot_btn_approximately_align__(self): + self.approximately_align = MainWindow_approximately_align() + root_path = self.ui.plainTextEdit_root_path.toPlainText() + sampID = int(self.ui.comboBox_sampID.currentText()) + self.approximately_align.show(root_path, sampID) + def __slot_btn_preprocess__(self): self.preprocess = MainWindow_preprocess() diff --git a/func/Module_precisely_align.py b/func/Module_precisely_align.py index 410795f..01b7208 100644 --- a/func/Module_precisely_align.py +++ b/func/Module_precisely_align.py @@ -18,6 +18,7 @@ from yaml import dump, load, FullLoader from func.utils.PublicFunc import PublicFunc from func.utils.Constants import Constants, ConfigParams +from func.utils.Result import Result from ui.MainWindow.MainWindow_precisely_align import Ui_MainWindow_precisely_align from ui.setting.precisely_align_input_setting import Ui_MainWindow_precisely_align_input_setting @@ -401,46 +402,49 @@ class MainWindow_precisely_align(QMainWindow): @overrides def closeEvent(self, event): - PublicFunc.__disableAllButton__(self, ButtonState) + 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() + PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg(Constants.SHUTTING_DOWN)) + QApplication.processEvents() - # 清空画框 - del self.point0 - del self.point1 - del self.selected_point0 - del self.selected_point1 - del self.selected_point2 - del self.selected_point3 - del self.stem_black0 - del self.stem_black1 - del self.figToolbar.ax0_BCG_rectangle_front - del self.figToolbar.ax0_BCG_rectangle_back - del self.figToolbar.ax1_ECG_rectangle_front - del self.figToolbar.ax1_ECG_rectangle_back - if self.ax0 is not None: - self.ax0.clear() - if self.ax1 is not None: - self.ax1.clear() - if self.ax2 is not None: - self.ax2.clear() - if self.ax3 is not None: - self.ax3.clear() - if self.ax4 is not None: - self.ax4.clear() + # 清空画框 + del self.point0 + del self.point1 + del self.selected_point0 + del self.selected_point1 + del self.selected_point2 + del self.selected_point3 + del self.stem_black0 + del self.stem_black1 + del self.figToolbar.ax0_BCG_rectangle_front + del self.figToolbar.ax0_BCG_rectangle_back + del self.figToolbar.ax1_ECG_rectangle_front + del self.figToolbar.ax1_ECG_rectangle_back + if self.ax0 is not None: + self.ax0.clear() + if self.ax1 is not None: + self.ax1.clear() + if self.ax2 is not None: + self.ax2.clear() + if self.ax3 is not None: + self.ax3.clear() + if self.ax4 is not None: + self.ax4.clear() - # 释放资源 - del self.data - self.fig.clf() - plt.close(self.fig) - self.deleteLater() - collect() - self.canvas = None - event.accept() + # 释放资源 + del self.data + self.fig.clf() + plt.close(self.fig) + self.deleteLater() + collect() + self.canvas = None + event.accept() + else: + event.ignore() - @staticmethod - def __reset__(): + def __reset__(self): ButtonState["Current"].update(ButtonState["Default"].copy()) def __plot__(self, plot_element=None): @@ -483,8 +487,8 @@ class MainWindow_precisely_align(QMainWindow): label=Constants.PRECISELY_ALIGN_PLOT_LABEL_RRIV) self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT) - status = True - info = Constants.DRAWING_FINISHED + self.canvas.draw() + return Result().success(info=Constants.DRAWING_FINISHED) elif sender == self.ui.pushButton_calculate_correlation and plot_element is not None and plot_element["mode"] == "init": self.gs = gridspec.GridSpec(2, 2, height_ratios=[1, 1], width_ratios=[1, 1]) self.fig.subplots_adjust(top=0.88, bottom=0.05, right=0.98, left=0.05, hspace=0.15, wspace=0.15) @@ -549,8 +553,8 @@ class MainWindow_precisely_align(QMainWindow): self.ax2.legend(loc=Constants.PLOT_UPPER_RIGHT) self.ax3.legend(loc=Constants.PLOT_UPPER_RIGHT) - status = True - info = Constants.DRAWING_FINISHED + self.canvas.draw() + return Result().success(info=Constants.DRAWING_FINISHED) elif sender == self.ui.pushButton_correlation_align or (plot_element is not None and plot_element["mode"] == "select"): self.gs = gridspec.GridSpec(1, 1, height_ratios=[1]) self.fig.subplots_adjust(top=0.95, bottom=0.05, right=0.98, left=0.05, hspace=0, wspace=0) @@ -570,8 +574,8 @@ class MainWindow_precisely_align(QMainWindow): self.ax4.legend(loc=Constants.PLOT_UPPER_RIGHT) - status = True - info = Constants.DRAWING_FINISHED + self.canvas.draw() + return Result().success(info=Constants.DRAWING_FINISHED) elif sender == self.ui.pushButton_view_align: self.gs = gridspec.GridSpec(1, 1, height_ratios=[1]) self.fig.subplots_adjust(top=0.95, bottom=0.05, right=0.98, left=0.05, hspace=0, wspace=0) @@ -587,14 +591,11 @@ class MainWindow_precisely_align(QMainWindow): self.ax4.legend(loc=Constants.PLOT_UPPER_RIGHT) - status = True - info = Constants.DRAWING_FINISHED + self.canvas.draw() + return Result().success(info=Constants.DRAWING_FINISHED) else: - status = False - info = Constants.DRAWING_FAILURE - - self.canvas.draw() - return status, info + self.canvas.draw() + return Result().failure(info=Constants.DRAWING_FAILURE) def __update_info__(self): self.ui.spinBox_BCG_front_JJIV_1.setValue(Config["IV_Coordinate"]["BCG_front_1"]) @@ -625,38 +626,38 @@ class MainWindow_precisely_align(QMainWindow): # 导入数据 PublicFunc.progressbar_update(self, 1, 3, Constants.INPUTTING_DATA, 0) - status, info = self.data.open_file() - if not status: - PublicFunc.text_output(self.ui, "(1/3)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.data.open_file() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(1/3)" + result.info, Constants.TIPS_TYPE_INFO) # 处理数据 PublicFunc.progressbar_update(self, 2, 3, Constants.DRAWING_DATA, 50) - status, info, result = self.data.data_process_for_calculate_correlation() - if not status: - PublicFunc.text_output(self.ui, "(2/3)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.data.data_process_for_calculate_correlation() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(2/3)" + result.info, Constants.TIPS_TYPE_INFO) # 绘图 PublicFunc.progressbar_update(self, 3, 3, Constants.DRAWING_DATA, 70) - status, info = self.__plot__(result) - if not status: - PublicFunc.text_output(self.ui, "(3/3)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.__plot__(result.data) + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(3/3)" + result.info, Constants.TIPS_TYPE_INFO) - MainWindow_precisely_align.__reset__() + self.__reset__() self.figToolbar.action_Get_Range.setEnabled(True) self.rect_down = min(self.ax0.get_ylim()[0], self.ax1.get_ylim()[0]) - 10000 self.rect_up = max(self.ax0.get_ylim()[1], self.ax1.get_ylim()[1]) + 10000 @@ -681,45 +682,45 @@ class MainWindow_precisely_align(QMainWindow): # 计算前段相关性 PublicFunc.progressbar_update(self, 1, 3, Constants.PRECISELY_ALIGN_CALCULATING_CORRELATION_FRONT, 0) - status, info, result1 = self.data.calculate_correlation_front(mode, shift_front) - if not status: - PublicFunc.text_output(self.ui, "(1/3)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result1 = self.data.calculate_correlation_front(mode, shift_front) + if not result1.status: + PublicFunc.text_output(self.ui, "(1/3)" + result1.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result1.info, Constants.MSGBOX_TYPE_ERROR) PublicFunc.finish_operation(self, ButtonState) return else: - PublicFunc.text_output(self.ui, "(1/3)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(1/3)" + result1.info, Constants.TIPS_TYPE_INFO) # 计算后段相关性 PublicFunc.progressbar_update(self, 2, 3, Constants.PRECISELY_ALIGN_CALCULATING_CORRELATION_BACK, 30) - status, info, result2 = self.data.calculate_correlation_back(mode, shift_back) - if not status: - PublicFunc.text_output(self.ui, "(2/3)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result2 = self.data.calculate_correlation_back(mode, shift_back) + if not result2.status: + PublicFunc.text_output(self.ui, "(2/3)" + result2.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, result2.info, Constants.MSGBOX_TYPE_ERROR) PublicFunc.finish_operation(self, ButtonState) return else: - PublicFunc.text_output(self.ui, "(2/3)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(2/3)" + result2.info, Constants.TIPS_TYPE_INFO) # 绘图 PublicFunc.progressbar_update(self, 3, 3, Constants.DRAWING_DATA, 60) result = {} - result.update(result1) - result.update(result2) + result.update(result1.data) + result.update(result2.data) result.update({"mode": mode}) if mode == "init": - status, info = self.__plot__(result) + result = self.__plot__(result) elif mode == "select": - status, info = self.redraw_calculate_coordination(result) + result = self.redraw_calculate_coordination(result) else: raise ValueError("模式不存在") - if not status: - PublicFunc.text_output(self.ui, "(3/3)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(3/3)" + result.info, Constants.TIPS_TYPE_INFO) self.figToolbar.action_Get_Range.setEnabled(False) self.figToolbar.deactivate_figToorbar_getRange_mode() @@ -739,31 +740,31 @@ class MainWindow_precisely_align(QMainWindow): # 处理相关对齐 PublicFunc.progressbar_update(self, 1, 2, Constants.PRECISELY_ALIGN_ALIGNING_CORRELATION, 0) - status, info, result = self.data.correlation_align(mode) - if not status: - PublicFunc.text_output(self.ui, "(1/2)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.data.correlation_align(mode) + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(1/2)" + result.info, Constants.TIPS_TYPE_INFO) # 绘图 PublicFunc.progressbar_update(self, 2, 2, Constants.DRAWING_DATA, 50) - result.update({"mode": mode}) + result.data.update({"mode": mode}) if mode == "init": - status, info = self.__plot__(result) + result = self.__plot__(result.data) elif mode == "select": - status, info = self.redraw_correlation_align(result) + result = self.redraw_correlation_align(result.data) else: raise ValueError("模式不存在") - if not status: - PublicFunc.text_output(self.ui, "(2/2)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(2/2)" + result.info, Constants.TIPS_TYPE_INFO) ButtonState["Current"].update(ButtonState["Statue_3"].copy()) PublicFunc.finish_operation(self, ButtonState) @@ -773,25 +774,25 @@ class MainWindow_precisely_align(QMainWindow): # 数据后处理 PublicFunc.progressbar_update(self, 1, 2, Constants.PRECISELY_ALIGN_POSTPROCESSING_VIEW, 0) - status, info = self.data.data_postprocess() - if not status: - PublicFunc.text_output(self.ui, "(1/2)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.data.data_postprocess() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(1/2)" + result.info, Constants.TIPS_TYPE_INFO) # 绘图 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) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(2/2)" + result.info, Constants.TIPS_TYPE_INFO) ButtonState["Current"].update(ButtonState["Statue_4"].copy()) PublicFunc.finish_operation(self, ButtonState) @@ -805,14 +806,14 @@ class MainWindow_precisely_align(QMainWindow): # 保存对齐信息 PublicFunc.progressbar_update(self, 1, 6, Constants.PRECISELY_ALIGN_SAVING_ALIGNINFO, 0) - status, info = self.data.save_alignInfo() - if not status: - PublicFunc.text_output(self.ui, "(1/6)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.data.save_alignInfo() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(1/6)" + result.info, Constants.TIPS_TYPE_INFO) # 保存切割后orgBcg PublicFunc.progressbar_update(self, 2, 6, Constants.PRECISELY_ALIGN_SAVING_RES_ORGBCG, 0) @@ -823,18 +824,18 @@ class MainWindow_precisely_align(QMainWindow): for start in range(0, total_rows, chunk_size): end = min(start + chunk_size, total_rows) chunk = DataFrame(self.data.res_orgBcg.reshape(-1)).iloc[start:end] - status, info = self.data.save_res_orgBcg(chunk) + result = self.data.save_res_orgBcg(chunk) progress = int((end / total_rows) * 100) self.progressbar.setValue(progress) QApplication.processEvents() - if not status: - PublicFunc.text_output(self.ui, "(2/6)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(2/6)" + result.info, Constants.TIPS_TYPE_INFO) # 保存切割后BCG PublicFunc.progressbar_update(self, 3, 6, Constants.PRECISELY_ALIGN_SAVING_RES_BCG, 0) @@ -845,18 +846,18 @@ class MainWindow_precisely_align(QMainWindow): for start in range(0, total_rows, chunk_size): end = min(start + chunk_size, total_rows) chunk = DataFrame(self.data.res_BCG.reshape(-1)).iloc[start:end] - status, info = self.data.save_res_BCG(chunk) + result = self.data.save_res_BCG(chunk) progress = int((end / total_rows) * 100) self.progressbar.setValue(progress) QApplication.processEvents() - if not status: - PublicFunc.text_output(self.ui, "(3/6)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(3/6)" + result.info, Constants.TIPS_TYPE_INFO) # 保存切割后ECG PublicFunc.progressbar_update(self, 4, 6, Constants.PRECISELY_ALIGN_SAVING_CUT_ECG, 0) @@ -867,18 +868,18 @@ class MainWindow_precisely_align(QMainWindow): for start in range(0, total_rows, chunk_size): end = min(start + chunk_size, total_rows) chunk = DataFrame(self.data.cut_ECG.reshape(-1)).iloc[start:end] - status, info = self.data.save_cut_ECG(chunk) + result = self.data.save_cut_ECG(chunk) progress = int((end / total_rows) * 100) self.progressbar.setValue(progress) QApplication.processEvents() - if not status: - PublicFunc.text_output(self.ui, "(4/6)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(4/6)" + result.info, Constants.TIPS_TYPE_INFO) # 保存切割后J峰 PublicFunc.progressbar_update(self, 5, 6, Constants.PRECISELY_ALIGN_SAVING_CUT_JPEAK, 0) @@ -889,18 +890,18 @@ class MainWindow_precisely_align(QMainWindow): for start in range(0, total_rows, chunk_size): end = min(start + chunk_size, total_rows) chunk = DataFrame(self.data.cut_Jpeak.reshape(-1)).iloc[start:end] - status, info = self.data.save_Jpeak(chunk) + result = self.data.save_Jpeak(chunk) progress = int((end / total_rows) * 100) self.progressbar.setValue(progress) QApplication.processEvents() - if not status: - PublicFunc.text_output(self.ui, "(5/6)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(5/6)" + result.info, Constants.TIPS_TYPE_INFO) # 保存切割后R峰 PublicFunc.progressbar_update(self, 6, 6, Constants.PRECISELY_ALIGN_SAVING_CUT_RPEAK, 0) @@ -911,20 +912,20 @@ class MainWindow_precisely_align(QMainWindow): for start in range(0, total_rows, chunk_size): end = min(start + chunk_size, total_rows) chunk = DataFrame(self.data.cut_Rpeak.reshape(-1)).iloc[start:end] - status, info = self.data.save_Rpeak(chunk) + result = self.data.save_Rpeak(chunk) progress = int((end / total_rows) * 100) self.progressbar.setValue(progress) QApplication.processEvents() - if not status: - PublicFunc.text_output(self.ui, "(6/6)" + info, Constants.TIPS_TYPE_ERROR) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + 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)" + info, Constants.TIPS_TYPE_INFO) - PublicFunc.msgbox_output(self, Constants.SAVING_FINISHED, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(6/6)" + result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.msgbox_output(self, result.info, Constants.TIPS_TYPE_INFO) PublicFunc.finish_operation(self, ButtonState) def __update_coordinate__(self): @@ -1065,10 +1066,9 @@ class MainWindow_precisely_align(QMainWindow): self.ax2.set_ylim(self.ax2_ylime) self.canvas.draw() + return Result().success(info=Constants.DRAWING_FINISHED) - return True, Constants.DRAWING_FINISHED - - return False, Constants.DRAWING_FAILURE + return Result().failure(info=Constants.DRAWING_FAILURE) def redraw_correlation_align(self, plot_element=None): if plot_element is not None and plot_element["mode"] == "select": @@ -1103,10 +1103,9 @@ class MainWindow_precisely_align(QMainWindow): self.ax4.set_ylim(self.ax4_ylime) self.canvas.draw() + return Result().success(info=Constants.DRAWING_FINISHED) - return True, Constants.DRAWING_FINISHED - - return False, Constants.DRAWING_FAILURE + return Result().failure(info=Constants.DRAWING_FAILURE) def toggle_home(self): if self.ax0 is not None: @@ -1424,7 +1423,7 @@ class Data: or (not Path(Config["Path"]["Input_Jpeak"]).exists()) or (not Path(Config["Path"]["Input_ECG"]).exists()) or (not Path(Config["Path"]["Input_Rpeak"]).exists())): - return False, Constants.INPUT_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Data_Path_Not_Exist"] + return Result().failure(info=Constants.INPUT_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Data_Path_Not_Exist"]) try: self.raw_orgBcg = read_csv(Config["Path"]["Input_orgBcg"], @@ -1445,15 +1444,13 @@ class Data: self.argmax_BCG = np_argmax(self.raw_BCG) self.argmax_ECG = np_argmax(self.raw_ECG) except Exception: - return False, Constants.INPUT_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Read_Data_Exception"] + return Result().failure(info=Constants.INPUT_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Read_Data_Exception"]) - return True, Constants.INPUT_FINISHED + return Result().success(info=Constants.INPUT_FINISHED) def data_process_for_calculate_correlation(self): - result = {} - if self.Jpeak is None or self.Rpeak is None: - return False, Constants.PRECISELY_ALIGN_PROCESS_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Data_Not_Exist"], result + return Result().failure(info=Constants.PRECISELY_ALIGN_PROCESS_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Data_Not_Exist"]) try: self.JJIs = diff(self.Jpeak) @@ -1463,20 +1460,18 @@ class Data: result = {"JJIVs": JJIVs, "RRIVs": RRIVs} except Exception: - return False, Constants.PRECISELY_ALIGN_PROCESS_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Process_Data_Exception"], result + return Result().failure(info=Constants.PRECISELY_ALIGN_PROCESS_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Process_Data_Exception"]) - return True, Constants.PRECISELY_ALIGN_PROCESS_FINISHED, result + return Result().success(info=Constants.PRECISELY_ALIGN_PROCESS_FINISHED, data=result) def calculate_correlation_front(self, mode, shift_front=None): - result = {} - if ((Config["IV_Coordinate"]["BCG_front_1"] == Config["IV_Coordinate"]["BCG_front_2"]) or (Config["IV_Coordinate"]["ECG_front_1"] == Config["IV_Coordinate"]["ECG_front_2"])): - return False, Constants.PRECISELY_ALIGN_CALCULATE_FAILURE_FRONT + Constants.PRECISELY_ALIGN_FAILURE_REASON["Calculate_Correlation_Value_Equal"], result + return Result().failure(info=Constants.PRECISELY_ALIGN_CALCULATE_FAILURE_FRONT + Constants.PRECISELY_ALIGN_FAILURE_REASON["Calculate_Correlation_Value_Equal"]) if ((Config["IV_Coordinate"]["BCG_front_2"] - Config["IV_Coordinate"]["BCG_front_1"]) >= (Config["IV_Coordinate"]["ECG_front_2"] - Config["IV_Coordinate"]["ECG_front_1"])): - return False, Constants.PRECISELY_ALIGN_CALCULATE_FAILURE_FRONT + Constants.PRECISELY_ALIGN_FAILURE_REASON["Calculate_Correlation_JJIVRange_too_Large"], result + return Result().failure(info=Constants.PRECISELY_ALIGN_CALCULATE_FAILURE_FRONT + Constants.PRECISELY_ALIGN_FAILURE_REASON["Calculate_Correlation_JJIVRange_too_Large"]) try: if mode == "init": @@ -1530,20 +1525,18 @@ class Data: } } except Exception: - return False, Constants.PRECISELY_ALIGN_CALCULATE_FAILURE_FRONT + Constants.PRECISELY_ALIGN_FAILURE_REASON["Calculate_Correlation_Exception"], result + return Result().failure(info=Constants.PRECISELY_ALIGN_CALCULATE_FAILURE_FRONT + Constants.PRECISELY_ALIGN_FAILURE_REASON["Calculate_Correlation_Exception"]) - return True, Constants.PRECISELY_ALIGN_CALCULATE_FINISHED_FRONT, result + return Result().success(info=Constants.PRECISELY_ALIGN_CALCULATE_FINISHED_FRONT, data=result) def calculate_correlation_back(self, mode, shift_back=None): - result = {} - if ((Config["IV_Coordinate"]["BCG_back_1"] == Config["IV_Coordinate"]["BCG_back_2"]) or (Config["IV_Coordinate"]["ECG_back_1"] == Config["IV_Coordinate"]["ECG_back_2"])): - return False, Constants.PRECISELY_ALIGN_CALCULATE_FAILURE_BACK + Constants.PRECISELY_ALIGN_FAILURE_REASON["Calculate_Correlation_Value_Equal"], result + return Result().failure(info=Constants.PRECISELY_ALIGN_CALCULATE_FAILURE_BACK + Constants.PRECISELY_ALIGN_FAILURE_REASON["Calculate_Correlation_Value_Equal"]) if ((Config["IV_Coordinate"]["BCG_back_2"] - Config["IV_Coordinate"]["BCG_back_1"]) >= (Config["IV_Coordinate"]["ECG_back_2"] - Config["IV_Coordinate"]["ECG_back_1"])): - return False, Constants.PRECISELY_ALIGN_CALCULATE_FAILURE_BACK + Constants.PRECISELY_ALIGN_FAILURE_REASON["Calculate_Correlation_JJIVRange_too_Large"], result + return Result().failure(info=Constants.PRECISELY_ALIGN_CALCULATE_FAILURE_BACK + Constants.PRECISELY_ALIGN_FAILURE_REASON["Calculate_Correlation_JJIVRange_too_Large"]) try: if mode == "init": @@ -1597,13 +1590,11 @@ class Data: } } except Exception: - return False, Constants.PRECISELY_ALIGN_CALCULATE_FAILURE_BACK + Constants.PRECISELY_ALIGN_FAILURE_REASON["Calculate_Correlation_Exception"], result + return Result().failure(info=Constants.PRECISELY_ALIGN_CALCULATE_FAILURE_BACK + Constants.PRECISELY_ALIGN_FAILURE_REASON["Calculate_Correlation_Exception"]) - return True, Constants.PRECISELY_ALIGN_CALCULATE_FINISHED_BACK, result + return Result().success(info=Constants.PRECISELY_ALIGN_CALCULATE_FINISHED_BACK, data=result) def correlation_align(self, mode): - result = {} - try: if mode == "init": anchor0 = [Config["front"]["anchor_R"], Config["front"]["anchor_J"]] @@ -1683,9 +1674,9 @@ class Data: else: raise ValueError("模式不存在") except Exception: - return False, Constants.PRECISELY_ALIGN_ALIGN_CORRELATION_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Correlation_Align_Exception"], result + return Result().failure(info=Constants.PRECISELY_ALIGN_ALIGN_CORRELATION_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Correlation_Align_Exception"]) - return True, Constants.PRECISELY_ALIGN_ALIGN_CORRELATION_FINISHED, result + return Result().success(info=Constants.PRECISELY_ALIGN_ALIGN_CORRELATION_FINISHED, data=result) def data_postprocess(self): try: @@ -1738,9 +1729,10 @@ class Data: Config["frontcut_index_ECG"] = frontcut_index_ECG Config["backcut_index_ECG"] = backcut_index_ECG except Exception: - return False, Constants.PRECISELY_ALIGN_POSTPROCESS_VIEW_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["PostProcess_Align_Exception"] + return Result().failure(info=Constants.PRECISELY_ALIGN_POSTPROCESS_VIEW_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["PostProcess_Align_Exception"]) - return True, f"{Constants.PRECISELY_ALIGN_POSTPROCESS_VIEW_FINISHED},BCG前后段被切割的坐标值为[{frontcut_index_BCG}, {backcut_index_BCG}],ECG前后段被切割的坐标值为[{frontcut_index_ECG}, {backcut_index_ECG}]" + info = f"{Constants.PRECISELY_ALIGN_POSTPROCESS_VIEW_FINISHED},BCG前后段被切割的坐标值为[{frontcut_index_BCG}, {backcut_index_BCG}],ECG前后段被切割的坐标值为[{frontcut_index_ECG}, {backcut_index_ECG}]" + return Result().success(info=info) def save_alignInfo(self): try: @@ -1778,64 +1770,64 @@ class Data: DataFrame(save_data).to_csv(Config["Path"]["Save_BCG_AlignInfo"], index=False, header=False) DataFrame(save_data).to_csv(Config["Path"]["Save_ECG_AlignInfo"], index=False, header=False) except Exception: - return False, Constants.PRECISELY_ALIGN_SAVING_ALIGNINFO_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"] + return Result().failure(info=Constants.PRECISELY_ALIGN_SAVING_ALIGNINFO_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"]) - return True, Constants.PRECISELY_ALIGN_SAVING_ALIGNINFO_FINISHED + return Result().success(info=Constants.PRECISELY_ALIGN_SAVING_ALIGNINFO_FINISHED) def save_res_orgBcg(self, chunk): if self.res_orgBcg is None: - return False, Constants.PRECISELY_ALIGN_SAVING_RES_ORGBCG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["res_orgBcg_Not_Exist"] + return Result().failure(info=Constants.PRECISELY_ALIGN_SAVING_RES_ORGBCG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["res_orgBcg_Not_Exist"]) try: chunk.to_csv(Config["Path"]["Save_orgBcg"], mode='a', index=False, header=False) except Exception: - return False, Constants.PRECISELY_ALIGN_SAVING_RES_ORGBCG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"] + return Result().failure(info=Constants.PRECISELY_ALIGN_SAVING_RES_ORGBCG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"]) - return True, Constants.PRECISELY_ALIGN_SAVING_RES_ORGBCG_FINISHED + return Result().success(info=Constants.PRECISELY_ALIGN_SAVING_RES_ORGBCG_FINISHED) def save_res_BCG(self, chunk): if self.res_BCG is None: - return False, Constants.PRECISELY_ALIGN_SAVING_RES_BCG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["res_BCG_Not_Exist"] + return Result().failure(info=Constants.PRECISELY_ALIGN_SAVING_RES_BCG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["res_BCG_Not_Exist"]) try: chunk.to_csv(Config["Path"]["Save_BCG"], mode='a', index=False, header=False) except Exception: - return False, Constants.PRECISELY_ALIGN_SAVING_RES_BCG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"] + return Result().failure(info=Constants.PRECISELY_ALIGN_SAVING_RES_BCG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"]) - return True, Constants.PRECISELY_ALIGN_SAVING_RES_BCG_FINISHED + return Result().success(info=Constants.PRECISELY_ALIGN_SAVING_RES_BCG_FINISHED) def save_cut_ECG(self, chunk): if self.cut_ECG is None: - return False, Constants.PRECISELY_ALIGN_SAVING_CUT_ECG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["cut_ECG_Not_Exist"] + return Result().failure(info=Constants.PRECISELY_ALIGN_SAVING_CUT_ECG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["cut_ECG_Not_Exist"]) try: chunk.to_csv(Config["Path"]["Save_ECG"], mode='a', index=False, header=False) except Exception: - return False, Constants.PRECISELY_ALIGN_SAVING_CUT_ECG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"] + return Result().failure(info=Constants.PRECISELY_ALIGN_SAVING_CUT_ECG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"]) - return True, Constants.PRECISELY_ALIGN_SAVING_CUT_ECG_FINISHED + return Result().success(info=Constants.PRECISELY_ALIGN_SAVING_CUT_ECG_FINISHED) def save_Jpeak(self, chunk): if self.cut_Jpeak is None: - return False, Constants.PRECISELY_ALIGN_SAVING_CUT_JPEAK_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["cut_Jpeak_Not_Exist"] + return Result().failure(info=Constants.PRECISELY_ALIGN_SAVING_CUT_JPEAK_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["cut_Jpeak_Not_Exist"]) try: chunk.to_csv(Config["Path"]["Save_Jpeak"], mode='a', index=False, header=False) except Exception: - return False, Constants.PRECISELY_ALIGN_SAVING_CUT_JPEAK_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"] + return Result().failure(info=Constants.PRECISELY_ALIGN_SAVING_CUT_JPEAK_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"]) - return True, Constants.PRECISELY_ALIGN_SAVING_CUT_JPEAK_FINISHED + return Result().success(info=Constants.PRECISELY_ALIGN_SAVING_CUT_JPEAK_FINISHED) def save_Rpeak(self, chunk): if self.cut_Rpeak is None: - return False, Constants.PRECISELY_ALIGN_SAVING_CUT_RPEAK_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["cut_Rpeak_Not_Exist"] + return Result().failure(info=Constants.PRECISELY_ALIGN_SAVING_CUT_RPEAK_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["cut_Rpeak_Not_Exist"]) try: chunk.to_csv(Config["Path"]["Save_Rpeak"], mode='a', index=False, header=False) except Exception: - return False, Constants.PRECISELY_ALIGN_SAVING_CUT_RPEAK_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"] + return Result().failure(info=Constants.PRECISELY_ALIGN_SAVING_CUT_RPEAK_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"]) - return True, Constants.PRECISELY_ALIGN_SAVING_CUT_RPEAK_FINISHED + return Result().success(info=Constants.PRECISELY_ALIGN_SAVING_CUT_RPEAK_FINISHED) class CustomNavigationToolbar(NavigationToolbar2QT): diff --git a/func/Module_preprocess.py b/func/Module_preprocess.py index 690818f..526baa6 100644 --- a/func/Module_preprocess.py +++ b/func/Module_preprocess.py @@ -14,6 +14,7 @@ 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 ui.MainWindow.MainWindow_preprocess import Ui_MainWindow_preprocess from ui.setting.preprocess_input_setting import Ui_MainWindow_preprocess_input_setting @@ -237,25 +238,28 @@ class MainWindow_preprocess(QMainWindow): @overrides def closeEvent(self, event): - PublicFunc.__disableAllButton__(self, ButtonState) + 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() + PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg(Constants.SHUTTING_DOWN)) + QApplication.processEvents() - # 清空画框 - self.ax0.clear() + # 清空画框 + self.ax0.clear() - # 释放资源 - del self.data - self.fig.clf() - plt.close(self.fig) - self.deleteLater() - collect() - self.canvas = None - event.accept() + # 释放资源 + del self.data + self.fig.clf() + plt.close(self.fig) + self.deleteLater() + collect() + self.canvas = None + event.accept() + else: + event.ignore() - @staticmethod - def __reset__(): + def __reset__(self): ButtonState["Current"].update(ButtonState["Default"].copy()) ButtonState["Current"]["pushButton_view"] = True @@ -273,14 +277,11 @@ class MainWindow_preprocess(QMainWindow): color=Constants.PLOT_COLOR_BLUE, label=Constants.PREPROCESS_PLOT_LABEL_PROCESSED_DATA) self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) - status = True - info = Constants.DRAWING_FINISHED + self.canvas.draw() + return Result().success(info=Constants.DRAWING_FINISHED) else: - status = False - info = Constants.DRAWING_FAILURE - - self.canvas.draw() - return status, info + self.canvas.draw() + return Result().success(info=Constants.DRAWING_FAILURE) def __update_config__(self): if self.mode == "BCG": @@ -306,16 +307,16 @@ class MainWindow_preprocess(QMainWindow): # 导入数据 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) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.data.open_file() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(1/1)" + result.info, Constants.TIPS_TYPE_INFO) - MainWindow_preprocess.__reset__() + self.__reset__() PublicFunc.finish_operation(self, ButtonState) def __slot_btn_view__(self): @@ -323,25 +324,25 @@ class MainWindow_preprocess(QMainWindow): # 数据预处理 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) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + result = self.data.preprocess() + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(1/2)" + result.info, Constants.TIPS_TYPE_INFO) # 绘图 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) - PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + 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)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(2/2)" + result.info, Constants.TIPS_TYPE_INFO) ButtonState["Current"]["pushButton_save"] = True PublicFunc.finish_operation(self, ButtonState) @@ -363,20 +364,20 @@ class MainWindow_preprocess(QMainWindow): for start in range(0, total_rows, chunk_size): end = min(start + chunk_size, total_rows) chunk = DataFrame(self.data.processed_data.reshape(-1)).iloc[start:end] - status, info = self.data.save(chunk) + result = 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) + 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)" + info, Constants.TIPS_TYPE_INFO) - PublicFunc.msgbox_output(self, info, Constants.TIPS_TYPE_INFO) + 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 reset_axes(self): @@ -393,20 +394,20 @@ class Data: def open_file(self): if not Path(Config["Path"]["Input"]).exists(): - return False, Constants.INPUT_FAILURE + Constants.PREPROCESS_FAILURE_REASON["Data_Path_Not_Exist"] + return Result().failure(info=Constants.INPUT_FAILURE + Constants.PREPROCESS_FAILURE_REASON["Data_Path_Not_Exist"]) try: self.raw_data = read_csv(Config["Path"]["Input"], encoding=ConfigParams.UTF8_ENCODING, header=None).to_numpy().reshape(-1) except Exception: - return False, Constants.INPUT_FAILURE + Constants.PREPROCESS_FAILURE_REASON["Read_Data_Exception"] + return Result().failure(info=Constants.INPUT_FAILURE + Constants.PREPROCESS_FAILURE_REASON["Read_Data_Exception"]) - return True, Constants.INPUT_FINISHED + return Result().success(info=Constants.INPUT_FINISHED) def preprocess(self): if self.raw_data is None: - return False, Constants.PREPROCESS_PROCESS_FAILURE + Constants.PREPROCESS_FAILURE_REASON["Raw_Data_Not_Exist"] + Result().failure(info=Constants.PREPROCESS_PROCESS_FAILURE + Constants.PREPROCESS_FAILURE_REASON["Raw_Data_Not_Exist"]) try: if Config["InputConfig"]["Freq"] != Config["OutputConfig"]["Freq"]: @@ -428,17 +429,18 @@ class Data: else: raise ValueError("模式不存在") except Exception: - return False, Constants.PREPROCESS_PROCESS_FAILURE + Constants.PREPROCESS_FAILURE_REASON["Filter_Exception"] + Result().failure(info=Constants.PREPROCESS_PROCESS_FAILURE + Constants.PREPROCESS_FAILURE_REASON["Filter_Exception"]) + + return Result().success(info=Constants.PREPROCESS_PROCESS_FINISHED) - return True, Constants.PREPROCESS_PROCESS_FINISHED def save(self, chunk): if self.processed_data is None: - return False, Constants.SAVING_FAILURE + Constants.PREPROCESS_FAILURE_REASON["Processed_Data_Not_Exist"] + return Result().failure(info=Constants.SAVING_FAILURE + Constants.PREPROCESS_FAILURE_REASON["Processed_Data_Not_Exist"]) try: chunk.to_csv(Config["Path"]["Save"], mode='a', index=False, header=False, float_format='%.4f') except Exception: - return False, Constants.SAVING_FAILURE + Constants.PREPROCESS_FAILURE_REASON["Save_Exception"] + return Result().failure(info=Constants.SAVING_FAILURE + Constants.PREPROCESS_FAILURE_REASON["Save_Exception"]) - return True, Constants.SAVING_FINISHED + return Result().success(Constants.SAVING_FINISHED) \ No newline at end of file diff --git a/func/utils/ConfigParams.py b/func/utils/ConfigParams.py index 8513331..eeece1a 100644 --- a/func/utils/ConfigParams.py +++ b/func/utils/ConfigParams.py @@ -30,6 +30,24 @@ class ConfigParams: FONT: str = "Microsoft YaHei UI" # 数据粗同步 + APPROXIMATELY_ALIGN_CONFIG_FILE_PATH: str = "./config/Config_approximately_align.yaml" + APPROXIMATELY_ALIGN_CONFIG_NEW_CONTENT: dict = { + "InputConfig": { + "orgBcgFreq": 1000, + "ThoFreq": 100, + "AbdFreq": 100 + }, + "ApplyFrequency": 5, + "Filter": { + "BandPassOrder": 4, + "BandPassLow": 0.01, + "BandPassHigh": 0.7 + } + } + APPROXIMATELY_ALIGN_INPUT_ORGBCG_FILENAME: str = "orgBcg_Raw_" + APPROXIMATELY_ALIGN_INPUT_THO_FILENAME: str = "Effort Tho_Raw_" + APPROXIMATELY_ALIGN_INPUT_ABD_FILENAME: str = "Effort Abd_Raw_" + APPROXIMATELY_ALIGN_SAVE_FILENAME: str = "Approximately_Align_Info" # 预处理 PREPROCESS_CONFIG_FILE_PATH: str = "./config/Config_preprocess.yaml" @@ -200,21 +218,6 @@ class ConfigParams: VALIDATOR_INTEGER = QIntValidator(-2**31, 2**31 - 1) VALIDATOR_DOUBLE = QDoubleValidator(-1e100, 1e100, 10) - # 数据粗同步 - APPROXIMATELY_ALIGN_INPUT_ORGBCG_FILENAME: str = "orgBcg_Raw_" - APPROXIMATELY_ALIGN_INPUT_PSG_FILENAME: str = "A" - APPROXIMATELY_ALIGN_SAVE_FILENAME: str = "Approximately_Align_Info" - - APPROXIMATELY_ALIGN_INPUT_ORGBCG_DEFAULT_FS: int = 1000 - APPROXIMATELY_ALIGN_INPUT_PSG_DEFAULT_FS: int = 100 - - APPROXIMATELY_ALIGN_THO_CUSTOM_CHANNEL_DEFAULT: int = 3 - APPROXIMATELY_ALIGN_ABD_CUSTOM_CHANNE_DEFAULT: int = 4 - APPROXIMATELY_ALIGN_BUTTERORDER_DEFAULT: int = 4 - APPROXIMATELY_ALIGN_BUTTERLOWPASSFREQ_CHANNE_DEFAULT: float = 0.01 - APPROXIMATELY_ALIGN_BUTTERHIGHPASSFREQ_DEFAULT: float = 0.70 - APPROXIMATELY_ALIGN_APPLYFREQ_DEFAULT: float = 5 - # 体动打标 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 4fbc214..e36b7fb 100644 --- a/func/utils/Constants.py +++ b/func/utils/Constants.py @@ -74,6 +74,65 @@ class Constants: } """ + # 数据粗同步 + APPROXIMATELY_ONLY_ALIGN_RESAMPLING: str = "正在仅重采样" + APPROXIMATELY_ONLY_ALIGN_RESAMPLE_FINISHED: str = "仅重采样完成" + APPROXIMATELY_ONLY_ALIGN_RESAMPLE_FAILURE: str = "仅重采样失败" + + APPROXIMATELY_RESP_GETTING: str = "正在呼吸提取" + APPROXIMATELY_RESP_GET_FINISHED: str = "呼吸提取完成" + APPROXIMATELY_RESP_GET_FAILURE: str = "呼吸提取失败" + + APPROXIMATELY_PRE_ALIGN_RESAMPLING: str = "正在预重采样" + APPROXIMATELY_PRE_ALIGN_RESAMPLE_FINISHED: str = "预重采样完成" + APPROXIMATELY_PRE_ALIGN_RESAMPLE_FAILURE: str = "预重采样失败" + + APPROXIMATELY_DELETING_BASE: str = "正在去基线" + APPROXIMATELY_DELETE_BASE_FINISHED: str = "去基线完成" + APPROXIMATELY_DELETE_BASE_FAILURE: str = "去基线失败" + + APPROXIMATELY_STANDARDIZING: str = "正在标准化" + APPROXIMATELY_STANDARDIZE_FINISHED: str = "标准化完成" + APPROXIMATELY_STANDARDIZE_FAILURE: str = "标准化失败" + + APPROXIMATELY_ALIGN_RESAMPLING: str = "正在重采样" + APPROXIMATELY_ALIGN_RESAMPLE_FINISHED: str = "重采样完成" + APPROXIMATELY_ALIGN_RESAMPLE_FAILURE: str = "重采样失败" + + APPROXIMATELY_CORRELATION_CALCULATING1: str = "正在计算互相关1/2" + APPROXIMATELY_CORRELATION_CALCULATE1_FINISHED: str = "计算互相关1/2完成" + APPROXIMATELY_CORRELATION_CALCULATE1_FAILURE: str = "计算互相关1/2失败" + + APPROXIMATELY_CORRELATION_CALCULATING2: str = "正在计算互相关2/2" + APPROXIMATELY_CORRELATION_CALCULATE2_FINISHED: str = "计算互相关2/2完成" + APPROXIMATELY_CORRELATION_CALCULATE2_FAILURE: str = "计算互相关2/2失败" + + APPROXIMATELY_MAXVALUE_POS_CALCULATING: str = "正在计算最大值位置" + APPROXIMATELY_MAXVALUE_POS_CALCULATE_FINISHED: str = "计算最大值位置完成" + APPROXIMATELY_MAXVALUE_POS_CALCULATE_FAILURE: str = "计算最大值位置失败" + + APPROXIMATELY_EPOCH_GETTING: str = "正在获取epoch" + APPROXIMATELY_EPOCH_GET_FINISHED: str = "获取epoch完成" + APPROXIMATELY_EPOCH_GET_FAILURE: str = "获取epoch失败" + + APPROXIMATELY_ALIGN_FAILURE_REASON = { + "Data_Path_Not_Exist": "(路径不存在)", + "Read_Data_Exception": "(读取数据异常)", + "Raw_Data_Not_Exist": "(原始数据不存在)", + "Only_Resample_Exception": "(仅重采样异常)", + "Resp_Get_Exception": "(呼吸提取异常)", + "Pre_Resample_Exception": "(预重采样异常)", + "Delete_Base_Exception": "(去基线异常)", + "Standardize_Exception": "(标准化异常)", + "Resample_Exception": "(重采样异常)", + "Calculate_Correlation1_Exception": "(计算互相关1/2异常)", + "Calculate_Correlation2_Exception": "(计算互相关2/2异常)", + "Calculate_Maxvalue_Pos_Exception": "(计算最大值位置异常)", + "Get_Epoch_Exception": "(获取epoch异常)", + "Processed_Data_Not_Exist": "(处理后数据不存在)", + "Save_Exception": "(保存异常)" + } + # 预处理 PREPROCESS_PROCESSING_DATA: str = "正在处理数据" PREPROCESS_PROCESS_FINISHED: str = "处理完成" @@ -263,8 +322,8 @@ class Constants: PRECISELY_ALIGN_PLOT_LABEL_CORRE_RRIV_JJIV: str = "corre(RRIV, JJIV)" PRECISELY_ALIGN_PLOT_LABEL_ECG: str = "ECG" PRECISELY_ALIGN_PLOT_LABEL_BCG: str = "BCG" - PRECISELY_ALIGN_PLOT_LABEL_RPEAK: str = "Rpeak_ECG" - PRECISELY_ALIGN_PLOT_LABEL_JPEAK: str = "Jpeak_BCG" + PRECISELY_ALIGN_PLOT_LABEL_RPEAK: str = "peak_ECG" + PRECISELY_ALIGN_PLOT_LABEL_JPEAK: str = "peak_BCG" PRECISELY_ALIGN_PLOT_LABEL_SELECTED_POINT: str = "Selected Point" PRECISELY_ALIGN_NO_POINT_IN_THE_INTERVAL: str = "所选区间内无有效点" PRECISELY_ALIGN_ACTION_GET_RANGE_NAME: str = f"设置范围({ConfigParams.PRECISELY_ALIGN_ACTION_GET_RANGE_SHORTCUT_KEY})" @@ -298,13 +357,6 @@ class Constants: # 体动标注 # TODO:弃用 - # 数据粗同步 - APPROXIMATELY_ALIGN_FILES_NOT_FOUND: str = f"无法找到{ConfigParams.APPROXIMATELY_ALIGN_INPUT_ORGBCG_FILENAME}{ConfigParams.ENDSWITH_TXT}或{ConfigParams.APPROXIMATELY_ALIGN_INPUT_PSG_FILENAME}{ConfigParams.ENDSWITH_EDF},无法执行<数据粗同步>" - APPROXIMATELY_ALIGN_FILES_FOUND: str = f"找到{ConfigParams.APPROXIMATELY_ALIGN_INPUT_ORGBCG_FILENAME}{ConfigParams.ENDSWITH_TXT}和{ConfigParams.APPROXIMATELY_ALIGN_INPUT_PSG_FILENAME}{ConfigParams.ENDSWITH_EDF}" - - APPROXIMATELY_ALIGN_RUNNING: str = "开始执行任务<数据粗同步>" - APPROXIMATELY_RECORD_NOT_FOUND: str = "没有保存记录" - # 体动打标 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/Result.py b/func/utils/Result.py new file mode 100644 index 0000000..c630d35 --- /dev/null +++ b/func/utils/Result.py @@ -0,0 +1,48 @@ +class Result: + def __init__(self, status=False, info="", data=None): + """ + 初始化 Result 对象 + :param status: 布尔值,表示业务操作是否成功,默认为 False + :param info: 字符串,表示业务提示信息,默认为空字符串 + :param data: 字典,表示返回的数据,默认为 None + """ + self.status = status + self.info = info + self.data = data if data is not None else {} + + def success(self, info="", data=None): + """ + 设置业务操作成功 + :param info: 成功提示信息 + :param data: 返回的数据 + """ + self.status = True + self.info = info + self.data = data if data is not None else {} + return self + + def failure(self, info=""): + """ + 设置业务操作失败 + :param info: 失败提示信息 + """ + self.status = False + self.info = info + return self + + def to_dict(self): + """ + 将对象转换为字典 + :return: 包含 status、info 和 data 的字典 + """ + return { + "status": self.status, + "info": self.info, + "data": self.data + } + + def __str__(self): + """ + 返回对象的字符串表示 + """ + return str(self.to_dict()) \ No newline at end of file diff --git a/ui/MainWindow/MainWindow_approximately_align.py b/ui/MainWindow/MainWindow_approximately_align.py new file mode 100644 index 0000000..c216bdd --- /dev/null +++ b/ui/MainWindow/MainWindow_approximately_align.py @@ -0,0 +1,550 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'MainWindow_approximately_align.ui' +## +## Created by: Qt User Interface Compiler version 6.8.2 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, + QMetaObject, QObject, QPoint, QRect, + QSize, QTime, QUrl, Qt) +from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, + QFont, QFontDatabase, QGradient, QIcon, + QImage, QKeySequence, QLinearGradient, QPainter, + QPalette, QPixmap, QRadialGradient, QTransform) +from PySide6.QtWidgets import (QAbstractSpinBox, QApplication, QCheckBox, QGridLayout, + QGroupBox, QHBoxLayout, QLabel, QMainWindow, + QPushButton, QRadioButton, QSizePolicy, QSpacerItem, + QSpinBox, QStatusBar, QTextBrowser, QVBoxLayout, + QWidget) + +class Ui_MainWindow_approximately_align(object): + def setupUi(self, MainWindow_approximately_align): + if not MainWindow_approximately_align.objectName(): + MainWindow_approximately_align.setObjectName(u"MainWindow_approximately_align") + MainWindow_approximately_align.resize(1920, 1080) + self.centralwidget = QWidget(MainWindow_approximately_align) + self.centralwidget.setObjectName(u"centralwidget") + self.gridLayout = QGridLayout(self.centralwidget) + self.gridLayout.setObjectName(u"gridLayout") + self.groupBox_left = QGroupBox(self.centralwidget) + self.groupBox_left.setObjectName(u"groupBox_left") + font = QFont() + font.setPointSize(10) + self.groupBox_left.setFont(font) + self.verticalLayout = QVBoxLayout(self.groupBox_left) + self.verticalLayout.setObjectName(u"verticalLayout") + self.horizontalLayout_4 = QHBoxLayout() + self.horizontalLayout_4.setObjectName(u"horizontalLayout_4") + self.pushButton_input_setting = QPushButton(self.groupBox_left) + self.pushButton_input_setting.setObjectName(u"pushButton_input_setting") + sizePolicy = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.pushButton_input_setting.sizePolicy().hasHeightForWidth()) + self.pushButton_input_setting.setSizePolicy(sizePolicy) + font1 = QFont() + font1.setPointSize(12) + self.pushButton_input_setting.setFont(font1) + + self.horizontalLayout_4.addWidget(self.pushButton_input_setting) + + self.pushButton_input = QPushButton(self.groupBox_left) + self.pushButton_input.setObjectName(u"pushButton_input") + sizePolicy.setHeightForWidth(self.pushButton_input.sizePolicy().hasHeightForWidth()) + self.pushButton_input.setSizePolicy(sizePolicy) + self.pushButton_input.setFont(font1) + + self.horizontalLayout_4.addWidget(self.pushButton_input) + + + self.verticalLayout.addLayout(self.horizontalLayout_4) + + self.horizontalLayout_2 = QHBoxLayout() + self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") + self.label_3 = QLabel(self.groupBox_left) + self.label_3.setObjectName(u"label_3") + self.label_3.setFont(font1) + + self.horizontalLayout_2.addWidget(self.label_3) + + self.label_orgBcg_length = QLabel(self.groupBox_left) + self.label_orgBcg_length.setObjectName(u"label_orgBcg_length") + self.label_orgBcg_length.setFont(font1) + + self.horizontalLayout_2.addWidget(self.label_orgBcg_length) + + self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) + + self.horizontalLayout_2.addItem(self.horizontalSpacer) + + self.label_6 = QLabel(self.groupBox_left) + self.label_6.setObjectName(u"label_6") + self.label_6.setFont(font1) + + self.horizontalLayout_2.addWidget(self.label_6) + + self.label_PSG_length = QLabel(self.groupBox_left) + self.label_PSG_length.setObjectName(u"label_PSG_length") + self.label_PSG_length.setFont(font1) + + self.horizontalLayout_2.addWidget(self.label_PSG_length) + + + self.verticalLayout.addLayout(self.horizontalLayout_2) + + self.groupBox_standardize = QGroupBox(self.groupBox_left) + self.groupBox_standardize.setObjectName(u"groupBox_standardize") + self.verticalLayout_5 = QVBoxLayout(self.groupBox_standardize) + self.verticalLayout_5.setObjectName(u"verticalLayout_5") + self.horizontalLayout = QHBoxLayout() + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.checkBox_orgBcgDelBase = QCheckBox(self.groupBox_standardize) + self.checkBox_orgBcgDelBase.setObjectName(u"checkBox_orgBcgDelBase") + self.checkBox_orgBcgDelBase.setFont(font1) + self.checkBox_orgBcgDelBase.setChecked(True) + + self.horizontalLayout.addWidget(self.checkBox_orgBcgDelBase) + + self.checkBox_PSGDelBase = QCheckBox(self.groupBox_standardize) + self.checkBox_PSGDelBase.setObjectName(u"checkBox_PSGDelBase") + self.checkBox_PSGDelBase.setFont(font1) + self.checkBox_PSGDelBase.setChecked(True) + + self.horizontalLayout.addWidget(self.checkBox_PSGDelBase) + + self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) + + self.horizontalLayout.addItem(self.horizontalSpacer_2) + + self.checkBox_RawSignal = QCheckBox(self.groupBox_standardize) + self.checkBox_RawSignal.setObjectName(u"checkBox_RawSignal") + self.checkBox_RawSignal.setFont(font1) + + self.horizontalLayout.addWidget(self.checkBox_RawSignal) + + + self.verticalLayout_5.addLayout(self.horizontalLayout) + + self.horizontalLayout_5 = QHBoxLayout() + self.horizontalLayout_5.setObjectName(u"horizontalLayout_5") + self.checkBox_orgBcgZScore = QCheckBox(self.groupBox_standardize) + self.checkBox_orgBcgZScore.setObjectName(u"checkBox_orgBcgZScore") + self.checkBox_orgBcgZScore.setFont(font1) + self.checkBox_orgBcgZScore.setChecked(True) + + self.horizontalLayout_5.addWidget(self.checkBox_orgBcgZScore) + + self.checkBox_PSGZScore = QCheckBox(self.groupBox_standardize) + self.checkBox_PSGZScore.setObjectName(u"checkBox_PSGZScore") + self.checkBox_PSGZScore.setFont(font1) + self.checkBox_PSGZScore.setChecked(True) + + self.horizontalLayout_5.addWidget(self.checkBox_PSGZScore) + + self.horizontalSpacer_3 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) + + self.horizontalLayout_5.addItem(self.horizontalSpacer_3) + + self.pushButton_Standardize = QPushButton(self.groupBox_standardize) + self.pushButton_Standardize.setObjectName(u"pushButton_Standardize") + self.pushButton_Standardize.setFont(font1) + + self.horizontalLayout_5.addWidget(self.pushButton_Standardize) + + + self.verticalLayout_5.addLayout(self.horizontalLayout_5) + + self.verticalLayout_5.setStretch(0, 1) + self.verticalLayout_5.setStretch(1, 1) + + self.verticalLayout.addWidget(self.groupBox_standardize) + + self.groupBox_get_position = QGroupBox(self.groupBox_left) + self.groupBox_get_position.setObjectName(u"groupBox_get_position") + self.verticalLayout_8 = QVBoxLayout(self.groupBox_get_position) + self.verticalLayout_8.setObjectName(u"verticalLayout_8") + self.horizontalLayout_6 = QHBoxLayout() + self.horizontalLayout_6.setObjectName(u"horizontalLayout_6") + self.label = QLabel(self.groupBox_get_position) + self.label.setObjectName(u"label") + self.label.setFont(font1) + + self.horizontalLayout_6.addWidget(self.label) + + self.spinBox_orgBcgPreA = QSpinBox(self.groupBox_get_position) + self.spinBox_orgBcgPreA.setObjectName(u"spinBox_orgBcgPreA") + self.spinBox_orgBcgPreA.setFont(font1) + self.spinBox_orgBcgPreA.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_orgBcgPreA.setMaximum(999999) + + self.horizontalLayout_6.addWidget(self.spinBox_orgBcgPreA) + + self.label_2 = QLabel(self.groupBox_get_position) + self.label_2.setObjectName(u"label_2") + self.label_2.setFont(font1) + + self.horizontalLayout_6.addWidget(self.label_2) + + self.spinBox_PSGPreA = QSpinBox(self.groupBox_get_position) + self.spinBox_PSGPreA.setObjectName(u"spinBox_PSGPreA") + self.spinBox_PSGPreA.setFont(font1) + self.spinBox_PSGPreA.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_PSGPreA.setMaximum(999999) + + self.horizontalLayout_6.addWidget(self.spinBox_PSGPreA) + + self.horizontalLayout_6.setStretch(0, 1) + self.horizontalLayout_6.setStretch(1, 2) + self.horizontalLayout_6.setStretch(2, 1) + self.horizontalLayout_6.setStretch(3, 2) + + self.verticalLayout_8.addLayout(self.horizontalLayout_6) + + self.horizontalLayout_8 = QHBoxLayout() + self.horizontalLayout_8.setObjectName(u"horizontalLayout_8") + self.label_4 = QLabel(self.groupBox_get_position) + self.label_4.setObjectName(u"label_4") + self.label_4.setFont(font1) + + self.horizontalLayout_8.addWidget(self.label_4) + + self.spinBox_orgBcgPreCut = QSpinBox(self.groupBox_get_position) + self.spinBox_orgBcgPreCut.setObjectName(u"spinBox_orgBcgPreCut") + self.spinBox_orgBcgPreCut.setFont(font1) + self.spinBox_orgBcgPreCut.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_orgBcgPreCut.setMaximum(999999) + + self.horizontalLayout_8.addWidget(self.spinBox_orgBcgPreCut) + + self.label_5 = QLabel(self.groupBox_get_position) + self.label_5.setObjectName(u"label_5") + self.label_5.setFont(font1) + + self.horizontalLayout_8.addWidget(self.label_5) + + self.spinBox_PSGPreCut = QSpinBox(self.groupBox_get_position) + self.spinBox_PSGPreCut.setObjectName(u"spinBox_PSGPreCut") + self.spinBox_PSGPreCut.setFont(font1) + self.spinBox_PSGPreCut.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_PSGPreCut.setMaximum(999999) + + self.horizontalLayout_8.addWidget(self.spinBox_PSGPreCut) + + self.horizontalLayout_8.setStretch(0, 1) + self.horizontalLayout_8.setStretch(1, 2) + self.horizontalLayout_8.setStretch(2, 1) + self.horizontalLayout_8.setStretch(3, 2) + + self.verticalLayout_8.addLayout(self.horizontalLayout_8) + + self.horizontalLayout_9 = QHBoxLayout() + self.horizontalLayout_9.setObjectName(u"horizontalLayout_9") + self.label_7 = QLabel(self.groupBox_get_position) + self.label_7.setObjectName(u"label_7") + self.label_7.setFont(font1) + + self.horizontalLayout_9.addWidget(self.label_7) + + self.spinBox_orgBcgPostCut = QSpinBox(self.groupBox_get_position) + self.spinBox_orgBcgPostCut.setObjectName(u"spinBox_orgBcgPostCut") + self.spinBox_orgBcgPostCut.setFont(font1) + self.spinBox_orgBcgPostCut.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_orgBcgPostCut.setMaximum(999999) + + self.horizontalLayout_9.addWidget(self.spinBox_orgBcgPostCut) + + self.label_8 = QLabel(self.groupBox_get_position) + self.label_8.setObjectName(u"label_8") + self.label_8.setFont(font1) + + self.horizontalLayout_9.addWidget(self.label_8) + + self.spinBox_PSGPostCut = QSpinBox(self.groupBox_get_position) + self.spinBox_PSGPostCut.setObjectName(u"spinBox_PSGPostCut") + self.spinBox_PSGPostCut.setFont(font1) + self.spinBox_PSGPostCut.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_PSGPostCut.setMaximum(999999) + + self.horizontalLayout_9.addWidget(self.spinBox_PSGPostCut) + + self.horizontalLayout_9.setStretch(0, 1) + self.horizontalLayout_9.setStretch(1, 2) + self.horizontalLayout_9.setStretch(2, 1) + self.horizontalLayout_9.setStretch(3, 2) + + self.verticalLayout_8.addLayout(self.horizontalLayout_9) + + self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + + self.verticalLayout_8.addItem(self.verticalSpacer_2) + + self.horizontalLayout_7 = QHBoxLayout() + self.horizontalLayout_7.setObjectName(u"horizontalLayout_7") + self.pushButton_CutOff = QPushButton(self.groupBox_get_position) + self.pushButton_CutOff.setObjectName(u"pushButton_CutOff") + self.pushButton_CutOff.setFont(font1) + + self.horizontalLayout_7.addWidget(self.pushButton_CutOff) + + self.horizontalSpacer_5 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) + + self.horizontalLayout_7.addItem(self.horizontalSpacer_5) + + self.pushButton_GetPos = QPushButton(self.groupBox_get_position) + self.pushButton_GetPos.setObjectName(u"pushButton_GetPos") + self.pushButton_GetPos.setFont(font1) + + self.horizontalLayout_7.addWidget(self.pushButton_GetPos) + + + self.verticalLayout_8.addLayout(self.horizontalLayout_7) + + self.verticalLayout_8.setStretch(0, 2) + self.verticalLayout_8.setStretch(1, 2) + self.verticalLayout_8.setStretch(2, 2) + self.verticalLayout_8.setStretch(3, 1) + self.verticalLayout_8.setStretch(4, 2) + + self.verticalLayout.addWidget(self.groupBox_get_position) + + self.groupBox_align_position = QGroupBox(self.groupBox_left) + self.groupBox_align_position.setObjectName(u"groupBox_align_position") + self.gridLayout_2 = QGridLayout(self.groupBox_align_position) + self.gridLayout_2.setObjectName(u"gridLayout_2") + self.radioButton_NTHO = QRadioButton(self.groupBox_align_position) + self.radioButton_NTHO.setObjectName(u"radioButton_NTHO") + self.radioButton_NTHO.setFont(font1) + + self.gridLayout_2.addWidget(self.radioButton_NTHO, 0, 1, 1, 1) + + self.radioButton_PTHO = QRadioButton(self.groupBox_align_position) + self.radioButton_PTHO.setObjectName(u"radioButton_PTHO") + self.radioButton_PTHO.setFont(font1) + + self.gridLayout_2.addWidget(self.radioButton_PTHO, 0, 0, 1, 1) + + self.radioButton_PABD = QRadioButton(self.groupBox_align_position) + self.radioButton_PABD.setObjectName(u"radioButton_PABD") + self.radioButton_PABD.setFont(font1) + + self.gridLayout_2.addWidget(self.radioButton_PABD, 0, 2, 1, 1) + + self.radioButton_NABD = QRadioButton(self.groupBox_align_position) + self.radioButton_NABD.setObjectName(u"radioButton_NABD") + self.radioButton_NABD.setFont(font1) + + self.gridLayout_2.addWidget(self.radioButton_NABD, 1, 0, 1, 1) + + self.radioButton_custom = QRadioButton(self.groupBox_align_position) + self.radioButton_custom.setObjectName(u"radioButton_custom") + self.radioButton_custom.setFont(font1) + + self.gridLayout_2.addWidget(self.radioButton_custom, 1, 1, 1, 1) + + self.spinBox_custom = QSpinBox(self.groupBox_align_position) + self.spinBox_custom.setObjectName(u"spinBox_custom") + self.spinBox_custom.setFont(font1) + self.spinBox_custom.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_custom.setMinimum(-1000000) + self.spinBox_custom.setMaximum(1000000) + + self.gridLayout_2.addWidget(self.spinBox_custom, 1, 2, 1, 1) + + + self.verticalLayout.addWidget(self.groupBox_align_position) + + self.groupBox_view_partially = QGroupBox(self.groupBox_left) + self.groupBox_view_partially.setObjectName(u"groupBox_view_partially") + self.verticalLayout_2 = QVBoxLayout(self.groupBox_view_partially) + self.verticalLayout_2.setObjectName(u"verticalLayout_2") + self.horizontalLayout_10 = QHBoxLayout() + self.horizontalLayout_10.setObjectName(u"horizontalLayout_10") + self.label_9 = QLabel(self.groupBox_view_partially) + self.label_9.setObjectName(u"label_9") + self.label_9.setFont(font1) + + self.horizontalLayout_10.addWidget(self.label_9) + + self.spinBox_SelectEpoch = QSpinBox(self.groupBox_view_partially) + self.spinBox_SelectEpoch.setObjectName(u"spinBox_SelectEpoch") + self.spinBox_SelectEpoch.setFont(font1) + self.spinBox_SelectEpoch.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_SelectEpoch.setMaximum(2000) + + self.horizontalLayout_10.addWidget(self.spinBox_SelectEpoch) + + self.horizontalSpacer_4 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) + + self.horizontalLayout_10.addItem(self.horizontalSpacer_4) + + self.pushButton_JUMP = QPushButton(self.groupBox_view_partially) + self.pushButton_JUMP.setObjectName(u"pushButton_JUMP") + self.pushButton_JUMP.setFont(font1) + + self.horizontalLayout_10.addWidget(self.pushButton_JUMP) + + + self.verticalLayout_2.addLayout(self.horizontalLayout_10) + + self.gridLayout_3 = QGridLayout() + self.gridLayout_3.setObjectName(u"gridLayout_3") + self.pushButton_EP10 = QPushButton(self.groupBox_view_partially) + self.pushButton_EP10.setObjectName(u"pushButton_EP10") + self.pushButton_EP10.setFont(font1) + + self.gridLayout_3.addWidget(self.pushButton_EP10, 0, 1, 1, 1) + + self.pushButton_EP1 = QPushButton(self.groupBox_view_partially) + self.pushButton_EP1.setObjectName(u"pushButton_EP1") + self.pushButton_EP1.setFont(font1) + + self.gridLayout_3.addWidget(self.pushButton_EP1, 0, 0, 1, 1) + + self.pushButton_EP100 = QPushButton(self.groupBox_view_partially) + self.pushButton_EP100.setObjectName(u"pushButton_EP100") + self.pushButton_EP100.setFont(font1) + + self.gridLayout_3.addWidget(self.pushButton_EP100, 0, 2, 1, 1) + + self.pushButton_EM1 = QPushButton(self.groupBox_view_partially) + self.pushButton_EM1.setObjectName(u"pushButton_EM1") + self.pushButton_EM1.setFont(font1) + + self.gridLayout_3.addWidget(self.pushButton_EM1, 1, 0, 1, 1) + + self.pushButton_EM10 = QPushButton(self.groupBox_view_partially) + self.pushButton_EM10.setObjectName(u"pushButton_EM10") + self.pushButton_EM10.setFont(font1) + + self.gridLayout_3.addWidget(self.pushButton_EM10, 1, 1, 1, 1) + + self.pushButton_EM100 = QPushButton(self.groupBox_view_partially) + self.pushButton_EM100.setObjectName(u"pushButton_EM100") + self.pushButton_EM100.setFont(font1) + + self.gridLayout_3.addWidget(self.pushButton_EM100, 1, 2, 1, 1) + + + self.verticalLayout_2.addLayout(self.gridLayout_3) + + self.verticalLayout_2.setStretch(0, 1) + self.verticalLayout_2.setStretch(1, 2) + + self.verticalLayout.addWidget(self.groupBox_view_partially) + + self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + + self.verticalLayout.addItem(self.verticalSpacer) + + self.pushButton_save = QPushButton(self.groupBox_left) + self.pushButton_save.setObjectName(u"pushButton_save") + sizePolicy.setHeightForWidth(self.pushButton_save.sizePolicy().hasHeightForWidth()) + self.pushButton_save.setSizePolicy(sizePolicy) + self.pushButton_save.setFont(font1) + + self.verticalLayout.addWidget(self.pushButton_save) + + self.groupBox = QGroupBox(self.groupBox_left) + self.groupBox.setObjectName(u"groupBox") + self.verticalLayout_6 = QVBoxLayout(self.groupBox) + self.verticalLayout_6.setObjectName(u"verticalLayout_6") + self.textBrowser_info = QTextBrowser(self.groupBox) + self.textBrowser_info.setObjectName(u"textBrowser_info") + + self.verticalLayout_6.addWidget(self.textBrowser_info) + + + self.verticalLayout.addWidget(self.groupBox) + + self.verticalLayout.setStretch(0, 1) + self.verticalLayout.setStretch(1, 1) + self.verticalLayout.setStretch(2, 3) + self.verticalLayout.setStretch(3, 5) + self.verticalLayout.setStretch(4, 2) + self.verticalLayout.setStretch(5, 4) + self.verticalLayout.setStretch(6, 1) + self.verticalLayout.setStretch(7, 1) + self.verticalLayout.setStretch(8, 4) + + self.gridLayout.addWidget(self.groupBox_left, 0, 0, 1, 1) + + self.groupBox_canvas = QGroupBox(self.centralwidget) + self.groupBox_canvas.setObjectName(u"groupBox_canvas") + self.groupBox_canvas.setFont(font) + self.verticalLayout_7 = QVBoxLayout(self.groupBox_canvas) + self.verticalLayout_7.setObjectName(u"verticalLayout_7") + self.verticalLayout_canvas = QVBoxLayout() + self.verticalLayout_canvas.setObjectName(u"verticalLayout_canvas") + self.label_Pic = QLabel(self.groupBox_canvas) + self.label_Pic.setObjectName(u"label_Pic") + + self.verticalLayout_canvas.addWidget(self.label_Pic) + + + self.verticalLayout_7.addLayout(self.verticalLayout_canvas) + + + self.gridLayout.addWidget(self.groupBox_canvas, 0, 1, 1, 1) + + self.gridLayout.setColumnStretch(0, 3) + self.gridLayout.setColumnStretch(1, 10) + MainWindow_approximately_align.setCentralWidget(self.centralwidget) + self.statusbar = QStatusBar(MainWindow_approximately_align) + self.statusbar.setObjectName(u"statusbar") + MainWindow_approximately_align.setStatusBar(self.statusbar) + + self.retranslateUi(MainWindow_approximately_align) + + QMetaObject.connectSlotsByName(MainWindow_approximately_align) + # setupUi + + def retranslateUi(self, MainWindow_approximately_align): + MainWindow_approximately_align.setWindowTitle(QCoreApplication.translate("MainWindow_approximately_align", u"\u6570\u636e\u7c97\u540c\u6b65", None)) + self.groupBox_left.setTitle(QCoreApplication.translate("MainWindow_approximately_align", u"\u6570\u636e\u7c97\u540c\u6b65", None)) + self.pushButton_input_setting.setText(QCoreApplication.translate("MainWindow_approximately_align", u"\u5bfc\u5165\u8bbe\u7f6e", None)) + self.pushButton_input.setText(QCoreApplication.translate("MainWindow_approximately_align", u"\u5f00\u59cb\u5bfc\u5165", None)) + self.label_3.setText(QCoreApplication.translate("MainWindow_approximately_align", u"orgBcg\u65f6\u957f(min)\uff1a", None)) + self.label_orgBcg_length.setText(QCoreApplication.translate("MainWindow_approximately_align", u"0", None)) + self.label_6.setText(QCoreApplication.translate("MainWindow_approximately_align", u"PSG\u65f6\u957f(min)\uff1a", None)) + self.label_PSG_length.setText(QCoreApplication.translate("MainWindow_approximately_align", u"0", None)) + self.groupBox_standardize.setTitle(QCoreApplication.translate("MainWindow_approximately_align", u"\u6807\u51c6\u5316", None)) + self.checkBox_orgBcgDelBase.setText(QCoreApplication.translate("MainWindow_approximately_align", u"orgBcg\u53bb\u57fa\u7ebf", None)) + self.checkBox_PSGDelBase.setText(QCoreApplication.translate("MainWindow_approximately_align", u"PSG\u53bb\u57fa\u7ebf", None)) + self.checkBox_RawSignal.setText(QCoreApplication.translate("MainWindow_approximately_align", u"\u539f\u59cb\u4fe1\u53f7", None)) + self.checkBox_orgBcgZScore.setText(QCoreApplication.translate("MainWindow_approximately_align", u"orgBcg\u6807\u51c6\u5316", None)) + self.checkBox_PSGZScore.setText(QCoreApplication.translate("MainWindow_approximately_align", u"PSG\u6807\u51c6\u5316", None)) + self.pushButton_Standardize.setText(QCoreApplication.translate("MainWindow_approximately_align", u"\u5e94\u7528", None)) + self.groupBox_get_position.setTitle(QCoreApplication.translate("MainWindow_approximately_align", u"\u622a\u65ad", None)) + self.label.setText(QCoreApplication.translate("MainWindow_approximately_align", u"orgBcg_\u8865\u96f6\uff1a", None)) + self.label_2.setText(QCoreApplication.translate("MainWindow_approximately_align", u"PSG_\u8865\u96f6\uff1a", None)) + self.label_4.setText(QCoreApplication.translate("MainWindow_approximately_align", u"orgBcg_Pre\uff1a", None)) + self.label_5.setText(QCoreApplication.translate("MainWindow_approximately_align", u"PSG_Pre\uff1a", None)) + self.label_7.setText(QCoreApplication.translate("MainWindow_approximately_align", u"orgBcg_Post\uff1a", None)) + self.label_8.setText(QCoreApplication.translate("MainWindow_approximately_align", u"PSG_Post\uff1a", None)) + self.pushButton_CutOff.setText(QCoreApplication.translate("MainWindow_approximately_align", u"\u5e94\u7528", None)) + self.pushButton_GetPos.setText(QCoreApplication.translate("MainWindow_approximately_align", u"\u8ba1\u7b97\u5bf9\u9f50", None)) + self.groupBox_align_position.setTitle(QCoreApplication.translate("MainWindow_approximately_align", u"\u5bf9\u9f50\u8d77\u59cb\u4f4d\u7f6e", None)) + self.radioButton_NTHO.setText(QCoreApplication.translate("MainWindow_approximately_align", u"\u5907\u90092", None)) + self.radioButton_PTHO.setText(QCoreApplication.translate("MainWindow_approximately_align", u"\u5907\u90091", None)) + self.radioButton_PABD.setText(QCoreApplication.translate("MainWindow_approximately_align", u"\u5907\u90093", None)) + self.radioButton_NABD.setText(QCoreApplication.translate("MainWindow_approximately_align", u"\u5907\u90094", None)) + self.radioButton_custom.setText(QCoreApplication.translate("MainWindow_approximately_align", u"\u81ea\u5b9a\u4e49", None)) + self.groupBox_view_partially.setTitle(QCoreApplication.translate("MainWindow_approximately_align", u"\u5c40\u90e8\u89c2\u6d4b", None)) + self.label_9.setText(QCoreApplication.translate("MainWindow_approximately_align", u"Epoch\uff1a", None)) + self.pushButton_JUMP.setText(QCoreApplication.translate("MainWindow_approximately_align", u"\u8df3\u8f6c", None)) + self.pushButton_EP10.setText(QCoreApplication.translate("MainWindow_approximately_align", u"Epoch+10", None)) + self.pushButton_EP1.setText(QCoreApplication.translate("MainWindow_approximately_align", u"Epoch+1", None)) + self.pushButton_EP100.setText(QCoreApplication.translate("MainWindow_approximately_align", u"Epoch+100", None)) + self.pushButton_EM1.setText(QCoreApplication.translate("MainWindow_approximately_align", u"Epoch-1", None)) + self.pushButton_EM10.setText(QCoreApplication.translate("MainWindow_approximately_align", u"Epoch-10", None)) + self.pushButton_EM100.setText(QCoreApplication.translate("MainWindow_approximately_align", u"Epoch-100", None)) + self.pushButton_save.setText(QCoreApplication.translate("MainWindow_approximately_align", u"\u4fdd\u5b58\u7ed3\u679c", None)) + self.groupBox.setTitle(QCoreApplication.translate("MainWindow_approximately_align", u"\u65e5\u5fd7", None)) + self.groupBox_canvas.setTitle(QCoreApplication.translate("MainWindow_approximately_align", u"\u7ed8\u56fe\u533a", None)) + self.label_Pic.setText("") + # retranslateUi + diff --git a/ui/MainWindow/MainWindow_approximately_align.ui b/ui/MainWindow/MainWindow_approximately_align.ui new file mode 100644 index 0000000..e052b07 --- /dev/null +++ b/ui/MainWindow/MainWindow_approximately_align.ui @@ -0,0 +1,803 @@ + + + MainWindow_approximately_align + + + + 0 + 0 + 1920 + 1080 + + + + 数据粗同步 + + + + + + + + 10 + + + + 数据粗同步 + + + + + + + + + 0 + 0 + + + + + 12 + + + + 导入设置 + + + + + + + + 0 + 0 + + + + + 12 + + + + 开始导入 + + + + + + + + + + + + 12 + + + + orgBcg时长(min): + + + + + + + + 12 + + + + 0 + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + 12 + + + + PSG时长(min): + + + + + + + + 12 + + + + 0 + + + + + + + + + 标准化 + + + + + + + + + 12 + + + + orgBcg去基线 + + + true + + + + + + + + 12 + + + + PSG去基线 + + + true + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + 12 + + + + 原始信号 + + + + + + + + + + + + 12 + + + + orgBcg标准化 + + + true + + + + + + + + 12 + + + + PSG标准化 + + + true + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + 12 + + + + 应用 + + + + + + + + + + + + 截断 + + + + + + + + + 12 + + + + orgBcg_补零: + + + + + + + + 12 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 999999 + + + + + + + + 12 + + + + PSG_补零: + + + + + + + + 12 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 999999 + + + + + + + + + + + + 12 + + + + orgBcg_Pre: + + + + + + + + 12 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 999999 + + + + + + + + 12 + + + + PSG_Pre: + + + + + + + + 12 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 999999 + + + + + + + + + + + + 12 + + + + orgBcg_Post: + + + + + + + + 12 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 999999 + + + + + + + + 12 + + + + PSG_Post: + + + + + + + + 12 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 999999 + + + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + + + + 12 + + + + 应用 + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + 12 + + + + 计算对齐 + + + + + + + + + + + + 对齐起始位置 + + + + + + + 12 + + + + 备选2 + + + + + + + + 12 + + + + 备选1 + + + + + + + + 12 + + + + 备选3 + + + + + + + + 12 + + + + 备选4 + + + + + + + + 12 + + + + 自定义 + + + + + + + + 12 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + -1000000 + + + 1000000 + + + + + + + + + + 局部观测 + + + + + + + + + 12 + + + + Epoch: + + + + + + + + 12 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 2000 + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + 12 + + + + 跳转 + + + + + + + + + + + + 12 + + + + Epoch+10 + + + + + + + + 12 + + + + Epoch+1 + + + + + + + + 12 + + + + Epoch+100 + + + + + + + + 12 + + + + Epoch-1 + + + + + + + + 12 + + + + Epoch-10 + + + + + + + + 12 + + + + Epoch-100 + + + + + + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + 12 + + + + 保存结果 + + + + + + + 日志 + + + + + + + + + + + + + + + + 10 + + + + 绘图区 + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui/MainWindow/MainWindow_detect_Jpeak.py b/ui/MainWindow/MainWindow_detect_Jpeak.py index 7e699ac..45f3592 100644 --- a/ui/MainWindow/MainWindow_detect_Jpeak.py +++ b/ui/MainWindow/MainWindow_detect_Jpeak.py @@ -302,7 +302,7 @@ class Ui_MainWindow_detect_Jpeak(object): self.action_selectPath.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u6570\u636e\u8def\u5f84\u9009\u62e9", None)) self.action.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u52a0\u8f7d\u5b58\u6863", None)) self.groupBox_canvas.setTitle(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u7ed8\u56fe\u533a", None)) - self.groupBox_left.setTitle(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u9884\u5904\u7406", None)) + self.groupBox_left.setTitle(QCoreApplication.translate("MainWindow_detect_Jpeak", u"BCG\u7684J\u5cf0\u7b97\u6cd5\u5b9a\u4f4d", None)) self.pushButton_input_setting.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u5bfc\u5165\u8bbe\u7f6e", None)) self.pushButton_input.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u5f00\u59cb\u5bfc\u5165", None)) self.groupBox_args.setTitle(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u53c2\u6570\u8f93\u5165", None)) diff --git a/ui/MainWindow/MainWindow_detect_Jpeak.ui b/ui/MainWindow/MainWindow_detect_Jpeak.ui index 4ebbc38..28c524b 100644 --- a/ui/MainWindow/MainWindow_detect_Jpeak.ui +++ b/ui/MainWindow/MainWindow_detect_Jpeak.ui @@ -54,7 +54,7 @@ - 预处理 + BCG的J峰算法定位 diff --git a/ui/MainWindow/MainWindow_detect_Rpeak.py b/ui/MainWindow/MainWindow_detect_Rpeak.py index 0065a81..5029b61 100644 --- a/ui/MainWindow/MainWindow_detect_Rpeak.py +++ b/ui/MainWindow/MainWindow_detect_Rpeak.py @@ -220,7 +220,7 @@ class Ui_MainWindow_detect_Rpeak(object): def retranslateUi(self, MainWindow_detect_Rpeak): MainWindow_detect_Rpeak.setWindowTitle(QCoreApplication.translate("MainWindow_detect_Rpeak", u"ECG\u7684R\u5cf0\u7b97\u6cd5\u5b9a\u4f4d", None)) - self.groupBox_left.setTitle(QCoreApplication.translate("MainWindow_detect_Rpeak", u"\u9884\u5904\u7406", None)) + self.groupBox_left.setTitle(QCoreApplication.translate("MainWindow_detect_Rpeak", u"ECG\u7684R\u5cf0\u7b97\u6cd5\u5b9a\u4f4d", None)) self.pushButton_input_setting.setText(QCoreApplication.translate("MainWindow_detect_Rpeak", u"\u5bfc\u5165\u8bbe\u7f6e", None)) self.pushButton_input.setText(QCoreApplication.translate("MainWindow_detect_Rpeak", u"\u5f00\u59cb\u5bfc\u5165", None)) self.groupBox_args.setTitle(QCoreApplication.translate("MainWindow_detect_Rpeak", u"\u53c2\u6570\u8f93\u5165", None)) diff --git a/ui/MainWindow/MainWindow_detect_Rpeak.ui b/ui/MainWindow/MainWindow_detect_Rpeak.ui index 06bbba1..fbf46f1 100644 --- a/ui/MainWindow/MainWindow_detect_Rpeak.ui +++ b/ui/MainWindow/MainWindow_detect_Rpeak.ui @@ -23,7 +23,7 @@ - 预处理 + ECG的R峰算法定位 diff --git a/ui/MainWindow/MainWindow_precisely_align.py b/ui/MainWindow/MainWindow_precisely_align.py index 0a9827c..7a51e76 100644 --- a/ui/MainWindow/MainWindow_precisely_align.py +++ b/ui/MainWindow/MainWindow_precisely_align.py @@ -513,7 +513,7 @@ class Ui_MainWindow_precisely_align(object): self.action_selectPath.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u6570\u636e\u8def\u5f84\u9009\u62e9", None)) self.action.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u52a0\u8f7d\u5b58\u6863", None)) self.groupBox_canvas.setTitle(QCoreApplication.translate("MainWindow_precisely_align", u"\u7ed8\u56fe\u533a", None)) - self.groupBox_left.setTitle(QCoreApplication.translate("MainWindow_precisely_align", u"\u9884\u5904\u7406", None)) + self.groupBox_left.setTitle(QCoreApplication.translate("MainWindow_precisely_align", u"\u6570\u636e\u7cbe\u540c\u6b65", None)) self.pushButton_input_setting.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u5bfc\u5165\u8bbe\u7f6e", None)) self.pushButton_input.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u5f00\u59cb\u5bfc\u5165", None)) self.groupBox_args.setTitle(QCoreApplication.translate("MainWindow_precisely_align", u"\u53c2\u6570\u8f93\u5165", None)) diff --git a/ui/MainWindow/MainWindow_precisely_align.ui b/ui/MainWindow/MainWindow_precisely_align.ui index e3cb460..566269e 100644 --- a/ui/MainWindow/MainWindow_precisely_align.ui +++ b/ui/MainWindow/MainWindow_precisely_align.ui @@ -54,7 +54,7 @@ - 预处理 + 数据精同步 diff --git a/ui/setting/approximately_align_input_setting.py b/ui/setting/approximately_align_input_setting.py new file mode 100644 index 0000000..bde3cfd --- /dev/null +++ b/ui/setting/approximately_align_input_setting.py @@ -0,0 +1,294 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'approximately_align_input_setting.ui' +## +## Created by: Qt User Interface Compiler version 6.8.2 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, + QMetaObject, QObject, QPoint, QRect, + QSize, QTime, QUrl, Qt) +from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, + QFont, QFontDatabase, QGradient, QIcon, + QImage, QKeySequence, QLinearGradient, QPainter, + QPalette, QPixmap, QRadialGradient, QTransform) +from PySide6.QtWidgets import (QApplication, QDoubleSpinBox, QGridLayout, QGroupBox, + QHBoxLayout, QLabel, QMainWindow, QPlainTextEdit, + QPushButton, QSizePolicy, QSpacerItem, QSpinBox, + QVBoxLayout, QWidget) + +class Ui_MainWindow_approximately_align_input_setting(object): + def setupUi(self, MainWindow_approximately_align_input_setting): + if not MainWindow_approximately_align_input_setting.objectName(): + MainWindow_approximately_align_input_setting.setObjectName(u"MainWindow_approximately_align_input_setting") + MainWindow_approximately_align_input_setting.resize(600, 780) + self.centralwidget = QWidget(MainWindow_approximately_align_input_setting) + self.centralwidget.setObjectName(u"centralwidget") + self.gridLayout = QGridLayout(self.centralwidget) + self.gridLayout.setObjectName(u"gridLayout") + self.pushButton_cancel = QPushButton(self.centralwidget) + self.pushButton_cancel.setObjectName(u"pushButton_cancel") + font = QFont() + font.setPointSize(12) + self.pushButton_cancel.setFont(font) + + self.gridLayout.addWidget(self.pushButton_cancel, 2, 3, 1, 1) + + self.groupBox = QGroupBox(self.centralwidget) + self.groupBox.setObjectName(u"groupBox") + font1 = QFont() + font1.setPointSize(10) + self.groupBox.setFont(font1) + self.verticalLayout_2 = QVBoxLayout(self.groupBox) + self.verticalLayout_2.setObjectName(u"verticalLayout_2") + self.groupBox_2 = QGroupBox(self.groupBox) + self.groupBox_2.setObjectName(u"groupBox_2") + self.verticalLayout_3 = QVBoxLayout(self.groupBox_2) + self.verticalLayout_3.setObjectName(u"verticalLayout_3") + self.horizontalLayout = QHBoxLayout() + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.label = QLabel(self.groupBox_2) + self.label.setObjectName(u"label") + self.label.setFont(font) + + self.horizontalLayout.addWidget(self.label) + + self.spinBox_input_orgBcg_freq = QSpinBox(self.groupBox_2) + self.spinBox_input_orgBcg_freq.setObjectName(u"spinBox_input_orgBcg_freq") + self.spinBox_input_orgBcg_freq.setFont(font) + self.spinBox_input_orgBcg_freq.setMinimum(1) + self.spinBox_input_orgBcg_freq.setMaximum(1000000) + + self.horizontalLayout.addWidget(self.spinBox_input_orgBcg_freq) + + + self.verticalLayout_3.addLayout(self.horizontalLayout) + + self.plainTextEdit_file_path_input_orgBcg = QPlainTextEdit(self.groupBox_2) + self.plainTextEdit_file_path_input_orgBcg.setObjectName(u"plainTextEdit_file_path_input_orgBcg") + + self.verticalLayout_3.addWidget(self.plainTextEdit_file_path_input_orgBcg) + + self.verticalLayout_3.setStretch(0, 1) + self.verticalLayout_3.setStretch(1, 2) + + self.verticalLayout_2.addWidget(self.groupBox_2) + + self.groupBox_3 = QGroupBox(self.groupBox) + self.groupBox_3.setObjectName(u"groupBox_3") + self.verticalLayout_5 = QVBoxLayout(self.groupBox_3) + self.verticalLayout_5.setObjectName(u"verticalLayout_5") + self.horizontalLayout_2 = QHBoxLayout() + self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") + self.label_2 = QLabel(self.groupBox_3) + self.label_2.setObjectName(u"label_2") + self.label_2.setFont(font) + + self.horizontalLayout_2.addWidget(self.label_2) + + self.spinBox_input_Tho_freq = QSpinBox(self.groupBox_3) + self.spinBox_input_Tho_freq.setObjectName(u"spinBox_input_Tho_freq") + self.spinBox_input_Tho_freq.setFont(font) + self.spinBox_input_Tho_freq.setMinimum(1) + self.spinBox_input_Tho_freq.setMaximum(1000000) + + self.horizontalLayout_2.addWidget(self.spinBox_input_Tho_freq) + + + self.verticalLayout_5.addLayout(self.horizontalLayout_2) + + self.plainTextEdit_file_path_input_Tho = QPlainTextEdit(self.groupBox_3) + self.plainTextEdit_file_path_input_Tho.setObjectName(u"plainTextEdit_file_path_input_Tho") + + self.verticalLayout_5.addWidget(self.plainTextEdit_file_path_input_Tho) + + self.verticalLayout_5.setStretch(0, 1) + self.verticalLayout_5.setStretch(1, 2) + + self.verticalLayout_2.addWidget(self.groupBox_3) + + self.groupBox_4 = QGroupBox(self.groupBox) + self.groupBox_4.setObjectName(u"groupBox_4") + self.verticalLayout_6 = QVBoxLayout(self.groupBox_4) + self.verticalLayout_6.setObjectName(u"verticalLayout_6") + self.horizontalLayout_3 = QHBoxLayout() + self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") + self.label_3 = QLabel(self.groupBox_4) + self.label_3.setObjectName(u"label_3") + self.label_3.setFont(font) + + self.horizontalLayout_3.addWidget(self.label_3) + + self.spinBox_input_Abd_freq = QSpinBox(self.groupBox_4) + self.spinBox_input_Abd_freq.setObjectName(u"spinBox_input_Abd_freq") + self.spinBox_input_Abd_freq.setFont(font) + self.spinBox_input_Abd_freq.setMinimum(1) + self.spinBox_input_Abd_freq.setMaximum(1000000) + + self.horizontalLayout_3.addWidget(self.spinBox_input_Abd_freq) + + + self.verticalLayout_6.addLayout(self.horizontalLayout_3) + + self.plainTextEdit_file_path_input_Abd = QPlainTextEdit(self.groupBox_4) + self.plainTextEdit_file_path_input_Abd.setObjectName(u"plainTextEdit_file_path_input_Abd") + + self.verticalLayout_6.addWidget(self.plainTextEdit_file_path_input_Abd) + + self.verticalLayout_6.setStretch(0, 1) + self.verticalLayout_6.setStretch(1, 2) + + self.verticalLayout_2.addWidget(self.groupBox_4) + + self.groupBox_5 = QGroupBox(self.groupBox) + self.groupBox_5.setObjectName(u"groupBox_5") + self.horizontalLayout_4 = QHBoxLayout(self.groupBox_5) + self.horizontalLayout_4.setObjectName(u"horizontalLayout_4") + self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) + + self.horizontalLayout_4.addItem(self.horizontalSpacer_2) + + self.label_4 = QLabel(self.groupBox_5) + self.label_4.setObjectName(u"label_4") + self.label_4.setFont(font) + self.label_4.setAlignment(Qt.AlignmentFlag.AlignCenter) + + self.horizontalLayout_4.addWidget(self.label_4) + + self.spinBox_bandpassOrder = QSpinBox(self.groupBox_5) + self.spinBox_bandpassOrder.setObjectName(u"spinBox_bandpassOrder") + self.spinBox_bandpassOrder.setFont(font) + self.spinBox_bandpassOrder.setMinimum(1) + self.spinBox_bandpassOrder.setMaximum(10) + + self.horizontalLayout_4.addWidget(self.spinBox_bandpassOrder) + + self.horizontalSpacer_4 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) + + self.horizontalLayout_4.addItem(self.horizontalSpacer_4) + + self.label_6 = QLabel(self.groupBox_5) + self.label_6.setObjectName(u"label_6") + self.label_6.setFont(font) + self.label_6.setAlignment(Qt.AlignmentFlag.AlignCenter) + + self.horizontalLayout_4.addWidget(self.label_6) + + self.doubleSpinBox_bandpassLow = QDoubleSpinBox(self.groupBox_5) + self.doubleSpinBox_bandpassLow.setObjectName(u"doubleSpinBox_bandpassLow") + self.doubleSpinBox_bandpassLow.setFont(font) + self.doubleSpinBox_bandpassLow.setMaximum(100.000000000000000) + + self.horizontalLayout_4.addWidget(self.doubleSpinBox_bandpassLow) + + self.label_7 = QLabel(self.groupBox_5) + self.label_7.setObjectName(u"label_7") + self.label_7.setFont(font) + self.label_7.setAlignment(Qt.AlignmentFlag.AlignCenter) + + self.horizontalLayout_4.addWidget(self.label_7) + + self.doubleSpinBox_bandpassHigh = QDoubleSpinBox(self.groupBox_5) + self.doubleSpinBox_bandpassHigh.setObjectName(u"doubleSpinBox_bandpassHigh") + self.doubleSpinBox_bandpassHigh.setFont(font) + self.doubleSpinBox_bandpassHigh.setMaximum(100.000000000000000) + + self.horizontalLayout_4.addWidget(self.doubleSpinBox_bandpassHigh) + + self.horizontalSpacer_3 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) + + self.horizontalLayout_4.addItem(self.horizontalSpacer_3) + + + self.verticalLayout_2.addWidget(self.groupBox_5) + + self.groupBox_6 = QGroupBox(self.groupBox) + self.groupBox_6.setObjectName(u"groupBox_6") + self.horizontalLayout_5 = QHBoxLayout(self.groupBox_6) + self.horizontalLayout_5.setObjectName(u"horizontalLayout_5") + self.label_5 = QLabel(self.groupBox_6) + self.label_5.setObjectName(u"label_5") + self.label_5.setFont(font) + self.label_5.setAlignment(Qt.AlignmentFlag.AlignCenter) + + self.horizontalLayout_5.addWidget(self.label_5) + + self.spinBox_display_freq = QSpinBox(self.groupBox_6) + self.spinBox_display_freq.setObjectName(u"spinBox_display_freq") + self.spinBox_display_freq.setFont(font) + self.spinBox_display_freq.setMinimum(1) + self.spinBox_display_freq.setMaximum(1000) + + self.horizontalLayout_5.addWidget(self.spinBox_display_freq) + + self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) + + self.horizontalLayout_5.addItem(self.horizontalSpacer) + + + self.verticalLayout_2.addWidget(self.groupBox_6) + + self.groupBox_7 = QGroupBox(self.groupBox) + self.groupBox_7.setObjectName(u"groupBox_7") + self.verticalLayout_8 = QVBoxLayout(self.groupBox_7) + self.verticalLayout_8.setObjectName(u"verticalLayout_8") + self.plainTextEdit_file_path_save = QPlainTextEdit(self.groupBox_7) + self.plainTextEdit_file_path_save.setObjectName(u"plainTextEdit_file_path_save") + + self.verticalLayout_8.addWidget(self.plainTextEdit_file_path_save) + + + self.verticalLayout_2.addWidget(self.groupBox_7) + + self.verticalLayout_2.setStretch(0, 1) + self.verticalLayout_2.setStretch(1, 1) + self.verticalLayout_2.setStretch(2, 1) + self.verticalLayout_2.setStretch(3, 1) + self.verticalLayout_2.setStretch(4, 1) + self.verticalLayout_2.setStretch(5, 1) + + self.gridLayout.addWidget(self.groupBox, 0, 0, 1, 4) + + self.pushButton_confirm = QPushButton(self.centralwidget) + self.pushButton_confirm.setObjectName(u"pushButton_confirm") + self.pushButton_confirm.setFont(font) + + self.gridLayout.addWidget(self.pushButton_confirm, 2, 2, 1, 1) + + MainWindow_approximately_align_input_setting.setCentralWidget(self.centralwidget) + + self.retranslateUi(MainWindow_approximately_align_input_setting) + + QMetaObject.connectSlotsByName(MainWindow_approximately_align_input_setting) + # setupUi + + def retranslateUi(self, MainWindow_approximately_align_input_setting): + MainWindow_approximately_align_input_setting.setWindowTitle(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"\u5bfc\u5165\u8bbe\u7f6e", None)) + self.pushButton_cancel.setText(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"\u53d6\u6d88", None)) + self.groupBox.setTitle(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"\u6587\u4ef6\u8def\u5f84", None)) + self.groupBox_2.setTitle(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"\u539f\u59cborgBcg\u8def\u5f84", None)) + self.label.setText(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"\u91c7\u6837\u7387(Hz)\uff1a", None)) + self.plainTextEdit_file_path_input_orgBcg.setPlainText("") + self.plainTextEdit_file_path_input_orgBcg.setPlaceholderText(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"\u6587\u4ef6\u8def\u5f84", None)) + self.groupBox_3.setTitle(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"\u539f\u59cbTho\u8def\u5f84", None)) + self.label_2.setText(QCoreApplication.translate("MainWindow_approximately_align_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_approximately_align_input_setting", u"\u6587\u4ef6\u8def\u5f84", None)) + self.groupBox_4.setTitle(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"\u539f\u59cbAbd\u8def\u5f84", None)) + self.label_3.setText(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"\u91c7\u6837\u7387(Hz)\uff1a", None)) + self.plainTextEdit_file_path_input_Abd.setPlainText("") + self.plainTextEdit_file_path_input_Abd.setPlaceholderText(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"\u6587\u4ef6\u8def\u5f84", None)) + self.groupBox_5.setTitle(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"\u547c\u5438\u63d0\u53d6\u6ee4\u6ce2\u5668\u8bbe\u7f6e", None)) + self.label_4.setText(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"\u9636\u6570\uff1a", None)) + self.label_6.setText(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"\u5e26\u901a\u622a\u6b62\u9891\u7387(Hz)\uff1a", None)) + self.label_7.setText(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"~", None)) + self.groupBox_6.setTitle(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"\u663e\u793a\u8bbe\u7f6e", None)) + self.label_5.setText(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"\u663e\u793a\u6570\u636e\u9891\u7387(Hz)\uff1a", None)) + self.groupBox_7.setTitle(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"\u7c97\u540c\u6b65\u7ed3\u679c\u4fdd\u5b58\u8def\u5f84", None)) + self.plainTextEdit_file_path_save.setPlaceholderText(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"\u4fdd\u5b58\u8def\u5f84", None)) + self.pushButton_confirm.setText(QCoreApplication.translate("MainWindow_approximately_align_input_setting", u"\u786e\u5b9a", None)) + # retranslateUi + diff --git a/ui/setting/approximately_align_input_setting.ui b/ui/setting/approximately_align_input_setting.ui new file mode 100644 index 0000000..12f0e27 --- /dev/null +++ b/ui/setting/approximately_align_input_setting.ui @@ -0,0 +1,411 @@ + + + MainWindow_approximately_align_input_setting + + + + 0 + 0 + 600 + 780 + + + + 导入设置 + + + + + + + + 12 + + + + 取消 + + + + + + + + 10 + + + + 文件路径 + + + + + + 原始orgBcg路径 + + + + + + + + + 12 + + + + 采样率(Hz): + + + + + + + + 12 + + + + 1 + + + 1000000 + + + + + + + + + + + + 文件路径 + + + + + + + + + + 原始Tho路径 + + + + + + + + + 12 + + + + 采样率(Hz): + + + + + + + + 12 + + + + 1 + + + 1000000 + + + + + + + + + + + + 文件路径 + + + + + + + + + + 原始Abd路径 + + + + + + + + + 12 + + + + 采样率(Hz): + + + + + + + + 12 + + + + 1 + + + 1000000 + + + + + + + + + + + + 文件路径 + + + + + + + + + + 呼吸提取滤波器设置 + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + 12 + + + + 阶数: + + + Qt::AlignmentFlag::AlignCenter + + + + + + + + 12 + + + + 1 + + + 10 + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + 12 + + + + 带通截止频率(Hz): + + + Qt::AlignmentFlag::AlignCenter + + + + + + + + 12 + + + + 100.000000000000000 + + + + + + + + 12 + + + + ~ + + + Qt::AlignmentFlag::AlignCenter + + + + + + + + 12 + + + + 100.000000000000000 + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + + + 显示设置 + + + + + + + 12 + + + + 显示数据频率(Hz): + + + Qt::AlignmentFlag::AlignCenter + + + + + + + + 12 + + + + 1 + + + 1000 + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + + + 粗同步结果保存路径 + + + + + + 保存路径 + + + + + + + + + + + + + + 12 + + + + 确定 + + + + + + + + + diff --git a/数据结构化输入和输出命名规范.md b/数据结构化输入和输出命名规范.md index 145ee7d..761fa93 100644 --- a/数据结构化输入和输出命名规范.md +++ b/数据结构化输入和输出命名规范.md @@ -25,6 +25,7 @@ |-BCG_Raw_采样率.txt |-JPeak_revise.txt |-JPeak_revise_corrected.txt + |-Approximately_Align_Info.csv .../OrgBCG_Origin/ |-... .../PSG_Aligned/ @@ -72,7 +73,7 @@ 输出: -粗同步后的位置索引:`./Sync_Index//Approximately_Align_Info.csv` +粗同步后的位置索引:`./OrgBCG_Text//Approximately_Align_Info.csv` ### 2 预处理