from gc import collect from pathlib import Path from traceback import format_exc import matplotlib.pyplot as plt from PySide6.QtCore import QCoreApplication, QTimer from PySide6.QtGui import QAction, QFont from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication, QTableWidget, QTableWidgetItem from matplotlib import gridspec, patches from matplotlib.backends.backend_qt import NavigationToolbar2QT from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg from numpy.fft import fft, fftfreq from overrides import overrides from pandas import read_csv, DataFrame, concat from yaml import dump, load, FullLoader from func.utils.PublicFunc import PublicFunc from func.utils.Constants import Constants, ConfigParams from func.utils.Result import Result from ui.MainWindow.MainWindow_artifact_label import Ui_MainWindow_artifact_label from ui.setting.artifact_label_input_setting import Ui_MainWindow_artifact_label_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, "pushButton_type_1": False, "pushButton_type_2": False, "pushButton_type_3": False, "pushButton_type_4": False, "pushButton_type_5": False, "pushButton_delete": False }, "Current": { "pushButton_input_setting": True, "pushButton_input": True, "pushButton_prev_move": False, "pushButton_pause": False, "pushButton_next_move": False, "pushButton_save": False, "pushButton_type_1": False, "pushButton_type_2": False, "pushButton_type_3": False, "pushButton_type_4": False, "pushButton_type_5": False, "pushButton_delete": False } } class SettingWindow(QMainWindow): def __init__(self, root_path, sampID): super(SettingWindow, self).__init__() self.ui = Ui_MainWindow_artifact_label_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_orgBcg.valueChanged.connect(self.__update_ui__) self.ui.spinBox_input_freq_BCG.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.ARTIFACT_LABEL_CONFIG_FILE_PATH).exists(): with open(ConfigParams.ARTIFACT_LABEL_CONFIG_FILE_PATH, "w") as f: dump(ConfigParams.ARTIFACT_LABEL_CONFIG_NEW_CONTENT, f) with open(ConfigParams.ARTIFACT_LABEL_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_ALIGNED / Path(str(self.sampID)) / Path(ConfigParams.ARTIFACT_LABEL_INPUT_ORGBCG_FILENAME + str(Config["InputConfig"]["orgBcgFreq"]) + ConfigParams.ENDSWITH_TXT))), "Input_BCG": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / Path(str(self.sampID)) / Path(ConfigParams.ARTIFACT_LABEL_INPUT_BCG_FILENAME + str(Config["InputConfig"]["BCGFreq"]) + ConfigParams.ENDSWITH_TXT))), "Save_a": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / Path(str(self.sampID)) / Path(ConfigParams.ARTIFACT_LABEL_SAVE_FILENAME_A + ConfigParams.ENDSWITH_TXT))), "Save_b": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / Path(str(self.sampID)) / Path(ConfigParams.ARTIFACT_LABEL_SAVE_FILENAME_B + ConfigParams.ENDSWITH_TXT))), "Save_c": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / Path(str(self.sampID)) / Path(ConfigParams.ARTIFACT_LABEL_SAVE_FILENAME_C + ConfigParams.ENDSWITH_CSV))) } }) # 数据回显 self.ui.spinBox_input_freq_orgBcg.setValue(Config["InputConfig"]["orgBcgFreq"]) self.ui.spinBox_input_freq_BCG.setValue(Config["InputConfig"]["BCGFreq"]) 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_save_a.setPlainText(Config["Path"]["Save_a"]) self.ui.plainTextEdit_file_path_save_b.setPlainText(Config["Path"]["Save_b"]) self.ui.plainTextEdit_file_path_save_c.setPlainText(Config["Path"]["Save_c"]) def __write_config__(self): # 从界面写入配置 Config["InputConfig"]["orgBcgFreq"] = self.ui.spinBox_input_freq_orgBcg.value() Config["InputConfig"]["BCGFreq"] = self.ui.spinBox_input_freq_BCG.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"]["Save_a"] = self.ui.plainTextEdit_file_path_save_a.toPlainText() Config["Path"]["Save_b"] = self.ui.plainTextEdit_file_path_save_b.toPlainText() Config["Path"]["Save_c"] = self.ui.plainTextEdit_file_path_save_c.toPlainText() # 保存配置到文件 self.config["InputConfig"]["orgBcgFreq"] = self.ui.spinBox_input_freq_orgBcg.value() self.config["InputConfig"]["BCGFreq"] = self.ui.spinBox_input_freq_BCG.value() with open(ConfigParams.ARTIFACT_LABEL_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_ALIGNED / Path(str(self.sampID)) / Path(ConfigParams.ARTIFACT_LABEL_INPUT_ORGBCG_FILENAME + str(self.ui.spinBox_input_freq_orgBcg.value()) + ConfigParams.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_input_BCG.setPlainText( str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / Path(str(self.sampID)) / Path(ConfigParams.ARTIFACT_LABEL_INPUT_BCG_FILENAME + str(self.ui.spinBox_input_freq_BCG.value()) + ConfigParams.ENDSWITH_TXT)))) class MainWindow_artifact_label(QMainWindow): def __init__(self): super(MainWindow_artifact_label, self).__init__() self.ui = Ui_MainWindow_artifact_label() self.ui.setupUi(self) self.root_path = None self.sampID = None self.data = None self.setting = None # 初始化进度条 self.progressbar = None PublicFunc.add_progressbar(self) #初始化画框 self.fig = None self.canvas = None self.figToolbar = None self.gs = None self.ax0 = None self.ax1 = None self.rectangles_ax0_patches = [] self.rectangles_ax1_patches = [] self.annotation_tableWidget = None self.rect_left = None self.rect_right = None self.is_left_button_pressed = None self.pressed_number = None self.rect_up = None self.rect_down = 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) @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_Label_Artifact.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._actions['zoom'].triggered.connect(self.toggle_zoom) self.figToolbar._actions['pan'].triggered.connect(self.toggle_pan) self.figToolbar.action_Label_Artifact.triggered.connect(self.toggle_label_artifact) 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], sharex=self.ax0, sharey=self.ax0) self.ax1.grid(True) self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) PublicFunc.__resetAllButton__(self, ButtonState) 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.tableWidget_type_1.setHorizontalHeaderLabels(['序号', '起始时间', '终止时间']) self.ui.tableWidget_type_2.setHorizontalHeaderLabels(['序号', '起始时间', '终止时间']) self.ui.tableWidget_type_3.setHorizontalHeaderLabels(['序号', '起始时间', '终止时间']) self.ui.tableWidget_type_4.setHorizontalHeaderLabels(['序号', '起始时间', '终止时间']) self.ui.tableWidget_type_5.setHorizontalHeaderLabels(['序号', '起始时间', '终止时间']) self.ui.tableWidget_type_1.setEditTriggers(QTableWidget.NoEditTriggers) self.ui.tableWidget_type_2.setEditTriggers(QTableWidget.NoEditTriggers) self.ui.tableWidget_type_3.setEditTriggers(QTableWidget.NoEditTriggers) self.ui.tableWidget_type_4.setEditTriggers(QTableWidget.NoEditTriggers) self.ui.tableWidget_type_5.setEditTriggers(QTableWidget.NoEditTriggers) self.ui.tableWidget_type_1.horizontalHeader().setStretchLastSection(True) self.ui.tableWidget_type_2.horizontalHeader().setStretchLastSection(True) self.ui.tableWidget_type_3.horizontalHeader().setStretchLastSection(True) self.ui.tableWidget_type_4.horizontalHeader().setStretchLastSection(True) self.ui.tableWidget_type_5.horizontalHeader().setStretchLastSection(True) self.ui.pushButton_input.clicked.connect(self.__slot_btn_input__) self.ui.pushButton_type_1.clicked.connect(self.__slot_btn_label__) self.ui.pushButton_type_2.clicked.connect(self.__slot_btn_label__) self.ui.pushButton_type_3.clicked.connect(self.__slot_btn_label__) self.ui.pushButton_type_4.clicked.connect(self.__slot_btn_label__) self.ui.pushButton_type_5.clicked.connect(self.__slot_btn_label__) self.ui.pushButton_save.clicked.connect(self.__slot_btn_save__) self.ui.pushButton_delete.clicked.connect(self.__slot_btn_delete_label__) 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_type_1.cellDoubleClicked.connect(self.__slot_tableWidget_on_cell_double_clicked__) self.ui.tableWidget_type_2.cellDoubleClicked.connect(self.__slot_tableWidget_on_cell_double_clicked__) self.ui.tableWidget_type_3.cellDoubleClicked.connect(self.__slot_tableWidget_on_cell_double_clicked__) self.ui.tableWidget_type_4.cellDoubleClicked.connect(self.__slot_tableWidget_on_cell_double_clicked__) self.ui.tableWidget_type_5.cellDoubleClicked.connect(self.__slot_tableWidget_on_cell_double_clicked__) self.ui.pushButton_input_setting.clicked.connect(self.setting.show) @overrides def closeEvent(self, event): reply = QMessageBox.question(self, '确认', '确认退出吗?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: PublicFunc.__disableAllButton__(self, ButtonState) PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg(Constants.SHUTTING_DOWN)) QApplication.processEvents() # 清空画框 del self.rectangles_ax0_patches del self.rectangles_ax1_patches del self.annotation_tableWidget self.ax0.clear() self.ax1.clear() # 释放资源 del self.data self.fig.clf() plt.close(self.fig) self.deleteLater() collect() self.canvas = None event.accept() else: event.ignore() def __reset__(self): ButtonState["Current"].update(ButtonState["Default"].copy()) def __plot__(self): # 清空画框 if self.annotation_tableWidget is not None: self.annotation_tableWidget.remove() self.annotation_tableWidget = None self.reset_axes() sender = self.sender() if sender == self.ui.pushButton_input: try: self.ax0.plot(self.data.orgBcg, label=Constants.ARTIFACT_LABEL_PLOT_LABEL_ORGBCG_SYNC, color=Constants.PLOT_COLOR_BLUE) self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) self.ax1.plot(self.data.BCG, label=Constants.ARTIFACT_LABEL_PLOT_LABEL_BCG_SYNC, color=Constants.PLOT_COLOR_BLUE) self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT) self.rect_down = min(self.ax0.get_ylim()[0], self.ax1.get_ylim()[0]) - 1000 self.rect_up = max(self.ax0.get_ylim()[1], self.ax1.get_ylim()[1]) + 1000 self.canvas.draw() self.__plot_artifact__() self.ax0.autoscale(False) self.ax1.autoscale(False) except Exception as e: return Result().failure(info=Constants.DRAWING_FAILURE + "\n" + format_exc()) return Result().success(info=Constants.DRAWING_FINISHED) else: self.canvas.draw() self.ax0.autoscale(False) self.ax1.autoscale(False) return Result().failure(info=Constants.DRAWING_FAILURE) def __plot_artifact__(self): if len(self.ax0.patches) != 0: for patch in self.ax0.patches: if patch in self.rectangles_ax0_patches: patch.remove() if len(self.ax1.patches) != 0: for patch in self.ax1.patches: if patch in self.rectangles_ax1_patches: patch.remove() self.rectangles_ax0_patches = [] self.rectangles_ax1_patches = [] self.ax1.callbacks.connect('xlim_changed', lambda ax: self.on_xlim_change(ax)) self.canvas.draw() # 绘制体动 for i in range(0, len(self.data.df_Artifact_a)): if self.data.df_Artifact_a.iloc[i][1] == 1: # 橙色,剧烈体动 rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), height=self.rect_up - self.rect_down, fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, color=Constants.PLOT_COLOR_DEEP_YELLOW) self.rectangles_ax0_patches.append(rectangle) rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), height=self.rect_up - self.rect_down, fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, color=Constants.PLOT_COLOR_DEEP_YELLOW) self.rectangles_ax1_patches.append(rectangle) elif self.data.df_Artifact_a.iloc[i][1] == 2: # 黄色,脉冲体动 rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), height=self.rect_up - self.rect_down, fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, color=Constants.PLOT_COLOR_YELLOW) self.rectangles_ax0_patches.append(rectangle) rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), height=self.rect_up - self.rect_down, fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, color=Constants.PLOT_COLOR_YELLOW) self.rectangles_ax1_patches.append(rectangle) elif self.data.df_Artifact_a.iloc[i][1] == 3: # 青色,常规体动 rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), height=self.rect_up - self.rect_down, fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, color=Constants.PLOT_COLOR_AQUA) self.rectangles_ax0_patches.append(rectangle) rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), height=self.rect_up - self.rect_down, fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, color=Constants.PLOT_COLOR_AQUA) self.rectangles_ax1_patches.append(rectangle) elif self.data.df_Artifact_a.iloc[i][1] == 4: # 紫色,疑似鼾声 rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), height=self.rect_up - self.rect_down, fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, color=Constants.PLOT_COLOR_PURPLE_PINK) self.rectangles_ax0_patches.append(rectangle) rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), height=self.rect_up - self.rect_down, fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, color=Constants.PLOT_COLOR_PURPLE_PINK) self.rectangles_ax1_patches.append(rectangle) elif self.data.df_Artifact_a.iloc[i][1] == 5: # 灰色,离床 rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), height=self.rect_up - self.rect_down, fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, color=Constants.PLOT_COLOR_DEEP_GREY) self.rectangles_ax0_patches.append(rectangle) rectangle = patches.Rectangle((self.data.df_Artifact_a.iloc[i][2], self.rect_down), width=(self.data.df_Artifact_a.iloc[i][3] - self.data.df_Artifact_a.iloc[i][2]), height=self.rect_up - self.rect_down, fill=True, alpha=ConfigParams.ARTIFACT_LABEL_LABEL_TRANSPARENCY, color=Constants.PLOT_COLOR_DEEP_GREY) self.rectangles_ax1_patches.append(rectangle) for patch in self.rectangles_ax0_patches: self.ax0.add_patch(patch) for patch in self.rectangles_ax1_patches: self.ax1.add_patch(patch) self.canvas.draw() def update_label_args(self, rect_left, rect_right): try: # 计算傅里叶变换 fft_result = fft(self.data.orgBcg[rect_left:rect_right]) fft_freqs = fftfreq(len(self.data.orgBcg[rect_left:rect_right]), 1 / Config["InputConfig"]["orgBcgFreq"]) # 确定频率高于20Hz的成分 high_freq_indices = abs(fft_freqs) > 20 high_freq_fft = fft_result[high_freq_indices] # 计算能量 total_energy = sum(abs(fft_result) ** 2) high_freq_energy = sum(abs(high_freq_fft) ** 2) # 计算能量占比 energy_ratio_orgData_sync = round((high_freq_energy * 100 / total_energy), 6) # 计算傅里叶变换 fft_result = fft(self.data.orgBcg[rect_left:rect_right]) fft_freqs = fftfreq(len(self.data.orgBcg[rect_left:rect_right]), 1 / Config["InputConfig"]["orgBcgFreq"]) # 确定频率高于20Hz的成分 high_freq_indices = abs(fft_freqs) > 20 high_freq_fft = fft_result[high_freq_indices] # 计算能量 total_energy = sum(abs(fft_result) ** 2) high_freq_energy = sum(abs(high_freq_fft) ** 2) # 计算能量占比 energy_ratio_BCG_sync = round((high_freq_energy * 100 / total_energy), 6) self.ui.lineEdit_energy_percent_orgBcg.setText(str(energy_ratio_orgData_sync) + "%") self.ui.lineEdit_energy_percent_BCG.setText(str(energy_ratio_BCG_sync) + "%") self.ui.lineEdit_start_time.setText(str(int(self.rect_left))) self.ui.lineEdit_end_time.setText(str(int(self.rect_right))) self.ui.lineEdit_duration.setText(str(int(self.rect_right) - int(self.rect_left))) except Exception: self.ui.lineEdit_energy_percent_orgBcg.setText("获取异常") self.ui.lineEdit_energy_percent_BCG.setText("获取异常") self.ui.lineEdit_start_time.setText("获取异常") self.ui.lineEdit_end_time.setText("获取异常") self.ui.lineEdit_duration.setText("获取异常") def update_tableWidget(self): try: self.ui.tableWidget_type_1.clearContents() self.ui.tableWidget_type_2.clearContents() self.ui.tableWidget_type_3.clearContents() self.ui.tableWidget_type_4.clearContents() self.ui.tableWidget_type_5.clearContents() self.ui.tableWidget_type_1.setRowCount(0) self.ui.tableWidget_type_2.setRowCount(0) self.ui.tableWidget_type_3.setRowCount(0) self.ui.tableWidget_type_4.setRowCount(0) self.ui.tableWidget_type_5.setRowCount(0) for row, data in self.data.df_Artifact_a.iterrows(): if data["type"] == 1: self.ui.tableWidget_type_1.setRowCount(self.ui.tableWidget_type_1.rowCount() + 1) self.ui.tableWidget_type_1.setItem(self.ui.tableWidget_type_1.rowCount() - 1, 0, QTableWidgetItem(str(data["number"]))) self.ui.tableWidget_type_1.setItem(self.ui.tableWidget_type_1.rowCount() - 1, 1, QTableWidgetItem(str(data["startTime"]))) self.ui.tableWidget_type_1.setItem(self.ui.tableWidget_type_1.rowCount() - 1, 2, QTableWidgetItem(str(data["endTime"]))) elif data["type"] == 2: self.ui.tableWidget_type_2.setRowCount(self.ui.tableWidget_type_2.rowCount() + 1) self.ui.tableWidget_type_2.setItem(self.ui.tableWidget_type_2.rowCount() - 1, 0, QTableWidgetItem(str(data["number"]))) self.ui.tableWidget_type_2.setItem(self.ui.tableWidget_type_2.rowCount() - 1, 1, QTableWidgetItem(str(data["startTime"]))) self.ui.tableWidget_type_2.setItem(self.ui.tableWidget_type_2.rowCount() - 1, 2, QTableWidgetItem(str(data["endTime"]))) elif data["type"] == 3: self.ui.tableWidget_type_3.setRowCount(self.ui.tableWidget_type_3.rowCount() + 1) self.ui.tableWidget_type_3.setItem(self.ui.tableWidget_type_3.rowCount() - 1, 0, QTableWidgetItem(str(data["number"]))) self.ui.tableWidget_type_3.setItem(self.ui.tableWidget_type_3.rowCount() - 1, 1, QTableWidgetItem(str(data["startTime"]))) self.ui.tableWidget_type_3.setItem(self.ui.tableWidget_type_3.rowCount() - 1, 2, QTableWidgetItem(str(data["endTime"]))) elif data["type"] == 4: self.ui.tableWidget_type_4.setRowCount(self.ui.tableWidget_type_4.rowCount() + 1) self.ui.tableWidget_type_4.setItem(self.ui.tableWidget_type_4.rowCount() - 1, 0, QTableWidgetItem(str(data["number"]))) self.ui.tableWidget_type_4.setItem(self.ui.tableWidget_type_4.rowCount() - 1, 1, QTableWidgetItem(str(data["startTime"]))) self.ui.tableWidget_type_4.setItem(self.ui.tableWidget_type_4.rowCount() - 1, 2, QTableWidgetItem(str(data["endTime"]))) elif data["type"] == 5: self.ui.tableWidget_type_5.setRowCount(self.ui.tableWidget_type_5.rowCount() + 1) self.ui.tableWidget_type_5.setItem(self.ui.tableWidget_type_5.rowCount() - 1, 0, QTableWidgetItem(str(data["number"]))) self.ui.tableWidget_type_5.setItem(self.ui.tableWidget_type_5.rowCount() - 1, 1, QTableWidgetItem(str(data["startTime"]))) self.ui.tableWidget_type_5.setItem(self.ui.tableWidget_type_5.rowCount() - 1, 2, QTableWidgetItem(str(data["endTime"]))) except Exception as e: return Result().failure(info=Constants.ARTIFACT_LABEL_UPDATE_FAILURE + Constants.ARTIFACT_LABEL_FAILURE_REASON["Update_tableWidget_Exception"] + "\n" + format_exc()) return Result().success(info=Constants.ARTIFACT_LABEL_UPDATE_FINISHED) def update_Info(self): try: artifact_amount = [0, 0, 0, 0, 0] artifact_total_duration = [0, 0, 0, 0, 0] tableWidget_list = [self.ui.tableWidget_type_1, self.ui.tableWidget_type_2, self.ui.tableWidget_type_3, self.ui.tableWidget_type_4, self.ui.tableWidget_type_5] for index, tableWidget in enumerate(tableWidget_list): sum_of_differences = 0 for row in range(tableWidget.rowCount()): startTime = tableWidget.item(row, 1) endTime = tableWidget.item(row, 2) if startTime and endTime: # 确保单元格不为空 startTime = int(startTime.text()) endTime = int(endTime.text()) difference_amount = endTime - startTime sum_of_differences += difference_amount artifact_amount[index] = tableWidget.rowCount() artifact_total_duration[index] = sum_of_differences self.ui.spinBox_amount_type_1.setValue(artifact_amount[0]) self.ui.spinBox_amount_type_2.setValue(artifact_amount[1]) self.ui.spinBox_amount_type_3.setValue(artifact_amount[2]) self.ui.spinBox_amount_type_4.setValue(artifact_amount[3]) self.ui.spinBox_amount_type_5.setValue(artifact_amount[4]) self.ui.spinBox_duration_type_1.setValue(artifact_total_duration[0]) self.ui.spinBox_duration_type_2.setValue(artifact_total_duration[1]) self.ui.spinBox_duration_type_3.setValue(artifact_total_duration[2]) self.ui.spinBox_duration_type_4.setValue(artifact_total_duration[3]) self.ui.spinBox_duration_type_5.setValue(artifact_total_duration[4]) except Exception as e: return Result().failure(info=Constants.ARTIFACT_LABEL_UPDATE_FAILURE + Constants.ARTIFACT_LABEL_FAILURE_REASON["Update_Info_Exception"] + "\n" + format_exc()) return Result().success(info=Constants.ARTIFACT_LABEL_UPDATE_FINISHED) def __slot_btn_input__(self): PublicFunc.__disableAllButton__(self, ButtonState) self.reset_axes() self.canvas.draw() self.data = Data() # 导入数据 PublicFunc.progressbar_update(self, 1, 5, Constants.INPUTTING_DATA, 0) result = self.data.open_file() if not result.status: PublicFunc.text_output(self.ui, "(1/5)" + result.info, Constants.TIPS_TYPE_ERROR) PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) PublicFunc.finish_operation(self, ButtonState) return else: PublicFunc.text_output(self.ui, "(1/5)" + result.info, Constants.TIPS_TYPE_INFO) # 获取存档 PublicFunc.progressbar_update(self, 2, 5, Constants.ARTIFACT_LABEL_LOADING_ARCHIVE, 50) result = self.data.get_archive() if not result.status: PublicFunc.text_output(self.ui, "(2/5)" + result.info, Constants.TIPS_TYPE_ERROR) PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) PublicFunc.finish_operation(self, ButtonState) return else: PublicFunc.text_output(self.ui, "(2/5)" + result.info, Constants.TIPS_TYPE_INFO) # 绘图 PublicFunc.progressbar_update(self, 3, 5, Constants.DRAWING_DATA, 60) result = self.__plot__() if not result.status: PublicFunc.text_output(self.ui, "(3/5)" + result.info, Constants.TIPS_TYPE_ERROR) PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) PublicFunc.finish_operation(self, ButtonState) return else: PublicFunc.text_output(self.ui, "(3/5)" + result.info, Constants.TIPS_TYPE_INFO) # 更新表格 PublicFunc.progressbar_update(self, 4, 5, Constants.ARTIFACT_LABEL_UPDATING_TABLE, 90) result = self.update_tableWidget() if not result.status: PublicFunc.text_output(self.ui, "(4/5)" + result.info, Constants.TIPS_TYPE_ERROR) PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) PublicFunc.finish_operation(self, ButtonState) return else: PublicFunc.text_output(self.ui, "(4/5)" + result.info, Constants.TIPS_TYPE_INFO) # 更新信息 PublicFunc.progressbar_update(self, 5, 5, Constants.ARTIFACT_LABEL_UPDATING_INFO, 95) result = self.update_Info() if not result.status: PublicFunc.text_output(self.ui, "(5/5)" + result.info, Constants.TIPS_TYPE_ERROR) PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) PublicFunc.finish_operation(self, ButtonState) return else: PublicFunc.text_output(self.ui, "(5/5)" + result.info, Constants.TIPS_TYPE_INFO) self.__reset__() self.figToolbar.action_Label_Artifact.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 ButtonState["Current"]["pushButton_type_1"] = True ButtonState["Current"]["pushButton_type_2"] = True ButtonState["Current"]["pushButton_type_3"] = True ButtonState["Current"]["pushButton_type_4"] = True ButtonState["Current"]["pushButton_type_5"] = True PublicFunc.finish_operation(self, ButtonState) def __slot_btn_label__(self): sender = self.sender() if sender == self.ui.pushButton_type_1: type = 1 elif sender == self.ui.pushButton_type_2: type = 2 elif sender == self.ui.pushButton_type_3: type = 3 elif sender == self.ui.pushButton_type_4: type = 4 elif sender == self.ui.pushButton_type_5: type = 5 else: raise ValueError() if (self.ui.lineEdit_start_time.text() == Constants.STRING_IS_EMPTY or self.ui.lineEdit_end_time.text() == Constants.STRING_IS_EMPTY): PublicFunc.msgbox_output(self, Constants.ARTIFACT_LABEL_MISS_ARGS, Constants.MSGBOX_TYPE_ERROR) return for index, row in self.data.df_Artifact_a.iterrows(): value_startTime = row['startTime'] value_endTime = row['endTime'] if value_startTime <= int(self.ui.lineEdit_end_time.text()) and int( self.ui.lineEdit_start_time.text()) <= value_endTime: PublicFunc.msgbox_output(self, f"{Constants.ARTIFACT_LABEL_OVERLAPPING}{row['number']}", Constants.MSGBOX_TYPE_ERROR) return new_row = {'number': int(len(self.data.df_Artifact_a) + 1), 'type': int(type), 'startTime': int(self.ui.lineEdit_start_time.text()), 'endTime': int(self.ui.lineEdit_end_time.text())} self.data.df_Artifact_a = concat([self.data.df_Artifact_a, DataFrame([new_row])], ignore_index=True) sorted_part = self.data.df_Artifact_a[['type', 'startTime', 'endTime']].sort_values(by='startTime').reset_index( drop=True) self.data.df_Artifact_a[['type', 'startTime', 'endTime']] = sorted_part self.update_tableWidget() self.update_Info() self.__plot_artifact__() target_row = self.data.df_Artifact_a[ self.data.df_Artifact_a.eq(int(self.ui.lineEdit_start_time.text())).any(axis=1)] if not target_row.empty: first_column_value = target_row.iloc[0, 0] # 获取第1列的值 else: raise AttributeError() PublicFunc.text_output(self.ui, f"新增体动标签{first_column_value}, 类型{new_row['type']},从{int(self.ui.lineEdit_start_time.text())}ms到{int(self.ui.lineEdit_end_time.text())}ms", Constants.TIPS_TYPE_INFO) self.__slot_btn_save__() def __slot_btn_save__(self): PublicFunc.__disableAllButton__(self, ButtonState) # 保存 PublicFunc.progressbar_update(self, 1, 1, Constants.SAVING_DATA, 0) amount = [ self.ui.spinBox_amount_type_1.value(), self.ui.spinBox_amount_type_2.value(), self.ui.spinBox_amount_type_3.value(), self.ui.spinBox_amount_type_4.value(), self.ui.spinBox_amount_type_5.value() ] duration = [ self.ui.spinBox_duration_type_1.value(), self.ui.spinBox_duration_type_2.value(), self.ui.spinBox_duration_type_3.value(), self.ui.spinBox_duration_type_4.value(), self.ui.spinBox_duration_type_5.value() ] result = self.data.save(amount, duration) if not result.status: PublicFunc.text_output(self.ui, "(1/1)" + result.info, Constants.TIPS_TYPE_ERROR) PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR) PublicFunc.finish_operation(self, ButtonState) return else: PublicFunc.text_output(self.ui, "(1/1)" + result.info, Constants.TIPS_TYPE_INFO) PublicFunc.finish_operation(self, ButtonState) def __slot_btn_delete_label__(self): if self.pressed_number is not None: self.data.df_Artifact_a = self.data.df_Artifact_a[self.data.df_Artifact_a['number'] != self.pressed_number] self.data.df_Artifact_a = self.data.df_Artifact_a.reset_index(drop=True) sorted_part = self.data.df_Artifact_a[['type', 'startTime', 'endTime']].sort_values(by='startTime').reset_index( drop=True) self.data.df_Artifact_a[['type', 'startTime', 'endTime']] = sorted_part self.data.df_Artifact_a['number'] = self.data.df_Artifact_a.index + 1 try: if self.annotation_tableWidget: self.annotation_tableWidget.remove() except AttributeError: pass self.annotation_tableWidget = None self.reset_labelBtn_color() self.update_tableWidget() self.update_Info() self.__plot_artifact__() self.__slot_btn_save__() PublicFunc.text_output(self.ui, f"{self.pressed_number}{Constants.ARTIFACT_LABEL_DELETE_ARTIFACT_SUCCESSFULLY}", Constants.TIPS_TYPE_INFO) else: PublicFunc.text_output(self.ui, f"{self.pressed_number}{Constants.ARTIFACT_LABEL_DELETE_ARTIFACT_FAILURE}", Constants.TIPS_TYPE_ERROR) PublicFunc.msgbox_output(self, f"{self.pressed_number}{Constants.ARTIFACT_LABEL_DELETE_ARTIFACT_FAILURE}", Constants.MSGBOX_TYPE_ERROR) self.pressed_number = None 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.BCG): self.autoplay_xlim_start = int(len(self.data.BCG) - Config["AutoplayArgs"]["MaxRange"]) self.autoplay_xlim_end = int(len(self.data.BCG)) 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.ARTIFACT_LABEL_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.ARTIFACT_LABEL_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.ARTIFACT_LABEL_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.ARTIFACT_LABEL_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.ARTIFACT_LABEL_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.ARTIFACT_LABEL_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.ARTIFACT_LABEL_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.BCG): self.autoplay_xlim_start = int(self.data.BCG) - Config["AutoplayArgs"]["MaxRange"] self.autoplay_xlim_end = int(self.data.BCG) 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_type_1: self.pressed_number = int( self.ui.tableWidget_type_1.item(row, 0).text()) startTime = int(self.ui.tableWidget_type_1.item(row, 1).text()) endTime = int(self.ui.tableWidget_type_1.item(row, 2).text()) type = 1 elif sender == self.ui.tableWidget_type_2: self.pressed_number = int( self.ui.tableWidget_type_2.item(row, 0).text()) startTime = int(self.ui.tableWidget_type_2.item(row, 1).text()) endTime = int(self.ui.tableWidget_type_2.item(row, 2).text()) type = 2 elif sender == self.ui.tableWidget_type_3: self.pressed_number = int( self.ui.tableWidget_type_3.item(row, 0).text()) startTime = int(self.ui.tableWidget_type_3.item(row, 1).text()) endTime = int(self.ui.tableWidget_type_3.item(row, 2).text()) type = 3 elif sender == self.ui.tableWidget_type_4: self.pressed_number = int( self.ui.tableWidget_type_4.item(row, 0).text()) startTime = int(self.ui.tableWidget_type_4.item(row, 1).text()) endTime = int(self.ui.tableWidget_type_4.item(row, 2).text()) type = 4 elif sender == self.ui.tableWidget_type_5: self.pressed_number = int( self.ui.tableWidget_type_5.item(row, 0).text()) startTime = int(self.ui.tableWidget_type_5.item(row, 1).text()) endTime = int(self.ui.tableWidget_type_5.item(row, 2).text()) type = 5 else: raise ValueError() self.ax0.set_xlim(startTime - 60000, endTime + 60000) self.annotation_tableWidget = self.ax0.annotate(f'number={int(self.pressed_number)}, duration={int(endTime - startTime)}ms', xy=(int(startTime + (endTime - startTime) / 2), self.ax0.get_ylim()[0]), xytext=( int(startTime + (endTime - startTime) / 2), 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.change_labelBtn_color(type) self.ui.pushButton_delete.setEnabled(True) self.canvas.draw() self.rect_left = startTime self.rect_right = endTime self.update_label_args(int(self.rect_left), int(self.rect_right)) PublicFunc.text_output(self.ui, f"{Constants.ARTIFACT_LABEL_JUMP_ARTIFACT}{str(self.pressed_number)}", Constants.TIPS_TYPE_INFO) def reset_axes(self): self.ax0.clear() self.ax1.clear() self.ax0.grid(True) self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) self.ax0.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) self.ax1.grid(True) self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) def on_xlim_change(self, event_ax): try: if self.annotation_tableWidget: self.annotation_tableWidget.remove() except AttributeError: pass self.annotation_tableWidget = None self.reset_labelBtn_color() ButtonState["Current"]["pushButton_delete"] = False PublicFunc.__enableAllButton__(self, ButtonState) 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.BCG): 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 change_labelBtn_color(self, type): if type == 1: self.ui.pushButton_type_1.setStyleSheet( Constants.ARTIFACT_LABEL_LABELBTN_STYLE_1) self.ui.pushButton_type_2.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_3.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_4.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_5.setStyleSheet(Constants.STRING_IS_EMPTY) elif type == 2: self.ui.pushButton_type_1.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_2.setStyleSheet( Constants.ARTIFACT_LABEL_LABELBTN_STYLE_2) self.ui.pushButton_type_3.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_4.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_5.setStyleSheet(Constants.STRING_IS_EMPTY) elif type == 3: self.ui.pushButton_type_1.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_2.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_3.setStyleSheet( Constants.ARTIFACT_LABEL_LABELBTN_STYLE_3) self.ui.pushButton_type_4.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_5.setStyleSheet(Constants.STRING_IS_EMPTY) elif type == 4: self.ui.pushButton_type_1.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_2.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_3.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_4.setStyleSheet( Constants.ARTIFACT_LABEL_LABELBTN_STYLE_4) self.ui.pushButton_type_5.setStyleSheet(Constants.STRING_IS_EMPTY) elif type == 5: self.ui.pushButton_type_1.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_2.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_3.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_4.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_5.setStyleSheet( Constants.ARTIFACT_LABEL_LABELBTN_STYLE_5) def reset_labelBtn_color(self): self.ui.pushButton_type_1.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_2.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_3.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_4.setStyleSheet(Constants.STRING_IS_EMPTY) self.ui.pushButton_type_5.setStyleSheet(Constants.STRING_IS_EMPTY) def toggle_home(self): if Config["AutoplayArgs"]["AutoplayMode"] != "pause": self.ui.pushButton_pause.click() 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.rect_left = None self.rect_right = None self.ui.lineEdit_start_time.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_end_time.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_duration.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_energy_percent_orgBcg.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_energy_percent_BCG.setText(Constants.STRING_IS_EMPTY) self.canvas.draw() 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.ARTIFACT_LABEL_RECOVER_SCALE, Constants.TIPS_TYPE_INFO) def toggle_zoom(self): 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.rect_left = None self.rect_right = None self.ui.lineEdit_start_time.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_end_time.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_duration.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_energy_percent_orgBcg.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_energy_percent_BCG.setText(Constants.STRING_IS_EMPTY) self.canvas.draw() def toggle_pan(self): 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.rect_left = None self.rect_right = None self.ui.lineEdit_start_time.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_end_time.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_duration.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_energy_percent_orgBcg.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_energy_percent_BCG.setText(Constants.STRING_IS_EMPTY) self.canvas.draw() def toggle_label_artifact(self, state): if state: self.deactivate_figToolbar_buttons() self.figToolbar.action_Label_Artifact.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.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.rect_left = None self.rect_right = None self.ui.lineEdit_start_time.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_end_time.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_duration.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_energy_percent_orgBcg.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_energy_percent_BCG.setText(Constants.STRING_IS_EMPTY) self.canvas.draw() 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(): 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_Artifact.isChecked(): self.reset_labelBtn_color() ButtonState["Current"]["pushButton_delete"] = False PublicFunc.__enableAllButton__(self, ButtonState) if event.button == 1: self.is_left_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.rect_left = None self.rect_right = None self.ui.lineEdit_start_time.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_end_time.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_duration.setText(Constants.STRING_IS_EMPTY) self.canvas.draw() self.ui.lineEdit_energy_percent_orgBcg.setText(Constants.STRING_IS_EMPTY) self.ui.lineEdit_energy_percent_BCG.setText(Constants.STRING_IS_EMPTY) def on_release(self, event): 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: self.rect_left = self.figToolbar.rect_start_x self.rect_right = self.figToolbar.rect_end_x elif self.figToolbar.rect_start_x > self.figToolbar.rect_end_x: self.rect_left = self.figToolbar.rect_end_x self.rect_right = self.figToolbar.rect_start_x else: self.rect_left = self.figToolbar.rect_start_x self.rect_right = self.figToolbar.rect_start_x else: self.rect_left = self.figToolbar.rect_start_x self.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.rect_left < 0: self.rect_left = 0 elif self.rect_left >= len(self.data.BCG): self.rect_left = 0 self.rect_right = 0 if self.rect_right >= len(self.data.BCG): self.rect_right = len(self.data.BCG) - 1 elif self.rect_right < 0: self.rect_left = 0 self.rect_right = 0 if int(self.rect_left) != int(self.rect_right): self.update_label_args(int(self.rect_left), int(self.rect_right)) self.figToolbar.rect_start_x = None self.figToolbar.rect_end_x = 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=0.2, color='r') 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=0.2, color='r') self.ax1.add_patch(self.figToolbar.rect_patch_ax1) # 更新矩形patch的位置和大小 x_start = self.figToolbar.rect_start_x x_end = self.figToolbar.rect_end_x self.figToolbar.rect_patch_ax0.set_xy((min(x_start, x_end), self.rect_down)) self.figToolbar.rect_patch_ax0.set_width(abs(x_end - x_start)) self.figToolbar.rect_patch_ax0.set_height(self.rect_up - self.rect_down) self.figToolbar.rect_patch_ax1.set_xy((min(x_start, x_end), self.rect_down)) self.figToolbar.rect_patch_ax1.set_width(abs(x_end - x_start)) self.figToolbar.rect_patch_ax1.set_height(self.rect_up - self.rect_down) self.canvas.draw() class Data: def __init__(self): self.orgBcg = None self.BCG = None self.Artifact_a = None self.df_Artifact_a = DataFrame(columns=["number", "type", "startTime", "endTime"]) def open_file(self): if (not Path(Config["Path"]["Input_orgBcg"]).exists()) or (not Path(Config["Path"]["Input_BCG"]).exists()): return Result().failure(info=Constants.INPUT_FAILURE + Constants.ARTIFACT_LABEL_FAILURE_REASON["Data_Path_Not_Exist"]) try: self.orgBcg = read_csv(Config["Path"]["Input_orgBcg"], encoding=ConfigParams.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.BCG = read_csv(Config["Path"]["Input_BCG"], encoding=ConfigParams.UTF8_ENCODING, header=None).to_numpy().reshape(-1) except Exception as e: return Result().failure(info=Constants.INPUT_FAILURE + Constants.ARTIFACT_LABEL_FAILURE_REASON["Read_Data_Exception"] + "\n" + format_exc()) # 检查同步后的orgBcg信号和同步后的BCG信号长度是否相同 if len(self.orgBcg) != len(self.BCG): return Result().failure(info=Constants.INPUT_FAILURE + Constants.ARTIFACT_LABEL_FAILURE_REASON["Data_Length_not_Correct"]) return Result().success(info=Constants.INPUT_FINISHED) def get_archive(self): if not Path(Config["Path"]["Save_a"]).exists(): self.Artifact_a = [] return Result().success(info=Constants.ARTIFACT_LABEL_ARCHIVE_NOT_EXIST) else: self.Artifact_a = read_csv(Config["Path"]["Save_a"], encoding=ConfigParams.UTF8_ENCODING, header=None).to_numpy().reshape(-1) try: # 检查体动标签正确性,长度 if len(self.Artifact_a) % 4 != 0: return Result().failure(info=Constants.INPUT_FAILURE + Constants.ARTIFACT_LABEL_FAILURE_REASON[ "Artifact_Format_Not_Correct"]) for i in range(0, len(self.Artifact_a), 4): unit_data = self.Artifact_a[i:i + 4] if len(unit_data) < 4: break self.df_Artifact_a.loc[len(self.df_Artifact_a)] = [int(unit_data[j]) for j in range(4)] except Exception as e: return Result().failure(info=Constants.INPUT_FAILURE + Constants.ARTIFACT_LABEL_FAILURE_REASON[ "Get_Artifact_Format_Exception"] + "\n" + format_exc()) return Result().success(info=Constants.ARTIFACT_LABEL_ARCHIVE_EXIST) def save(self, amount, duration): try: # Artifact_a.txt和Artifact_c.csv的内容遍历 output_lines = [] for row_index in range(len(self.df_Artifact_a)): for col in self.df_Artifact_a.columns: value = self.df_Artifact_a.at[row_index, col] output_lines.append(str(value)) # Artifact_b.txt的内容遍历 dict = { 'type': [1, 2, 3, 4, 5], 'amount': [int(amount[0]), int(amount[1]), int(amount[2]), int(amount[3]), int(amount[4])], 'duration': [int(duration[0]), int(duration[1]), int(duration[2]), int(duration[3]), int(duration[4])] } df_Artifact_b = DataFrame(dict) # 写入文件并保存 self.df_Artifact_a.to_csv(Path(Config["Path"]["Save_a"]), header=False, index=False, sep='\n') df_Artifact_b.to_csv(Path(Config["Path"]["Save_b"]), header=False, index=False, sep='\n') self.df_Artifact_a.to_csv(Path(Config["Path"]["Save_c"]), index=False, encoding=ConfigParams.GBK_ENCODING) except Exception as e: return Result().failure(info=Constants.SAVING_FAILURE + Constants.ARTIFACT_LABEL_FAILURE_REASON[ "Save_Exception"] + "\n" + format_exc()) return Result().success(info=Constants.SAVING_FINISHED) class CustomNavigationToolbar(NavigationToolbar2QT): def __init__(self, canvas, parent): super().__init__(canvas, parent) # 初始化画框工具栏 self.action_Label_Artifact = QAction(Constants.ARTIFACT_LABEL_ACTION_LABEL, self) self.action_Label_Artifact.setFont(QFont(ConfigParams.FONT, 14)) self.action_Label_Artifact.setCheckable(True) self.action_Label_Artifact.setShortcut(QCoreApplication.translate( "MainWindow", ConfigParams.ARTIFACT_LABEL_ACTION_LABEL_ARTIFACT_SHORTCUT_KEY)) self.insertAction(self._actions['pan'], self.action_Label_Artifact) 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_label_artifact() def pan(self, *args): super().pan(*args) self.deactivate_figToorbar_label_artifact() def deactivate_figToorbar_label_artifact(self): if self.action_Label_Artifact.isChecked(): self.action_Label_Artifact.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