Files
Signal_Label_Reborn/func/Module_precisely_align.py
2025-05-08 19:53:01 +08:00

1954 lines
102 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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_orgBcg": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT /
Path(str(self.sampID)) / Path(ConfigParams.PRECISELY_ALIGN_INPUT_ORGBCG_FILENAME +
str(Config["InputConfig"]["ECGFreq"]) +
ConfigParams.ENDSWITH_TXT))),
"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_AlignInfo": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED /
Path(str(self.sampID)) / Path(ConfigParams.PRECISELY_ALIGN_SAVE_BCG_ALIGNINFO_FILENAME +
ConfigParams.ENDSWITH_TXT))),
"Save_ECG_AlignInfo": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_ALIGNED /
Path(str(self.sampID)) / Path(ConfigParams.PRECISELY_ALIGN_SAVE_ECG_ALIGNINFO_FILENAME +
ConfigParams.ENDSWITH_TXT))),
"Save_orgBcg": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED /
Path(str(self.sampID)) / Path(ConfigParams.PRECISELY_ALIGN_SAVE_ORGBCG_FILENAME +
str(Config["InputConfig"]["ECGFreq"]) +
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 +
str(Config["InputConfig"]["ECGFreq"]) +
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 +
str(Config["InputConfig"]["ECGFreq"]) +
ConfigParams.ENDSWITH_TXT))),
"Save_Jpeak": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED /
Path(str(self.sampID)) / Path(ConfigParams.PRECISELY_ALIGN_SAVE_JPEAK_FILENAME +
ConfigParams.ENDSWITH_TXT))),
"Save_Rpeak": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_ALIGNED /
Path(str(self.sampID)) / Path(ConfigParams.PRECISELY_ALIGN_SAVE_RPEAK_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_orgBcg.setPlainText(Config["Path"]["Input_orgBcg"])
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_AlignInfo.setPlainText(Config["Path"]["Save_BCG_AlignInfo"])
self.ui.plainTextEdit_file_path_save_ECG_AlignInfo.setPlainText(Config["Path"]["Save_ECG_AlignInfo"])
self.ui.plainTextEdit_file_path_save_orgBcg.setPlainText(Config["Path"]["Save_orgBcg"])
self.ui.plainTextEdit_file_path_save_BCG.setPlainText(Config["Path"]["Save_BCG"])
self.ui.plainTextEdit_file_path_save_ECG.setPlainText(Config["Path"]["Save_ECG"])
self.ui.plainTextEdit_file_path_save_Jpeak.setPlainText(Config["Path"]["Save_Jpeak"])
self.ui.plainTextEdit_file_path_save_Rpeak.setPlainText(Config["Path"]["Save_Rpeak"])
def __write_config__(self):
# 从界面写入配置
Config["InputConfig"]["ECGFreq"] = self.ui.spinBox_input_freq_ECG.value()
Config["Path"]["Input_orgBcg"] = self.ui.plainTextEdit_file_path_input_orgBcg.toPlainText()
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_AlignInfo"] = self.ui.plainTextEdit_file_path_save_BCG_AlignInfo.toPlainText()
Config["Path"]["Save_ECG_AlignInfo"] = self.ui.plainTextEdit_file_path_save_ECG_AlignInfo.toPlainText()
Config["Path"]["Save_orgBcg"] = self.ui.plainTextEdit_file_path_save_orgBcg.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()
Config["Path"]["Save_Jpeak"] = self.ui.plainTextEdit_file_path_save_Jpeak.toPlainText()
Config["Path"]["Save_Rpeak"] = self.ui.plainTextEdit_file_path_save_Rpeak.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_orgBcg.setPlainText(
str((Path(self.root_path) /
ConfigParams.PUBLIC_PATH_ORGBCG_TEXT /
Path(str(self.sampID)) /
Path(ConfigParams.PRECISELY_ALIGN_INPUT_ORGBCG_FILENAME +
str(self.ui.spinBox_input_freq_ECG.value()) +
ConfigParams.ENDSWITH_TXT))))
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))))
self.ui.plainTextEdit_file_path_save_orgBcg.setPlainText(
str((Path(self.root_path) /
ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED /
Path(str(self.sampID)) /
Path(ConfigParams.PRECISELY_ALIGN_SAVE_ORGBCG_FILENAME +
str(self.ui.spinBox_input_freq_ECG.value()) +
ConfigParams.ENDSWITH_TXT))))
self.ui.plainTextEdit_file_path_save_BCG.setPlainText(
str((Path(self.root_path) /
ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED /
Path(str(self.sampID)) /
Path(ConfigParams.PRECISELY_ALIGN_SAVE_BCG_FILENAME +
str(self.ui.spinBox_input_freq_ECG.value()) +
ConfigParams.ENDSWITH_TXT))))
self.ui.plainTextEdit_file_path_save_ECG.setPlainText(
str((Path(self.root_path) /
ConfigParams.PUBLIC_PATH_PSG_ALIGNED /
Path(str(self.sampID)) /
Path(ConfigParams.PRECISELY_ALIGN_SAVE_ECG_FILENAME +
str(self.ui.spinBox_input_freq_ECG.value()) +
ConfigParams.ENDSWITH_TXT))))
self.ui.plainTextEdit_file_path_save_Jpeak.setPlainText(
str((Path(self.root_path) /
ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED /
Path(str(self.sampID)) /
Path(ConfigParams.PRECISELY_ALIGN_SAVE_JPEAK_FILENAME +
ConfigParams.ENDSWITH_TXT))))
self.ui.plainTextEdit_file_path_save_Rpeak.setPlainText(
str((Path(self.root_path) /
ConfigParams.PUBLIC_PATH_PSG_ALIGNED /
Path(str(self.sampID)) /
Path(ConfigParams.PRECISELY_ALIGN_SAVE_RPEAK_FILENAME +
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, 6, Constants.PRECISELY_ALIGN_SAVING_ALIGNINFO, 0)
status, info = self.data.save_alignInfo()
if not status:
PublicFunc.text_output(self.ui, "(1/6)" + info, Constants.TIPS_TYPE_ERROR)
PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR)
PublicFunc.finish_operation(self, ButtonState)
return
else:
PublicFunc.text_output(self.ui, "(1/6)" + info, Constants.TIPS_TYPE_INFO)
# 保存切割后orgBcg
PublicFunc.progressbar_update(self, 2, 6, Constants.PRECISELY_ALIGN_SAVING_RES_ORGBCG, 0)
total_rows = len(DataFrame(self.data.res_orgBcg.reshape(-1)))
chunk_size = ConfigParams.PRECISELY_ALIGN_SAVE_CHUNK_SIZE
with open(Config["Path"]["Save_orgBcg"], 'w') as f:
for start in range(0, total_rows, chunk_size):
end = min(start + chunk_size, total_rows)
chunk = DataFrame(self.data.res_orgBcg.reshape(-1)).iloc[start:end]
status, info = self.data.save_res_orgBcg(chunk)
progress = int((end / total_rows) * 100)
self.progressbar.setValue(progress)
QApplication.processEvents()
if not status:
PublicFunc.text_output(self.ui, "(2/6)" + info, Constants.TIPS_TYPE_ERROR)
PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR)
PublicFunc.finish_operation(self, ButtonState)
return
else:
PublicFunc.text_output(self.ui, "(2/6)" + info, Constants.TIPS_TYPE_INFO)
# 保存切割后BCG
PublicFunc.progressbar_update(self, 3, 6, Constants.PRECISELY_ALIGN_SAVING_RES_BCG, 0)
total_rows = len(DataFrame(self.data.res_BCG.reshape(-1)))
chunk_size = ConfigParams.PRECISELY_ALIGN_SAVE_CHUNK_SIZE
with open(Config["Path"]["Save_orgBcg"], 'w') as f:
for start in range(0, total_rows, chunk_size):
end = min(start + chunk_size, total_rows)
chunk = DataFrame(self.data.res_BCG.reshape(-1)).iloc[start:end]
status, info = self.data.save_res_BCG(chunk)
progress = int((end / total_rows) * 100)
self.progressbar.setValue(progress)
QApplication.processEvents()
if not status:
PublicFunc.text_output(self.ui, "(3/6)" + info, Constants.TIPS_TYPE_ERROR)
PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR)
PublicFunc.finish_operation(self, ButtonState)
return
else:
PublicFunc.text_output(self.ui, "(3/6)" + info, Constants.TIPS_TYPE_INFO)
# 保存切割后ECG
PublicFunc.progressbar_update(self, 4, 6, Constants.PRECISELY_ALIGN_SAVING_CUT_ECG, 0)
total_rows = len(DataFrame(self.data.cut_ECG.reshape(-1)))
chunk_size = ConfigParams.PRECISELY_ALIGN_SAVE_CHUNK_SIZE
with open(Config["Path"]["Save_ECG"], 'w') as f:
for start in range(0, total_rows, chunk_size):
end = min(start + chunk_size, total_rows)
chunk = DataFrame(self.data.cut_ECG.reshape(-1)).iloc[start:end]
status, info = self.data.save_cut_ECG(chunk)
progress = int((end / total_rows) * 100)
self.progressbar.setValue(progress)
QApplication.processEvents()
if not status:
PublicFunc.text_output(self.ui, "(4/6)" + info, Constants.TIPS_TYPE_ERROR)
PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR)
PublicFunc.finish_operation(self, ButtonState)
return
else:
PublicFunc.text_output(self.ui, "(4/6)" + info, Constants.TIPS_TYPE_INFO)
# 保存切割后J峰
PublicFunc.progressbar_update(self, 5, 6, Constants.PRECISELY_ALIGN_SAVING_CUT_JPEAK, 0)
total_rows = len(DataFrame(self.data.cut_Jpeak.reshape(-1)))
chunk_size = ConfigParams.PRECISELY_ALIGN_SAVE_PEAK_CHUNK_SIZE
with open(Config["Path"]["Save_Jpeak"], 'w') as f:
for start in range(0, total_rows, chunk_size):
end = min(start + chunk_size, total_rows)
chunk = DataFrame(self.data.cut_Jpeak.reshape(-1)).iloc[start:end]
status, info = self.data.save_Jpeak(chunk)
progress = int((end / total_rows) * 100)
self.progressbar.setValue(progress)
QApplication.processEvents()
if not status:
PublicFunc.text_output(self.ui, "(5/6)" + info, Constants.TIPS_TYPE_ERROR)
PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR)
PublicFunc.finish_operation(self, ButtonState)
return
else:
PublicFunc.text_output(self.ui, "(5/6)" + info, Constants.TIPS_TYPE_INFO)
# 保存切割后R峰
PublicFunc.progressbar_update(self, 6, 6, Constants.PRECISELY_ALIGN_SAVING_CUT_RPEAK, 0)
total_rows = len(DataFrame(self.data.cut_Rpeak.reshape(-1)))
chunk_size = ConfigParams.PRECISELY_ALIGN_SAVE_PEAK_CHUNK_SIZE
with open(Config["Path"]["Save_Rpeak"], 'w') as f:
for start in range(0, total_rows, chunk_size):
end = min(start + chunk_size, total_rows)
chunk = DataFrame(self.data.cut_Rpeak.reshape(-1)).iloc[start:end]
status, info = self.data.save_Rpeak(chunk)
progress = int((end / total_rows) * 100)
self.progressbar.setValue(progress)
QApplication.processEvents()
if not status:
PublicFunc.text_output(self.ui, "(6/6)" + info, Constants.TIPS_TYPE_ERROR)
PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR)
PublicFunc.finish_operation(self, ButtonState)
return
else:
PublicFunc.text_output(self.ui, "(6/6)" + info, Constants.TIPS_TYPE_INFO)
PublicFunc.msgbox_output(self, Constants.SAVING_FINISHED, Constants.TIPS_TYPE_INFO)
PublicFunc.finish_operation(self, ButtonState)
def __update_coordinate__(self):
try:
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"])
except AttributeError:
pass
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
return False, Constants.DRAWING_FAILURE
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
return False, Constants.DRAWING_FAILURE
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_orgBcg = Config["Path"]["Input_orgBcg"]
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_AlignInfo = Config["Path"]["Save_BCG_AlignInfo"]
self.file_path_save_ECG_AlignInfo = Config["Path"]["Save_ECG_AlignInfo"]
self.file_path_save_orgBcg = Config["Path"]["Save_orgBcg"]
self.file_path_save_BCG = Config["Path"]["Save_BCG"]
self.file_path_save_ECG = Config["Path"]["Save_ECG"]
self.file_path_save_Jpeak = Config["Path"]["Save_Jpeak"]
self.file_path_save_Rpeak = Config["Path"]["Save_Rpeak"]
self.raw_orgBcg = None
self.raw_BCG = None
self.Jpeak = None
self.Jpeak_y = None
self.raw_ECG = None
self.Rpeak = None
self.Rpeak_y = None
self.res_orgBcg = None
self.res_BCG = None
self.cut_ECG = None
self.cut_Jpeak = None
self.cut_Rpeak = 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_orgBcg = read_csv(self.file_path_input_orgBcg,
encoding=ConfigParams.UTF8_ENCODING,
header=None).to_numpy().reshape(-1)
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.res_orgBcg = self.raw_orgBcg
self.res_BCG = self.raw_BCG
self.cut_ECG = self.raw_ECG
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:]
self.res_orgBcg = self.res_orgBcg[-off:]
anchor0[1] = anchor0[1] + off
anchor1[1] = anchor1[1] + off
self.res_BCG = resample(self.res_BCG, orgfs, Config["InputConfig"]["ECGFreq"])
self.res_orgBcg = resample(self.res_orgBcg, 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:]
self.res_orgBcg = self.res_orgBcg[-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]
self.res_orgBcg = self.res_orgBcg[: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:]
self.res_orgBcg = self.res_orgBcg[-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]
self.res_orgBcg = self.res_orgBcg[: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_alignInfo(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_AlignInfo, index=False, header=False)
DataFrame(save_data).to_csv(self.file_path_save_ECG_AlignInfo, index=False, header=False)
except Exception as e:
print(e)
return False, Constants.PRECISELY_ALIGN_SAVING_ALIGNINFO_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"]
return True, Constants.PRECISELY_ALIGN_SAVING_ALIGNINFO_FINISHED
def save_res_orgBcg(self, chunk):
if self.res_orgBcg is None:
return False, Constants.PRECISELY_ALIGN_SAVING_RES_ORGBCG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["res_orgBcg_Not_Exist"]
try:
chunk.to_csv(self.file_path_save_orgBcg, mode='a', index=False, header=False)
except Exception:
return False, Constants.PRECISELY_ALIGN_SAVING_RES_ORGBCG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"]
return True, Constants.PRECISELY_ALIGN_SAVING_RES_ORGBCG_FINISHED
def save_res_BCG(self, chunk):
if self.res_BCG is None:
return False, Constants.PRECISELY_ALIGN_SAVING_RES_BCG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["res_BCG_Not_Exist"]
try:
chunk.to_csv(self.file_path_save_BCG, mode='a', index=False, header=False)
except Exception:
return False, Constants.PRECISELY_ALIGN_SAVING_RES_BCG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"]
return True, Constants.PRECISELY_ALIGN_SAVING_RES_BCG_FINISHED
def save_cut_ECG(self, chunk):
if self.cut_ECG is None:
return False, Constants.PRECISELY_ALIGN_SAVING_CUT_ECG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["cut_ECG_Not_Exist"]
try:
chunk.to_csv(self.file_path_save_ECG, mode='a', index=False, header=False)
except Exception:
return False, Constants.PRECISELY_ALIGN_SAVING_CUT_ECG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"]
return True, Constants.PRECISELY_ALIGN_SAVING_CUT_ECG_FINISHED
def save_Jpeak(self, chunk):
if self.cut_Jpeak is None:
return False, Constants.PRECISELY_ALIGN_SAVING_CUT_JPEAK_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["cut_Jpeak_Not_Exist"]
try:
chunk.to_csv(self.file_path_save_Jpeak, mode='a', index=False, header=False)
except Exception:
return False, Constants.PRECISELY_ALIGN_SAVING_CUT_JPEAK_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"]
return True, Constants.PRECISELY_ALIGN_SAVING_CUT_JPEAK_FINISHED
def save_Rpeak(self, chunk):
if self.cut_Rpeak is None:
return False, Constants.PRECISELY_ALIGN_SAVING_CUT_RPEAK_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["cut_Rpeak_Not_Exist"]
try:
chunk.to_csv(self.file_path_save_Rpeak, mode='a', index=False, header=False)
except Exception:
return False, Constants.PRECISELY_ALIGN_SAVING_CUT_RPEAK_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"]
return True, Constants.PRECISELY_ALIGN_SAVING_CUT_RPEAK_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