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 matplotlib.backends.backend_qt import NavigationToolbar2QT from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg from overrides import overrides from pandas import read_csv, DataFrame from scipy.signal import resample from yaml import dump, load, FullLoader from func.utils.PublicFunc import PublicFunc from func.utils.Constants import Constants, ConfigParams 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 Config = { } ButtonState = { "Default": { "pushButton_input_setting": True, "pushButton_input": True, "pushButton_prev_move": False, "pushButton_pause": False, "pushButton_next_move": False, "pushButton_save": False }, "Current": { "pushButton_input_setting": True, "pushButton_input": True, "pushButton_prev_move": False, "pushButton_pause": False, "pushButton_next_move": False, "pushButton_save": False } } class SettingWindow(QMainWindow): def __init__(self, mode, root_path, sampID): super(SettingWindow, self).__init__() self.ui = Ui_MainWindow_label_check_input_setting() self.ui.setupUi(self) self.mode = mode self.root_path = root_path self.sampID = sampID self.config = None self.__read_config__() self.ui.spinBox_input_freq_signal.valueChanged.connect(self.__update_ui__) self.ui.spinBox_bandPassOrder.valueChanged.connect(self.__update_ui__) self.ui.doubleSpinBox_bandPassLow.valueChanged.connect(self.__update_ui__) self.ui.doubleSpinBox_bandPassHigh.valueChanged.connect(self.__update_ui__) self.ui.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.LABEL_CHECK_CONFIG_FILE_PATH).exists(): with open(ConfigParams.LABEL_CHECK_CONFIG_FILE_PATH, "w") as f: dump(ConfigParams.LABEL_CHECK_CONFIG_NEW_CONTENT, f) with open(ConfigParams.LABEL_CHECK_CONFIG_FILE_PATH, "r") as f: file_config = load(f.read(), Loader=FullLoader) Config.update(file_config) self.config = file_config if self.mode == "BCG": Config.update({ "Path": { "Input_Signal": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / Path(str(self.sampID)) / Path(ConfigParams.LABEL_CHECK_INPUT_BCG_FILENAME + str(Config["InputConfig"]["Freq"]) + ConfigParams.ENDSWITH_TXT))), "Input_Peak": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / Path(str(self.sampID)) / Path(ConfigParams.LABEL_CHECK_INPUT_JPEAK_FILENAME + ConfigParams.ENDSWITH_TXT))), "Save": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / Path(str(self.sampID)) / Path(ConfigParams.LABEL_CHECK_SAVE_JPEAK_FILENAME + ConfigParams.ENDSWITH_TXT))) }, "Mode": self.mode }) elif self.mode == "ECG": Config.update({ "Path": { "Input_Signal": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / Path(str(self.sampID)) / Path(ConfigParams.LABEL_CHECK_INPUT_ECG_FILENAME + str(Config["InputConfig"]["Freq"]) + ConfigParams.ENDSWITH_TXT))), "Input_Peak": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / Path(str(self.sampID)) / Path(ConfigParams.LABEL_CHECK_INPUT_RPEAK_FILENAME + ConfigParams.ENDSWITH_TXT))), "Save": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / Path(str(self.sampID)) / Path(ConfigParams.LABEL_CHECK_SAVE_RPEAK_FILENAME + ConfigParams.ENDSWITH_TXT))) }, "Mode": self.mode }) else: raise ValueError # 数据回显 self.ui.spinBox_input_freq_signal.setValue(Config["InputConfig"]["Freq"]) self.ui.plainTextEdit_file_path_input_signal.setPlainText(Config["Path"]["Input_Signal"]) self.ui.plainTextEdit_file_path_input_peak.setPlainText(Config["Path"]["Input_Peak"]) self.ui.plainTextEdit_file_path_save.setPlainText(Config["Path"]["Save"]) if Config["Mode"] == "BCG": self.ui.spinBox_bandPassOrder.setValue(Config["Filter"]["BCGBandPassOrder"]) self.ui.doubleSpinBox_bandPassLow.setValue(Config["Filter"]["BCGBandPassLow"]) self.ui.doubleSpinBox_bandPassHigh.setValue(Config["Filter"]["BCGBandPassHigh"]) elif Config["Mode"] == "ECG": self.ui.spinBox_bandPassOrder.setValue(Config["Filter"]["ECGBandPassOrder"]) self.ui.doubleSpinBox_bandPassLow.setValue(Config["Filter"]["ECGBandPassLow"]) self.ui.doubleSpinBox_bandPassHigh.setValue(Config["Filter"]["ECGBandPassHigh"]) else: raise ValueError def __write_config__(self): # 从界面写入配置 Config["InputConfig"]["Freq"] = self.ui.spinBox_input_freq_signal.value() Config["Path"]["Input_Signal"] = self.ui.plainTextEdit_file_path_input_signal.toPlainText() Config["Path"]["Input_Peak"] = self.ui.plainTextEdit_file_path_input_peak.toPlainText() Config["Path"]["Save"] = self.ui.plainTextEdit_file_path_save.toPlainText() if Config["Mode"] == "BCG": Config["Filter"]["BCGBandPassOrder"] = self.ui.spinBox_bandPassOrder.value() Config["Filter"]["BCGBandPassLow"] = self.ui.doubleSpinBox_bandPassLow.value() Config["Filter"]["BCGBandPassHigh"] = self.ui.doubleSpinBox_bandPassHigh.value() elif Config["Mode"] == "ECG": Config["Filter"]["ECGBandPassOrder"] = self.ui.spinBox_bandPassOrder.value() Config["Filter"]["ECGBandPassLow"] = self.ui.doubleSpinBox_bandPassLow.value() Config["Filter"]["ECGBandPassHigh"] = self.ui.doubleSpinBox_bandPassHigh.value() else: raise ValueError # 保存配置到文件 self.config["InputConfig"]["Freq"] = self.ui.spinBox_input_freq_signal.value() with open(ConfigParams.LABEL_CHECK_CONFIG_FILE_PATH, "w") as f: dump(self.config, f) self.close() def __rollback_config__(self): self.__read_config__() def __update_ui__(self): if self.mode == "BCG": self.ui.plainTextEdit_file_path_input_signal.setPlainText( str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / Path(str(self.sampID)) / Path(ConfigParams.LABEL_CHECK_INPUT_BCG_FILENAME + str(self.ui.spinBox_input_freq_signal.value()) + ConfigParams.ENDSWITH_TXT)))) elif self.mode == "ECG": self.ui.plainTextEdit_file_path_input_signal.setPlainText( str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / Path(str(self.sampID)) / Path(ConfigParams.LABEL_CHECK_INPUT_ECG_FILENAME + str(self.ui.spinBox_input_freq_signal.value()) + ConfigParams.ENDSWITH_TXT)))) else: raise ValueError class MainWindow_label_check(QMainWindow): def __init__(self): super(MainWindow_label_check, self).__init__() self.ui = Ui_MainWindow_label_check() self.ui.setupUi(self) self.mode = None self.root_path = None self.sampID = None self.data = None self.original_peak = None self.corrected_peak = None self.setting = None # 初始化进度条 self.progressbar = None PublicFunc.add_progressbar(self) #初始化画框 self.fig = None self.canvas = None self.figToolbar = None self.gs = None self.ax0 = None self.ax1 = None self.line_processed_data_1 = None self.line_processed_data_2 = None self.point_peak_original = None self.point_peak_corrected = None self.msgBox = QMessageBox() self.msgBox.setWindowTitle(Constants.MAINWINDOW_MSGBOX_TITLE) @overrides def show(self, mode, root_path, sampID): super().show() self.mode = mode self.root_path = root_path self.sampID = sampID self.setting = SettingWindow(mode, root_path, sampID) # 初始化画框 self.fig = plt.figure(figsize=(12, 9), dpi=100) self.canvas = FigureCanvasQTAgg(self.fig) self.figToolbar = NavigationToolbar2QT(self.canvas) for action in self.figToolbar.actions(): if action.text() == "Subplots" or action.text() == "Customize": self.figToolbar.removeAction(action) self.ui.verticalLayout_canvas.addWidget(self.canvas) self.ui.verticalLayout_canvas.addWidget(self.figToolbar) self.gs = gridspec.GridSpec(2, 1, height_ratios=[1, 1]) self.fig.subplots_adjust(top=0.98, bottom=0.05, right=0.98, left=0.1, hspace=0, wspace=0) self.ax0 = self.fig.add_subplot(self.gs[0]) 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.grid(True) self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) PublicFunc.__resetAllButton__(self, ButtonState) self.ui.label_mode.setText(self.mode) # 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.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__) self.ui.spinBox_maxRange.editingFinished.connect(self.__update_config__) self.ui.spinBox_moveSpeed.editingFinished.connect(self.__update_config__) @overrides def closeEvent(self, event): PublicFunc.__disableAllButton__(self, ButtonState) PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg(Constants.SHUTTING_DOWN)) QApplication.processEvents() # 清空画框 if self.line_processed_data_1 and self.line_processed_data_2 and self.point_peak_original and self.point_peak_corrected: del self.line_processed_data_1 del self.line_processed_data_2 del self.point_peak_original del self.point_peak_corrected self.canvas.draw() # 释放资源 del self.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): # 清空画框 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 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.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) self.ax1.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_config__(self): Config["FindPeaks"]["MinInterval"] = self.ui.doubleSpinBox_findpeaks_min_interval.value() Config["FindPeaks"]["MinHeight"] = self.ui.doubleSpinBox_findpeaks_min_height.value() Config["CustomAutoplayArgs"]["MoveLength"] = self.ui.spinBox_moveLength.value() Config["CustomAutoplayArgs"]["MaxRange"] = self.ui.spinBox_maxRange.value() Config["CustomAutoplayArgs"]["MoveSpeed"] = self.ui.spinBox_moveSpeed.value() class Data: def __init__(self): self.file_path_input_signal = Config["Path"]["Input_Signal"] self.file_path_input_peak = Config["Path"]["Input_Peak"] self.file_path_save = Config["Path"]["Save"] self.raw_data = None self.processed_data = None self.peak = None