diff --git a/func/Module_detect_Jpeak.py b/func/Module_detect_Jpeak.py index 5f6db59..aa93d0a 100644 --- a/func/Module_detect_Jpeak.py +++ b/func/Module_detect_Jpeak.py @@ -144,10 +144,6 @@ class MainWindow_detect_Jpeak(QMainWindow): self.gs = None self.ax0 = None - self.line_data = None - self.point_peak = None - self.line_interval = None - self.msgBox = QMessageBox() self.msgBox.setWindowTitle(Constants.MAINWINDOW_MSGBOX_TITLE) @@ -207,11 +203,7 @@ class MainWindow_detect_Jpeak(QMainWindow): QApplication.processEvents() # 清空画框 - if self.line_data and self.point_peak: - del self.line_data - del self.point_peak - del self.line_interval - self.canvas.draw() + self.ax0.clear() # 释放资源 del self.data @@ -232,24 +224,18 @@ class MainWindow_detect_Jpeak(QMainWindow): def __plot__(self): # 清空画框 - if self.line_data and self.point_peak and self.line_interval: - try: - self.line_data.remove() - self.point_peak.remove() - self.line_interval.remove() - except ValueError: - pass + self.reset_axes() sender = self.sender() if sender == self.ui.pushButton_view: - self.line_data, = self.ax0.plot(self.data.processed_data, + self.ax0.plot(self.data.processed_data, color=Constants.PLOT_COLOR_BLUE, label=Constants.DETECT_JPEAK_PLOT_LABEL_BCG) - self.point_peak, = self.ax0.plot(self.data.peak, self.data.processed_data[self.data.peak], + self.ax0.plot(self.data.peak, self.data.processed_data[self.data.peak], 'r.', label=Constants.DETECT_JPEAK_PLOT_LABEL_J_PEAKS) - self.line_interval, = self.ax0.plot(self.data.interval, + self.ax0.plot(self.data.interval, color=Constants.PLOT_COLOR_ORANGE, label=Constants.DETECT_JPEAK_PLOT_LABEL_INTERVAL) self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) @@ -278,13 +264,7 @@ class MainWindow_detect_Jpeak(QMainWindow): PublicFunc.__disableAllButton__(self, ButtonState) # 清空画框 - if self.line_data and self.point_peak and self.line_interval: - try: - self.line_data.remove() - self.point_peak.remove() - self.line_interval.remove() - except ValueError: - pass + self.reset_axes() self.canvas.draw() # 清空模型列表 @@ -401,6 +381,12 @@ class MainWindow_detect_Jpeak(QMainWindow): PublicFunc.finish_operation(self, ButtonState) + def reset_axes(self): + + self.ax0.clear() + self.ax0.grid(True) + self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + def update_ui_comboBox_model(self, model_list): self.ui.comboBox_model.clear() @@ -479,8 +465,7 @@ class Data: try: # DataFrame(self.processed_data.reshape(-1)).to_csv(self.file_path_save, # index=False, - # header=False, - # float_format='%.4f') + # header=False) chunk.to_csv(self.file_path_save, mode='a', index=False, header=False) except Exception: return False, Constants.SAVING_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Save_Exception"] diff --git a/func/Module_detect_Rpeak.py b/func/Module_detect_Rpeak.py index 8071279..f9ce3a1 100644 --- a/func/Module_detect_Rpeak.py +++ b/func/Module_detect_Rpeak.py @@ -142,11 +142,6 @@ class MainWindow_detect_Rpeak(QMainWindow): self.ax0 = None self.ax1 = None - self.line_data = None - self.point_peak = None - self.line_interval = None - self.point_RRIV = None - self.msgBox = QMessageBox() self.msgBox.setWindowTitle(Constants.MAINWINDOW_MSGBOX_TITLE) @@ -202,11 +197,8 @@ class MainWindow_detect_Rpeak(QMainWindow): QApplication.processEvents() # 清空画框 - if self.line_data and self.point_peak: - del self.line_data - del self.point_peak - del self.line_interval - self.canvas.draw() + self.ax0.clear() + self.ax1.clear() # 释放资源 del self.data @@ -226,28 +218,21 @@ class MainWindow_detect_Rpeak(QMainWindow): def __plot__(self): # 清空画框 - if self.line_data and self.point_peak and self.line_interval and self.point_RRIV: - try: - self.line_data.remove() - self.point_peak.remove() - self.line_interval.remove() - self.point_RRIV.remove() - except ValueError: - pass + self.reset_axes() sender = self.sender() if sender == self.ui.pushButton_view: - self.point_RRIV, = self.ax0.plot(self.data.peak[2:], self.data.RRIV, + self.ax0.plot(self.data.peak[2:], self.data.RRIV, 'r.', label=Constants.DETECT_RPEAK_PLOT_LABEL_RRIV) - self.line_data, = self.ax1.plot(self.data.processed_data, + self.ax1.plot(self.data.processed_data, color=Constants.PLOT_COLOR_BLUE, label=Constants.DETECT_RPEAK_PLOT_LABEL_ECG) - self.point_peak, = self.ax1.plot(self.data.peak, self.data.processed_data[self.data.peak], + self.ax1.plot(self.data.peak, self.data.processed_data[self.data.peak], 'r*', label=Constants.DETECT_RPEAK_PLOT_LABEL_R_PEAKS) - self.line_interval, = self.ax1.plot(self.data.interval, + self.ax1.plot(self.data.interval, color=Constants.PLOT_COLOR_GREEN, label=Constants.DETECT_RPEAK_PLOT_LABEL_INTERVAL) self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) @@ -273,14 +258,7 @@ class MainWindow_detect_Rpeak(QMainWindow): PublicFunc.__disableAllButton__(self, ButtonState) # 清空画框 - if self.line_data and self.point_peak and self.line_interval and self.point_RRIV: - try: - self.line_data.remove() - self.point_peak.remove() - self.line_interval.remove() - self.point_RRIV.remove() - except ValueError: - pass + self.reset_axes() self.canvas.draw() # 清空方法列表 @@ -402,6 +380,16 @@ class MainWindow_detect_Rpeak(QMainWindow): PublicFunc.finish_operation(self, ButtonState) + def reset_axes(self): + + self.ax0.clear() + self.ax1.clear() + self.ax0.grid(True) + self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax0.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) + self.ax1.grid(True) + self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + def update_ui_comboBox_method(self, method_list): self.ui.comboBox_method.clear() @@ -472,8 +460,7 @@ class Data: try: # DataFrame(self.processed_data.reshape(-1)).to_csv(self.file_path_save, # index=False, - # header=False, - # float_format='%.4f') + # header=False) chunk.to_csv(self.file_path_save, mode='a', index=False, header=False) except Exception: return False, Constants.SAVING_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Save_Exception"] diff --git a/func/Module_label_check.py b/func/Module_label_check.py index d62c66d..687cd9d 100644 --- a/func/Module_label_check.py +++ b/func/Module_label_check.py @@ -213,8 +213,6 @@ class MainWindow_label_check(QMainWindow): self.is_left_button_pressed = None self.is_right_button_pressed = None - self.line_processed_data_1 = None - self.line_processed_data_2 = None self.point_peak_original = None self.point_peak_corrected = None self.annotation_tableWidget = None @@ -250,6 +248,7 @@ class MainWindow_label_check(QMainWindow): self.fig = plt.figure(figsize=(12, 9), dpi=100) self.canvas = FigureCanvasQTAgg(self.fig) self.figToolbar = CustomNavigationToolbar(self.canvas, self) + self.figToolbar.action_Label_Multiple.setEnabled(False) for action in self.figToolbar._actions.values(): action.setEnabled(False) for action in self.figToolbar.actions(): @@ -300,7 +299,6 @@ class MainWindow_label_check(QMainWindow): self.ui.tableWidget_peak_corrected.cellDoubleClicked.connect( self.__slot_tableWidget_on_cell_double_clicked__) - self.ui.doubleSpinBox_findpeaks_min_interval.editingFinished.connect(self.__update_config__) self.ui.doubleSpinBox_findpeaks_min_height.editingFinished.connect(self.__update_config__) self.ui.spinBox_moveLength.editingFinished.connect(self.__update_config__) @@ -316,12 +314,11 @@ class MainWindow_label_check(QMainWindow): QApplication.processEvents() # 清空画框 - if self.line_processed_data_1 and self.line_processed_data_2 and self.point_peak_original and self.point_peak_corrected: - del self.line_processed_data_1 - del self.line_processed_data_2 - del self.point_peak_original - del self.point_peak_corrected - self.canvas.draw() + del self.point_peak_original + del self.point_peak_corrected + del self.annotation_tableWidget + self.ax0.clear() + self.ax1.clear() # 释放资源 del self.data @@ -340,25 +337,28 @@ class MainWindow_label_check(QMainWindow): def __plot__(self): # 清空画框 - if self.line_processed_data_1 and self.line_processed_data_2 and self.point_peak_original and self.point_peak_corrected: - try: - self.line_processed_data_1.remove() - self.line_processed_data_2.remove() - self.point_peak_original.remove() - self.point_peak_corrected.remove() - except ValueError: - pass + if self.point_peak_original is not None: + self.point_peak_original.remove() + self.point_peak_original = None + if self.point_peak_corrected is not None: + self.point_peak_corrected.remove() + self.point_peak_corrected = None + if self.annotation_tableWidget is not None: + self.annotation_tableWidget.remove() + self.annotation_tableWidget = None + + self.reset_axes() sender = self.sender() if sender == self.ui.pushButton_input: self.ui.spinBox_data_length.setValue(len(self.data.processed_data)) - self.line_processed_data_1, = self.ax0.plot(self.data.processed_data, - label=Constants.LABEL_CHECK_PLOT_LABEL_SIGNAL, - color=Constants.PLOT_COLOR_BLUE) - self.line_processed_data_2, = self.ax1.plot(self.data.processed_data, - label=Constants.LABEL_CHECK_PLOT_LABEL_SIGNAL, - color=Constants.PLOT_COLOR_BLUE) + self.ax0.plot(self.data.processed_data, + label=Constants.LABEL_CHECK_PLOT_LABEL_SIGNAL, + color=Constants.PLOT_COLOR_BLUE) + self.ax1.plot(self.data.processed_data, + label=Constants.LABEL_CHECK_PLOT_LABEL_SIGNAL, + color=Constants.PLOT_COLOR_BLUE) self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT) status = True @@ -382,7 +382,7 @@ class MainWindow_label_check(QMainWindow): self.ax1.callbacks.connect('xlim_changed', lambda ax: self.on_xlim_change(ax)) self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT) - except Exception as e: + except Exception: return False, Constants.DRAWING_FAILURE self.canvas.draw() @@ -431,14 +431,17 @@ class MainWindow_label_check(QMainWindow): PublicFunc.__disableAllButton__(self, ButtonState) # 清空画框 - if self.line_processed_data_1 and self.line_processed_data_2 and self.point_peak_original and self.point_peak_corrected: - try: - self.line_processed_data_1.remove() - self.line_processed_data_2.remove() - self.point_peak_original.remove() - self.point_peak_corrected.remove() - except ValueError: - pass + if self.point_peak_original is not None: + self.point_peak_original.remove() + self.point_peak_original = None + if self.point_peak_corrected is not None: + self.point_peak_corrected.remove() + self.point_peak_corrected = None + if self.annotation_tableWidget is not None: + self.annotation_tableWidget.remove() + self.annotation_tableWidget = None + + self.reset_axes() self.canvas.draw() self.data = Data() @@ -653,14 +656,24 @@ class MainWindow_label_check(QMainWindow): self.canvas.draw() PublicFunc.text_output(self.ui, f"{Constants.LABEL_CHECK_JUMP_X_INDEX}{str(int(x))}", Constants.TIPS_TYPE_INFO) + def reset_axes(self): + + self.ax0.clear() + self.ax1.clear() + self.ax0.grid(True) + self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax0.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) + self.ax1.grid(True) + self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + def on_xlim_change(self, event_ax): try: - if self.annotation_tableWidget: + if self.annotation_tableWidget is not None: self.annotation_tableWidget.remove() + self.annotation_tableWidget = None except AttributeError: pass - self.annotation_tableWidget = None def autoplay_move_xlim(self): @@ -967,7 +980,6 @@ class Data: class CustomNavigationToolbar(NavigationToolbar2QT): - def __init__(self, canvas, parent): super().__init__(canvas, parent) # 初始化画框工具栏 @@ -997,24 +1009,20 @@ class CustomNavigationToolbar(NavigationToolbar2QT): self.rect_patch_ax0 = None # 用于绘制矩形的patch self.rect_patch_ax1 = None # 用于绘制矩形的patch - def home(self, *args): pass - def zoom(self, *args): super().zoom(*args) self.deactivate_figToorbar_changeLabel_mode() - def pan(self, *args): super().pan(*args) self.deactivate_figToorbar_changeLabel_mode() - def deactivate_figToorbar_changeLabel_mode(self): if self.action_Label_Multiple.isChecked(): diff --git a/func/Module_mainwindow.py b/func/Module_mainwindow.py index a9db44a..f18e683 100644 --- a/func/Module_mainwindow.py +++ b/func/Module_mainwindow.py @@ -4,7 +4,6 @@ from PySide6.QtWidgets import QMainWindow, QMessageBox, QFileDialog from matplotlib import use from yaml import dump, load, FullLoader - from func.utils.PublicFunc import PublicFunc from ui.MainWindow.MainWindow_menu import Ui_Signal_Label @@ -12,6 +11,7 @@ from func.Module_preprocess import MainWindow_preprocess from func.Module_detect_Jpeak import MainWindow_detect_Jpeak from func.Module_detect_Rpeak import MainWindow_detect_Rpeak from func.Module_label_check import MainWindow_label_check +from func.Module_precisely_align import MainWindow_precisely_align from func.utils.Constants import Constants, ConfigParams @@ -44,6 +44,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.detect_Jpeak = None self.detect_Rpeak = None self.label_check = None + self.precisely_align = None # 绑定槽函数 self.ui.pushButton_open.clicked.connect(self.__slot_btn_open__) @@ -53,6 +54,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.ui.pushButton_detect_Rpeak.clicked.connect(self.__slot_btn_detect_Rpeak__) self.ui.pushButton_label_check_BCG.clicked.connect(self.__slot_btn_label_check__) self.ui.pushButton_label_check_ECG.clicked.connect(self.__slot_btn_label_check__) + self.ui.pushButton_precisely_align.clicked.connect(self.__slot_btn_precisely_align__) @staticmethod def __read_config__(): @@ -98,7 +100,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): elif sender == self.ui.pushButton_preprocess_ECG: mode = "ECG" else: - mode = "ModeNotExist" + raise ValueError("模式不存在") self.preprocess.show(mode, root_path, sampID) def __slot_btn_detect_Jpeak__(self): @@ -127,9 +129,16 @@ class MainWindow(QMainWindow, Ui_Signal_Label): elif sender == self.ui.pushButton_label_check_ECG: mode = "ECG" else: - mode = "ModeNotExist" + raise ValueError("模式不存在") self.label_check.show(mode, root_path, sampID) + def __slot_btn_precisely_align__(self): + + self.precisely_align = MainWindow_precisely_align() + root_path = self.ui.plainTextEdit_root_path.toPlainText() + sampID = int(self.ui.comboBox_sampID.currentText()) + self.precisely_align.show(root_path, sampID) + def seek_sampID(self, path): if not Path(path).exists(): diff --git a/func/Module_precisely_align.py b/func/Module_precisely_align.py new file mode 100644 index 0000000..3c25974 --- /dev/null +++ b/func/Module_precisely_align.py @@ -0,0 +1,1684 @@ +from gc import collect +from pathlib import Path + +import matplotlib.pyplot as plt +from PySide6.QtCore import QCoreApplication +from PySide6.QtGui import QAction, QFont +from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication, QButtonGroup +from matplotlib import gridspec, patches +from matplotlib.backends.backend_qt import NavigationToolbar2QT +from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg +from numpy import (diff, where, correlate, corrcoef, sum as np_sum, max as np_max, min as np_min, arange, array, + append, delete, abs as np_abs, argmin as np_argmin, argmax as np_argmax, asarray) +from overrides import overrides +from pandas import read_csv, DataFrame +from resampy import resample +from scipy.signal import find_peaks +from yaml import dump, load, FullLoader + +from func.utils.PublicFunc import PublicFunc +from func.utils.Constants import Constants, ConfigParams + +from ui.MainWindow.MainWindow_precisely_align import Ui_MainWindow_precisely_align +from ui.setting.precisely_align_input_setting import Ui_MainWindow_precisely_align_input_setting + + +Config = { + +} + +ButtonState = { + "Default": { + "pushButton_input_setting": True, + "pushButton_input": True, + "pushButton_calculate_correlation": False, + "pushButton_correlation_align": False, + "pushButton_view_align": False, + "pushButton_save": False + }, + "Current": { + "pushButton_input_setting": True, + "pushButton_input": True, + "pushButton_calculate_correlation": False, + "pushButton_correlation_align": False, + "pushButton_view_align": False, + "pushButton_save": False + }, + "Statue_1": { + "pushButton_input_setting": True, + "pushButton_input": True, + "pushButton_calculate_correlation": True, + "pushButton_correlation_align": False, + "pushButton_view_align": False, + "pushButton_save": False + }, + "Statue_2": { + "pushButton_input_setting": True, + "pushButton_input": True, + "pushButton_calculate_correlation": True, + "pushButton_correlation_align": True, + "pushButton_view_align": False, + "pushButton_save": False + }, + "Statue_3": { + "pushButton_input_setting": True, + "pushButton_input": True, + "pushButton_calculate_correlation": False, + "pushButton_correlation_align": False, + "pushButton_view_align": True, + "pushButton_save": False + }, + "Statue_4": { + "pushButton_input_setting": True, + "pushButton_input": True, + "pushButton_calculate_correlation": False, + "pushButton_correlation_align": False, + "pushButton_view_align": False, + "pushButton_save": True + }, +} + + +class SettingWindow(QMainWindow): + + def __init__(self, root_path, sampID): + + super(SettingWindow, self).__init__() + self.ui = Ui_MainWindow_precisely_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_freq_ECG.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.PRECISELY_ALIGN_CONFIG_FILE_PATH).exists(): + with open(ConfigParams.PRECISELY_ALIGN_CONFIG_FILE_PATH, "w") as f: + dump(ConfigParams.PRECISELY_ALIGN_CONFIG_NEW_CONTENT, f) + + with open(ConfigParams.PRECISELY_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_BCG": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + Path(str(self.sampID)) / Path(ConfigParams.PRECISELY_ALIGN_INPUT_BCG_FILENAME + + str(Config["InputConfig"]["ECGFreq"]) + + ConfigParams.ENDSWITH_TXT))), + "Input_Jpeak": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + Path(str(self.sampID)) / Path(ConfigParams.PRECISELY_ALIGN_INPUT_JPEAK_FILENAME + + ConfigParams.ENDSWITH_TXT))), + "Input_ECG": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / + Path(str(self.sampID)) / Path(ConfigParams.PRECISELY_ALIGN_INPUT_ECG_FILENAME + + str(Config["InputConfig"]["ECGFreq"]) + + ConfigParams.ENDSWITH_TXT))), + "Input_Rpeak": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / + Path(str(self.sampID)) / Path(ConfigParams.PRECISELY_ALIGN_INPUT_RPEAK_FILENAME + + ConfigParams.ENDSWITH_TXT))), + "Save_BCG": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + Path(str(self.sampID)) / Path(ConfigParams.PRECISELY_ALIGN_SAVE_BCG_FILENAME + + ConfigParams.ENDSWITH_TXT))), + "Save_ECG": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + Path(str(self.sampID)) / Path(ConfigParams.PRECISELY_ALIGN_SAVE_ECG_FILENAME + + ConfigParams.ENDSWITH_TXT))) + }, + "Coordinate": { + "BCG_front_1": 0, + "BCG_front_2": 0, + "BCG_back_1": 0, + "BCG_back_2": 0, + "ECG_front_1": 0, + "ECG_front_2": 0, + "ECG_back_1": 0, + "ECG_back_2": 0 + }, + "IV_Coordinate": { + "BCG_front_1": 0, + "BCG_front_2": 0, + "BCG_back_1": 0, + "BCG_back_2": 0, + "ECG_front_1": 0, + "ECG_front_2": 0, + "ECG_back_1": 0, + "ECG_back_2": 0 + }, + "front": { + "shift": 0, + "offset_interval": 0, + "anchor_J": 0, + "anchor_R": 0, + "offset_interval_duration": 0 + }, + "back": { + "shift": 0, + "offset_interval": 0, + "anchor_J": 0, + "anchor_R": 0, + "offset_interval_duration": 0 + }, + "offset_anchor": 0, + "orgfs": 0, + "offset_correct": 0, + "frontcut_index_BCG": 0, + "backcut_index_BCG": 0, + "frontcut_index_ECG": 0, + "backcut_index_ECG": 0 + }) + + # 数据回显 + self.ui.spinBox_input_freq_ECG.setValue(Config["InputConfig"]["ECGFreq"]) + self.ui.plainTextEdit_file_path_input_BCG.setPlainText(Config["Path"]["Input_BCG"]) + self.ui.plainTextEdit_file_path_input_Jpeak.setPlainText(Config["Path"]["Input_Jpeak"]) + self.ui.plainTextEdit_file_path_input_ECG.setPlainText(Config["Path"]["Input_ECG"]) + self.ui.plainTextEdit_file_path_input_Rpeak.setPlainText(Config["Path"]["Input_Rpeak"]) + self.ui.plainTextEdit_file_path_save_BCG.setPlainText(Config["Path"]["Save_BCG"]) + self.ui.plainTextEdit_file_path_save_ECG.setPlainText(Config["Path"]["Save_ECG"]) + + def __write_config__(self): + + # 从界面写入配置 + Config["InputConfig"]["ECGFreq"] = self.ui.spinBox_input_freq_ECG.value() + Config["Path"]["Input_BCG"] = self.ui.plainTextEdit_file_path_input_BCG.toPlainText() + Config["Path"]["Input_Jpeak"] = self.ui.plainTextEdit_file_path_input_Jpeak.toPlainText() + Config["Path"]["Input_ECG"] = self.ui.plainTextEdit_file_path_input_ECG.toPlainText() + Config["Path"]["Input_Rpeak"] = self.ui.plainTextEdit_file_path_input_Rpeak.toPlainText() + Config["Path"]["Save_BCG"] = self.ui.plainTextEdit_file_path_save_BCG.toPlainText() + Config["Path"]["Save_ECG"] = self.ui.plainTextEdit_file_path_save_ECG.toPlainText() + + # 保存配置到文件 + self.config["InputConfig"]["ECGFreq"] = self.ui.spinBox_input_freq_ECG.value() + + with open(ConfigParams.PRECISELY_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_BCG.setPlainText( + str((Path(self.root_path) / + ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + Path(str(self.sampID)) / + Path(ConfigParams.PRECISELY_ALIGN_INPUT_BCG_FILENAME + + str(self.ui.spinBox_input_freq_ECG.value()) + + ConfigParams.ENDSWITH_TXT)))) + self.ui.plainTextEdit_file_path_input_ECG.setPlainText( + str((Path(self.root_path) / + ConfigParams.PUBLIC_PATH_PSG_TEXT / + Path(str(self.sampID)) / + Path(ConfigParams.PRECISELY_ALIGN_INPUT_ECG_FILENAME + + str(self.ui.spinBox_input_freq_ECG.value()) + + ConfigParams.ENDSWITH_TXT)))) + + +class MainWindow_precisely_align(QMainWindow): + + def __init__(self): + + super(MainWindow_precisely_align, self).__init__() + self.ui = Ui_MainWindow_precisely_align() + self.ui.setupUi(self) + + self.root_path = None + self.sampID = None + + self.data = None + + self.setting = None + + self.buttonGroup = None + + # 初始化进度条 + self.progressbar = None + PublicFunc.add_progressbar(self) + + # 初始化画框 + self.fig = None + self.canvas = None + self.figToolbar = None + self.gs = None + self.ax0 = None + self.ax1 = None + self.ax2 = None + self.ax3 = None + self.ax4 = None + self.is_left_button_pressed = None + + self.rect_down = None + self.rect_up = None + + self.point0 = None + self.point1 = None + self.selected_point0 = None + self.selected_point1 = None + self.selected_point2 = None + self.selected_point3 = None + self.stem_black0 = None + self.stem_black1 = None + + self.ax0_xlime = None + self.ax0_ylime = None + self.ax2_xlime = None + self.ax2_ylime = None + self.ax4_xlime = None + self.ax4_ylime = None + + self.msgBox = QMessageBox() + self.msgBox.setWindowTitle(Constants.MAINWINDOW_MSGBOX_TITLE) + + @overrides + def show(self, root_path, sampID): + + super().show() + self.root_path = root_path + self.sampID = sampID + + self.setting = SettingWindow(root_path, sampID) + + # 初始化画框 + self.fig = plt.figure(figsize=(12, 9), dpi=100) + self.canvas = FigureCanvasQTAgg(self.fig) + self.figToolbar = CustomNavigationToolbar(self.canvas, self) + self.figToolbar.action_Get_Range.setEnabled(False) + for action in self.figToolbar._actions.values(): + action.setEnabled(False) + for action in self.figToolbar.actions(): + if action.text() == "Subplots" or action.text() == "Customize": + self.figToolbar.removeAction(action) + self.figToolbar._actions['home'].triggered.connect(self.toggle_home) + self.figToolbar.action_Get_Range.triggered.connect(self.toggle_getRange) + self.ui.verticalLayout_canvas.addWidget(self.canvas) + self.ui.verticalLayout_canvas.addWidget(self.figToolbar) + + PublicFunc.__resetAllButton__(self, ButtonState) + + self.buttonGroup = QButtonGroup(self) + + self.__update_info__() + + self.buttonGroup.addButton(self.ui.radioButton_BCG_front) + self.buttonGroup.addButton(self.ui.radioButton_ECG_front) + self.buttonGroup.addButton(self.ui.radioButton_BCG_back) + self.buttonGroup.addButton(self.ui.radioButton_ECG_back) + + self.ui.pushButton_input.clicked.connect(self.__slot_btn_input__) + self.ui.pushButton_input_setting.clicked.connect(self.setting.show) + self.ui.pushButton_calculate_correlation.clicked.connect(self.__slot_btn_calculate_correlation__) + self.ui.pushButton_correlation_align.clicked.connect(self.__slot_btn_correlation_align__) + self.ui.pushButton_view_align.clicked.connect(self.__slot_btn_view_align__) + self.ui.pushButton_save.clicked.connect(self.__slot_btn_save__) + self.canvas.mpl_connect('pick_event', self.on_pick) + + self.ui.spinBox_BCG_front_JJIV_1.editingFinished.connect(self.__update_coordinate__) + self.ui.spinBox_BCG_front_JJIV_2.editingFinished.connect(self.__update_coordinate__) + self.ui.spinBox_BCG_back_JJIV_1.editingFinished.connect(self.__update_coordinate__) + self.ui.spinBox_BCG_back_JJIV_2.editingFinished.connect(self.__update_coordinate__) + self.ui.spinBox_ECG_front_RRIV_1.editingFinished.connect(self.__update_coordinate__) + self.ui.spinBox_ECG_front_RRIV_2.editingFinished.connect(self.__update_coordinate__) + self.ui.spinBox_ECG_back_RRIV_1.editingFinished.connect(self.__update_coordinate__) + self.ui.spinBox_ECG_back_RRIV_2.editingFinished.connect(self.__update_coordinate__) + + @overrides + def closeEvent(self, event): + + PublicFunc.__disableAllButton__(self, ButtonState) + + 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.data + self.fig.clf() + plt.close(self.fig) + self.deleteLater() + collect() + self.canvas = None + event.accept() + + @staticmethod + def __reset__(): + + ButtonState["Current"].update(ButtonState["Default"].copy()) + + def __plot__(self, plot_element=None): + + # 清空画框 + if self.figToolbar.ax0_BCG_rectangle_front is not None: + self.figToolbar.ax0_BCG_rectangle_front.remove() + if self.figToolbar.ax0_BCG_rectangle_back is not None: + self.figToolbar.ax0_BCG_rectangle_back.remove() + if self.figToolbar.ax1_ECG_rectangle_front is not None: + self.figToolbar.ax1_ECG_rectangle_front.remove() + if self.figToolbar.ax1_ECG_rectangle_back is not None: + self.figToolbar.ax1_ECG_rectangle_back.remove() + self.figToolbar.ax0_BCG_rectangle_front = None + self.figToolbar.ax0_BCG_rectangle_back = None + self.figToolbar.ax1_ECG_rectangle_front = None + self.figToolbar.ax1_ECG_rectangle_back = None + self.reset_axes() + + sender = self.sender() + + if sender == self.ui.pushButton_input: + self.gs = gridspec.GridSpec(2, 1, height_ratios=[1, 1]) + self.fig.subplots_adjust(top=0.95, bottom=0.05, right=0.98, left=0.05, hspace=0.15, wspace=0) + self.ax0 = self.fig.add_subplot(self.gs[0]) + self.ax0.grid(True) + self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax1 = self.fig.add_subplot(self.gs[1], sharex=self.ax0, sharey=self.ax0) + self.ax1.grid(True) + self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + + Jpeak = self.data.Jpeak[:-2] + Rpeak = self.data.Rpeak[:-2] + self.ax0.set_title("JJIV") + self.ax0.stem(Jpeak, plot_element["JJIVs"], + markerfmt="C0.", linefmt=Constants.PLOT_COLOR_GREEN, + label=Constants.PRECISELY_ALIGN_PLOT_LABEL_JJIV) + self.ax1.set_title("RRIV") + self.ax1.stem(Rpeak, plot_element["RRIVs"], + markerfmt="C0.", linefmt=Constants.PLOT_COLOR_ORANGE, + 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 + 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) + self.ax0 = self.fig.add_subplot(self.gs[0]) + self.ax0.grid(True) + self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax1 = self.fig.add_subplot(self.gs[2]) + self.ax1.grid(True) + self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax2 = self.fig.add_subplot(self.gs[1]) + self.ax2.grid(True) + self.ax2.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax3 = self.fig.add_subplot(self.gs[3]) + self.ax3.grid(True) + self.ax3.xaxis.set_major_formatter(ConfigParams.FORMATTER) + + self.ax0.set_title( + "front\ncorre_IIV: {}, corre_II: {}\nsame_sign_rate:{}, total_time_ratio: {}\nshift: {}, alignment offset: {} seconds\noffset_interval: {}, anchor_J: {}, anchor_R: {}".format( + plot_element["front"]["correlation_IIV"], plot_element["front"]["correlation_II"], + plot_element["front"]["same_sign_rate"], plot_element["front"]["total_time_ratio"], + plot_element["front"]["shift"], plot_element["front"]["offset_interval_duration"], + plot_element["front"]["offset_interval"], plot_element["front"]["anchor_J"], + plot_element["front"]["anchor_R"])) + self.ax0.stem(plot_element["front"]["corre"], markerfmt="C0.", + label=Constants.PRECISELY_ALIGN_PLOT_LABEL_CORRE_RRIV_JJIV) + self.selected_point0, = self.ax0.plot(plot_element["front"]["shift"], + plot_element["front"]["corre"][plot_element["front"]["shift"]] + 1, 'v', + color=Constants.PLOT_COLOR_RED, picker=True, pickradius=5, + label=Constants.PRECISELY_ALIGN_PLOT_LABEL_SELECTED_POINT) + self.ax0.plot(plot_element["front"]["corre"], 'o', color=Constants.PLOT_COLOR_BLUE, + markersize=3, picker=True, pickradius=5) + self.ax1.stem(plot_element["front"]["RRIVs"], markerfmt="b.", + label=Constants.PRECISELY_ALIGN_PLOT_LABEL_RRIV) + self.stem_black0 = self.ax1.stem(arange(plot_element["front"]["shift"], + plot_element["front"]["shift"] + len(plot_element["front"]["JJIVs"])), + plot_element["front"]["JJIVs"], markerfmt="ko", + label=Constants.PRECISELY_ALIGN_PLOT_LABEL_JJIV) + self.ax2.set_title( + "back\ncorre_IIV: {}, corre_II: {}\nsame_sign_rate:{}, total_time_ratio: {}\nshift: {}, alignment offset: {} seconds\noffset_interval: {}, anchor_J: {}, anchor_R: {}".format( + plot_element["back"]["correlation_IIV"], plot_element["back"]["correlation_II"], + plot_element["back"]["same_sign_rate"], plot_element["back"]["total_time_ratio"], + plot_element["back"]["shift"], plot_element["back"]["offset_interval_duration"], + plot_element["back"]["offset_interval"], plot_element["back"]["anchor_J"], + plot_element["back"]["anchor_R"])) + self.ax2.stem(plot_element["back"]["corre"], markerfmt="C0.", + label=Constants.PRECISELY_ALIGN_PLOT_LABEL_CORRE_RRIV_JJIV) + self.selected_point1, = self.ax2.plot(plot_element["back"]["shift"], + plot_element["back"]["corre"][plot_element["back"]["shift"]] + 1, 'v', + color=Constants.PLOT_COLOR_RED, picker=True, pickradius=5, + label=Constants.PRECISELY_ALIGN_PLOT_LABEL_SELECTED_POINT) + self.ax2.plot(plot_element["back"]["corre"], 'o', color=Constants.PLOT_COLOR_BLUE, + markersize=3, picker=True, pickradius=5) + self.ax3.stem(plot_element["back"]["RRIVs"], markerfmt="b.", + label=Constants.PRECISELY_ALIGN_PLOT_LABEL_RRIV) + self.stem_black1 = self.ax3.stem(arange(plot_element["back"]["shift"], + plot_element["back"]["shift"] + len(plot_element["back"]["JJIVs"])), + plot_element["back"]["JJIVs"], markerfmt="ko", + label=Constants.PRECISELY_ALIGN_PLOT_LABEL_JJIV) + + self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) + self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT) + self.ax2.legend(loc=Constants.PLOT_UPPER_RIGHT) + self.ax3.legend(loc=Constants.PLOT_UPPER_RIGHT) + + status = True + 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) + self.ax4 = self.fig.add_subplot(self.gs[0]) + self.ax4.grid(True) + self.ax4.xaxis.set_major_formatter(ConfigParams.FORMATTER) + + self.ax4.set_title("offset correct") + self.ax4.plot(plot_element["cut_ECG"], color=Constants.PLOT_COLOR_GREEN, label=Constants.PRECISELY_ALIGN_PLOT_LABEL_ECG) + self.ax4.plot(plot_element["res_BCG"], color=Constants.PLOT_COLOR_ORANGE, label=Constants.PRECISELY_ALIGN_PLOT_LABEL_BCG) + self.ax4.plot([plot_element["anchor00"], plot_element["anchor00"]], [plot_element["b"], plot_element["a"]], 'k--') + self.ax4.plot([plot_element["anchor10"], plot_element["anchor10"]], [plot_element["b"], plot_element["a"]], 'k--') + self.point0, = self.ax4.plot(plot_element["peak_ECG"], plot_element["cut_ECG"][plot_element["peak_ECG"]], + 'o', markersize=3, color=Constants.PLOT_COLOR_BLUE, picker=True, pickradius=5, label=Constants.PRECISELY_ALIGN_PLOT_LABEL_RPEAK) + self.point1, = self.ax4.plot(plot_element["peak_BCG"], plot_element["res_BCG"][plot_element["peak_BCG"]], + 'o', markersize=3, color=Constants.PLOT_COLOR_RED, picker=True, pickradius=5, label=Constants.PRECISELY_ALIGN_PLOT_LABEL_JPEAK) + + self.ax4.legend(loc=Constants.PLOT_UPPER_RIGHT) + + status = True + 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) + self.ax4 = self.fig.add_subplot(self.gs[0]) + self.ax4.grid(True) + self.ax4.xaxis.set_major_formatter(ConfigParams.FORMATTER) + + self.ax4.set_title("result preview") + self.ax4.plot(self.data.cut_ECG, color=Constants.PLOT_COLOR_GREEN, label=Constants.PRECISELY_ALIGN_PLOT_LABEL_ECG) + self.ax4.plot(self.data.res_BCG, color=Constants.PLOT_COLOR_ORANGE, label=Constants.PRECISELY_ALIGN_PLOT_LABEL_BCG) + self.ax4.plot(self.data.cut_Rpeak, self.data.cut_ECG[self.data.cut_Rpeak], 'v', color=Constants.PLOT_COLOR_BLUE, label=Constants.PRECISELY_ALIGN_PLOT_LABEL_RPEAK) + self.ax4.plot(self.data.cut_Jpeak, self.data.res_BCG[self.data.cut_Jpeak], 'v', color=Constants.PLOT_COLOR_RED, label=Constants.PRECISELY_ALIGN_PLOT_LABEL_JPEAK) + + self.ax4.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 + + def __update_info__(self): + + self.ui.spinBox_BCG_front_JJIV_1.setValue(Config["IV_Coordinate"]["BCG_front_1"]) + self.ui.spinBox_BCG_front_JJIV_2.setValue(Config["IV_Coordinate"]["BCG_front_2"]) + self.ui.spinBox_BCG_back_JJIV_1.setValue(Config["IV_Coordinate"]["BCG_back_1"]) + self.ui.spinBox_BCG_back_JJIV_2.setValue(Config["IV_Coordinate"]["BCG_back_2"]) + self.ui.spinBox_ECG_front_RRIV_1.setValue(Config["IV_Coordinate"]["ECG_front_1"]) + self.ui.spinBox_ECG_front_RRIV_2.setValue(Config["IV_Coordinate"]["ECG_front_2"]) + self.ui.spinBox_ECG_back_RRIV_1.setValue(Config["IV_Coordinate"]["ECG_back_1"]) + self.ui.spinBox_ECG_back_RRIV_2.setValue(Config["IV_Coordinate"]["ECG_back_2"]) + self.ui.spinBox_BCG_front_Signal_1.setValue(Config["Coordinate"]["BCG_front_1"]) + self.ui.spinBox_BCG_front_Signal_2.setValue(Config["Coordinate"]["BCG_front_2"]) + self.ui.spinBox_BCG_back_Signal_1.setValue(Config["Coordinate"]["BCG_back_1"]) + self.ui.spinBox_BCG_back_Signal_2.setValue(Config["Coordinate"]["BCG_back_2"]) + self.ui.spinBox_ECG_front_Signal_1.setValue(Config["Coordinate"]["ECG_front_1"]) + self.ui.spinBox_ECG_front_Signal_2.setValue(Config["Coordinate"]["ECG_front_2"]) + self.ui.spinBox_ECG_back_Signal_1.setValue(Config["Coordinate"]["ECG_back_1"]) + self.ui.spinBox_ECG_back_Signal_2.setValue(Config["Coordinate"]["ECG_back_2"]) + + def __slot_btn_input__(self): + + PublicFunc.__disableAllButton__(self, ButtonState) + + # 清空画框 + self.reset_axes() + self.canvas.draw() + + self.data = Data() + + # 导入数据 + 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) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(1/3)" + 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) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(2/3)" + 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) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(3/3)" + info, Constants.TIPS_TYPE_INFO) + + MainWindow_precisely_align.__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 + for action in self.figToolbar._actions.values(): + action.setEnabled(True) + ButtonState["Current"].update(ButtonState["Statue_1"].copy()) + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_calculate_correlation__(self, test1=None, shift_front=None, shift_back=None): + # TODO:这里有个未知的问BUG,虽然不影响功能,但会影响代码整洁性,第一个形参赋值为None时,之后使用变量时将会变成False,不知道为什么 + + PublicFunc.__disableAllButton__(self, ButtonState) + + sender = self.sender() + if sender == self.ui.pushButton_calculate_correlation: + mode = "init" + else: + mode = "select" + self.ax0_xlime = self.ax0.get_xlim() + self.ax0_ylime = self.ax0.get_ylim() + self.ax2_xlime = self.ax2.get_xlim() + self.ax2_ylime = self.ax2.get_ylim() + + # 计算前段相关性 + 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) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(1/3)" + 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) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(2/3)" + info, Constants.TIPS_TYPE_INFO) + + # 绘图 + PublicFunc.progressbar_update(self, 3, 3, Constants.DRAWING_DATA, 60) + result = {} + result.update(result1) + result.update(result2) + result.update({"mode": mode}) + if mode == "init": + status, info = self.__plot__(result) + elif mode == "select": + status, info = 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) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(3/3)" + info, Constants.TIPS_TYPE_INFO) + + self.figToolbar.action_Get_Range.setEnabled(False) + self.figToolbar.deactivate_figToorbar_getRange_mode() + ButtonState["Current"].update(ButtonState["Statue_2"].copy()) + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_correlation_align__(self): + + PublicFunc.__disableAllButton__(self, ButtonState) + + sender = self.sender() + if sender == self.ui.pushButton_correlation_align: + mode = "init" + else: + mode = "select" + self.ax4_xlime = self.ax4.get_xlim() + self.ax4_ylime = self.ax4.get_ylim() + + # 处理相关对齐 + 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) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(1/2)" + info, Constants.TIPS_TYPE_INFO) + + # 绘图 + PublicFunc.progressbar_update(self, 2, 2, Constants.DRAWING_DATA, 50) + result.update({"mode": mode}) + if mode == "init": + status, info = self.__plot__(result) + elif mode == "select": + status, info = self.redraw_correlation_align(result) + 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) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(2/2)" + info, Constants.TIPS_TYPE_INFO) + + ButtonState["Current"].update(ButtonState["Statue_3"].copy()) + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_view_align__(self): + + PublicFunc.__disableAllButton__(self, ButtonState) + + # 数据后处理 + 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) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(1/2)" + 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) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(2/2)" + info, Constants.TIPS_TYPE_INFO) + + ButtonState["Current"].update(ButtonState["Statue_4"].copy()) + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_save__(self): + + reply = QMessageBox.question(self, Constants.QUESTION_TITLE, Constants.QUESTION_CONTENT, + QMessageBox.Yes | QMessageBox.No, + QMessageBox.Yes) + if reply == QMessageBox.Yes: + PublicFunc.__disableAllButton__(self, ButtonState) + + # 保存 + PublicFunc.progressbar_update(self, 1, 1, Constants.SAVING_DATA, 0) + status, info = self.data.save() + if not status: + PublicFunc.text_output(self.ui, "(1/1)" + info, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR) + PublicFunc.finish_operation(self, ButtonState) + return + else: + PublicFunc.text_output(self.ui, "(1/1)" + info, Constants.TIPS_TYPE_INFO) + PublicFunc.msgbox_output(self, info, Constants.TIPS_TYPE_INFO) + + PublicFunc.finish_operation(self, ButtonState) + + def __update_coordinate__(self): + + if self.data is not None: + if self.data.Jpeak is None or self.data.Rpeak is None: + PublicFunc.msgbox_output(self, Constants.PRECISELY_ALIGN_FAILURE_REASON["Data_Not_Exist"], Constants.MSGBOX_TYPE_ERROR) + return + + sender = self.sender() + + if sender == self.ui.spinBox_BCG_front_JJIV_1: + if self.ui.spinBox_BCG_front_JJIV_1.value() >= len(self.data.Jpeak[:-2]): + self.ui.spinBox_BCG_front_JJIV_1.setValue(len(self.data.Jpeak[:-2]) - 1) + Config["IV_Coordinate"]["BCG_front_1"] = self.ui.spinBox_BCG_front_JJIV_1.value() + Config["Coordinate"]["BCG_front_1"] = self.data.Jpeak[:-2][self.ui.spinBox_BCG_front_JJIV_1.value()] + self.ui.spinBox_BCG_front_Signal_1.setValue(Config["Coordinate"]["BCG_front_1"]) + elif sender == self.ui.spinBox_BCG_front_JJIV_2: + if self.ui.spinBox_BCG_front_JJIV_2.value() >= len(self.data.Jpeak[:-2]): + self.ui.spinBox_BCG_front_JJIV_2.setValue(len(self.data.Jpeak[:-2]) - 1) + Config["IV_Coordinate"]["BCG_front_2"] = self.ui.spinBox_BCG_front_JJIV_2.value() + Config["Coordinate"]["BCG_front_2"] = self.data.Jpeak[:-2][self.ui.spinBox_BCG_front_JJIV_2.value()] + self.ui.spinBox_BCG_front_Signal_2.setValue(Config["Coordinate"]["BCG_front_2"]) + elif sender == self.ui.spinBox_BCG_back_JJIV_1: + if self.ui.spinBox_BCG_back_JJIV_1.value() >= len(self.data.Jpeak[:-2]): + self.ui.spinBox_BCG_back_JJIV_1.setValue(len(self.data.Jpeak[:-2]) - 1) + Config["IV_Coordinate"]["BCG_back_1"] = self.ui.spinBox_BCG_back_JJIV_1.value() + Config["Coordinate"]["BCG_back_1"] = self.data.Jpeak[:-2][self.ui.spinBox_BCG_back_JJIV_1.value()] + self.ui.spinBox_BCG_back_Signal_1.setValue(Config["Coordinate"]["BCG_back_1"]) + elif sender == self.ui.spinBox_BCG_back_JJIV_2: + if self.ui.spinBox_BCG_back_JJIV_2.value() >= len(self.data.Jpeak[:-2]): + self.ui.spinBox_BCG_back_JJIV_2.setValue(len(self.data.Jpeak[:-2]) - 1) + Config["IV_Coordinate"]["BCG_back_2"] = self.ui.spinBox_BCG_back_JJIV_2.value() + Config["Coordinate"]["BCG_back_2"] = self.data.Jpeak[:-2][self.ui.spinBox_BCG_back_JJIV_2.value()] + self.ui.spinBox_BCG_back_Signal_2.setValue(Config["Coordinate"]["BCG_back_2"]) + elif sender == self.ui.spinBox_ECG_front_RRIV_1: + if self.ui.spinBox_ECG_front_RRIV_1.value() >= len(self.data.Rpeak[:-2]): + self.ui.spinBox_ECG_front_RRIV_1.setValue(len(self.data.Rpeak[:-2]) - 1) + Config["IV_Coordinate"]["ECG_front_1"] = self.ui.spinBox_ECG_front_RRIV_1.value() + Config["Coordinate"]["ECG_front_1"] = self.data.Rpeak[:-2][self.ui.spinBox_ECG_front_RRIV_1.value()] + self.ui.spinBox_ECG_front_Signal_1.setValue(Config["Coordinate"]["ECG_front_1"]) + elif sender == self.ui.spinBox_ECG_front_RRIV_2: + if self.ui.spinBox_ECG_front_RRIV_2.value() >= len(self.data.Rpeak[:-2]): + self.ui.spinBox_ECG_front_RRIV_2.setValue(len(self.data.Rpeak[:-2]) - 1) + Config["IV_Coordinate"]["ECG_front_2"] = self.ui.spinBox_ECG_front_RRIV_2.value() + Config["Coordinate"]["ECG_front_2"] = self.data.Rpeak[:-2][self.ui.spinBox_ECG_front_RRIV_2.value()] + self.ui.spinBox_ECG_front_Signal_2.setValue(Config["Coordinate"]["ECG_front_2"]) + elif sender == self.ui.spinBox_ECG_back_RRIV_1: + if self.ui.spinBox_ECG_back_RRIV_1.value() >= len(self.data.Rpeak[:-2]): + self.ui.spinBox_ECG_back_RRIV_1.setValue(len(self.data.Rpeak[:-2]) - 1) + Config["IV_Coordinate"]["ECG_back_1"] = self.ui.spinBox_ECG_back_RRIV_1.value() + Config["Coordinate"]["ECG_back_1"] = self.data.Rpeak[:-2][self.ui.spinBox_ECG_back_RRIV_1.value()] + self.ui.spinBox_ECG_back_Signal_1.setValue(Config["Coordinate"]["ECG_back_1"]) + elif sender == self.ui.spinBox_ECG_back_RRIV_2: + if self.ui.spinBox_ECG_back_RRIV_2.value() >= len(self.data.Rpeak[:-2]): + self.ui.spinBox_ECG_back_RRIV_2.setValue(len(self.data.Rpeak[:-2]) - 1) + Config["IV_Coordinate"]["ECG_back_2"] = self.ui.spinBox_ECG_back_RRIV_2.value() + Config["Coordinate"]["ECG_back_2"] = self.data.Rpeak[:-2][self.ui.spinBox_ECG_back_RRIV_2.value()] + self.ui.spinBox_ECG_back_Signal_2.setValue(Config["Coordinate"]["ECG_back_2"]) + + def reset_axes(self): + + for ax in self.fig.axes: + self.fig.delaxes(ax) + if self.ax0 is not None: + self.ax0.clear() + self.ax0.grid(True) + self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + if self.ax1 is not None: + self.ax1.clear() + self.ax1.grid(True) + self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + if self.ax2 is not None: + self.ax2.clear() + self.ax2.grid(True) + self.ax2.xaxis.set_major_formatter(ConfigParams.FORMATTER) + if self.ax3 is not None: + self.ax3.clear() + self.ax3.grid(True) + self.ax3.xaxis.set_major_formatter(ConfigParams.FORMATTER) + if self.ax4 is not None: + self.ax4.clear() + self.ax4.grid(True) + self.ax4.xaxis.set_major_formatter(ConfigParams.FORMATTER) + + def redraw_calculate_coordination(self, plot_element=None): + + if plot_element is not None and plot_element["mode"] == "select": + if self.selected_point0 is not None: + self.selected_point0.remove() + self.selected_point0 = None + if self.selected_point1 is not None: + self.selected_point1.remove() + self.selected_point1 = None + if self.stem_black0 is not None: + self.stem_black0.remove() + self.stem_black0 = None + if self.stem_black1 is not None: + self.stem_black1.remove() + self.stem_black1 = None + + self.ax0.set_title( + "front\ncorre_IIV: {}, corre_II: {}\nsame_sign_rate:{}, total_time_ratio: {}\nshift: {}, alignment offset: {} seconds\noffset_interval: {}, anchor_J: {}, anchor_R: {}".format( + plot_element["front"]["correlation_IIV"], plot_element["front"]["correlation_II"], + plot_element["front"]["same_sign_rate"], plot_element["front"]["total_time_ratio"], + plot_element["front"]["shift"], plot_element["front"]["offset_interval_duration"], + plot_element["front"]["offset_interval"], plot_element["front"]["anchor_J"], + plot_element["front"]["anchor_R"])) + self.ax2.set_title( + "back\ncorre_IIV: {}, corre_II: {}\nsame_sign_rate:{}, total_time_ratio: {}\nshift: {}, alignment offset: {} seconds\noffset_interval: {}, anchor_J: {}, anchor_R: {}".format( + plot_element["back"]["correlation_IIV"], plot_element["back"]["correlation_II"], + plot_element["back"]["same_sign_rate"], plot_element["back"]["total_time_ratio"], + plot_element["back"]["shift"], plot_element["back"]["offset_interval_duration"], + plot_element["back"]["offset_interval"], plot_element["back"]["anchor_J"], + plot_element["back"]["anchor_R"])) + self.selected_point0, = self.ax0.plot(plot_element["front"]["shift"], + plot_element["front"]["corre"][plot_element["front"]["shift"]] + 1, 'v', + color=Constants.PLOT_COLOR_RED, picker=True, pickradius=5, + label=Constants.PRECISELY_ALIGN_PLOT_LABEL_SELECTED_POINT) + self.stem_black0 = self.ax1.stem(arange(plot_element["front"]["shift"], + plot_element["front"]["shift"] + len(plot_element["front"]["JJIVs"])), + plot_element["front"]["JJIVs"], markerfmt="ko", + label=Constants.PRECISELY_ALIGN_PLOT_LABEL_JJIV) + self.selected_point1, = self.ax2.plot(plot_element["back"]["shift"], + plot_element["back"]["corre"][plot_element["back"]["shift"]] + 1, 'v', + color=Constants.PLOT_COLOR_RED, picker=True, pickradius=5, + label=Constants.PRECISELY_ALIGN_PLOT_LABEL_SELECTED_POINT) + self.stem_black1 = self.ax3.stem(arange(plot_element["back"]["shift"], + plot_element["back"]["shift"] + len(plot_element["back"]["JJIVs"])), + plot_element["back"]["JJIVs"], markerfmt="ko", + label=Constants.PRECISELY_ALIGN_PLOT_LABEL_JJIV) + + self.ax0.autoscale(False) + self.ax2.autoscale(False) + self.ax0.set_xlim(self.ax0_xlime) + self.ax0.set_ylim(self.ax0_ylime) + self.ax2.set_xlim(self.ax2_xlime) + self.ax2.set_ylim(self.ax2_ylime) + + self.canvas.draw() + + return True, Constants.DRAWING_FINISHED + + def redraw_correlation_align(self, plot_element=None): + + if plot_element is not None and plot_element["mode"] == "select": + if self.selected_point0 is not None: + self.selected_point0.remove() + self.selected_point0 = None + if self.selected_point1 is not None: + self.selected_point1.remove() + self.selected_point1 = None + if self.selected_point2 is not None: + self.selected_point2.remove() + self.selected_point2 = None + if self.selected_point3 is not None: + self.selected_point3.remove() + self.selected_point3 = None + + if len(self.data.correlation_align_point_match_ECG) > 0: + self.selected_point0, = self.ax4.plot( + [self.data.correlation_align_point_match_ECG[0], self.data.correlation_align_point_match_ECG[0]], [plot_element["b"], plot_element["a"]], 'b--') + if len(self.data.correlation_align_point_match_ECG) == 2: + self.selected_point1, = self.ax4.plot( + [self.data.correlation_align_point_match_ECG[1], self.data.correlation_align_point_match_ECG[1]], [plot_element["b"], plot_element["a"]], 'b--') + if len(self.data.correlation_align_point_match_BCG) > 0: + self.selected_point2, = self.ax4.plot( + [self.data.correlation_align_point_match_BCG[0], self.data.correlation_align_point_match_BCG[0]], [plot_element["b"], plot_element["a"]], 'r--') + if len(self.data.correlation_align_point_match_BCG) == 2: + self.selected_point3, = self.ax4.plot( + [self.data.correlation_align_point_match_BCG[1], self.data.correlation_align_point_match_BCG[1]], [plot_element["b"], plot_element["a"]], 'r--') + + self.ax4.autoscale(False) + self.ax4.set_xlim(self.ax4_xlime) + self.ax4.set_ylim(self.ax4_ylime) + + self.canvas.draw() + + return True, Constants.DRAWING_FINISHED + + def toggle_home(self): + + if self.ax0 is not None: + self.ax0.autoscale(True) + self.ax0.relim() + self.ax0.autoscale_view() + self.canvas.draw() + self.ax0.autoscale(False) + if self.ax1 is not None: + self.ax1.autoscale(True) + self.ax1.relim() + self.ax1.autoscale_view() + self.canvas.draw() + self.ax1.autoscale(False) + if self.ax2 is not None: + self.ax2.autoscale(True) + self.ax2.relim() + self.ax2.autoscale_view() + self.canvas.draw() + self.ax2.autoscale(False) + if self.ax3 is not None: + self.ax3.autoscale(True) + self.ax3.relim() + self.ax3.autoscale_view() + self.canvas.draw() + self.ax3.autoscale(False) + if self.ax4 is not None: + self.ax4.autoscale(True) + self.ax4.relim() + self.ax4.autoscale_view() + self.canvas.draw() + self.ax4.autoscale(False) + + PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_RECOVER_SCALE, Constants.TIPS_TYPE_INFO) + + def toggle_getRange(self, state): + + if state: + self.deactivate_figToolbar_buttons() + self.figToolbar.action_Get_Range.setChecked(True) + self.figToolbar.cid_mouse_press = self.canvas.mpl_connect( + "button_press_event", self.on_click) + self.figToolbar.cid_mouse_release = self.canvas.mpl_connect( + "button_release_event", self.on_release) + self.figToolbar.cid_mouse_hold = self.canvas.mpl_connect( + "motion_notify_event", self.on_hold) + else: + if self.figToolbar.cid_mouse_press is not None: + self.canvas.mpl_disconnect(self.figToolbar.cid_mouse_press) + self.figToolbar.cid_mouse_press = None + if self.figToolbar.cid_mouse_release is not None: + self.canvas.mpl_disconnect(self.figToolbar.cid_mouse_release) + self.figToolbar.cid_mouse_release = None + if self.figToolbar.cid_mouse_hold: + self.canvas.mpl_disconnect(self.figToolbar.cid_mouse_hold) + self.figToolbar.cid_mouse_hold = None + + def deactivate_figToolbar_buttons(self): + + for action in self.figToolbar._actions.values(): + if action.isChecked() == True: + if action == self.figToolbar._actions['pan']: + self.figToolbar.pan() + if action == self.figToolbar._actions['zoom']: + self.figToolbar.zoom() + + def on_click(self, event): + + if self.figToolbar.action_Get_Range.isChecked(): + if event.button == 1: + self.is_left_button_pressed = True + self.figToolbar.rect_start_x = event.xdata + # 如果矩形patch已存在,先移除 + if self.ui.radioButton_BCG_front.isChecked(): + if self.figToolbar.ax0_BCG_rectangle_front is not None: + self.figToolbar.ax0_BCG_rectangle_front.remove() + self.figToolbar.ax0_BCG_rectangle_front = None + elif self.ui.radioButton_BCG_back.isChecked(): + if self.figToolbar.ax0_BCG_rectangle_back is not None: + self.figToolbar.ax0_BCG_rectangle_back.remove() + self.figToolbar.ax0_BCG_rectangle_back = None + elif self.ui.radioButton_ECG_front.isChecked(): + if self.figToolbar.ax1_ECG_rectangle_front is not None: + self.figToolbar.ax1_ECG_rectangle_front.remove() + self.figToolbar.ax1_ECG_rectangle_front = None + elif self.ui.radioButton_ECG_back.isChecked(): + if self.figToolbar.ax1_ECG_rectangle_back is not None: + self.figToolbar.ax1_ECG_rectangle_back.remove() + self.figToolbar.ax1_ECG_rectangle_back = None + else: + raise ValueError("模式未选择") + self.canvas.draw() + + def on_release(self, event): + + if self.figToolbar.action_Get_Range.isChecked(): + if self.figToolbar.rect_start_x is not None: + self.figToolbar.rect_end_x = event.xdata + if self.figToolbar.rect_start_x is not None and self.figToolbar.rect_end_x is not None: + if self.figToolbar.rect_start_x < self.figToolbar.rect_end_x: + rect_left = self.figToolbar.rect_start_x + rect_right = self.figToolbar.rect_end_x + elif self.figToolbar.rect_start_x > self.figToolbar.rect_end_x: + rect_left = self.figToolbar.rect_end_x + rect_right = self.figToolbar.rect_start_x + else: + rect_left = self.figToolbar.rect_start_x + rect_right = self.figToolbar.rect_start_x + else: + rect_left = self.figToolbar.rect_start_x + rect_right = self.figToolbar.rect_start_x + if event.button == 1 and self.is_left_button_pressed: + self.is_left_button_pressed = False + if self.ui.radioButton_BCG_front.isChecked() or self.ui.radioButton_BCG_back.isChecked(): + if rect_left < 0: + rect_left = 0 + elif rect_left >= len(self.data.raw_BCG): + rect_left = 0 + rect_right = 0 + if rect_right >= len(self.data.raw_BCG): + rect_right = len(self.data.raw_BCG) - 1 + elif rect_right < 0: + rect_left = 0 + rect_right = 0 + indices = where((self.data.Jpeak[:-2] >= rect_left) & (self.data.Jpeak[:-2] <= rect_right))[0] + if indices is None or len(indices) <= 0: + if self.ui.radioButton_BCG_front.isChecked(): + Config["IV_Coordinate"]["BCG_front_1"] = 0 + Config["IV_Coordinate"]["BCG_front_2"] = 0 + Config["Coordinate"]["BCG_front_1"] = 0 + Config["Coordinate"]["BCG_front_2"] = 0 + elif self.ui.radioButton_BCG_back.isChecked(): + Config["IV_Coordinate"]["BCG_back_1"] = 0 + Config["IV_Coordinate"]["BCG_back_2"] = 0 + Config["Coordinate"]["BCG_back_1"] = 0 + Config["Coordinate"]["BCG_back_2"] = 0 + PublicFunc.text_output(self.ui, Constants.PRECISELY_ALIGN_NO_POINT_IN_THE_INTERVAL, + Constants.TIPS_TYPE_INFO) + else: + if self.ui.radioButton_BCG_front.isChecked(): + Config["IV_Coordinate"]["BCG_front_1"] = indices[0] + Config["IV_Coordinate"]["BCG_front_2"] = indices[-1] + Config["Coordinate"]["BCG_front_1"] = self.data.Jpeak[:-2][indices[0]] + Config["Coordinate"]["BCG_front_2"] = self.data.Jpeak[:-2][indices[-1]] + elif self.ui.radioButton_BCG_back.isChecked(): + Config["IV_Coordinate"]["BCG_back_1"] = indices[0] + Config["IV_Coordinate"]["BCG_back_2"] = indices[-1] + Config["Coordinate"]["BCG_back_1"] = self.data.Jpeak[:-2][indices[0]] + Config["Coordinate"]["BCG_back_2"] = self.data.Jpeak[:-2][indices[-1]] + elif self.ui.radioButton_ECG_front.isChecked() or self.ui.radioButton_ECG_back.isChecked(): + if rect_left < 0: + rect_left = 0 + elif rect_left >= len(self.data.raw_ECG): + rect_left = 0 + rect_right = 0 + if rect_right >= len(self.data.raw_ECG): + rect_right = len(self.data.raw_ECG) - 1 + elif rect_right < 0: + rect_left = 0 + rect_right = 0 + indices = where((self.data.Rpeak[:-2] >= rect_left) & (self.data.Rpeak[:-2] <= rect_right))[0] + if indices is None or len(indices) <= 0: + if self.ui.radioButton_ECG_front.isChecked(): + Config["IV_Coordinate"]["ECG_front_1"] = 0 + Config["IV_Coordinate"]["ECG_front_2"] = 0 + Config["Coordinate"]["ECG_front_1"] = 0 + Config["Coordinate"]["ECG_front_2"] = 0 + elif self.ui.radioButton_ECG_back.isChecked(): + Config["IV_Coordinate"]["ECG_back_1"] = 0 + Config["IV_Coordinate"]["ECG_back_2"] = 0 + Config["Coordinate"]["ECG_back_1"] = 0 + Config["Coordinate"]["ECG_back_2"] = 0 + PublicFunc.text_output(self.ui, Constants.PRECISELY_ALIGN_NO_POINT_IN_THE_INTERVAL, + Constants.TIPS_TYPE_INFO) + else: + if self.ui.radioButton_ECG_front.isChecked(): + Config["IV_Coordinate"]["ECG_front_1"] = indices[0] + Config["IV_Coordinate"]["ECG_front_2"] = indices[-1] + Config["Coordinate"]["ECG_front_1"] = self.data.Rpeak[:-2][indices[0]] + Config["Coordinate"]["ECG_front_2"] = self.data.Rpeak[:-2][indices[-1]] + elif self.ui.radioButton_ECG_back.isChecked(): + Config["IV_Coordinate"]["ECG_back_1"] = indices[0] + Config["IV_Coordinate"]["ECG_back_2"] = indices[-1] + Config["Coordinate"]["ECG_back_1"] = self.data.Rpeak[:-2][indices[0]] + Config["Coordinate"]["ECG_back_2"] = self.data.Rpeak[:-2][indices[-1]] + + self.figToolbar.rect_start_x = None + self.figToolbar.rect_end_x = None + + self.__update_info__() + self.canvas.draw() + + def on_hold(self, event): + + if event.button == 1: + if self.figToolbar.rect_start_x is not None and event.xdata is not None: + self.figToolbar.rect_end_x = event.xdata + + # 更新矩形patch的位置和大小 + x_start = self.figToolbar.rect_start_x + x_end = self.figToolbar.rect_end_x + + # 如果矩形patch不存在,则创建一个新的 + if self.figToolbar.ax0_BCG_rectangle_front is None and self.is_left_button_pressed: + self.figToolbar.ax0_BCG_rectangle_front = patches.Rectangle((0, 0), 1, 1, + fill=True, + alpha=ConfigParams.LABEL_CHECK_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_PINK) + self.ax0.add_patch(self.figToolbar.ax0_BCG_rectangle_front) + if self.figToolbar.ax0_BCG_rectangle_back is None and self.is_left_button_pressed: + self.figToolbar.ax0_BCG_rectangle_back = patches.Rectangle((0, 0), 1, 1, + fill=True, + alpha=ConfigParams.LABEL_CHECK_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_PINK) + self.ax0.add_patch(self.figToolbar.ax0_BCG_rectangle_back) + if self.figToolbar.ax1_ECG_rectangle_front is None and self.is_left_button_pressed: + self.figToolbar.ax1_ECG_rectangle_front = patches.Rectangle((0, 0), 1, 1, + fill=True, + alpha=ConfigParams.LABEL_CHECK_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_PINK) + self.ax1.add_patch(self.figToolbar.ax1_ECG_rectangle_front) + if self.figToolbar.ax1_ECG_rectangle_back is None and self.is_left_button_pressed: + self.figToolbar.ax1_ECG_rectangle_back = patches.Rectangle((0, 0), 1, 1, + fill=True, + alpha=ConfigParams.LABEL_CHECK_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_PINK) + self.ax1.add_patch(self.figToolbar.ax1_ECG_rectangle_back) + + if self.ui.radioButton_BCG_front.isChecked(): + self.figToolbar.ax0_BCG_rectangle_front.set_xy((min(x_start, x_end), self.rect_down)) + self.figToolbar.ax0_BCG_rectangle_front.set_width(abs(x_end - x_start)) + self.figToolbar.ax0_BCG_rectangle_front.set_height(self.rect_up - self.rect_down) + elif self.ui.radioButton_BCG_back.isChecked(): + self.figToolbar.ax0_BCG_rectangle_back.set_xy((min(x_start, x_end), self.rect_down)) + self.figToolbar.ax0_BCG_rectangle_back.set_width(abs(x_end - x_start)) + self.figToolbar.ax0_BCG_rectangle_back.set_height(self.rect_up - self.rect_down) + elif self.ui.radioButton_ECG_front.isChecked(): + self.figToolbar.ax1_ECG_rectangle_front.set_xy((min(x_start, x_end), self.rect_down)) + self.figToolbar.ax1_ECG_rectangle_front.set_width(abs(x_end - x_start)) + self.figToolbar.ax1_ECG_rectangle_front.set_height(self.rect_up - self.rect_down) + elif self.ui.radioButton_ECG_back.isChecked(): + self.figToolbar.ax1_ECG_rectangle_back.set_xy((min(x_start, x_end), self.rect_down)) + self.figToolbar.ax1_ECG_rectangle_back.set_width(abs(x_end - x_start)) + self.figToolbar.ax1_ECG_rectangle_back.set_height(self.rect_up - self.rect_down) + + self.canvas.draw() + + def on_pick(self, event): + + this_line = event.artist + if this_line.axes == self.ax0: + xdata = this_line.get_xdata() + ind = event.ind[-1] + shift_front = int(xdata[ind]) + self.__slot_btn_calculate_correlation__(shift_front=shift_front) + elif this_line.axes == self.ax2: + xdata = this_line.get_xdata() + ind = event.ind[-1] + shift_back = int(xdata[ind]) + self.__slot_btn_calculate_correlation__(shift_back=shift_back) + elif this_line.axes == self.ax4: + xdata = this_line.get_xdata() + ind = event.ind[-1] + nm = int(xdata[ind]) + if this_line == self.point0: + if nm in self.data.correlation_align_point_match_ECG: + self.data.correlation_align_point_match_ECG = delete(self.data.correlation_align_point_match_ECG, + where(self.data.correlation_align_point_match_ECG == nm)[0]) + elif len(self.data.correlation_align_point_match_ECG) < 2: + self.data.correlation_align_point_match_ECG = append(self.data.correlation_align_point_match_ECG, nm) + elif this_line == self.point1: + if nm in self.data.correlation_align_point_match_BCG: + self.data.correlation_align_point_match_BCG = delete(self.data.correlation_align_point_match_BCG, + where(self.data.correlation_align_point_match_BCG == nm)[0]) + elif len(self.data.correlation_align_point_match_BCG) < 2: + self.data.correlation_align_point_match_BCG = append(self.data.correlation_align_point_match_BCG, nm) + else: + raise ValueError("this_line不存在") + self.__slot_btn_correlation_align__() + +class Data: + + def __init__(self): + self.file_path_input_BCG = Config["Path"]["Input_BCG"] + self.file_path_input_Jpeak = Config["Path"]["Input_Jpeak"] + self.file_path_input_ECG = Config["Path"]["Input_ECG"] + self.file_path_input_Rpeak = Config["Path"]["Input_Rpeak"] + self.file_path_save_BCG = Config["Path"]["Save_BCG"] + self.file_path_save_ECG = Config["Path"]["Save_ECG"] + + self.raw_BCG = None + self.Jpeak = None + self.Jpeak_y = None + self.raw_ECG = None + self.Rpeak = None + self.Rpeak_y = None + + self.cut_ECG = None + self.res_BCG = None + self.cut_Rpeak = None + self.cut_Jpeak = None + + self.RRIs = None + self.JJIs = None + + self.JJIs0_front = None + self.RRIs0_front = None + self.JJIVs_front = None + self.RRIVs_front = None + self.JJIs0_back = None + self.RRIs0_back = None + self.JJIVs_back = None + self.RRIVs_back = None + self.corre_front = None + self.corre_back = None + + self.correlation_align_point_match_ECG = array([]).astype(int) + self.correlation_align_point_match_BCG = array([]).astype(int) + + self.argmax_BCG = None + self.argmax_ECG = None + + def open_file(self): + + if ((not Path(Config["Path"]["Input_BCG"]).exists()) + 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"] + + try: + self.raw_BCG = read_csv(self.file_path_input_BCG, + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + self.Jpeak = read_csv(self.file_path_input_Jpeak, + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + self.raw_ECG = read_csv(self.file_path_input_ECG, + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + self.Rpeak = read_csv(self.file_path_input_Rpeak, + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + 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 True, 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 + + try: + self.JJIs = diff(self.Jpeak) + JJIVs = diff(self.JJIs) + self.RRIs = diff(self.Rpeak) + RRIVs = diff(self.RRIs) + + result = {"JJIVs": JJIVs, "RRIVs": RRIVs} + except Exception: + return False, Constants.PRECISELY_ALIGN_PROCESS_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Process_Data_Exception"], result + + return True, Constants.PRECISELY_ALIGN_PROCESS_FINISHED, 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 + + 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 + + try: + if mode == "init": + self.JJIs0_front = self.JJIs[Config["IV_Coordinate"]["BCG_front_1"]:Config["IV_Coordinate"]["BCG_front_2"]] + self.RRIs0_front = self.RRIs[Config["IV_Coordinate"]["ECG_front_1"]:Config["IV_Coordinate"]["ECG_front_2"]] + self.JJIVs_front = diff(self.JJIs0_front) + self.RRIVs_front = diff(self.RRIs0_front) + self.corre_front = correlate(self.RRIVs_front, self.JJIVs_front, 'valid') + shift = np_argmax(self.corre_front) + else: + if shift_front is None: + shift = Config["front"]["shift"] + else: + shift = shift_front + RRIVs_cut = self.RRIVs_front[shift:shift + len(self.JJIVs_front)] + RRIs_cut = self.RRIs0_front[shift:shift + len(self.JJIs0_front)] + correlation = corrcoef(RRIVs_cut, self.JJIVs_front) + correlation_IIV = (correlation[0, 1] + correlation[1, 0]) / 2 + correlation = corrcoef(RRIs_cut, self.JJIs0_front) + correlation_II = (correlation[0, 1] + correlation[1, 0]) / 2 + same_sign_rate = np_sum(RRIVs_cut * self.JJIVs_front > 0) / len(self.JJIVs_front) + total_time_ratio = np_sum(self.JJIs0_front) / np_sum(self.RRIs0_front[shift:shift + len(self.JJIs0_front)]) + Jpeak_cut = self.Jpeak[Config["IV_Coordinate"]["BCG_front_1"]:Config["IV_Coordinate"]["BCG_front_2"] + 2] + Rpeak_cut = self.Rpeak[Config["IV_Coordinate"]["ECG_front_1"]:Config["IV_Coordinate"]["ECG_front_2"] + 2] + RRI = diff(Rpeak_cut) + offset_interval = np_sum(RRI[:shift]) - (Jpeak_cut[0] - Rpeak_cut[0]) + anchor_J = self.Jpeak[Config["IV_Coordinate"]["BCG_front_1"]] + anchor_R = self.Rpeak[Config["IV_Coordinate"]["ECG_front_1"] + shift] + offset_interval_duration = offset_interval / Config["InputConfig"]["ECGFreq"] + + Config["front"]["shift"] = shift + Config["front"]["offset_interval"] = offset_interval + Config["front"]["anchor_J"] = anchor_J + Config["front"]["anchor_R"] = anchor_R + Config["front"]["offset_interval_duration"] = offset_interval_duration + + result = { + "front": { + "correlation_IIV": correlation_IIV, + "correlation_II": correlation_II, + "same_sign_rate": same_sign_rate, + "total_time_ratio": total_time_ratio, + "shift": shift, + "corre": self.corre_front, + "JJIVs": self.JJIVs_front, + "RRIVs": self.RRIVs_front, + "offset_interval": offset_interval, + "anchor_J": anchor_J, + "anchor_R": anchor_R, + "offset_interval_duration": offset_interval_duration + } + } + except Exception: + return False, Constants.PRECISELY_ALIGN_CALCULATE_FAILURE_FRONT + Constants.PRECISELY_ALIGN_FAILURE_REASON["Calculate_Correlation_Exception"], result + + return True, Constants.PRECISELY_ALIGN_CALCULATE_FINISHED_FRONT, 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 + + 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 + + try: + if mode == "init": + self.JJIs0_back = self.JJIs[Config["IV_Coordinate"]["BCG_back_1"]:Config["IV_Coordinate"]["BCG_back_2"]] + self.RRIs0_back = self.RRIs[Config["IV_Coordinate"]["ECG_back_1"]:Config["IV_Coordinate"]["ECG_back_2"]] + self.JJIVs_back = diff(self.JJIs0_back) + self.RRIVs_back = diff(self.RRIs0_back) + self.corre_back = correlate(self.RRIVs_back, self.JJIVs_back, 'valid') + shift = np_argmax(self.corre_back) + else: + if shift_back is None: + shift = Config["back"]["shift"] + else: + shift = shift_back + RRIVs_cut = self.RRIVs_back[shift:shift + len(self.JJIVs_back)] + RRIs_cut = self.RRIs0_back[shift:shift + len(self.JJIs0_back)] + correlation = corrcoef(RRIVs_cut, self.JJIVs_back) + correlation_IIV = (correlation[0, 1] + correlation[1, 0]) / 2 + correlation = corrcoef(RRIs_cut, self.JJIs0_back) + correlation_II = (correlation[0, 1] + correlation[1, 0]) / 2 + same_sign_rate = np_sum(RRIVs_cut * self.JJIVs_back > 0) / len(self.JJIVs_back) + total_time_ratio = np_sum(self.JJIs0_back) / np_sum(self.RRIs0_back[shift:shift + len(self.JJIs0_back)]) + Jpeak_cut = self.Jpeak[Config["IV_Coordinate"]["BCG_back_1"]:Config["IV_Coordinate"]["BCG_back_2"] + 2] + Rpeak_cut = self.Rpeak[Config["IV_Coordinate"]["ECG_back_1"]:Config["IV_Coordinate"]["ECG_back_2"] + 2] + RRI = diff(Rpeak_cut) + offset_interval = np_sum(RRI[:shift]) - (Jpeak_cut[0] - Rpeak_cut[0]) + anchor_J = self.Jpeak[Config["IV_Coordinate"]["BCG_back_1"]] + anchor_R = self.Rpeak[Config["IV_Coordinate"]["ECG_back_1"] + shift] + offset_interval_duration = offset_interval / Config["InputConfig"]["ECGFreq"] + + Config["back"]["shift"] = shift + Config["back"]["offset_interval"] = offset_interval + Config["back"]["anchor_J"] = anchor_J + Config["back"]["anchor_R"] = anchor_R + Config["back"]["offset_interval_duration"] = offset_interval_duration + + result = { + "back": { + "correlation_IIV": correlation_IIV, + "correlation_II": correlation_II, + "same_sign_rate": same_sign_rate, + "total_time_ratio": total_time_ratio, + "shift": shift, + "corre": self.corre_back, + "JJIVs": self.JJIVs_back, + "RRIVs": self.RRIVs_back, + "offset_interval": offset_interval, + "anchor_J": anchor_J, + "anchor_R": anchor_R, + "offset_interval_duration": offset_interval_duration + } + } + except Exception: + return False, Constants.PRECISELY_ALIGN_CALCULATE_FAILURE_BACK + Constants.PRECISELY_ALIGN_FAILURE_REASON["Calculate_Correlation_Exception"], result + + return True, Constants.PRECISELY_ALIGN_CALCULATE_FINISHED_BACK, result + + def correlation_align(self, mode): + + result = {} + + try: + if mode == "init": + anchor0 = [Config["front"]["anchor_R"], Config["front"]["anchor_J"]] + anchor1 = [Config["back"]["anchor_R"], Config["back"]["anchor_J"]] + Config["orgfs"] = ((int(anchor1[1]) - int(anchor0[1])) * Config["InputConfig"]["ECGFreq"] / + (int(anchor1[0]) - int(anchor0[0]))) + Config["offset_anchor"] = anchor0[0] - anchor0[1] + + orgfs = Config["orgfs"] + off = Config["offset_anchor"] + + self.cut_ECG = self.raw_ECG + self.res_BCG = self.raw_BCG + self.cut_Rpeak = self.Rpeak + + if off > 0: + self.cut_ECG = self.cut_ECG[off:] + anchor0[0] = anchor0[0] - off + anchor1[0] = anchor1[0] - off + idxs = where(self.cut_Rpeak > off)[0] + self.cut_Rpeak = self.cut_Rpeak[idxs] - off + else: + self.res_BCG = self.res_BCG[-off:] + anchor0[1] = anchor0[1] + off + anchor1[1] = anchor1[1] + off + + self.res_BCG = resample(self.res_BCG, orgfs, Config["InputConfig"]["ECGFreq"]) + + anchor0[1] = round(int(anchor0[1]) * Config["InputConfig"]["ECGFreq"] / orgfs) + anchor1[1] = round(int(anchor1[1]) * Config["InputConfig"]["ECGFreq"] / orgfs) + off = anchor1[0] - anchor1[1] + + if off > 0: + self.cut_ECG = self.cut_ECG[off:] + anchor0[0] = anchor0[0] - off + anchor1[0] = anchor1[0] - off + idxs = where(self.cut_Rpeak > off)[0] + self.cut_Rpeak = self.cut_Rpeak[idxs] - off + else: + self.res_BCG = self.res_BCG[-off:] + anchor0[1] = anchor0[1] + off + anchor1[1] = anchor1[1] + off + + datalen = np_min([len(self.cut_ECG), len(self.res_BCG)]) + self.cut_ECG = self.cut_ECG[:datalen] + self.res_BCG = self.res_BCG[:datalen] + a = np_max([np_max(self.cut_ECG), np_max(self.res_BCG)]) + b = np_min([np_min(self.cut_ECG), np_min(self.res_BCG)]) + peak_ECG, _ = find_peaks(self.cut_ECG) + peak_BCG, _ = find_peaks(self.res_BCG) + + idxs = where(self.cut_Rpeak < datalen)[0] + self.cut_Rpeak = self.cut_Rpeak[idxs] + + result = { + "res_BCG": self.res_BCG, + "cut_ECG": self.cut_ECG, + "anchor00": anchor0[0], + "anchor10": anchor1[0], + "a": a, + "b": b, + "peak_ECG": peak_ECG, + "peak_BCG": peak_BCG + } + elif mode == "select": + a = np_max([np_max(self.raw_ECG), np_max(self.raw_BCG)]) + b = np_min([np_min(self.raw_ECG), np_min(self.raw_BCG)]) + result = { + "a": a, + "b": b + } + else: + raise ValueError("模式不存在") + except Exception: + return False, Constants.PRECISELY_ALIGN_ALIGN_CORRELATION_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Correlation_Align_Exception"], result + + return True, Constants.PRECISELY_ALIGN_ALIGN_CORRELATION_FINISHED, result + + def data_postprocess(self): + + try: + if len(self.correlation_align_point_match_ECG) != 2 and len(self.correlation_align_point_match_BCG) != 2: + off = 0 + else: + self.correlation_align_point_match_ECG.sort() + self.correlation_align_point_match_BCG.sort() + off = round(((int(self.correlation_align_point_match_ECG[1]) - int(self.correlation_align_point_match_BCG[1])) + (int(self.correlation_align_point_match_ECG[0]) - int(self.correlation_align_point_match_BCG[0]))) / 2) + + anchor0 = [Config["front"]["anchor_R"], Config["front"]["anchor_J"]] + anchor1 = [Config["back"]["anchor_R"], Config["back"]["anchor_J"]] + + if off > 0: + self.cut_ECG = self.cut_ECG[off:] + anchor0[0] = anchor0[0] - off + anchor1[0] = anchor1[0] - off + self.cut_Rpeak = self.cut_Rpeak[where(self.cut_Rpeak > off)[0]] - off + else: + self.res_BCG = self.res_BCG[-off:] + anchor0[1] = anchor0[1] + off + anchor1[1] = anchor1[1] + off + + datalen = np_min([len(self.cut_ECG), len(self.res_BCG)]) + self.cut_ECG = self.cut_ECG[:datalen] + self.res_BCG = self.res_BCG[:datalen] + + idxs = where(self.cut_Rpeak < datalen)[0] + self.cut_Rpeak = self.cut_Rpeak[idxs] + + Config["offset_correct"] = off + + self.cut_Jpeak = [] + peaks, _ = find_peaks(self.res_BCG) + for i in self.cut_Rpeak: + tmp = np_abs(peaks - i) + idx = np_argmin(tmp) + self.cut_Jpeak.append(peaks[idx]) + self.cut_Jpeak = asarray(self.cut_Jpeak).astype(int) + + frontcut_index_BCG = int((self.argmax_BCG - np_argmax(self.res_BCG) / Config["InputConfig"]["ECGFreq"] * Config["orgfs"])) + backcut_index_BCG = int(len(self.res_BCG) / Config["InputConfig"]["ECGFreq"] * Config["orgfs"] + np_argmax(self.raw_BCG) - np_argmax(self.res_BCG) / Config["InputConfig"]["ECGFreq"] * Config["orgfs"]) + frontcut_index_ECG = self.argmax_ECG - np_argmax(self.cut_ECG) + backcut_index_ECG = len(self.cut_ECG) + self.argmax_ECG - np_argmax(self.cut_ECG) + + Config["frontcut_index_BCG"] = frontcut_index_BCG + Config["backcut_index_BCG"] = backcut_index_BCG + 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 True, f"{Constants.PRECISELY_ALIGN_POSTPROCESS_VIEW_FINISHED},BCG前后段被切割的坐标值为[{frontcut_index_BCG}, {backcut_index_BCG}],ECG前后段被切割的坐标值为[{frontcut_index_ECG}, {backcut_index_ECG}]" + + def save(self): + + try: + save_data = { + "front": { + "N_JJIV": [Config["IV_Coordinate"]["BCG_front_1"], Config["IV_Coordinate"]["BCG_front_2"]], + "BCG_coordinate": [Config["Coordinate"]["BCG_front_1"], Config["Coordinate"]["BCG_front_2"]], + "N_RRIV": [Config["IV_Coordinate"]["ECG_front_1"], Config["IV_Coordinate"]["ECG_front_2"]], + "ECG_coordinate": [Config["Coordinate"]["ECG_front_1"], Config["Coordinate"]["ECG_front_2"]], + "shift": Config["front"]["shift"], + "offset_interval": Config["front"]["offset_interval"], + "offset_interval_duration": Config["front"]["offset_interval_duration"], + "anchorsRJ": [Config["front"]["anchor_R"], Config["front"]["anchor_J"]] + }, + "back": { + "N_JJIV": [Config["IV_Coordinate"]["BCG_back_1"], Config["IV_Coordinate"]["BCG_back_2"]], + "BCG_coordinate": [Config["Coordinate"]["BCG_back_1"], Config["Coordinate"]["BCG_back_2"]], + "N_RRIV": [Config["IV_Coordinate"]["ECG_back_1"], Config["IV_Coordinate"]["ECG_back_2"]], + "ECG_coordinate": [Config["Coordinate"]["ECG_back_1"], Config["Coordinate"]["ECG_back_2"]], + "shift": Config["back"]["shift"], + "offset_interval": Config["back"]["offset_interval"], + "offset_interval_duration": Config["back"]["offset_interval_duration"], + "anchorsRJ": [Config["back"]["anchor_R"], Config["back"]["anchor_J"]] + }, + "offset_anchor": Config["offset_anchor"], + "orgfs": Config["orgfs"], + "cut_index": { + "front_BCG": Config["frontcut_index_BCG"], + "back_BCG": Config["backcut_index_BCG"], + "front_ECG": Config["frontcut_index_ECG"], + "back_ECG": Config["backcut_index_ECG"] + } + } + save_data = [str(save_data)] + DataFrame(save_data).to_csv(self.file_path_save_BCG, index=False, header=False) + DataFrame(save_data).to_csv(self.file_path_save_ECG, index=False, header=False) + except Exception as e: + print(e) + return False, Constants.SAVING_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Save_Exception"] + + return True, Constants.SAVING_FINISHED + + +class CustomNavigationToolbar(NavigationToolbar2QT): + + def __init__(self, canvas, parent): + super().__init__(canvas, parent) + # 初始化画框工具栏 + self.action_Get_Range = QAction(Constants.PRECISELY_ALIGN_ACTION_GET_RANGE_NAME, self) + self.action_Get_Range.setFont(QFont(ConfigParams.FONT, 14)) + self.action_Get_Range.setCheckable(True) + self.action_Get_Range.setShortcut(QCoreApplication.translate( + "MainWindow", + ConfigParams.PRECISELY_ALIGN_ACTION_GET_RANGE_SHORTCUT_KEY)) + self.insertAction(self._actions['pan'], self.action_Get_Range) + + self._actions['pan'].setShortcut(QCoreApplication.translate( + "MainWindow", + ConfigParams.ACTION_PAN_SHORTCUT_KEY)) + self._actions['zoom'].setShortcut(QCoreApplication.translate( + "MainWindow", + ConfigParams.ACTION_ZOOM_SHORTCUT_KEY)) + + # 用于存储事件连接ID + self.cid_mouse_press = None + self.cid_mouse_release = None + self.cid_mouse_hold = None + + # 初始化矩形选择区域 + self.rect_start_x = None + self.rect_end_x = None + self.ax0_BCG_rectangle_front = None + self.ax0_BCG_rectangle_back = None + self.ax1_ECG_rectangle_front = None + self.ax1_ECG_rectangle_back = None + + def home(self, *args): + + pass + + def zoom(self, *args): + + super().zoom(*args) + self.deactivate_figToorbar_getRange_mode() + + def pan(self, *args): + + super().pan(*args) + self.deactivate_figToorbar_getRange_mode() + + def deactivate_figToorbar_getRange_mode(self): + + if self.action_Get_Range.isChecked(): + self.action_Get_Range.setChecked(False) + if self.cid_mouse_press is not None: + self.canvas.mpl_disconnect(self.cid_mouse_press) + self.cid_mouse_press = None + if self.cid_mouse_release is not None: + self.canvas.mpl_disconnect(self.cid_mouse_release) + self.cid_mouse_release = None + if self.cid_mouse_hold is not None: + self.canvas.mpl_disconnect(self.cid_mouse_hold) + self.cid_mouse_hold = None \ No newline at end of file diff --git a/func/Module_preprocess.py b/func/Module_preprocess.py index f04d911..b927fa0 100644 --- a/func/Module_preprocess.py +++ b/func/Module_preprocess.py @@ -192,9 +192,6 @@ class MainWindow_preprocess(QMainWindow): self.gs = None self.ax0 = None - self.line_raw_data = None - self.line_processed_data = None - self.msgBox = QMessageBox() self.msgBox.setWindowTitle(Constants.MAINWINDOW_MSGBOX_TITLE) @@ -254,10 +251,7 @@ class MainWindow_preprocess(QMainWindow): QApplication.processEvents() # 清空画框 - if self.line_raw_data and self.line_processed_data: - del self.line_raw_data - del self.line_processed_data - self.canvas.draw() + self.ax0.clear() # 释放资源 del self.data @@ -277,22 +271,17 @@ class MainWindow_preprocess(QMainWindow): def __plot__(self): # 清空画框 - if self.line_raw_data and self.line_processed_data: - try: - self.line_raw_data.remove() - self.line_processed_data.remove() - except ValueError: - pass + self.reset_axes() sender = self.sender() if sender == self.ui.pushButton_view: - self.line_raw_data, = self.ax0.plot(self.data.raw_data, - color=Constants.PLOT_COLOR_RED, - label=Constants.PREPROCESS_PLOT_LABEL_ORIGINAL_DATA) - self.line_processed_data, = self.ax0.plot(self.data.processed_data + Constants.PREPROCESS_OUTPUT_INPUT_AMP_OFFSET, - color=Constants.PLOT_COLOR_BLUE, - label=Constants.PREPROCESS_PLOT_LABEL_PROCESSED_DATA) + self.ax0.plot(self.data.raw_data, + color=Constants.PLOT_COLOR_RED, + label=Constants.PREPROCESS_PLOT_LABEL_ORIGINAL_DATA) + self.ax0.plot(self.data.processed_data + Constants.PREPROCESS_OUTPUT_INPUT_AMP_OFFSET, + 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 @@ -321,12 +310,8 @@ class MainWindow_preprocess(QMainWindow): PublicFunc.__disableAllButton__(self, ButtonState) # 清空画框 - if self.line_raw_data and self.line_processed_data: - try: - self.line_raw_data.remove() - self.line_processed_data.remove() - except ValueError: - pass + self.reset_axes() + self.canvas.draw() self.data = Data() @@ -408,6 +393,12 @@ class MainWindow_preprocess(QMainWindow): PublicFunc.finish_operation(self, ButtonState) + def reset_axes(self): + + self.ax0.clear() + self.ax0.grid(True) + self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + class Data: diff --git a/func/utils/ConfigParams.py b/func/utils/ConfigParams.py index 92bc7bf..51fb2de 100644 --- a/func/utils/ConfigParams.py +++ b/func/utils/ConfigParams.py @@ -27,6 +27,7 @@ class ConfigParams: FORMATTER = FuncFormatter(lambda x, p: f"{x:.0f}") ACTION_PAN_SHORTCUT_KEY: str = "X" ACTION_ZOOM_SHORTCUT_KEY: str = "C" + FONT: str = "Microsoft YaHei UI" # 数据粗同步 @@ -127,22 +128,28 @@ class ConfigParams: LABEL_CHECK_LABEL_TRANSPARENCY: float = 0.2 LABEL_CHECK_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY: str = "Z" + # 数据精同步 + PRECISELY_ALIGN_CONFIG_FILE_PATH: str = "./config/Config_precisely_align.yaml" + PRECISELY_ALIGN_CONFIG_NEW_CONTENT = { + "InputConfig": { + "ECGFreq": 1000 + } + } + PRECISELY_ALIGN_INPUT_BCG_FILENAME: str = "DSbcg_sig_" + PRECISELY_ALIGN_INPUT_JPEAK_FILENAME: str = "JPeak_revise_corrected" + PRECISELY_ALIGN_SAVE_BCG_FILENAME: str = "Align_info" + PRECISELY_ALIGN_INPUT_ECG_FILENAME: str = "ECG_filter_" + PRECISELY_ALIGN_INPUT_RPEAK_FILENAME: str = "final_Rpeak_corrected" + PRECISELY_ALIGN_SAVE_ECG_FILENAME: str = "Align_info" + PRECISELY_ALIGN_ACTION_GET_RANGE_SHORTCUT_KEY: str = "Z" + # 体动标注 # TODO:弃用 - # 通用 - # 目前用到这个编码的地方: - # 里的保存和读取csv文件的地方(注意的是,读取原始数据时依然使用UTF-8) - VALIDATOR_INTEGER = QIntValidator(-2**31, 2**31 - 1) VALIDATOR_DOUBLE = QDoubleValidator(-1e100, 1e100, 10) - FONT: str = "Microsoft YaHei UI" - - # 菜单界面 - MATPLOTLIB_PLOT_PRECISION_PARAM: int = 10000 - # 数据粗同步 APPROXIMATELY_ALIGN_INPUT_ORGBCG_FILENAME: str = "orgBcg_Raw_" APPROXIMATELY_ALIGN_INPUT_PSG_FILENAME: str = "A" diff --git a/func/utils/Constants.py b/func/utils/Constants.py index dc67c9c..2487567 100644 --- a/func/utils/Constants.py +++ b/func/utils/Constants.py @@ -11,6 +11,9 @@ class Constants: MSGBOX_TYPE_ERROR: str = "Error" MSGBOX_TYPE_QUESTION: str = "Question" + MAINWINDOW_ROOT_PATH_NOT_EXIST: str = "根目录路径输入错误" + MAINWINDOW_MSGBOX_TITLE: str = "消息" + INPUTTING_DATA: str = "正在导入数据" INPUT_FINISHED: str = "导入完成" INPUT_FAILURE: str = "导入失败" @@ -193,24 +196,53 @@ class Constants: LABEL_CHECK_NO_POINT_IN_THE_INTERVAL: str = "所选区间内无新增或删除点" LABEL_CHECK_ACTION_LABEL_MULTIPLE_NAME: str = f"批量更改标签({ConfigParams.LABEL_CHECK_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY})" + # 数据精同步 + PRECISELY_ALIGN_PROCESSING_DATA: str = "正在处理数据" + PRECISELY_ALIGN_PROCESS_FINISHED: str = "处理完成" + PRECISELY_ALIGN_PROCESS_FAILURE: str = "处理失败" + PRECISELY_ALIGN_CALCULATING_CORRELATION_FRONT: str = "正在计算前段相关性" + PRECISELY_ALIGN_CALCULATE_FINISHED_FRONT: str = "计算前段相关性完成" + PRECISELY_ALIGN_CALCULATE_FAILURE_FRONT: str = "计算前段相关性失败" + PRECISELY_ALIGN_CALCULATING_CORRELATION_BACK: str = "正在计算后段相关性" + PRECISELY_ALIGN_CALCULATE_FINISHED_BACK: str = "计算后段相关性完成" + PRECISELY_ALIGN_CALCULATE_FAILURE_BACK: str = "计算后段相关性失败" + PRECISELY_ALIGN_ALIGNING_CORRELATION: str = "正在处理相关对齐" + PRECISELY_ALIGN_ALIGN_CORRELATION_FINISHED: str = "处理相关对齐完成" + PRECISELY_ALIGN_ALIGN_CORRELATION_FAILURE: str = "处理相关对齐失败" + + PRECISELY_ALIGN_POSTPROCESSING_VIEW: str = "正在数据后处理" + PRECISELY_ALIGN_POSTPROCESS_VIEW_FINISHED: str = "数据后处理完成" + PRECISELY_ALIGN_POSTPROCESS_VIEW_FAILURE: str = "数据后处理失败" + + PRECISELY_ALIGN_FAILURE_REASON = { + "Data_Path_Not_Exist": "(数据路径不存在)", + "Read_Data_Exception": "(读取数据异常)", + "Data_Not_Exist": "(数据不存在)", + "Process_Data_Exception": "(处理数据异常)", + "Calculate_Correlation_Value_Equal": "(计算相关性参数相同)", + "Calculate_Correlation_JJIVRange_too_Large": "(计算相关性JJIV范围大于RRIV范围)", + "Calculate_Correlation_Exception": "(计算相关性异常)", + "Correlation_Align_Exception": "(处理相关对齐异常)", + "PostProcess_Align_Exception": "(数据后处理异常)", + "Save_Exception": "(保存异常)" + } + + PRECISELY_ALIGN_PLOT_LABEL_JJIV: str = "JJIV" + PRECISELY_ALIGN_PLOT_LABEL_RRIV: str = "RRIV" + 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_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})" # 体动标注 # TODO:弃用 - - # 通用 - - FOLDER_DIR_NOT_EXIST_THEN_CREATE: str = "检测到保存路径所指向的文件夹不存在,已创建相应文件夹" - - # 菜单界面 - MAINWINDOW_ROOT_PATH_NOT_EXIST: str = "根目录路径输入错误" - MAINWINDOW_MSGBOX_TITLE: str = "消息" - MAINWINDOW_DIALOG_TITLE: str = "确认数据的采样率" - MAINWINDOW_BACK_TO_MENU: str = "返回主菜单" - MAINWINDOW_QUESTION_BACK_TO_MENU: str = "确定要返回主菜单吗" - # 数据粗同步 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}" diff --git a/ui/MainWindow/MainWindow_precisely_align.py b/ui/MainWindow/MainWindow_precisely_align.py index d4ade48..0a9827c 100644 --- a/ui/MainWindow/MainWindow_precisely_align.py +++ b/ui/MainWindow/MainWindow_precisely_align.py @@ -18,33 +18,33 @@ from PySide6.QtGui import (QAction, QBrush, QColor, QConicalGradient, QTransform) from PySide6.QtWidgets import (QAbstractSpinBox, QApplication, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QMainWindow, QPushButton, - QSizePolicy, QSpacerItem, QSpinBox, QStatusBar, - QTextBrowser, QVBoxLayout, QWidget) + QRadioButton, QSizePolicy, QSpacerItem, QSpinBox, + QStatusBar, QTextBrowser, QVBoxLayout, QWidget) -class Ui_MainWindow_detect_Jpeak(object): - def setupUi(self, MainWindow_detect_Jpeak): - if not MainWindow_detect_Jpeak.objectName(): - MainWindow_detect_Jpeak.setObjectName(u"MainWindow_detect_Jpeak") - MainWindow_detect_Jpeak.setEnabled(True) - MainWindow_detect_Jpeak.resize(1920, 1080) +class Ui_MainWindow_precisely_align(object): + def setupUi(self, MainWindow_precisely_align): + if not MainWindow_precisely_align.objectName(): + MainWindow_precisely_align.setObjectName(u"MainWindow_precisely_align") + MainWindow_precisely_align.setEnabled(True) + MainWindow_precisely_align.resize(1920, 1080) sizePolicy = QSizePolicy(QSizePolicy.Policy.Ignored, QSizePolicy.Policy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(MainWindow_detect_Jpeak.sizePolicy().hasHeightForWidth()) - MainWindow_detect_Jpeak.setSizePolicy(sizePolicy) + sizePolicy.setHeightForWidth(MainWindow_precisely_align.sizePolicy().hasHeightForWidth()) + MainWindow_precisely_align.setSizePolicy(sizePolicy) font = QFont() font.setPointSize(12) - MainWindow_detect_Jpeak.setFont(font) - self.action_selectPath = QAction(MainWindow_detect_Jpeak) + MainWindow_precisely_align.setFont(font) + self.action_selectPath = QAction(MainWindow_precisely_align) self.action_selectPath.setObjectName(u"action_selectPath") font1 = QFont() font1.setFamilies([u"\u9ed1\u4f53"]) font1.setPointSize(14) self.action_selectPath.setFont(font1) - self.action = QAction(MainWindow_detect_Jpeak) + self.action = QAction(MainWindow_precisely_align) self.action.setObjectName(u"action") self.action.setFont(font1) - self.centralwidget = QWidget(MainWindow_detect_Jpeak) + self.centralwidget = QWidget(MainWindow_precisely_align) self.centralwidget.setObjectName(u"centralwidget") self.gridLayout = QGridLayout(self.centralwidget) self.gridLayout.setObjectName(u"gridLayout") @@ -100,164 +100,332 @@ class Ui_MainWindow_detect_Jpeak(object): self.groupBox_2.setObjectName(u"groupBox_2") self.verticalLayout_2 = QVBoxLayout(self.groupBox_2) self.verticalLayout_2.setObjectName(u"verticalLayout_2") - self.horizontalLayout_2 = QHBoxLayout() - self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") - self.label_3 = QLabel(self.groupBox_2) - self.label_3.setObjectName(u"label_3") - self.label_3.setFont(font) - self.label_3.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.gridLayout_2 = QGridLayout() + self.gridLayout_2.setObjectName(u"gridLayout_2") + self.spinBox_BCG_front_Signal_2 = QSpinBox(self.groupBox_2) + self.spinBox_BCG_front_Signal_2.setObjectName(u"spinBox_BCG_front_Signal_2") + self.spinBox_BCG_front_Signal_2.setEnabled(False) + self.spinBox_BCG_front_Signal_2.setFont(font) + self.spinBox_BCG_front_Signal_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_BCG_front_Signal_2.setMinimum(0) + self.spinBox_BCG_front_Signal_2.setMaximum(1000000000) - self.horizontalLayout_2.addWidget(self.label_3) + self.gridLayout_2.addWidget(self.spinBox_BCG_front_Signal_2, 1, 4, 1, 1) - self.spinBox_BCG_front_1 = QSpinBox(self.groupBox_2) - self.spinBox_BCG_front_1.setObjectName(u"spinBox_BCG_front_1") - self.spinBox_BCG_front_1.setFont(font) - self.spinBox_BCG_front_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) - self.spinBox_BCG_front_1.setMinimum(0) - self.spinBox_BCG_front_1.setMaximum(1000000000) + self.spinBox_BCG_front_JJIV_1 = QSpinBox(self.groupBox_2) + self.spinBox_BCG_front_JJIV_1.setObjectName(u"spinBox_BCG_front_JJIV_1") + self.spinBox_BCG_front_JJIV_1.setFont(font) + self.spinBox_BCG_front_JJIV_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_BCG_front_JJIV_1.setMinimum(0) + self.spinBox_BCG_front_JJIV_1.setMaximum(1000000000) - self.horizontalLayout_2.addWidget(self.spinBox_BCG_front_1) + self.gridLayout_2.addWidget(self.spinBox_BCG_front_JJIV_1, 0, 2, 1, 1) + + self.radioButton_BCG_front = QRadioButton(self.groupBox_2) + self.radioButton_BCG_front.setObjectName(u"radioButton_BCG_front") + self.radioButton_BCG_front.setFont(font) + self.radioButton_BCG_front.setChecked(True) + + self.gridLayout_2.addWidget(self.radioButton_BCG_front, 0, 0, 2, 1) self.label_4 = QLabel(self.groupBox_2) self.label_4.setObjectName(u"label_4") self.label_4.setFont(font) self.label_4.setAlignment(Qt.AlignmentFlag.AlignCenter) - self.horizontalLayout_2.addWidget(self.label_4) + self.gridLayout_2.addWidget(self.label_4, 0, 3, 1, 1) - self.spinBox_BCG_front_2 = QSpinBox(self.groupBox_2) - self.spinBox_BCG_front_2.setObjectName(u"spinBox_BCG_front_2") - self.spinBox_BCG_front_2.setFont(font) - self.spinBox_BCG_front_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) - self.spinBox_BCG_front_2.setMinimum(0) - self.spinBox_BCG_front_2.setMaximum(1000000000) + self.spinBox_BCG_front_Signal_1 = QSpinBox(self.groupBox_2) + self.spinBox_BCG_front_Signal_1.setObjectName(u"spinBox_BCG_front_Signal_1") + self.spinBox_BCG_front_Signal_1.setEnabled(False) + self.spinBox_BCG_front_Signal_1.setFont(font) + self.spinBox_BCG_front_Signal_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_BCG_front_Signal_1.setMinimum(0) + self.spinBox_BCG_front_Signal_1.setMaximum(1000000000) - self.horizontalLayout_2.addWidget(self.spinBox_BCG_front_2) + self.gridLayout_2.addWidget(self.spinBox_BCG_front_Signal_1, 1, 2, 1, 1) + self.spinBox_BCG_front_JJIV_2 = QSpinBox(self.groupBox_2) + self.spinBox_BCG_front_JJIV_2.setObjectName(u"spinBox_BCG_front_JJIV_2") + self.spinBox_BCG_front_JJIV_2.setFont(font) + self.spinBox_BCG_front_JJIV_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_BCG_front_JJIV_2.setMinimum(0) + self.spinBox_BCG_front_JJIV_2.setMaximum(1000000000) - self.verticalLayout_2.addLayout(self.horizontalLayout_2) - - self.horizontalLayout_5 = QHBoxLayout() - self.horizontalLayout_5.setObjectName(u"horizontalLayout_5") - self.label_5 = QLabel(self.groupBox_2) - 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_ECG_front_1 = QSpinBox(self.groupBox_2) - self.spinBox_ECG_front_1.setObjectName(u"spinBox_ECG_front_1") - self.spinBox_ECG_front_1.setFont(font) - self.spinBox_ECG_front_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) - self.spinBox_ECG_front_1.setMinimum(0) - self.spinBox_ECG_front_1.setMaximum(1000000000) - - self.horizontalLayout_5.addWidget(self.spinBox_ECG_front_1) + self.gridLayout_2.addWidget(self.spinBox_BCG_front_JJIV_2, 0, 4, 1, 1) self.label_6 = QLabel(self.groupBox_2) self.label_6.setObjectName(u"label_6") self.label_6.setFont(font) self.label_6.setAlignment(Qt.AlignmentFlag.AlignCenter) - self.horizontalLayout_5.addWidget(self.label_6) + self.gridLayout_2.addWidget(self.label_6, 1, 3, 1, 1) - self.spinBox_ECG_front_2 = QSpinBox(self.groupBox_2) - self.spinBox_ECG_front_2.setObjectName(u"spinBox_ECG_front_2") - self.spinBox_ECG_front_2.setFont(font) - self.spinBox_ECG_front_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) - self.spinBox_ECG_front_2.setMinimum(0) - self.spinBox_ECG_front_2.setMaximum(1000000000) + self.label = QLabel(self.groupBox_2) + self.label.setObjectName(u"label") + self.label.setFont(font) - self.horizontalLayout_5.addWidget(self.spinBox_ECG_front_2) + self.gridLayout_2.addWidget(self.label, 0, 1, 1, 1) + + self.label_2 = QLabel(self.groupBox_2) + self.label_2.setObjectName(u"label_2") + self.label_2.setFont(font) + + self.gridLayout_2.addWidget(self.label_2, 1, 1, 1, 1) - self.verticalLayout_2.addLayout(self.horizontalLayout_5) + self.verticalLayout_2.addLayout(self.gridLayout_2) self.verticalLayout_5.addWidget(self.groupBox_2) + self.groupBox_4 = QGroupBox(self.groupBox_args) + self.groupBox_4.setObjectName(u"groupBox_4") + self.verticalLayout_4 = QVBoxLayout(self.groupBox_4) + self.verticalLayout_4.setObjectName(u"verticalLayout_4") + self.gridLayout_3 = QGridLayout() + self.gridLayout_3.setObjectName(u"gridLayout_3") + self.spinBox_BCG_back_Signal_2 = QSpinBox(self.groupBox_4) + self.spinBox_BCG_back_Signal_2.setObjectName(u"spinBox_BCG_back_Signal_2") + self.spinBox_BCG_back_Signal_2.setEnabled(False) + self.spinBox_BCG_back_Signal_2.setFont(font) + self.spinBox_BCG_back_Signal_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_BCG_back_Signal_2.setMinimum(0) + self.spinBox_BCG_back_Signal_2.setMaximum(1000000000) + + self.gridLayout_3.addWidget(self.spinBox_BCG_back_Signal_2, 1, 4, 1, 1) + + self.spinBox_BCG_back_Signal_1 = QSpinBox(self.groupBox_4) + self.spinBox_BCG_back_Signal_1.setObjectName(u"spinBox_BCG_back_Signal_1") + self.spinBox_BCG_back_Signal_1.setEnabled(False) + self.spinBox_BCG_back_Signal_1.setFont(font) + self.spinBox_BCG_back_Signal_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_BCG_back_Signal_1.setMinimum(0) + self.spinBox_BCG_back_Signal_1.setMaximum(1000000000) + + self.gridLayout_3.addWidget(self.spinBox_BCG_back_Signal_1, 1, 2, 1, 1) + + self.spinBox_BCG_back_JJIV_2 = QSpinBox(self.groupBox_4) + self.spinBox_BCG_back_JJIV_2.setObjectName(u"spinBox_BCG_back_JJIV_2") + self.spinBox_BCG_back_JJIV_2.setFont(font) + self.spinBox_BCG_back_JJIV_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_BCG_back_JJIV_2.setMinimum(0) + self.spinBox_BCG_back_JJIV_2.setMaximum(1000000000) + + self.gridLayout_3.addWidget(self.spinBox_BCG_back_JJIV_2, 0, 4, 1, 1) + + self.radioButton_BCG_back = QRadioButton(self.groupBox_4) + self.radioButton_BCG_back.setObjectName(u"radioButton_BCG_back") + self.radioButton_BCG_back.setFont(font) + self.radioButton_BCG_back.setChecked(False) + + self.gridLayout_3.addWidget(self.radioButton_BCG_back, 0, 0, 2, 1) + + self.spinBox_BCG_back_JJIV_1 = QSpinBox(self.groupBox_4) + self.spinBox_BCG_back_JJIV_1.setObjectName(u"spinBox_BCG_back_JJIV_1") + self.spinBox_BCG_back_JJIV_1.setFont(font) + self.spinBox_BCG_back_JJIV_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_BCG_back_JJIV_1.setMinimum(0) + self.spinBox_BCG_back_JJIV_1.setMaximum(1000000000) + + self.gridLayout_3.addWidget(self.spinBox_BCG_back_JJIV_1, 0, 2, 1, 1) + + self.label_7 = QLabel(self.groupBox_4) + self.label_7.setObjectName(u"label_7") + self.label_7.setFont(font) + self.label_7.setAlignment(Qt.AlignmentFlag.AlignCenter) + + self.gridLayout_3.addWidget(self.label_7, 1, 3, 1, 1) + + self.label_5 = QLabel(self.groupBox_4) + self.label_5.setObjectName(u"label_5") + self.label_5.setFont(font) + self.label_5.setAlignment(Qt.AlignmentFlag.AlignCenter) + + self.gridLayout_3.addWidget(self.label_5, 0, 3, 1, 1) + + self.label_3 = QLabel(self.groupBox_4) + self.label_3.setObjectName(u"label_3") + self.label_3.setFont(font) + + self.gridLayout_3.addWidget(self.label_3, 0, 1, 1, 1) + + self.label_12 = QLabel(self.groupBox_4) + self.label_12.setObjectName(u"label_12") + self.label_12.setFont(font) + + self.gridLayout_3.addWidget(self.label_12, 1, 1, 1, 1) + + + self.verticalLayout_4.addLayout(self.gridLayout_3) + + + self.verticalLayout_5.addWidget(self.groupBox_4) + self.groupBox_3 = QGroupBox(self.groupBox_args) self.groupBox_3.setObjectName(u"groupBox_3") self.verticalLayout_3 = QVBoxLayout(self.groupBox_3) self.verticalLayout_3.setObjectName(u"verticalLayout_3") - self.horizontalLayout_6 = QHBoxLayout() - self.horizontalLayout_6.setObjectName(u"horizontalLayout_6") - self.label_7 = QLabel(self.groupBox_3) - self.label_7.setObjectName(u"label_7") - self.label_7.setFont(font) - self.label_7.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.gridLayout_4 = QGridLayout() + self.gridLayout_4.setObjectName(u"gridLayout_4") + self.spinBox_ECG_front_RRIV_2 = QSpinBox(self.groupBox_3) + self.spinBox_ECG_front_RRIV_2.setObjectName(u"spinBox_ECG_front_RRIV_2") + self.spinBox_ECG_front_RRIV_2.setFont(font) + self.spinBox_ECG_front_RRIV_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_ECG_front_RRIV_2.setMinimum(0) + self.spinBox_ECG_front_RRIV_2.setMaximum(1000000000) - self.horizontalLayout_6.addWidget(self.label_7) - - self.spinBox_BCG_back_1 = QSpinBox(self.groupBox_3) - self.spinBox_BCG_back_1.setObjectName(u"spinBox_BCG_back_1") - self.spinBox_BCG_back_1.setFont(font) - self.spinBox_BCG_back_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) - self.spinBox_BCG_back_1.setMinimum(0) - self.spinBox_BCG_back_1.setMaximum(1000000000) - - self.horizontalLayout_6.addWidget(self.spinBox_BCG_back_1) - - self.label_8 = QLabel(self.groupBox_3) - self.label_8.setObjectName(u"label_8") - self.label_8.setFont(font) - self.label_8.setAlignment(Qt.AlignmentFlag.AlignCenter) - - self.horizontalLayout_6.addWidget(self.label_8) - - self.spinBox_BCG_back_2 = QSpinBox(self.groupBox_3) - self.spinBox_BCG_back_2.setObjectName(u"spinBox_BCG_back_2") - self.spinBox_BCG_back_2.setFont(font) - self.spinBox_BCG_back_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) - self.spinBox_BCG_back_2.setMinimum(0) - self.spinBox_BCG_back_2.setMaximum(1000000000) - - self.horizontalLayout_6.addWidget(self.spinBox_BCG_back_2) - - - self.verticalLayout_3.addLayout(self.horizontalLayout_6) - - self.horizontalLayout_7 = QHBoxLayout() - self.horizontalLayout_7.setObjectName(u"horizontalLayout_7") - self.label_9 = QLabel(self.groupBox_3) - self.label_9.setObjectName(u"label_9") - self.label_9.setFont(font) - self.label_9.setAlignment(Qt.AlignmentFlag.AlignCenter) - - self.horizontalLayout_7.addWidget(self.label_9) - - self.spinBox_ECG_back_1 = QSpinBox(self.groupBox_3) - self.spinBox_ECG_back_1.setObjectName(u"spinBox_ECG_back_1") - self.spinBox_ECG_back_1.setFont(font) - self.spinBox_ECG_back_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) - self.spinBox_ECG_back_1.setMinimum(0) - self.spinBox_ECG_back_1.setMaximum(1000000000) - - self.horizontalLayout_7.addWidget(self.spinBox_ECG_back_1) + self.gridLayout_4.addWidget(self.spinBox_ECG_front_RRIV_2, 0, 4, 1, 1) self.label_10 = QLabel(self.groupBox_3) self.label_10.setObjectName(u"label_10") self.label_10.setFont(font) self.label_10.setAlignment(Qt.AlignmentFlag.AlignCenter) - self.horizontalLayout_7.addWidget(self.label_10) + self.gridLayout_4.addWidget(self.label_10, 1, 3, 1, 1) - self.spinBox_ECG_back_2 = QSpinBox(self.groupBox_3) - self.spinBox_ECG_back_2.setObjectName(u"spinBox_ECG_back_2") - self.spinBox_ECG_back_2.setFont(font) - self.spinBox_ECG_back_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) - self.spinBox_ECG_back_2.setMinimum(0) - self.spinBox_ECG_back_2.setMaximum(1000000000) + self.radioButton_ECG_front = QRadioButton(self.groupBox_3) + self.radioButton_ECG_front.setObjectName(u"radioButton_ECG_front") + self.radioButton_ECG_front.setFont(font) - self.horizontalLayout_7.addWidget(self.spinBox_ECG_back_2) + self.gridLayout_4.addWidget(self.radioButton_ECG_front, 0, 0, 2, 1) + + self.spinBox_ECG_front_Signal_2 = QSpinBox(self.groupBox_3) + self.spinBox_ECG_front_Signal_2.setObjectName(u"spinBox_ECG_front_Signal_2") + self.spinBox_ECG_front_Signal_2.setEnabled(False) + self.spinBox_ECG_front_Signal_2.setFont(font) + self.spinBox_ECG_front_Signal_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_ECG_front_Signal_2.setMinimum(0) + self.spinBox_ECG_front_Signal_2.setMaximum(1000000000) + + self.gridLayout_4.addWidget(self.spinBox_ECG_front_Signal_2, 1, 4, 1, 1) + + self.spinBox_ECG_front_Signal_1 = QSpinBox(self.groupBox_3) + self.spinBox_ECG_front_Signal_1.setObjectName(u"spinBox_ECG_front_Signal_1") + self.spinBox_ECG_front_Signal_1.setEnabled(False) + self.spinBox_ECG_front_Signal_1.setFont(font) + self.spinBox_ECG_front_Signal_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_ECG_front_Signal_1.setMinimum(0) + self.spinBox_ECG_front_Signal_1.setMaximum(1000000000) + + self.gridLayout_4.addWidget(self.spinBox_ECG_front_Signal_1, 1, 2, 1, 1) + + self.spinBox_ECG_front_RRIV_1 = QSpinBox(self.groupBox_3) + self.spinBox_ECG_front_RRIV_1.setObjectName(u"spinBox_ECG_front_RRIV_1") + self.spinBox_ECG_front_RRIV_1.setFont(font) + self.spinBox_ECG_front_RRIV_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_ECG_front_RRIV_1.setMinimum(0) + self.spinBox_ECG_front_RRIV_1.setMaximum(1000000000) + + self.gridLayout_4.addWidget(self.spinBox_ECG_front_RRIV_1, 0, 2, 1, 1) + + self.label_8 = QLabel(self.groupBox_3) + self.label_8.setObjectName(u"label_8") + self.label_8.setFont(font) + self.label_8.setAlignment(Qt.AlignmentFlag.AlignCenter) + + self.gridLayout_4.addWidget(self.label_8, 0, 3, 1, 1) + + self.label_13 = QLabel(self.groupBox_3) + self.label_13.setObjectName(u"label_13") + self.label_13.setFont(font) + + self.gridLayout_4.addWidget(self.label_13, 0, 1, 1, 1) + + self.label_14 = QLabel(self.groupBox_3) + self.label_14.setObjectName(u"label_14") + self.label_14.setFont(font) + + self.gridLayout_4.addWidget(self.label_14, 1, 1, 1, 1) - self.verticalLayout_3.addLayout(self.horizontalLayout_7) + self.verticalLayout_3.addLayout(self.gridLayout_4) self.verticalLayout_5.addWidget(self.groupBox_3) + self.groupBox_5 = QGroupBox(self.groupBox_args) + self.groupBox_5.setObjectName(u"groupBox_5") + self.verticalLayout_8 = QVBoxLayout(self.groupBox_5) + self.verticalLayout_8.setObjectName(u"verticalLayout_8") + self.gridLayout_5 = QGridLayout() + self.gridLayout_5.setObjectName(u"gridLayout_5") + self.radioButton_ECG_back = QRadioButton(self.groupBox_5) + self.radioButton_ECG_back.setObjectName(u"radioButton_ECG_back") + self.radioButton_ECG_back.setFont(font) + + self.gridLayout_5.addWidget(self.radioButton_ECG_back, 0, 0, 2, 1) + + self.label_11 = QLabel(self.groupBox_5) + self.label_11.setObjectName(u"label_11") + self.label_11.setFont(font) + self.label_11.setAlignment(Qt.AlignmentFlag.AlignCenter) + + self.gridLayout_5.addWidget(self.label_11, 1, 3, 1, 1) + + self.spinBox_ECG_back_RRIV_2 = QSpinBox(self.groupBox_5) + self.spinBox_ECG_back_RRIV_2.setObjectName(u"spinBox_ECG_back_RRIV_2") + self.spinBox_ECG_back_RRIV_2.setFont(font) + self.spinBox_ECG_back_RRIV_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_ECG_back_RRIV_2.setMinimum(0) + self.spinBox_ECG_back_RRIV_2.setMaximum(1000000000) + + self.gridLayout_5.addWidget(self.spinBox_ECG_back_RRIV_2, 0, 4, 1, 1) + + self.spinBox_ECG_back_Signal_2 = QSpinBox(self.groupBox_5) + self.spinBox_ECG_back_Signal_2.setObjectName(u"spinBox_ECG_back_Signal_2") + self.spinBox_ECG_back_Signal_2.setEnabled(False) + self.spinBox_ECG_back_Signal_2.setFont(font) + self.spinBox_ECG_back_Signal_2.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_ECG_back_Signal_2.setMinimum(0) + self.spinBox_ECG_back_Signal_2.setMaximum(1000000000) + + self.gridLayout_5.addWidget(self.spinBox_ECG_back_Signal_2, 1, 4, 1, 1) + + self.spinBox_ECG_back_RRIV_1 = QSpinBox(self.groupBox_5) + self.spinBox_ECG_back_RRIV_1.setObjectName(u"spinBox_ECG_back_RRIV_1") + self.spinBox_ECG_back_RRIV_1.setFont(font) + self.spinBox_ECG_back_RRIV_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_ECG_back_RRIV_1.setMinimum(0) + self.spinBox_ECG_back_RRIV_1.setMaximum(1000000000) + + self.gridLayout_5.addWidget(self.spinBox_ECG_back_RRIV_1, 0, 2, 1, 1) + + self.spinBox_ECG_back_Signal_1 = QSpinBox(self.groupBox_5) + self.spinBox_ECG_back_Signal_1.setObjectName(u"spinBox_ECG_back_Signal_1") + self.spinBox_ECG_back_Signal_1.setEnabled(False) + self.spinBox_ECG_back_Signal_1.setFont(font) + self.spinBox_ECG_back_Signal_1.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons) + self.spinBox_ECG_back_Signal_1.setMinimum(0) + self.spinBox_ECG_back_Signal_1.setMaximum(1000000000) + + self.gridLayout_5.addWidget(self.spinBox_ECG_back_Signal_1, 1, 2, 1, 1) + + self.label_9 = QLabel(self.groupBox_5) + self.label_9.setObjectName(u"label_9") + self.label_9.setFont(font) + self.label_9.setAlignment(Qt.AlignmentFlag.AlignCenter) + + self.gridLayout_5.addWidget(self.label_9, 0, 3, 1, 1) + + self.label_15 = QLabel(self.groupBox_5) + self.label_15.setObjectName(u"label_15") + self.label_15.setFont(font) + + self.gridLayout_5.addWidget(self.label_15, 0, 1, 1, 1) + + self.label_16 = QLabel(self.groupBox_5) + self.label_16.setObjectName(u"label_16") + self.label_16.setFont(font) + + self.gridLayout_5.addWidget(self.label_16, 1, 1, 1, 1) + + + self.verticalLayout_8.addLayout(self.gridLayout_5) + + + self.verticalLayout_5.addWidget(self.groupBox_5) + self.verticalLayout.addWidget(self.groupBox_args) @@ -288,13 +456,13 @@ class Ui_MainWindow_detect_Jpeak(object): self.horizontalLayout_3 = QHBoxLayout() self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") - self.pushButton_precise_align = QPushButton(self.groupBox_left) - self.pushButton_precise_align.setObjectName(u"pushButton_precise_align") - sizePolicy1.setHeightForWidth(self.pushButton_precise_align.sizePolicy().hasHeightForWidth()) - self.pushButton_precise_align.setSizePolicy(sizePolicy1) - self.pushButton_precise_align.setFont(font) + self.pushButton_view_align = QPushButton(self.groupBox_left) + self.pushButton_view_align.setObjectName(u"pushButton_view_align") + sizePolicy1.setHeightForWidth(self.pushButton_view_align.sizePolicy().hasHeightForWidth()) + self.pushButton_view_align.setSizePolicy(sizePolicy1) + self.pushButton_view_align.setFont(font) - self.horizontalLayout_3.addWidget(self.pushButton_precise_align) + self.horizontalLayout_3.addWidget(self.pushButton_view_align) self.pushButton_save = QPushButton(self.groupBox_left) self.pushButton_save.setObjectName(u"pushButton_save") @@ -321,7 +489,7 @@ class Ui_MainWindow_detect_Jpeak(object): self.verticalLayout.setStretch(0, 1) self.verticalLayout.setStretch(1, 7) - self.verticalLayout.setStretch(2, 3) + self.verticalLayout.setStretch(2, 2) self.verticalLayout.setStretch(3, 1) self.verticalLayout.setStretch(4, 1) self.verticalLayout.setStretch(5, 5) @@ -330,39 +498,53 @@ class Ui_MainWindow_detect_Jpeak(object): self.gridLayout.setColumnStretch(0, 2) self.gridLayout.setColumnStretch(1, 8) - MainWindow_detect_Jpeak.setCentralWidget(self.centralwidget) - self.statusbar = QStatusBar(MainWindow_detect_Jpeak) + MainWindow_precisely_align.setCentralWidget(self.centralwidget) + self.statusbar = QStatusBar(MainWindow_precisely_align) self.statusbar.setObjectName(u"statusbar") - MainWindow_detect_Jpeak.setStatusBar(self.statusbar) + MainWindow_precisely_align.setStatusBar(self.statusbar) - self.retranslateUi(MainWindow_detect_Jpeak) + self.retranslateUi(MainWindow_precisely_align) - QMetaObject.connectSlotsByName(MainWindow_detect_Jpeak) + QMetaObject.connectSlotsByName(MainWindow_precisely_align) # setupUi - def retranslateUi(self, MainWindow_detect_Jpeak): - MainWindow_detect_Jpeak.setWindowTitle(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u6570\u636e\u7cbe\u540c\u6b65", None)) - 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.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)) - self.groupBox_2.setTitle(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u524d\u6bb5\u533a\u95f4\u5750\u6807\u53d6\u503c", None)) - self.label_3.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"BCG", None)) - self.label_4.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"~", None)) - self.label_5.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"ECG", None)) - self.label_6.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"~", None)) - self.groupBox_3.setTitle(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u540e\u6bb5\u533a\u95f4\u5750\u6807\u53d6\u503c", None)) - self.label_7.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"BCG", None)) - self.label_8.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"~", None)) - self.label_9.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"ECG", None)) - self.label_10.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"~", None)) - self.pushButton_calculate_correlation.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u8ba1\u7b97\u76f8\u5173\u6027", None)) - self.pushButton_correlation_align.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u76f8\u5173\u5bf9\u9f50", None)) - self.pushButton_precise_align.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u7cbe\u7ec6\u5bf9\u9f50", None)) - self.pushButton_save.setText(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u4fdd\u5b58\u7ed3\u679c", None)) - self.groupBox.setTitle(QCoreApplication.translate("MainWindow_detect_Jpeak", u"\u65e5\u5fd7", None)) + def retranslateUi(self, MainWindow_precisely_align): + MainWindow_precisely_align.setWindowTitle(QCoreApplication.translate("MainWindow_precisely_align", u"\u6570\u636e\u7cbe\u540c\u6b65", None)) + 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.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)) + self.groupBox_2.setTitle(QCoreApplication.translate("MainWindow_precisely_align", u"\u524d\u6bb5BCG\u533a\u95f4\u5750\u6807\u53d6\u503c", None)) + self.radioButton_BCG_front.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u524d\u6bb5BCG", None)) + self.label_4.setText(QCoreApplication.translate("MainWindow_precisely_align", u"~", None)) + self.label_6.setText(QCoreApplication.translate("MainWindow_precisely_align", u"~", None)) + self.label.setText(QCoreApplication.translate("MainWindow_precisely_align", u"JJIV\u5e8f\u53f7", None)) + self.label_2.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u4fe1\u53f7\u5750\u6807", None)) + self.groupBox_4.setTitle(QCoreApplication.translate("MainWindow_precisely_align", u"\u540e\u6bb5BCG\u533a\u95f4\u5750\u6807\u53d6\u503c", None)) + self.radioButton_BCG_back.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u540e\u6bb5BCG", None)) + self.label_7.setText(QCoreApplication.translate("MainWindow_precisely_align", u"~", None)) + self.label_5.setText(QCoreApplication.translate("MainWindow_precisely_align", u"~", None)) + self.label_3.setText(QCoreApplication.translate("MainWindow_precisely_align", u"JJIV\u5e8f\u53f7", None)) + self.label_12.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u4fe1\u53f7\u5750\u6807", None)) + self.groupBox_3.setTitle(QCoreApplication.translate("MainWindow_precisely_align", u"\u524d\u6bb5ECG\u533a\u95f4\u5750\u6807\u53d6\u503c", None)) + self.label_10.setText(QCoreApplication.translate("MainWindow_precisely_align", u"~", None)) + self.radioButton_ECG_front.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u524d\u6bb5ECG", None)) + self.label_8.setText(QCoreApplication.translate("MainWindow_precisely_align", u"~", None)) + self.label_13.setText(QCoreApplication.translate("MainWindow_precisely_align", u"RRIV\u5e8f\u53f7", None)) + self.label_14.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u4fe1\u53f7\u5750\u6807", None)) + self.groupBox_5.setTitle(QCoreApplication.translate("MainWindow_precisely_align", u"\u540e\u6bb5ECG\u533a\u95f4\u5750\u6807\u53d6\u503c", None)) + self.radioButton_ECG_back.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u540e\u6bb5ECG", None)) + self.label_11.setText(QCoreApplication.translate("MainWindow_precisely_align", u"~", None)) + self.label_9.setText(QCoreApplication.translate("MainWindow_precisely_align", u"~", None)) + self.label_15.setText(QCoreApplication.translate("MainWindow_precisely_align", u"RRIV\u5e8f\u53f7", None)) + self.label_16.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u4fe1\u53f7\u5750\u6807", None)) + self.pushButton_calculate_correlation.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u8ba1\u7b97\u76f8\u5173\u6027", None)) + self.pushButton_correlation_align.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u76f8\u5173\u5bf9\u9f50", None)) + self.pushButton_view_align.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u67e5\u770b\u5bf9\u9f50\u7ed3\u679c", None)) + self.pushButton_save.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u4fdd\u5b58\u7ed3\u679c", None)) + self.groupBox.setTitle(QCoreApplication.translate("MainWindow_precisely_align", u"\u65e5\u5fd7", None)) # retranslateUi diff --git a/ui/MainWindow/MainWindow_precisely_align.ui b/ui/MainWindow/MainWindow_precisely_align.ui index 917f00f..e3cb460 100644 --- a/ui/MainWindow/MainWindow_precisely_align.ui +++ b/ui/MainWindow/MainWindow_precisely_align.ui @@ -1,7 +1,7 @@ - MainWindow_detect_Jpeak - + MainWindow_precisely_align + true @@ -56,7 +56,7 @@ 预处理 - + @@ -102,32 +102,20 @@ 参数输入 - + - 前段区间坐标取值 + 前段BCG区间坐标取值 - - - - - - 12 - + + + + + false - - BCG - - - Qt::AlignmentFlag::AlignCenter - - - - - 12 @@ -144,7 +132,40 @@ - + + + + + 12 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 0 + + + 1000000000 + + + + + + + + 12 + + + + 前段BCG + + + true + + + + @@ -159,8 +180,11 @@ - - + + + + false + 12 @@ -177,27 +201,8 @@ - - - - - - - - - 12 - - - - ECG - - - Qt::AlignmentFlag::AlignCenter - - - - - + + 12 @@ -214,7 +219,7 @@ - + @@ -229,21 +234,27 @@ - - + + 12 - - QAbstractSpinBox::ButtonSymbols::NoButtons + + JJIV序号 - - 0 + + + + + + + 12 + - - 1000000000 + + 信号坐标 @@ -253,30 +264,18 @@ - + - 后段区间坐标取值 + 后段BCG区间坐标取值 - + - - - - - - 12 - + + + + + false - - BCG - - - Qt::AlignmentFlag::AlignCenter - - - - - 12 @@ -293,8 +292,80 @@ - - + + + + false + + + + 12 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 0 + + + 1000000000 + + + + + + + + 12 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 0 + + + 1000000000 + + + + + + + + 12 + + + + 后段BCG + + + false + + + + + + + + 12 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 0 + + + 1000000000 + + + + + 12 @@ -308,45 +379,60 @@ - - - - - 12 - - - - QAbstractSpinBox::ButtonSymbols::NoButtons - - - 0 - - - 1000000000 - - - - - - - - - + + 12 - ECG + ~ Qt::AlignmentFlag::AlignCenter - - + + + + + 12 + + + + JJIV序号 + + + + + + + + 12 + + + + 信号坐标 + + + + + + + + + + + + 前段ECG区间坐标取值 + + + + + + 12 @@ -363,7 +449,7 @@ - + @@ -378,8 +464,23 @@ - - + + + + + 12 + + + + 前段ECG + + + + + + + false + 12 @@ -396,6 +497,241 @@ + + + + false + + + + 12 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 0 + + + 1000000000 + + + + + + + + 12 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 0 + + + 1000000000 + + + + + + + + 12 + + + + ~ + + + Qt::AlignmentFlag::AlignCenter + + + + + + + + 12 + + + + RRIV序号 + + + + + + + + 12 + + + + 信号坐标 + + + + + + + + + + + + 后段ECG区间坐标取值 + + + + + + + + + 12 + + + + 后段ECG + + + + + + + + 12 + + + + ~ + + + Qt::AlignmentFlag::AlignCenter + + + + + + + + 12 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 0 + + + 1000000000 + + + + + + + false + + + + 12 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 0 + + + 1000000000 + + + + + + + + 12 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 0 + + + 1000000000 + + + + + + + false + + + + 12 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 0 + + + 1000000000 + + + + + + + + 12 + + + + ~ + + + Qt::AlignmentFlag::AlignCenter + + + + + + + + 12 + + + + RRIV序号 + + + + + + + + 12 + + + + 信号坐标 + + + @@ -460,7 +796,7 @@ - + 0 @@ -473,7 +809,7 @@ - 精细对齐 + 查看对齐结果 diff --git a/ui/setting/precisely_align_input_setting.py b/ui/setting/precisely_align_input_setting.py index 4c9d8c4..2eb9e05 100644 --- a/ui/setting/precisely_align_input_setting.py +++ b/ui/setting/precisely_align_input_setting.py @@ -48,32 +48,12 @@ class Ui_MainWindow_precisely_align_input_setting(object): self.groupBox_file_path_input_BCG.setObjectName(u"groupBox_file_path_input_BCG") self.verticalLayout_5 = QVBoxLayout(self.groupBox_file_path_input_BCG) self.verticalLayout_5.setObjectName(u"verticalLayout_5") - self.horizontalLayout_2 = QHBoxLayout() - self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") - self.label_2 = QLabel(self.groupBox_file_path_input_BCG) - self.label_2.setObjectName(u"label_2") - self.label_2.setFont(font) - - self.horizontalLayout_2.addWidget(self.label_2) - - self.spinBox_input_freq_BCG = QSpinBox(self.groupBox_file_path_input_BCG) - self.spinBox_input_freq_BCG.setObjectName(u"spinBox_input_freq_BCG") - self.spinBox_input_freq_BCG.setFont(font) - self.spinBox_input_freq_BCG.setMinimum(1) - self.spinBox_input_freq_BCG.setMaximum(1000000) - - self.horizontalLayout_2.addWidget(self.spinBox_input_freq_BCG) - - - self.verticalLayout_5.addLayout(self.horizontalLayout_2) - self.plainTextEdit_file_path_input_BCG = QPlainTextEdit(self.groupBox_file_path_input_BCG) self.plainTextEdit_file_path_input_BCG.setObjectName(u"plainTextEdit_file_path_input_BCG") self.verticalLayout_5.addWidget(self.plainTextEdit_file_path_input_BCG) - self.verticalLayout_5.setStretch(0, 2) - self.verticalLayout_5.setStretch(1, 3) + self.verticalLayout_5.setStretch(0, 3) self.verticalLayout_2.addWidget(self.groupBox_file_path_input_BCG) @@ -140,10 +120,15 @@ class Ui_MainWindow_precisely_align_input_setting(object): self.groupBox_file_path_save.setObjectName(u"groupBox_file_path_save") self.verticalLayout_4 = QVBoxLayout(self.groupBox_file_path_save) self.verticalLayout_4.setObjectName(u"verticalLayout_4") - self.plainTextEdit_file_path_save = QPlainTextEdit(self.groupBox_file_path_save) - self.plainTextEdit_file_path_save.setObjectName(u"plainTextEdit_file_path_save") + self.plainTextEdit_file_path_save_BCG = QPlainTextEdit(self.groupBox_file_path_save) + self.plainTextEdit_file_path_save_BCG.setObjectName(u"plainTextEdit_file_path_save_BCG") - self.verticalLayout_4.addWidget(self.plainTextEdit_file_path_save) + self.verticalLayout_4.addWidget(self.plainTextEdit_file_path_save_BCG) + + self.plainTextEdit_file_path_save_ECG = QPlainTextEdit(self.groupBox_file_path_save) + self.plainTextEdit_file_path_save_ECG.setObjectName(u"plainTextEdit_file_path_save_ECG") + + self.verticalLayout_4.addWidget(self.plainTextEdit_file_path_save_ECG) self.verticalLayout_2.addWidget(self.groupBox_file_path_save) @@ -152,7 +137,7 @@ class Ui_MainWindow_precisely_align_input_setting(object): self.verticalLayout_2.setStretch(1, 4) self.verticalLayout_2.setStretch(2, 5) self.verticalLayout_2.setStretch(3, 4) - self.verticalLayout_2.setStretch(4, 4) + self.verticalLayout_2.setStretch(4, 8) self.gridLayout.addWidget(self.groupBox, 0, 0, 1, 4) @@ -177,7 +162,6 @@ class Ui_MainWindow_precisely_align_input_setting(object): self.pushButton_cancel.setText(QCoreApplication.translate("MainWindow_precisely_align_input_setting", u"\u53d6\u6d88", None)) self.groupBox.setTitle(QCoreApplication.translate("MainWindow_precisely_align_input_setting", u"\u6587\u4ef6\u8def\u5f84", None)) self.groupBox_file_path_input_BCG.setTitle(QCoreApplication.translate("MainWindow_precisely_align_input_setting", u"\u9884\u5904\u7406\u540e\u7684BCG\u8def\u5f84", None)) - self.label_2.setText(QCoreApplication.translate("MainWindow_precisely_align_input_setting", u"\u91c7\u6837\u7387(Hz)\uff1a", None)) self.plainTextEdit_file_path_input_BCG.setPlainText("") self.plainTextEdit_file_path_input_BCG.setPlaceholderText(QCoreApplication.translate("MainWindow_precisely_align_input_setting", u"\u6587\u4ef6\u8def\u5f84", None)) self.groupBox_file_path_input_Jpeak.setTitle(QCoreApplication.translate("MainWindow_precisely_align_input_setting", u"\u4eba\u5de5\u7ea0\u6b63\u540e\u7684J\u5cf0\u5cf0\u503c\u8def\u5f84", None)) @@ -191,7 +175,8 @@ class Ui_MainWindow_precisely_align_input_setting(object): self.plainTextEdit_file_path_input_Rpeak.setPlainText("") self.plainTextEdit_file_path_input_Rpeak.setPlaceholderText(QCoreApplication.translate("MainWindow_precisely_align_input_setting", u"\u6587\u4ef6\u8def\u5f84", None)) self.groupBox_file_path_save.setTitle(QCoreApplication.translate("MainWindow_precisely_align_input_setting", u"\u5bf9\u9f50\u4fe1\u606f\u4fdd\u5b58\u8def\u5f84", None)) - self.plainTextEdit_file_path_save.setPlaceholderText(QCoreApplication.translate("MainWindow_precisely_align_input_setting", u"\u4fdd\u5b58\u8def\u5f84", None)) + self.plainTextEdit_file_path_save_BCG.setPlaceholderText(QCoreApplication.translate("MainWindow_precisely_align_input_setting", u"\u4fdd\u5b58\u8def\u5f84", None)) + self.plainTextEdit_file_path_save_ECG.setPlaceholderText(QCoreApplication.translate("MainWindow_precisely_align_input_setting", u"\u4fdd\u5b58\u8def\u5f84", None)) self.pushButton_confirm.setText(QCoreApplication.translate("MainWindow_precisely_align_input_setting", u"\u786e\u5b9a", None)) # retranslateUi diff --git a/ui/setting/precisely_align_input_setting.ui b/ui/setting/precisely_align_input_setting.ui index cbe5884..69e0c90 100644 --- a/ui/setting/precisely_align_input_setting.ui +++ b/ui/setting/precisely_align_input_setting.ui @@ -37,44 +37,13 @@ 文件路径 - + 预处理后的BCG路径 - - - - - - - - 12 - - - - 采样率(Hz): - - - - - - - - 12 - - - - 1 - - - 1000000 - - - - - + @@ -183,7 +152,14 @@ - + + + 保存路径 + + + + + 保存路径