1、精简部分公共代码到PublicFunc.py中

2、完成了<人工纠正>的所有代码
This commit is contained in:
2025-05-06 13:40:35 +08:00
parent 10247fb738
commit b4c4e124f8
13 changed files with 858 additions and 178 deletions

View File

@ -54,3 +54,11 @@ def Butterworth_for_BCG_PreProcess(data, sample_rate, type, low_cut=0.0, high_cu
return sosfiltfilt(sos, array(data))
else: # 警告,滤波器类型必须有
raise ValueError("Please choose a type of fliter")
def data_preprocess_for_label_check(data, n, f1, f2, fs):
f1 = f1 / (fs / 2.0)
f2 = f2 / (fs / 2.0)
b, a = butter(n, [f1, f2], btype="bandpass")
data = array(filtfilt(b, a, data))
return data

View File

@ -290,12 +290,11 @@ class MainWindow_detect_Jpeak(QMainWindow):
# 清空模型列表
self.ui.comboBox_model.clear()
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(1/2)" + Constants.DETECT_JPEAK_LOADING_MODEL))
self.progressbar.setValue(0)
QApplication.processEvents()
self.data = Data()
self.model = Model()
# 寻找模型
self.model = Model()
PublicFunc.progressbar_update(self, 1, 2, Constants.DETECT_JPEAK_LOADING_MODEL, 0)
status, info = self.model.seek_model()
if not status:
PublicFunc.text_output(self.ui, "(1/2)" + info, Constants.TIPS_TYPE_ERROR)
@ -306,12 +305,8 @@ class MainWindow_detect_Jpeak(QMainWindow):
PublicFunc.text_output(self.ui, "(1/2)" + info, Constants.TIPS_TYPE_INFO)
self.update_ui_comboBox_model(self.model.model_list)
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(2/2)" + Constants.INPUTTING_DATA))
self.progressbar.setValue(10)
QApplication.processEvents()
# 导入数据
self.data = Data()
PublicFunc.progressbar_update(self, 2, 2, Constants.INPUTTING_DATA, 10)
status, info = self.data.open_file()
if not status:
PublicFunc.text_output(self.ui, "(2/2)" + info, Constants.TIPS_TYPE_ERROR)
@ -328,11 +323,8 @@ class MainWindow_detect_Jpeak(QMainWindow):
PublicFunc.__disableAllButton__(self, ButtonState)
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(1/3)" + Constants.DETECT_JPEAK_PROCESSING_DATA))
self.progressbar.setValue(0)
QApplication.processEvents()
# 数据预处理
PublicFunc.progressbar_update(self, 1, 3, Constants.DETECT_JPEAK_PROCESSING_DATA, 0)
status, info = self.data.preprocess()
if not status:
PublicFunc.text_output(self.ui, "(1/3)" + info, Constants.TIPS_TYPE_ERROR)
@ -342,11 +334,8 @@ class MainWindow_detect_Jpeak(QMainWindow):
else:
PublicFunc.text_output(self.ui, "(1/3)" + info, Constants.TIPS_TYPE_INFO)
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(2/3)" + Constants.DETECT_JPEAK_PREDICTING_PEAK))
self.progressbar.setValue(10)
QApplication.processEvents()
# 预测峰值
PublicFunc.progressbar_update(self, 2, 3, Constants.DETECT_JPEAK_PREDICTING_PEAK, 10)
self.model.selected_model = Config["DetectMethod"]
status, info = self.data.predict_Jpeak(self.model)
if not status:
@ -364,11 +353,8 @@ class MainWindow_detect_Jpeak(QMainWindow):
PublicFunc.text_output(self.ui, Constants.DETECT_JPEAK_PEAK_AMOUNT + str(len(self.data.peak)),
Constants.TIPS_TYPE_INFO)
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(3/3)" + Constants.DRAWING_DATA))
self.progressbar.setValue(70)
QApplication.processEvents()
# 绘图
PublicFunc.progressbar_update(self, 3, 3, Constants.DRAWING_DATA, 70)
status, info = self.__plot__()
if not status:
PublicFunc.text_output(self.ui, "(3/3)" + info, Constants.TIPS_TYPE_ERROR)
@ -390,11 +376,8 @@ class MainWindow_detect_Jpeak(QMainWindow):
if reply == QMessageBox.Yes:
PublicFunc.__disableAllButton__(self, ButtonState)
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(1/1)" + Constants.SAVING_DATA))
self.progressbar.setValue(0)
QApplication.processEvents()
# 保存
PublicFunc.progressbar_update(self, 1, 1, Constants.SAVING_DATA, 0)
# status, info = self.data.save()
total_rows = len(DataFrame(self.data.peak.reshape(-1)))
chunk_size = ConfigParams.DETECT_JPEAK_SAVE_CHUNK_SIZE

View File

@ -273,11 +273,12 @@ class MainWindow_detect_Rpeak(QMainWindow):
PublicFunc.__disableAllButton__(self, ButtonState)
# 清空画框
if self.line_data and self.point_peak and self.line_interval:
if self.line_data and self.point_peak and self.line_interval and self.point_RRIV:
try:
self.line_data.remove()
self.point_peak.remove()
self.line_interval.remove()
self.point_RRIV.remove()
except ValueError:
pass
self.canvas.draw()
@ -285,11 +286,11 @@ class MainWindow_detect_Rpeak(QMainWindow):
# 清空方法列表
self.ui.comboBox_method.clear()
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(1/2)" + Constants.DETECT_RPEAK_LOADING_METHOD))
self.progressbar.setValue(0)
QApplication.processEvents()
self.data = Data()
# 寻找方法
PublicFunc.progressbar_update(self, 1, 2, Constants.DETECT_RPEAK_LOADING_METHOD, 0)
# TODO获取检测方法的解耦
method_list = get_method()
if len(method_list) == 0 or method_list is None:
status = False
@ -306,12 +307,8 @@ class MainWindow_detect_Rpeak(QMainWindow):
PublicFunc.text_output(self.ui, "(1/2)" + info, Constants.TIPS_TYPE_INFO)
self.update_ui_comboBox_method(method_list)
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(2/2)" + Constants.INPUTTING_DATA))
self.progressbar.setValue(10)
QApplication.processEvents()
# 导入数据
self.data = Data()
PublicFunc.progressbar_update(self, 2, 2, Constants.INPUTTING_DATA, 10)
status, info = self.data.open_file()
if not status:
PublicFunc.text_output(self.ui, "(2/2)" + info, Constants.TIPS_TYPE_ERROR)
@ -328,11 +325,8 @@ class MainWindow_detect_Rpeak(QMainWindow):
PublicFunc.__disableAllButton__(self, ButtonState)
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(1/3)" + Constants.DETECT_RPEAK_PROCESSING_DATA))
self.progressbar.setValue(0)
QApplication.processEvents()
# 数据预处理
PublicFunc.progressbar_update(self, 1, 3, Constants.DETECT_RPEAK_PROCESSING_DATA, 0)
status, info = self.data.preprocess()
if not status:
PublicFunc.text_output(self.ui, "(1/3)" + info, Constants.TIPS_TYPE_ERROR)
@ -342,11 +336,8 @@ class MainWindow_detect_Rpeak(QMainWindow):
else:
PublicFunc.text_output(self.ui, "(1/3)" + info, Constants.TIPS_TYPE_INFO)
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(2/3)" + Constants.DETECT_RPEAK_PREDICTING_PEAK))
self.progressbar.setValue(10)
QApplication.processEvents()
# 预测峰值
PublicFunc.progressbar_update(self, 2, 3, Constants.DETECT_RPEAK_PREDICTING_PEAK, 10)
status, info = self.data.predict_Rpeak()
if not status:
PublicFunc.text_output(self.ui, "(2/3)" + info, Constants.TIPS_TYPE_ERROR)
@ -363,11 +354,8 @@ class MainWindow_detect_Rpeak(QMainWindow):
PublicFunc.text_output(self.ui, Constants.DETECT_RPEAK_PEAK_AMOUNT + str(len(self.data.peak)),
Constants.TIPS_TYPE_INFO)
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(3/3)" + Constants.DRAWING_DATA))
self.progressbar.setValue(70)
QApplication.processEvents()
# 绘图
PublicFunc.progressbar_update(self, 3, 3, Constants.DRAWING_DATA, 70)
status, info = self.__plot__()
if not status:
PublicFunc.text_output(self.ui, "(3/3)" + info, Constants.TIPS_TYPE_ERROR)
@ -389,11 +377,8 @@ class MainWindow_detect_Rpeak(QMainWindow):
if reply == QMessageBox.Yes:
PublicFunc.__disableAllButton__(self, ButtonState)
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(1/1)" + Constants.SAVING_DATA))
self.progressbar.setValue(0)
QApplication.processEvents()
# 保存
PublicFunc.progressbar_update(self, 1, 1, Constants.SAVING_DATA, 0)
# status, info = self.data.save()
total_rows = len(DataFrame(self.data.peak.reshape(-1)))
chunk_size = ConfigParams.DETECT_RPEAK_SAVE_CHUNK_SIZE

View File

@ -2,17 +2,21 @@ from gc import collect
from pathlib import Path
import matplotlib.pyplot as plt
from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication
from matplotlib import gridspec
from PySide6.QtCore import QTimer, QCoreApplication
from PySide6.QtGui import QAction, QFont
from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication, QTableWidgetItem, QTableWidget
from matplotlib import gridspec, patches
from matplotlib.backends.backend_qt import NavigationToolbar2QT
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg
from numpy import append, delete, arange
from overrides import overrides
from pandas import read_csv, DataFrame
from scipy.signal import resample
from scipy.signal import find_peaks
from yaml import dump, load, FullLoader
from func.utils.PublicFunc import PublicFunc
from func.utils.Constants import Constants, ConfigParams
from func.Filters.Preprocessing import data_preprocess_for_label_check
from ui.MainWindow.MainWindow_label_check import Ui_MainWindow_label_check
from ui.setting.label_check_input_setting import Ui_MainWindow_label_check_input_setting
@ -109,7 +113,7 @@ class SettingWindow(QMainWindow):
"Mode": self.mode
})
else:
raise ValueError
raise ValueError("模式不存在")
# 数据回显
self.ui.spinBox_input_freq_signal.setValue(Config["InputConfig"]["Freq"])
@ -125,7 +129,7 @@ class SettingWindow(QMainWindow):
self.ui.doubleSpinBox_bandPassLow.setValue(Config["Filter"]["ECGBandPassLow"])
self.ui.doubleSpinBox_bandPassHigh.setValue(Config["Filter"]["ECGBandPassHigh"])
else:
raise ValueError
raise ValueError("模式不存在")
def __write_config__(self):
@ -143,7 +147,7 @@ class SettingWindow(QMainWindow):
Config["Filter"]["ECGBandPassLow"] = self.ui.doubleSpinBox_bandPassLow.value()
Config["Filter"]["ECGBandPassHigh"] = self.ui.doubleSpinBox_bandPassHigh.value()
else:
raise ValueError
raise ValueError("模式不存在")
# 保存配置到文件
self.config["InputConfig"]["Freq"] = self.ui.spinBox_input_freq_signal.value()
@ -176,7 +180,7 @@ class SettingWindow(QMainWindow):
str(self.ui.spinBox_input_freq_signal.value()) +
ConfigParams.ENDSWITH_TXT))))
else:
raise ValueError
raise ValueError("模式不存在")
class MainWindow_label_check(QMainWindow):
@ -192,8 +196,6 @@ class MainWindow_label_check(QMainWindow):
self.sampID = None
self.data = None
self.original_peak = None
self.corrected_peak = None
self.setting = None
@ -208,11 +210,28 @@ class MainWindow_label_check(QMainWindow):
self.gs = None
self.ax0 = None
self.ax1 = None
self.is_left_button_pressed = None
self.is_right_button_pressed = None
self.line_processed_data_1 = None
self.line_processed_data_2 = None
self.point_peak_original = None
self.point_peak_corrected = None
self.annotation_tableWidget = None
# 初始化自动播放定时器
self.autoplay_xlim_start = None
self.autoplay_xlim_end = None
self.timer_autoplay = QTimer()
self.timer_autoplay.timeout.connect(self.autoplay_move_xlim)
Config.update({
"AutoplayArgs": {
"AutoplayMode": "pause",
"MoveLength": int(self.ui.label_moveLength_preset_1.text()),
"MaxRange": int(self.ui.label_maxRange_preset_1.text()),
"MoveSpeed": int(self.ui.label_moveSpeed_preset_1.text())
}
})
self.msgBox = QMessageBox()
self.msgBox.setWindowTitle(Constants.MAINWINDOW_MSGBOX_TITLE)
@ -230,10 +249,14 @@ class MainWindow_label_check(QMainWindow):
# 初始化画框
self.fig = plt.figure(figsize=(12, 9), dpi=100)
self.canvas = FigureCanvasQTAgg(self.fig)
self.figToolbar = NavigationToolbar2QT(self.canvas)
self.figToolbar = CustomNavigationToolbar(self.canvas, self)
for action in self.figToolbar._actions.values():
action.setEnabled(False)
for action in self.figToolbar.actions():
if action.text() == "Subplots" or action.text() == "Customize":
self.figToolbar.removeAction(action)
self.figToolbar._actions['home'].triggered.connect(self.toggle_home)
self.figToolbar.action_Label_Multiple.triggered.connect(self.toggle_changeLabel)
self.ui.verticalLayout_canvas.addWidget(self.canvas)
self.ui.verticalLayout_canvas.addWidget(self.figToolbar)
self.gs = gridspec.GridSpec(2, 1, height_ratios=[1, 1])
@ -242,17 +265,42 @@ class MainWindow_label_check(QMainWindow):
self.ax0.grid(True)
self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER)
self.ax0.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE)
self.ax1 = self.fig.add_subplot(self.gs[1])
self.ax1 = self.fig.add_subplot(self.gs[1], sharex=self.ax0, sharey=self.ax0)
self.ax1.grid(True)
self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER)
PublicFunc.__resetAllButton__(self, ButtonState)
self.ui.label_mode.setText(self.mode)
self.ui.doubleSpinBox_findpeaks_min_interval.setValue(Config["FindPeaks"]["MinInterval"])
self.ui.doubleSpinBox_findpeaks_min_height.setValue(Config["FindPeaks"]["MinHeight"])
self.ui.spinBox_moveLength.setValue(Config["CustomAutoplayArgs"]["MoveLength"])
self.ui.spinBox_maxRange.setValue(Config["CustomAutoplayArgs"]["MaxRange"])
self.ui.spinBox_moveSpeed.setValue(Config["CustomAutoplayArgs"]["MoveSpeed"])
# self.ui.pushButton_input.clicked.connect(self.__slot_btn_input__)
self.ui.tableWidget_peak_original.setHorizontalHeaderLabels(['Original'])
self.ui.tableWidget_peak_corrected.setHorizontalHeaderLabels(['Corrected'])
self.ui.tableWidget_peak_original.setEditTriggers(QTableWidget.NoEditTriggers)
self.ui.tableWidget_peak_corrected.setEditTriggers(QTableWidget.NoEditTriggers)
self.ui.tableWidget_peak_original.horizontalHeader().setStretchLastSection(True)
self.ui.tableWidget_peak_corrected.horizontalHeader().setStretchLastSection(True)
self.ui.pushButton_input.clicked.connect(self.__slot_btn_input__)
self.ui.pushButton_input_setting.clicked.connect(self.setting.show)
# self.ui.pushButton_save.clicked.connect(self.__slot_btn_save__)
self.ui.pushButton_save.clicked.connect(self.__slot_btn_save__)
self.ui.pushButton_prev_move.clicked.connect(self.__slot_btn_move__)
self.ui.pushButton_pause.clicked.connect(self.__slot_btn_move__)
self.ui.pushButton_next_move.clicked.connect(self.__slot_btn_move__)
self.ui.radioButton_move_preset_1.toggled.connect(self.__change_autoplay_args__)
self.ui.radioButton_move_preset_2.toggled.connect(self.__change_autoplay_args__)
self.ui.radioButton_move_preset_3.toggled.connect(self.__change_autoplay_args__)
self.ui.radioButton_move_custom.toggled.connect(self.__change_autoplay_args__)
self.ui.tableWidget_peak_original.cellDoubleClicked.connect(
self.__slot_tableWidget_on_cell_double_clicked__)
self.ui.tableWidget_peak_corrected.cellDoubleClicked.connect(
self.__slot_tableWidget_on_cell_double_clicked__)
self.ui.doubleSpinBox_findpeaks_min_interval.editingFinished.connect(self.__update_config__)
self.ui.doubleSpinBox_findpeaks_min_height.editingFinished.connect(self.__update_config__)
self.ui.spinBox_moveLength.editingFinished.connect(self.__update_config__)
@ -304,18 +352,13 @@ class MainWindow_label_check(QMainWindow):
sender = self.sender()
if sender == self.ui.pushButton_input:
# self.point_RRIV, = self.ax0.plot(self.data.peak[2:], self.data.RRIV,
# 'r.',
# label=Constants.DETECT_RPEAK_PLOT_LABEL_RRIV)
# self.line_data, = self.ax1.plot(self.data.processed_data,
# color=Constants.PLOT_COLOR_BLUE,
# label=Constants.DETECT_RPEAK_PLOT_LABEL_ECG)
# self.point_peak, = self.ax1.plot(self.data.peak, self.data.processed_data[self.data.peak],
# 'r*',
# label=Constants.DETECT_RPEAK_PLOT_LABEL_R_PEAKS)
# self.line_interval, = self.ax1.plot(self.data.interval,
# color=Constants.PLOT_COLOR_GREEN,
# label=Constants.DETECT_RPEAK_PLOT_LABEL_INTERVAL)
self.ui.spinBox_data_length.setValue(len(self.data.processed_data))
self.line_processed_data_1, = self.ax0.plot(self.data.processed_data,
label=Constants.LABEL_CHECK_PLOT_LABEL_SIGNAL,
color=Constants.PLOT_COLOR_BLUE)
self.line_processed_data_2, = self.ax1.plot(self.data.processed_data,
label=Constants.LABEL_CHECK_PLOT_LABEL_SIGNAL,
color=Constants.PLOT_COLOR_BLUE)
self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT)
self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT)
status = True
@ -325,6 +368,54 @@ class MainWindow_label_check(QMainWindow):
info = Constants.DRAWING_FAILURE
self.canvas.draw()
self.ax0.autoscale(False)
self.ax1.autoscale(False)
return status, info
def __plot_peaks__(self):
try:
self.point_peak_original, = self.ax0.plot(self.data.original_peak, self.data.original_peak_y, 'ro',
label=Constants.LABEL_CHECK_PLOT_LABEL_PEAK_ORIGINAL)
self.point_peak_corrected, = self.ax1.plot(self.data.corrected_peak, self.data.corrected_peak_y, 'ro',
label=Constants.LABEL_CHECK_PLOT_LABEL_PEAK_CORRECTED)
self.ax1.callbacks.connect('xlim_changed', lambda ax: self.on_xlim_change(ax))
self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT)
self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT)
except Exception as e:
return False, Constants.DRAWING_FAILURE
self.canvas.draw()
return True, Constants.DRAWING_FINISHED
def __redraw_peaks__(self):
self.point_peak_corrected.remove()
self.point_peak_corrected, = self.ax1.plot(self.data.corrected_peak, self.data.corrected_peak_y, 'ro',
label=Constants.LABEL_CHECK_PLOT_LABEL_PEAK_CORRECTED)
self.canvas.draw()
def __update_tableWidget_and_info__(self):
if self.data.original_peak is None or self.data.corrected_peak is None:
return False, Constants.LABEL_CHECK_FAILURE_REASON["Peak_Not_Exist"]
try:
self.ui.tableWidget_peak_original.setRowCount(len(self.data.original_peak))
self.ui.spinBox_peak_length_original.setValue(len(self.data.original_peak))
for row, value in enumerate(self.data.original_peak):
item = QTableWidgetItem(str(value).strip())
self.ui.tableWidget_peak_original.setItem(row, 0, item)
self.ui.tableWidget_peak_corrected.setRowCount(len(self.data.corrected_peak))
self.ui.spinBox_peak_length_corrected.setValue(len(self.data.corrected_peak))
for row, value in enumerate(self.data.corrected_peak):
item = QTableWidgetItem(str(value).strip())
self.ui.tableWidget_peak_corrected.setItem(row, 0, item)
status = True
info = Constants.UPDATING_FINISHED
except Exception:
status = False
info = Constants.UPDATING_FAILURE
return status, info
def __update_config__(self):
@ -335,6 +426,459 @@ class MainWindow_label_check(QMainWindow):
Config["CustomAutoplayArgs"]["MaxRange"] = self.ui.spinBox_maxRange.value()
Config["CustomAutoplayArgs"]["MoveSpeed"] = self.ui.spinBox_moveSpeed.value()
def __slot_btn_input__(self):
PublicFunc.__disableAllButton__(self, ButtonState)
# 清空画框
if self.line_processed_data_1 and self.line_processed_data_2 and self.point_peak_original and self.point_peak_corrected:
try:
self.line_processed_data_1.remove()
self.line_processed_data_2.remove()
self.point_peak_original.remove()
self.point_peak_corrected.remove()
except ValueError:
pass
self.canvas.draw()
self.data = Data()
# 导入数据
PublicFunc.progressbar_update(self, 1, 6, Constants.INPUTTING_DATA, 0)
status, info = self.data.open_file()
if not status:
PublicFunc.text_output(self.ui, "(1/6)" + info, Constants.TIPS_TYPE_ERROR)
PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR)
PublicFunc.finish_operation(self, ButtonState)
return
else:
PublicFunc.text_output(self.ui, "(1/6)" + info, Constants.TIPS_TYPE_INFO)
# 获取存档
PublicFunc.progressbar_update(self, 2, 6, Constants.LABEL_CHECK_LOADING_ARCHIVE, 20)
status, info = self.data.get_archive()
if not status:
PublicFunc.text_output(self.ui, "(2/6)" + info, Constants.TIPS_TYPE_ERROR)
PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR)
PublicFunc.finish_operation(self, ButtonState)
return
else:
PublicFunc.text_output(self.ui, "(2/6)" + info, Constants.TIPS_TYPE_INFO)
# 数据预处理
PublicFunc.progressbar_update(self, 3, 6, Constants.LABEL_CHECK_PROCESSING_DATA, 30)
status, info = self.data.preprocess()
if not status:
PublicFunc.text_output(self.ui, "(3/6)" + info, Constants.TIPS_TYPE_ERROR)
PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR)
PublicFunc.finish_operation(self, ButtonState)
return
else:
PublicFunc.text_output(self.ui, "(3/6)" + info, Constants.TIPS_TYPE_INFO)
# 更新表格
PublicFunc.progressbar_update(self, 4, 6, Constants.UPDATING_TABLEWIDGET_AND_INFO, 50)
status, info = self.__update_tableWidget_and_info__()
if not status:
PublicFunc.text_output(self.ui, "(4/6)" + info, Constants.TIPS_TYPE_ERROR)
PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR)
PublicFunc.finish_operation(self, ButtonState)
return
else:
PublicFunc.text_output(self.ui, "(4/6)" + info, Constants.TIPS_TYPE_INFO)
# 绘图
PublicFunc.progressbar_update(self, 5, 6, Constants.DRAWING_DATA, 60)
status, info = self.__plot__()
if not status:
PublicFunc.text_output(self.ui, "(5/6)" + info, Constants.TIPS_TYPE_ERROR)
PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR)
PublicFunc.finish_operation(self, ButtonState)
return
else:
PublicFunc.text_output(self.ui, "(5/6)" + info, Constants.TIPS_TYPE_INFO)
# 绘点
PublicFunc.progressbar_update(self, 6, 6, Constants.DRAWING_DATA, 80)
status, info = self.__plot_peaks__()
if not status:
PublicFunc.text_output(self.ui, "(6/6)" + info, Constants.TIPS_TYPE_ERROR)
PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR)
PublicFunc.finish_operation(self, ButtonState)
return
else:
PublicFunc.text_output(self.ui, "(6/6)" + info, Constants.TIPS_TYPE_INFO)
MainWindow_label_check.__reset__()
self.canvas.mpl_connect("motion_notify_event", self.on_motion)
self.figToolbar.action_Label_Multiple.setEnabled(True)
for action in self.figToolbar._actions.values():
action.setEnabled(True)
ButtonState["Current"]["pushButton_input"] = False
ButtonState["Current"]["pushButton_input_setting"] = False
ButtonState["Current"]["pushButton_prev_move"] = True
ButtonState["Current"]["pushButton_next_move"] = True
ButtonState["Current"]["pushButton_pause"] = True
ButtonState["Current"]["pushButton_save"] = True
PublicFunc.finish_operation(self, ButtonState)
def __slot_btn_save__(self):
reply = QMessageBox.question(self, Constants.QUESTION_TITLE,
Constants.QUESTION_CONTENT + Config["Path"]["Save"],
QMessageBox.Yes | QMessageBox.No,
QMessageBox.Yes)
if reply == QMessageBox.Yes:
PublicFunc.__disableAllButton__(self, ButtonState)
# 保存
PublicFunc.progressbar_update(self, 1, 1, Constants.SAVING_DATA, 0)
# status, info = self.data.save()
total_rows = len(DataFrame(self.data.corrected_peak.reshape(-1)))
chunk_size = ConfigParams.LABEL_CHECK_SAVE_CHUNK_SIZE
with open(Config["Path"]["Save"], 'w') as f:
for start in range(0, total_rows, chunk_size):
end = min(start + chunk_size, total_rows)
chunk = DataFrame(self.data.corrected_peak.reshape(-1)).iloc[start:end]
status, info = self.data.save(chunk)
progress = int((end / total_rows) * 100)
self.progressbar.setValue(progress)
QApplication.processEvents()
if not status:
PublicFunc.text_output(self.ui, "(1/1)" + info, Constants.TIPS_TYPE_ERROR)
PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR)
PublicFunc.finish_operation(self, ButtonState)
return
else:
PublicFunc.text_output(self.ui, "(1/1)" + info, Constants.TIPS_TYPE_INFO)
PublicFunc.msgbox_output(self, info, Constants.TIPS_TYPE_INFO)
PublicFunc.finish_operation(self, ButtonState)
def __slot_btn_move__(self):
if self.data is None:
return
sender = self.sender()
if sender == self.ui.pushButton_prev_move:
Config["AutoplayArgs"]["AutoplayMode"] = "prev"
self.autoplay_xlim_start = int(self.ax0.get_xlim()[1] - Config["AutoplayArgs"]["MaxRange"])
self.autoplay_xlim_end = int(self.ax0.get_xlim()[1])
if self.autoplay_xlim_end > len(self.data.processed_data):
self.autoplay_xlim_start = int(len(self.data.processed_data) - Config["AutoplayArgs"]["MaxRange"])
self.autoplay_xlim_end = int(len(self.data.processed_data))
self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end)
self.canvas.draw()
self.timer_autoplay.start(Config["AutoplayArgs"]["MoveSpeed"])
PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_PREV_MOVE, Constants.TIPS_TYPE_INFO)
elif sender == self.ui.pushButton_next_move:
Config["AutoplayArgs"]["AutoplayMode"] = "next"
self.autoplay_xlim_start = int(self.ax0.get_xlim()[0])
self.autoplay_xlim_end = int(self.ax0.get_xlim()[0] + Config["AutoplayArgs"]["MaxRange"])
if self.autoplay_xlim_start < 0:
self.autoplay_xlim_start = 0
self.autoplay_xlim_end = 0 + Config["AutoplayArgs"]["MaxRange"]
self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end)
self.canvas.draw()
self.timer_autoplay.start(Config["AutoplayArgs"]["MoveSpeed"])
PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_NEXT_MOVE, Constants.TIPS_TYPE_INFO)
elif sender == self.ui.pushButton_pause:
Config["AutoplayArgs"]["AutoplayMode"] = "pause"
self.timer_autoplay.stop()
PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_PAUSE, Constants.TIPS_TYPE_INFO)
def __change_autoplay_args__(self):
sender = self.sender()
if sender == self.ui.radioButton_move_preset_1 and self.ui.radioButton_move_preset_1.isChecked():
Config["AutoplayArgs"]["MoveLength"] = int(self.ui.label_moveLength_preset_1.text())
Config["AutoplayArgs"]["MaxRange"] = int(self.ui.label_maxRange_preset_1.text())
Config["AutoplayArgs"]["MoveSpeed"] = int(self.ui.label_moveSpeed_preset_1.text())
PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_SWITCH_PRESET_1, Constants.TIPS_TYPE_INFO)
elif sender == self.ui.radioButton_move_preset_2 and self.ui.radioButton_move_preset_2.isChecked():
Config["AutoplayArgs"]["MoveLength"] = int(self.ui.label_moveLength_preset_2.text())
Config["AutoplayArgs"]["MaxRange"] = int(self.ui.label_maxRange_preset_2.text())
Config["AutoplayArgs"]["MoveSpeed"] = int(self.ui.label_moveSpeed_preset_2.text())
PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_SWITCH_PRESET_2, Constants.TIPS_TYPE_INFO)
elif sender == self.ui.radioButton_move_preset_3 and self.ui.radioButton_move_preset_3.isChecked():
Config["AutoplayArgs"]["MoveLength"] = int(self.ui.label_moveLength_preset_3.text())
Config["AutoplayArgs"]["MaxRange"] = int(self.ui.label_maxRange_preset_3.text())
Config["AutoplayArgs"]["MoveSpeed"] = int(self.ui.label_moveSpeed_preset_3.text())
PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_SWITCH_PRESET_3, Constants.TIPS_TYPE_INFO)
elif sender == self.ui.radioButton_move_custom and self.ui.radioButton_move_custom.isChecked():
Config["AutoplayArgs"]["MoveLength"] = int(self.ui.spinBox_moveLength.value())
Config["AutoplayArgs"]["MaxRange"] = int(self.ui.spinBox_maxRange.value())
Config["AutoplayArgs"]["MoveSpeed"] = int(self.ui.spinBox_moveSpeed.value())
PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_SWITCH_CUSTOM, Constants.TIPS_TYPE_INFO)
if Config["AutoplayArgs"]["AutoplayMode"] == "next":
self.autoplay_xlim_start = int(self.ax0.get_xlim()[0])
self.autoplay_xlim_end = int(self.ax0.get_xlim()[0] + Config["AutoplayArgs"]["MaxRange"])
if self.autoplay_xlim_start < 0:
self.autoplay_xlim_start = 0
self.autoplay_xlim_end = 0 + Config["AutoplayArgs"]["MaxRange"]
self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end)
self.timer_autoplay.start(Config["AutoplayArgs"]["MoveSpeed"])
elif Config["AutoplayArgs"]["AutoplayMode"] == "prev":
self.autoplay_xlim_start = int(self.ax0.get_xlim()[1] - Config["AutoplayArgs"]["MaxRange"])
self.autoplay_xlim_end = int(self.ax0.get_xlim()[1])
if self.autoplay_xlim_end > len(self.data.processed_data):
self.autoplay_xlim_start = int(self.data.processed_data) - Config["AutoplayArgs"]["MaxRange"]
self.autoplay_xlim_end = int(self.data.processed_data)
self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end)
self.timer_autoplay.start(Config["AutoplayArgs"]["MoveSpeed"])
elif Config["AutoplayArgs"]["AutoplayMode"] == "pause":
self.timer_autoplay.stop()
def __slot_tableWidget_on_cell_double_clicked__(self, row, col):
if Config["AutoplayArgs"]["AutoplayMode"] != "pause":
self.ui.pushButton_pause.click()
sender = self.sender()
if sender == self.ui.tableWidget_peak_original:
x = float(self.ui.tableWidget_peak_original.item(row, col).text())
elif sender == self.ui.tableWidget_peak_corrected:
x = float(self.ui.tableWidget_peak_corrected.item(row, col).text())
else:
raise ValueError("表格跳转参数不存在")
self.ax0.set_xlim(x - 5000, x + 5000)
self.annotation_tableWidget = self.ax0.annotate(f'x={int(x)}', xy=(int(x), self.ax0.get_ylim()[0]),
xytext=(int(x), self.ax0.get_ylim()[0] + (self.ax0.get_ylim()[1] - self.ax0.get_ylim()[0]) * 0.1),
arrowprops=dict(facecolor=Constants.PLOT_COLOR_BLACK, shrink=0.1))
self.canvas.draw()
PublicFunc.text_output(self.ui, f"{Constants.LABEL_CHECK_JUMP_X_INDEX}{str(int(x))}", Constants.TIPS_TYPE_INFO)
def on_xlim_change(self, event_ax):
try:
if self.annotation_tableWidget:
self.annotation_tableWidget.remove()
except AttributeError:
pass
self.annotation_tableWidget = None
def autoplay_move_xlim(self):
if Config["AutoplayArgs"]["AutoplayMode"] == "prev" and self.autoplay_xlim_start < 0:
Config["AutoplayArgs"]["AutoplayMode"] = "pause"
self.timer_autoplay.stop()
elif Config["AutoplayArgs"]["AutoplayMode"] == "next" and self.autoplay_xlim_end > len(self.data.processed_data):
Config["AutoplayArgs"]["AutoplayMode"] = "pause"
self.timer_autoplay.stop()
else:
if Config["AutoplayArgs"]["AutoplayMode"] == "next":
self.autoplay_xlim_start += Config["AutoplayArgs"]["MoveLength"]
self.autoplay_xlim_end += Config["AutoplayArgs"]["MoveLength"]
elif Config["AutoplayArgs"]["AutoplayMode"] == "prev":
self.autoplay_xlim_start -= Config["AutoplayArgs"]["MoveLength"]
self.autoplay_xlim_end -= Config["AutoplayArgs"]["MoveLength"]
self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end)
self.canvas.draw()
def on_motion(self, event):
if event.inaxes and self.ui.checkBox_show_reference_line.isChecked():
# Clear previous reference lines and temporary points
for line in self.ax0.lines[1:]:
if (line.get_label() == "vline" or
line.get_label() == "hline"):
line.remove()
for line in self.ax1.lines[1:]:
if (line.get_label() == "vline" or
line.get_label() == "hline"):
line.remove()
# Draw vertical and horizontal reference lines
self.ax0.axvline(event.xdata, color=Constants.PLOT_COLOR_GRAY, linestyle='--', label="vline")
self.ax0.axhline(event.ydata, color=Constants.PLOT_COLOR_GRAY, linestyle='--', label="hline")
self.ax1.axvline(event.xdata, color=Constants.PLOT_COLOR_GRAY, linestyle='--', label="vline")
self.ax1.axhline(event.ydata, color=Constants.PLOT_COLOR_GRAY, linestyle='--', label="hline")
self.canvas.draw()
def toggle_home(self):
if Config["AutoplayArgs"]["AutoplayMode"] != "pause":
self.ui.pushButton_pause.click()
self.ax0.autoscale(True)
self.ax1.autoscale(True)
self.ax1.relim()
self.ax1.autoscale_view()
self.canvas.draw()
self.ax0.autoscale(False)
self.ax1.autoscale(False)
PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_RECOVER_SCALE, Constants.TIPS_TYPE_INFO)
def toggle_changeLabel(self, state):
if state:
self.deactivate_figToolbar_buttons()
self.figToolbar.action_Label_Multiple.setChecked(True)
self.figToolbar.cid_mouse_press = self.canvas.mpl_connect(
"button_press_event", self.on_click)
self.figToolbar.cid_mouse_release = self.canvas.mpl_connect(
"button_release_event", self.on_release)
self.figToolbar.cid_mouse_hold = self.canvas.mpl_connect(
"motion_notify_event", self.on_hold)
else:
if self.figToolbar.cid_mouse_press is not None:
self.canvas.mpl_disconnect(self.figToolbar.cid_mouse_press)
self.figToolbar.cid_mouse_press = None
if self.figToolbar.cid_mouse_release is not None:
self.canvas.mpl_disconnect(self.figToolbar.cid_mouse_release)
self.figToolbar.cid_mouse_release = None
if self.figToolbar.cid_mouse_hold:
self.canvas.mpl_disconnect(self.figToolbar.cid_mouse_hold)
self.figToolbar.cid_mouse_hold = None
def deactivate_figToolbar_buttons(self):
for action in self.figToolbar._actions.values():
if action.isChecked() == True:
if action == self.figToolbar._actions['pan']:
self.figToolbar.pan()
if action == self.figToolbar._actions['zoom']:
self.figToolbar.zoom()
def on_click(self, event):
if self.figToolbar.action_Label_Multiple.isChecked():
if event.button == 1 or event.button == 3: # 左键或右键
if event.button == 1:
self.is_left_button_pressed = True
elif event.button == 3:
self.is_right_button_pressed = True
self.figToolbar.rect_start_x = event.xdata
# 如果矩形patch已存在先移除
if self.figToolbar.rect_patch_ax0 is not None and self.figToolbar.rect_patch_ax1 is not None:
self.figToolbar.rect_patch_ax0.remove()
self.figToolbar.rect_patch_ax0 = None
self.figToolbar.rect_patch_ax1.remove()
self.figToolbar.rect_patch_ax1 = None
self.canvas.draw()
def on_release(self, event):
if self.figToolbar.action_Label_Multiple.isChecked():
if self.figToolbar.rect_start_x is not None:
self.figToolbar.rect_end_x = event.xdata
if self.figToolbar.rect_start_x is not None and self.figToolbar.rect_end_x is not None:
if self.figToolbar.rect_start_x < self.figToolbar.rect_end_x:
rect_left = self.figToolbar.rect_start_x
rect_right = self.figToolbar.rect_end_x
elif self.figToolbar.rect_start_x > self.figToolbar.rect_end_x:
rect_left = self.figToolbar.rect_end_x
rect_right = self.figToolbar.rect_start_x
else:
rect_left = self.figToolbar.rect_start_x
rect_right = self.figToolbar.rect_start_x
else:
rect_left = self.figToolbar.rect_start_x
rect_right = self.figToolbar.rect_start_x
if event.button == 1 and self.is_left_button_pressed:
self.is_left_button_pressed = False
if rect_left < 0:
rect_left = 0
elif rect_left >= len(self.data.processed_data):
rect_left = 0
rect_right = 0
if rect_right >= len(self.data.processed_data):
rect_right = len(self.data.processed_data) - 1
elif rect_right < 0:
rect_left = 0
rect_right = 0
selected_area_for_add_points = self.data.processed_data[int(rect_left):int(rect_right)]
peaks_idx, _ = find_peaks(selected_area_for_add_points,
height=Config["FindPeaks"]["MinHeight"],
distance=Config["FindPeaks"]["MinInterval"])
peaks_idx = peaks_idx + int(rect_left)
if len(peaks_idx) != 0:
PublicFunc.text_output(self.ui, f"{Constants.LABEL_CHECK_ADD_POINTS_SUCCESSFULLY}{peaks_idx}",
Constants.TIPS_TYPE_INFO)
else:
PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_NO_POINT_IN_THE_INTERVAL,
Constants.TIPS_TYPE_INFO)
self.data.corrected_peak = append(self.data.corrected_peak, peaks_idx)
self.data.corrected_peak_y = append(self.data.corrected_peak_y, self.data.processed_data[peaks_idx])
self.__redraw_peaks__()
elif event.button == 3 and self.is_right_button_pressed:
self.is_right_button_pressed = False
left_label2_to_delete = self.data.corrected_peak - rect_left
right_label2_to_delete = self.data.corrected_peak - rect_right
left_label2_to_delete_idx = len(left_label2_to_delete[left_label2_to_delete < 0])
right_label2_to_delete_idx = len(right_label2_to_delete[right_label2_to_delete < 0])
if left_label2_to_delete_idx != right_label2_to_delete_idx:
PublicFunc.text_output(self.ui, f"{Constants.LABEL_CHECK_REMOVE_POINTS_SUCCESSFULLY}{self.data.corrected_peak[left_label2_to_delete_idx:right_label2_to_delete_idx]}",
Constants.TIPS_TYPE_INFO)
else:
PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_NO_POINT_IN_THE_INTERVAL,
Constants.TIPS_TYPE_INFO)
self.data.corrected_peak = delete(self.data.corrected_peak, arange(left_label2_to_delete_idx, right_label2_to_delete_idx))
self.data.corrected_peak_y = delete(self.data.corrected_peak_y, arange(left_label2_to_delete_idx, right_label2_to_delete_idx))
self.__redraw_peaks__()
self.figToolbar.rect_start_x = None
self.figToolbar.rect_end_x = None
self.data.corrected_peak.sort()
self.data.corrected_peak_y = [self.data.processed_data[x] for x in self.data.corrected_peak]
self.__update_tableWidget_and_info__()
DataFrame(self.data.corrected_peak).to_csv(self.data.file_path_save,
index=False, header=False)
# 移除矩形patch
if self.figToolbar.rect_patch_ax0 is not None and self.figToolbar.rect_patch_ax1 is not None:
self.figToolbar.rect_patch_ax0.remove()
self.figToolbar.rect_patch_ax0 = None
self.figToolbar.rect_patch_ax1.remove()
self.figToolbar.rect_patch_ax1 = None
self.canvas.draw()
def on_hold(self, event):
if self.figToolbar.rect_start_x is not None and event.xdata is not None:
self.figToolbar.rect_end_x = event.xdata
# 如果矩形patch不存在则创建一个新的
if self.figToolbar.rect_patch_ax0 is None:
if self.is_left_button_pressed:
self.figToolbar.rect_patch_ax0 = patches.Rectangle((0, 0), 1, 1, fill=True,
alpha=ConfigParams.LABEL_CHECK_LABEL_TRANSPARENCY,
color=Constants.PLOT_COLOR_PINK)
elif self.is_right_button_pressed:
self.figToolbar.rect_patch_ax0 = patches.Rectangle((0, 0), 1, 1, fill=True,
alpha=ConfigParams.LABEL_CHECK_LABEL_TRANSPARENCY,
color=Constants.PLOT_COLOR_RED)
self.ax0.add_patch(self.figToolbar.rect_patch_ax0)
# 如果矩形patch不存在则创建一个新的
if self.figToolbar.rect_patch_ax1 is None:
if self.is_left_button_pressed:
self.figToolbar.rect_patch_ax1 = patches.Rectangle((0, 0), 1, 1, fill=True,
alpha=ConfigParams.LABEL_CHECK_LABEL_TRANSPARENCY,
color=Constants.PLOT_COLOR_PINK)
elif self.is_right_button_pressed:
self.figToolbar.rect_patch_ax1 = patches.Rectangle((0, 0), 1, 1, fill=True,
alpha=ConfigParams.LABEL_CHECK_LABEL_TRANSPARENCY,
color=Constants.PLOT_COLOR_RED)
self.ax1.add_patch(self.figToolbar.rect_patch_ax1)
# 更新矩形patch的位置和大小
x_start = self.figToolbar.rect_start_x
x_end = self.figToolbar.rect_end_x
rect_down = min(self.ax0.get_ylim()[0], self.ax1.get_ylim()[0]) - 1000
rect_up = max(self.ax0.get_ylim()[1], self.ax1.get_ylim()[1]) + 1000
self.figToolbar.rect_patch_ax0.set_xy((min(x_start, x_end), rect_down))
self.figToolbar.rect_patch_ax0.set_width(abs(x_end - x_start))
self.figToolbar.rect_patch_ax0.set_height(rect_up - rect_down)
self.figToolbar.rect_patch_ax1.set_xy((min(x_start, x_end), rect_down))
self.figToolbar.rect_patch_ax1.set_width(abs(x_end - x_start))
self.figToolbar.rect_patch_ax1.set_height(rect_up - rect_down)
self.canvas.draw()
class Data:
@ -345,4 +889,142 @@ class Data:
self.raw_data = None
self.processed_data = None
self.peak = None
self.original_peak = None
self.original_peak_y = None
self.corrected_peak = None
self.corrected_peak_y = None
def open_file(self):
if (not Path(Config["Path"]["Input_Signal"]).exists()) or (not Path(Config["Path"]["Input_Peak"]).exists()):
return False, Constants.INPUT_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Data_Path_Not_Exist"]
try:
self.raw_data = read_csv(self.file_path_input_signal,
encoding=ConfigParams.UTF8_ENCODING,
header=None).to_numpy().reshape(-1)
self.original_peak = read_csv(self.file_path_input_peak,
encoding=ConfigParams.UTF8_ENCODING,
header=None).to_numpy().reshape(-1)
except Exception:
return False, Constants.INPUT_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Read_Data_Exception"]
return True, Constants.INPUT_FINISHED
def get_archive(self):
if not Path(Config["Path"]["Save"]).exists():
self.corrected_peak = self.original_peak
return True, Constants.LABEL_CHECK_ARCHIVE_NOT_EXIST
else:
self.corrected_peak = read_csv(self.file_path_save,
encoding=ConfigParams.UTF8_ENCODING,
header=None).to_numpy().reshape(-1)
return True, Constants.LABEL_CHECK_ARCHIVE_EXIST
def preprocess(self):
if self.raw_data is None:
return False, Constants.LABEL_CHECK_PROCESS_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Raw_Data_Not_Exist"]
try:
if Config["Mode"] == "BCG":
self.processed_data = data_preprocess_for_label_check(self.raw_data,
Config["Filter"]["BCGBandPassOrder"],
Config["Filter"]["BCGBandPassLow"],
Config["Filter"]["BCGBandPassHigh"],
Config["InputConfig"]["Freq"])
elif Config["Mode"] == "ECG":
self.processed_data = data_preprocess_for_label_check(self.raw_data,
Config["Filter"]["ECGBandPassOrder"],
Config["Filter"]["ECGBandPassLow"],
Config["Filter"]["ECGBandPassHigh"],
Config["InputConfig"]["Freq"])
else:
raise ValueError("模式不存在")
self.original_peak_y = [self.processed_data[x] for x in self.original_peak]
self.corrected_peak_y = [self.processed_data[x] for x in self.corrected_peak]
except Exception:
return False, Constants.LABEL_CHECK_PROCESS_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Filter_Exception"]
return True, Constants.LABEL_CHECK_PROCESS_FINISHED
def save(self, chunk):
if self.corrected_peak is None:
return False, Constants.SAVING_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Peak_Not_Exist"]
try:
# DataFrame(self.corrected_peak.reshape(-1)).to_csv(self.file_path_save,
# index=False,
# header=False)
chunk.to_csv(self.file_path_save, mode='a', index=False, header=False)
except Exception:
return False, Constants.SAVING_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Save_Exception"]
return True, Constants.SAVING_FINISHED
class CustomNavigationToolbar(NavigationToolbar2QT):
def __init__(self, canvas, parent):
super().__init__(canvas, parent)
# 初始化画框工具栏
self.action_Label_Multiple = QAction(Constants.LABEL_CHECK_ACTION_LABEL_MULTIPLE_NAME, self)
self.action_Label_Multiple.setFont(QFont(ConfigParams.FONT, 14))
self.action_Label_Multiple.setCheckable(True)
self.action_Label_Multiple.setShortcut(QCoreApplication.translate(
"MainWindow",
ConfigParams.LABEL_CHECK_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY))
self.insertAction(self._actions['pan'], self.action_Label_Multiple)
self._actions['pan'].setShortcut(QCoreApplication.translate(
"MainWindow",
ConfigParams.ACTION_PAN_SHORTCUT_KEY))
self._actions['zoom'].setShortcut(QCoreApplication.translate(
"MainWindow",
ConfigParams.ACTION_ZOOM_SHORTCUT_KEY))
# 用于存储事件连接ID
self.cid_mouse_press = None
self.cid_mouse_release = None
self.cid_mouse_hold = None
# 初始化矩形选择区域
self.rect_start_x = None
self.rect_end_x = None
self.rect_patch_ax0 = None # 用于绘制矩形的patch
self.rect_patch_ax1 = None # 用于绘制矩形的patch
def home(self, *args):
pass
def zoom(self, *args):
super().zoom(*args)
self.deactivate_figToorbar_changeLabel_mode()
def pan(self, *args):
super().pan(*args)
self.deactivate_figToorbar_changeLabel_mode()
def deactivate_figToorbar_changeLabel_mode(self):
if self.action_Label_Multiple.isChecked():
self.action_Label_Multiple.setChecked(False)
if self.cid_mouse_press is not None:
self.canvas.mpl_disconnect(self.cid_mouse_press)
self.cid_mouse_press = None
if self.cid_mouse_release is not None:
self.canvas.mpl_disconnect(self.cid_mouse_release)
self.cid_mouse_release = None
if self.cid_mouse_hold is not None:
self.canvas.mpl_disconnect(self.cid_mouse_hold)
self.cid_mouse_hold = None

View File

@ -4,12 +4,14 @@ from PySide6.QtWidgets import QMainWindow, QMessageBox, QFileDialog
from matplotlib import use
from yaml import dump, load, FullLoader
from func.utils.PublicFunc import PublicFunc
from ui.MainWindow.MainWindow_menu import Ui_Signal_Label
from func.Module_preprocess import MainWindow_preprocess
from func.Module_detect_Jpeak import MainWindow_detect_Jpeak
from func.Module_detect_Rpeak import MainWindow_detect_Rpeak
from func.Module_label_check import MainWindow_label_check
from func.utils.Constants import Constants, ConfigParams
@ -115,7 +117,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label):
def __slot_btn_label_check__(self):
self.label_check = MainWindow_detect_Rpeak()
self.label_check = MainWindow_label_check()
sender = self.sender()
root_path = self.ui.plainTextEdit_root_path.toPlainText()

View File

@ -100,7 +100,7 @@ class SettingWindow(QMainWindow):
"Mode": self.mode
})
else:
raise ValueError
raise ValueError("模式不存在")
# 数据回显
self.ui.spinBox_input_freq.setValue(Config["InputConfig"]["Freq"])
@ -162,7 +162,7 @@ class SettingWindow(QMainWindow):
str(self.ui.spinBox_output_freq.value()) +
ConfigParams.ENDSWITH_TXT))))
else:
raise ValueError
raise ValueError("模式不存在")
class MainWindow_preprocess(QMainWindow):
@ -235,7 +235,7 @@ class MainWindow_preprocess(QMainWindow):
self.ui.doubleSpinBox_bandPassLow.setValue(Config["Filter"]["ECGBandPassLow"])
self.ui.doubleSpinBox_bandPassHigh.setValue(Config["Filter"]["ECGBandPassHigh"])
else:
raise ValueError
raise ValueError("模式不存在")
self.ui.pushButton_input.clicked.connect(self.__slot_btn_input__)
self.ui.pushButton_input_setting.clicked.connect(self.setting.show)
@ -314,7 +314,7 @@ class MainWindow_preprocess(QMainWindow):
Config["Filter"]["ECGBandPassLow"] = self.ui.doubleSpinBox_bandPassLow.value()
Config["Filter"]["ECGBandPassHigh"] = self.ui.doubleSpinBox_bandPassHigh.value()
else:
raise ValueError
raise ValueError("模式不存在")
def __slot_btn_input__(self):
@ -329,12 +329,10 @@ class MainWindow_preprocess(QMainWindow):
pass
self.canvas.draw()
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(1/1)" + Constants.INPUTTING_DATA))
self.progressbar.setValue(0)
QApplication.processEvents()
self.data = Data()
# 导入数据
self.data = Data()
PublicFunc.progressbar_update(self, 1, 1, Constants.INPUTTING_DATA, 0)
status, info = self.data.open_file()
if not status:
PublicFunc.text_output(self.ui, "(1/1)" + info, Constants.TIPS_TYPE_ERROR)
@ -351,11 +349,8 @@ class MainWindow_preprocess(QMainWindow):
PublicFunc.__disableAllButton__(self, ButtonState)
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(1/2)" + Constants.PREPROCESS_PROCESSING_DATA))
self.progressbar.setValue(0)
QApplication.processEvents()
# 数据预处理
PublicFunc.progressbar_update(self, 1, 2, Constants.PREPROCESS_PROCESSING_DATA, 0)
status, info = self.data.preprocess()
if not status:
PublicFunc.text_output(self.ui, "(1/2)" + info, Constants.TIPS_TYPE_ERROR)
@ -365,11 +360,8 @@ class MainWindow_preprocess(QMainWindow):
else:
PublicFunc.text_output(self.ui, "(1/2)" + info, Constants.TIPS_TYPE_INFO)
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(2/2)" + Constants.DRAWING_DATA))
self.progressbar.setValue(50)
QApplication.processEvents()
# 绘图
PublicFunc.progressbar_update(self, 2, 2, Constants.DRAWING_DATA, 50)
status, info = self.__plot__()
if not status:
PublicFunc.text_output(self.ui, "(2/2)" + info, Constants.TIPS_TYPE_ERROR)
@ -391,11 +383,8 @@ class MainWindow_preprocess(QMainWindow):
if reply == QMessageBox.Yes:
PublicFunc.__disableAllButton__(self, ButtonState)
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg("(1/1)" + Constants.SAVING_DATA))
self.progressbar.setValue(0)
QApplication.processEvents()
# 保存
PublicFunc.progressbar_update(self, 1, 1, Constants.SAVING_DATA, 0)
# status, info = self.data.save()
total_rows = len(DataFrame(self.data.processed_data.reshape(-1)))
chunk_size = ConfigParams.PREPROCESS_SAVE_CHUNK_SIZE
@ -467,7 +456,7 @@ class Data:
order=Config["Filter"]["ECGBandPassOrder"],
sample_rate=Config["OutputConfig"]["Freq"])
else:
raise ValueError
raise ValueError("模式不存在")
except Exception:
return False, Constants.PREPROCESS_PROCESS_FAILURE + Constants.PREPROCESS_FAILURE_REASON["Filter_Exception"]

View File

@ -124,6 +124,8 @@ class ConfigParams:
LABEL_CHECK_INPUT_RPEAK_FILENAME: str = "final_Rpeak"
LABEL_CHECK_SAVE_RPEAK_FILENAME: str = "final_Rpeak_corrected"
LABEL_CHECK_SAVE_CHUNK_SIZE: int = 100
LABEL_CHECK_LABEL_TRANSPARENCY: float = 0.2
LABEL_CHECK_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY: str = "Z"
# 体动标注
@ -156,35 +158,6 @@ class ConfigParams:
APPROXIMATELY_ALIGN_BUTTERHIGHPASSFREQ_DEFAULT: float = 0.70
APPROXIMATELY_ALIGN_APPLYFREQ_DEFAULT: float = 5
# 人工纠正
LABEL_CHECK_INPUT_BCG_FILENAME: str = "DSbcg_sig_"
LABEL_CHECK_INPUT_JPEAK_FILENAME: str = "JPeak_revise"
LABEL_CHECK_SAVE_JPEAK_FILENAME: str = "JPeak_revise_corrected"
LABEL_CHECK_INPUT_ECG_FILENAME: str = "ECG_filter_"
LABEL_CHECK_INPUT_RPEAK_FILENAME: str = "final_Rpeak"
LABEL_CHECK_SAVE_RPEAK_FILENAME: str = "final_Rpeak_corrected"
LABEL_CHECK_INPUT_DEFAULT_FS: int = 1000
LABEL_CHECK_DATA1_FILTER_ORDER_DEFAULT: int = 2
LABEL_CHECK_DATA1_BANDPASS_LOW_DEFAULT: int = 2
LABEL_CHECK_DATA1_BANDPASS_HIGH_DEFAULT: int = 10
LABEL_CHECK_DATA2_FILTER_ORDER_DEFAULT: int = 2
LABEL_CHECK_DATA2_BANDPASS_LOW_DEFAULT: int = 2
LABEL_CHECK_DATA2_BANDPASS_HIGH_DEFAULT: int = 15
LABEL_CHECK_FINDPEAKS_MIN_INTERVAL_DEFAULT: int = 1000
LABEL_CHECK_FINDPEAKS_MIN_HEIGHT_DEFAULT: int = 0.5
LABEL_CHECK_MOVELENGTH_DEFAULT: int = 15000
LABEL_CHECK_MAXRANGE_DEFAULT: int = 60000
LABEL_CHECK_MOVESPEED_DEFAULT: int = 1000
LABEL_CHECK_FILTER: str = "bandpass"
LABEL_CHECK_LABEL_TRANSPARENCY: float = 0.2
LABEL_CHECK_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY: str = "Z"
# 体动打标
ARTIFACT_LABEL_INPUT_BCG_FILENAME: str = "BCG_sync_"
ARTIFACT_LABEL_INPUT_XINXIAO_FILENAME: str = "orgBcg_sync_"

View File

@ -19,6 +19,10 @@ class Constants:
DRAWING_FINISHED: str = "绘制完成"
DRAWING_FAILURE: str = "绘制失败"
UPDATING_TABLEWIDGET_AND_INFO: str = "正在更新表格和信息"
UPDATING_FINISHED: str = "更新完成"
UPDATING_FAILURE: str = "更新失败"
SAVING_DATA: str = "正在保存数据"
SAVING_FINISHED: str = "保存完成"
SAVING_FAILURE: str = "保存失败"
@ -158,22 +162,38 @@ class Constants:
LABEL_CHECK_PROCESS_FINISHED: str = "处理完成"
LABEL_CHECK_PROCESS_FAILURE: str = "处理失败"
LABEL_CHECK_LOADING_ARCHIVE: str = "正在获取历史存档"
LABEL_CHECK_ARCHIVE_EXIST: str = "找到历史存档,成功读取"
LABEL_CHECK_ARCHIVE_NOT_EXIST: str = "未找到历史存档,创建新存档"
LABEL_CHECK_FAILURE_REASON = {
"Data_Path_Not_Exist": "(数据路径不存在)",
"Read_Data_Exception": "(读取数据异常)",
"Method_Not_Exist": "(检测方法不存在)",
"Read_Method_Exception": "(读取方法异常)",
"Predict_Exception": "(峰值预测异常)",
"Raw_Data_Not_Exist": "(原始数据不存在)",
"Filter_Exception": "(滤波器异常)",
"Processed_Data_Not_Exist": "(处理后数据不存在)",
"Peak_Not_Exist": "预测的峰值不存在)",
"Peak_Not_Exist": "(峰值不存在)",
"Save_Exception": "(保存异常)"
}
LABEL_CHECK_PLOT_LABEL_BCG: str = "Data_Processed"
LABEL_CHECK_PLOT_LABEL_SIGNAL: str = "Data_Processed"
LABEL_CHECK_PLOT_LABEL_PEAK_ORIGINAL: str = "Peaks_Original"
LABEL_CHECK_PLOT_LABEL_PEAK_CORRECTED: str = "Peaks_Corrected"
LABEL_CHECK_PREV_MOVE: str = "向前移动"
LABEL_CHECK_NEXT_MOVE: str = "向后移动"
LABEL_CHECK_PAUSE: str = "暂停移动"
LABEL_CHECK_SWITCH_PRESET_1: str = "变更为预设1"
LABEL_CHECK_SWITCH_PRESET_2: str = "变更为预设2"
LABEL_CHECK_SWITCH_PRESET_3: str = "变更为预设3"
LABEL_CHECK_SWITCH_CUSTOM: str = "变更为自定义,请注意,自定义的参数未经校验,过大或过小的参数可能导致程序异常"
LABEL_CHECK_JUMP_X_INDEX: str = "跳转到x坐标: "
LABEL_CHECK_RECOVER_SCALE: str = "尺度恢复"
LABEL_CHECK_ADD_POINTS_SUCCESSFULLY: str = "成功新增点,横坐标:"
LABEL_CHECK_REMOVE_POINTS_SUCCESSFULLY: str = "成功删除点,横坐标:"
LABEL_CHECK_NO_POINT_IN_THE_INTERVAL: str = "所选区间内无新增或删除点"
LABEL_CHECK_ACTION_LABEL_MULTIPLE_NAME: str = f"批量更改标签({ConfigParams.LABEL_CHECK_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY})"
# 体动标注
@ -198,45 +218,6 @@ class Constants:
APPROXIMATELY_ALIGN_RUNNING: str = "开始执行任务<数据粗同步>"
APPROXIMATELY_RECORD_NOT_FOUND: str = "没有保存记录"
# 人工纠正
LABEL_CHECK_FILES_BCG_NOT_FOUND: str = f"无法找到{ConfigParams.LABEL_CHECK_INPUT_BCG_FILENAME}{ConfigParams.ENDSWITH_TXT}{ConfigParams.LABEL_CHECK_INPUT_JPEAK_FILENAME}{ConfigParams.ENDSWITH_TXT},无法执行<BCG的J峰人工纠正>"
LABEL_CHECK_FILES_BCG_FOUND: str = f"找到{ConfigParams.LABEL_CHECK_INPUT_BCG_FILENAME}{ConfigParams.ENDSWITH_TXT}{ConfigParams.LABEL_CHECK_INPUT_JPEAK_FILENAME}{ConfigParams.ENDSWITH_TXT}"
LABEL_CHECK_FILES_ECG_NOT_FOUND: str = f"无法找到{ConfigParams.LABEL_CHECK_INPUT_ECG_FILENAME}{ConfigParams.ENDSWITH_TXT}{ConfigParams.LABEL_CHECK_INPUT_RPEAK_FILENAME}{ConfigParams.ENDSWITH_TXT},无法执行<ECG的R峰人工纠正>"
LABEL_CHECK_FILES_ECG_FOUND: str = f"找到{ConfigParams.LABEL_CHECK_INPUT_ECG_FILENAME}{ConfigParams.ENDSWITH_TXT}{ConfigParams.LABEL_CHECK_INPUT_RPEAK_FILENAME}{ConfigParams.ENDSWITH_TXT}"
LABEL_CHECK_HISTORICAL_SAVE_FOUND: str = f"找到历史存档文件{ConfigParams.LABEL_CHECK_SAVE_JPEAK_FILENAME}{ConfigParams.ENDSWITH_TXT}{ConfigParams.LABEL_CHECK_SAVE_RPEAK_FILENAME}{ConfigParams.ENDSWITH_TXT},已成功读取"
LABEL_CHECK_RUNNING: str = "开始执行任务<人工纠正>"
LABEL_CHECK_BCG_MODE: str = "BCG_MODE"
LABEL_CHECK_ECG_MODE: str = "ECG_MODE"
LABEL_CHECK_PLOT_LABEL_DATA1: str = "Data 1"
LABEL_CHECK_PLOT_LABEL_DATA2: str = "Data 2"
LABEL_CHECK_PLOT_LABEL_LABEL1: str = "Label 1"
LABEL_CHECK_PLOT_LABEL_LABEL2: str = "Label 2"
LABEL_CHECK_PLOT_LABEL_VLINE: str = "vline"
LABEL_CHECK_PLOT_LABEL_HLINE: str = "hline"
LABEL_CHECK_AUTOPLAY_LEFT: str = "LEFT"
LABEL_CHECK_AUTOPLAY_PAUSE: str = "PAUSE"
LABEL_CHECK_AUTOPLAY_RIGHT: str = "RIGHT"
LABEL_CHECK_AUTOPLAY_LEFT_INFO: str = "开始自动播放-向左"
LABEL_CHECK_AUTOPLAY_PAUSE_INFO: str = "暂停自动播放"
LABEL_CHECK_AUTOPLAY_RIGHT_INFO: str = "开始自动播放-向右"
LABEL_CHECK_AUTOPLAY_PRESET1_INFO: str = "切换到自动播放-预设1"
LABEL_CHECK_AUTOPLAY_PRESET2_INFO: str = "切换到自动播放-预设2"
LABEL_CHECK_AUTOPLAY_PRESET3_INFO: str = "切换到自动播放-预设3"
LABEL_CHECK_AUTOPLAY_PRESET_CUSTOM_INFO: str = "切换到自动播放-自定义"
LABEL_CHECK_AUTOPLAY_PRESET_CUSTOM_WARNING: str = "自定义的输入参数未做任何检查,请斟酌输入参数,否则可能会导致程序异常"
LABEL_CHECK_JUMP_X_INDEX: str = "跳转到x坐标: "
LABEL_CHECK_RECOVER_SCALE: str = "尺度恢复"
LABEL_CHECK_BUTTON_PRESS_EVENT: str = "button_press_event"
LABEL_CHECK_BUTTON_RELEASE_EVENT: str = "button_release_event"
LABEL_CHECK_MOTION_NOTIFY_EVENT: str = "motion_notify_event"
LABEL_CHECK_ADD_POINTS_SUCCESSFULLY: str = "成功新增点,横坐标:"
LABEL_CHECK_REMOVE_POINTS_SUCCESSFULLY: str = "成功删除点,横坐标:"
LABEL_CHECK_NO_POINT_IN_THE_INTERVAL: str = "所选区间内无新增或删除点"
LABEL_CHECK_CUSTOM_NAVIGATIONTOOLBAR_WIDGET_NAME: str = "MainWindow"
LABEL_CHECK_ACTION_LABEL_MULTIPLE_NAME: str = f"批量更改标签({ConfigParams.LABEL_CHECK_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY})"
# 体动打标
ARTIFACT_LABEL_FILES_NOT_FOUND: str = f"无法找到{ConfigParams.ARTIFACT_LABEL_INPUT_BCG_FILENAME}{ConfigParams.ENDSWITH_TXT}{ConfigParams.ARTIFACT_LABEL_INPUT_XINXIAO_FILENAME}{ConfigParams.ENDSWITH_TXT},无法执行<体动标注>"
ARTIFACT_LABEL_FILES_FOUND: str = f"找到{ConfigParams.ARTIFACT_LABEL_INPUT_BCG_FILENAME}{ConfigParams.ENDSWITH_TXT}{ConfigParams.ARTIFACT_LABEL_INPUT_XINXIAO_FILENAME}{ConfigParams.ENDSWITH_TXT}"

View File

@ -154,4 +154,15 @@ class PublicFunc:
mainWindow.progressbar.setValue(100)
QApplication.processEvents()
PublicFunc.__enableAllButton__(mainWindow, buttonState)
PublicFunc.__enableAllButton__(mainWindow, buttonState)
@staticmethod
def progressbar_update(mainWindow, current: int, total: int, msg: str, progressbarState: int):
if current > total:
raise ValueError("当前进度值大于总进度值")
if progressbarState < 0 or progressbarState > 100:
raise ValueError("进度条值的范围应该在[0, 100]")
PublicFunc.statusbar_show_msg(mainWindow, PublicFunc.format_status_msg(f"({str(current)}/{str(total)}){msg}"))
mainWindow.progressbar.setValue(progressbarState)
QApplication.processEvents()