From 85a69648e0573d107168ab03c540b92320dde5e9 Mon Sep 17 00:00:00 2001 From: Yorusora <2944763079@qq.com> Date: Thu, 22 May 2025 09:50:03 +0800 Subject: [PATCH 01/26] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BA=86=E9=87=8D?= =?UTF-8?q?=E7=BD=AE=E7=BB=98=E5=9B=BE=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_SA_label.py | 61 +++++++++++++++++++---------------- func/Module_artifact_label.py | 19 ++++++----- func/Module_label_check.py | 16 +++++---- func/Module_mainwindow.py | 16 ++++++++- func/Module_preprocess.py | 7 ++-- 5 files changed, 71 insertions(+), 48 deletions(-) diff --git a/func/Module_SA_label.py b/func/Module_SA_label.py index c6bbeff..53c6a72 100644 --- a/func/Module_SA_label.py +++ b/func/Module_SA_label.py @@ -1000,33 +1000,40 @@ class MainWindow_SA_label(QMainWindow): self.ui.spinBox_correctEnd.setValue(Config["BCG_EP"]) def reset_axes(self): - self.ax0.clear() - self.ax1.clear() - self.ax2.clear() - self.ax3.clear() - self.ax4.clear() - self.ax5.clear() - self.ax6.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) - self.ax1.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) - self.ax2.grid(True) - self.ax2.xaxis.set_major_formatter(ConfigParams.FORMATTER) - self.ax2.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) - self.ax3.grid(True) - self.ax3.xaxis.set_major_formatter(ConfigParams.FORMATTER) - self.ax3.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) - self.ax4.grid(True) - self.ax4.xaxis.set_major_formatter(ConfigParams.FORMATTER) - self.ax4.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) - self.ax5.grid(True) - self.ax5.xaxis.set_major_formatter(ConfigParams.FORMATTER) - self.ax5.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) - self.ax6.grid(True) - self.ax6.xaxis.set_major_formatter(ConfigParams.FORMATTER) + if self.ax0 is not None: + self.ax0.clear() + self.ax0.grid(True) + self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax0.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) + if self.ax1 is not None: + self.ax1.clear() + self.ax1.grid(True) + self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax1.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) + if self.ax2 is not None: + self.ax2.clear() + self.ax2.grid(True) + self.ax2.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax2.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) + if self.ax3 is not None: + self.ax3.clear() + self.ax3.grid(True) + self.ax3.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax3.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) + if self.ax4 is not None: + self.ax4.clear() + self.ax4.grid(True) + self.ax4.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax4.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) + if self.ax5 is not None: + self.ax5.clear() + self.ax5.grid(True) + self.ax5.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax5.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) + if self.ax6 is not None: + self.ax6.clear() + self.ax6.grid(True) + self.ax6.xaxis.set_major_formatter(ConfigParams.FORMATTER) def on_xlim_change(self, event_ax): # 获取当前x轴范围 diff --git a/func/Module_artifact_label.py b/func/Module_artifact_label.py index 805f9f9..7754abe 100644 --- a/func/Module_artifact_label.py +++ b/func/Module_artifact_label.py @@ -592,9 +592,6 @@ class MainWindow_artifact_label(QMainWindow): else: PublicFunc.text_output(self.ui, "(2/6)" + result.info, Constants.TIPS_TYPE_INFO) - self.__reset__() - PublicFunc.finish_operation(self, ButtonState) - # 获取存档 PublicFunc.progressbar_update(self, 3, 6, Constants.LOADING_ARCHIVE, 50) result = self.data.get_archive() @@ -929,13 +926,15 @@ class MainWindow_artifact_label(QMainWindow): 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) + if self.ax0 is not None: + self.ax0.clear() + self.ax0.grid(True) + self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax0.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) + if self.ax1 is not None: + self.ax1.clear() + self.ax1.grid(True) + self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) def on_xlim_change(self, event_ax): try: diff --git a/func/Module_label_check.py b/func/Module_label_check.py index 78ce4e9..b97a1fd 100644 --- a/func/Module_label_check.py +++ b/func/Module_label_check.py @@ -670,13 +670,15 @@ class MainWindow_label_check(QMainWindow): PublicFunc.text_output(self.ui, f"{Constants.LABEL_CHECK_JUMP_X_INDEX}{str(int(x))}", Constants.TIPS_TYPE_INFO) def reset_axes(self): - self.ax0.clear() - self.ax1.clear() - self.ax0.grid(True) - self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) - self.ax0.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) - self.ax1.grid(True) - self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + if self.ax0 is not None: + self.ax0.clear() + self.ax0.grid(True) + self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax0.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) + if self.ax1 is not None: + self.ax1.clear() + self.ax1.grid(True) + self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) def on_xlim_change(self, event_ax): try: diff --git a/func/Module_mainwindow.py b/func/Module_mainwindow.py index d89b0bc..b5d294a 100644 --- a/func/Module_mainwindow.py +++ b/func/Module_mainwindow.py @@ -16,6 +16,7 @@ from func.Module_label_check import MainWindow_label_check from func.Module_precisely_align import MainWindow_precisely_align from func.Module_cut_PSG import MainWindow_cut_PSG from func.Module_artifact_label import MainWindow_artifact_label +from func.Module_resp_quality_label import MainWindow_resp_quality_label from func.Module_SA_label import MainWindow_SA_label from func.utils.Constants import Constants, ConfigParams @@ -62,7 +63,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.precisely_align = None self.cut_PSG = None self.artifact_label = None - + self.resp_quality_label = None self.SA_label = None # 绑定槽函数 @@ -77,6 +78,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.ui.pushButton_precisely_align.clicked.connect(self.__slot_btn_precisely_align__) self.ui.pushButton_cut_PSG.clicked.connect(self.__slot_btn_cut_PSG__) self.ui.pushButton_artifact_label.clicked.connect(self.__slot_btn_artifact_label__) + self.ui.pushButton_resp_quality_label.clicked.connect(self.__slot_btn_resp_quality_label__) self.ui.pushButton_SA_label.clicked.connect(self.__slot_btn_SA_label__) @staticmethod @@ -222,6 +224,18 @@ class MainWindow(QMainWindow, Ui_Signal_Label): # 默认最大化显示而非固定分辨率 self.artifact_label.showMaximized() + def __slot_btn_resp_quality_label__(self): + self.resp_quality_label = MainWindow_resp_quality_label() + root_path = self.ui.plainTextEdit_root_path.toPlainText() + sampID = self.ui.comboBox_sampID.currentText() + if not self.check_root_path(): + return + if not self.check_sampID(): + return + self.resp_quality_label.show(root_path, int(sampID)) + # 默认最大化显示而非固定分辨率 + self.resp_quality_label.showMaximized() + def __slot_btn_SA_label__(self): self.SA_label = MainWindow_SA_label() root_path = self.ui.plainTextEdit_root_path.toPlainText() diff --git a/func/Module_preprocess.py b/func/Module_preprocess.py index cac14da..823aadd 100644 --- a/func/Module_preprocess.py +++ b/func/Module_preprocess.py @@ -385,9 +385,10 @@ class MainWindow_preprocess(QMainWindow): PublicFunc.finish_operation(self, ButtonState) def reset_axes(self): - self.ax0.clear() - self.ax0.grid(True) - self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + if self.ax0 is not None: + self.ax0.clear() + self.ax0.grid(True) + self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) class Data: From a7758e502e0bf63f52a81ecf2456a186c5e714d5 Mon Sep 17 00:00:00 2001 From: Yorusora <2944763079@qq.com> Date: Thu, 22 May 2025 10:02:32 +0800 Subject: [PATCH 02/26] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BA=86=E9=87=8D?= =?UTF-8?q?=E7=BD=AE=E7=BB=98=E5=9B=BE=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_artifact_label.py | 6 ++++-- func/Module_detect_Jpeak.py | 3 ++- func/Module_detect_Rpeak.py | 6 ++++-- func/Module_label_check.py | 6 ++++-- func/Module_preprocess.py | 3 ++- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/func/Module_artifact_label.py b/func/Module_artifact_label.py index 7754abe..f79f52b 100644 --- a/func/Module_artifact_label.py +++ b/func/Module_artifact_label.py @@ -300,8 +300,10 @@ class MainWindow_artifact_label(QMainWindow): del self.rectangles_ax0_patches del self.rectangles_ax1_patches del self.annotation_tableWidget - self.ax0.clear() - self.ax1.clear() + if self.ax0 is not None: + self.ax0.clear() + if self.ax1 is not None: + self.ax1.clear() # 释放资源 del self.data diff --git a/func/Module_detect_Jpeak.py b/func/Module_detect_Jpeak.py index 3744bf6..6f6c5b0 100644 --- a/func/Module_detect_Jpeak.py +++ b/func/Module_detect_Jpeak.py @@ -204,7 +204,8 @@ class MainWindow_detect_Jpeak(QMainWindow): QApplication.processEvents() # 清空画框 - self.ax0.clear() + if self.ax0 is not None: + self.ax0.clear() # 释放资源 del self.data diff --git a/func/Module_detect_Rpeak.py b/func/Module_detect_Rpeak.py index a64d20c..9b73f7d 100644 --- a/func/Module_detect_Rpeak.py +++ b/func/Module_detect_Rpeak.py @@ -197,8 +197,10 @@ class MainWindow_detect_Rpeak(QMainWindow): QApplication.processEvents() # 清空画框 - self.ax0.clear() - self.ax1.clear() + if self.ax0 is not None: + self.ax0.clear() + if self.ax1 is not None: + self.ax1.clear() # 释放资源 del self.data diff --git a/func/Module_label_check.py b/func/Module_label_check.py index b97a1fd..ec22501 100644 --- a/func/Module_label_check.py +++ b/func/Module_label_check.py @@ -340,8 +340,10 @@ class MainWindow_label_check(QMainWindow): del self.point_peak_original del self.point_peak_corrected del self.annotation_tableWidget - self.ax0.clear() - self.ax1.clear() + if self.ax0 is not None: + self.ax0.clear() + if self.ax1 is not None: + self.ax1.clear() # 释放资源 del self.data diff --git a/func/Module_preprocess.py b/func/Module_preprocess.py index 823aadd..dbf6921 100644 --- a/func/Module_preprocess.py +++ b/func/Module_preprocess.py @@ -239,7 +239,8 @@ class MainWindow_preprocess(QMainWindow): QApplication.processEvents() # 清空画框 - self.ax0.clear() + if self.ax0 is not None: + self.ax0.clear() # 释放资源 del self.data From c6778b55486fc6aae2e598cebca4ab271a0cb01c Mon Sep 17 00:00:00 2001 From: Yorusora <2944763079@qq.com> Date: Thu, 22 May 2025 10:38:47 +0800 Subject: [PATCH 03/26] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BA=86=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E6=95=B0=E6=8D=AE=E7=9A=84=E4=BB=A3=E7=A0=81=20?= =?UTF-8?q?=E6=9B=B4=E6=96=B0README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 + func/Module_SA_label.py | 23 ++++++----- func/Module_artifact_label.py | 3 -- func/Module_detect_Jpeak.py | 3 -- func/Module_detect_Rpeak.py | 3 -- func/Module_label_check.py | 26 ++++++++---- func/Module_precisely_align.py | 75 +++++++++++++++++++--------------- func/Module_preprocess.py | 3 -- func/utils/ConfigParams.py | 34 +++++++++++++-- func/utils/Constants.py | 30 +++++++++----- 10 files changed, 125 insertions(+), 77 deletions(-) diff --git a/README.md b/README.md index 1b5bdd7..76d5310 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ 2、体动选取区域的判别尚未做的很完整,选中多个已有的体动的区域时可能会出现问题 +3、部分模块在导入失败后重新导入时会出现问题,已知模块有<人工纠正>、<体动标注>、<呼吸可用性及间期标注>、<睡眠呼吸暂停事件标注>,主要是涉及到按钮状态的设置,有待后续优化 + ## 1、主菜单 ![](/img/0.png) diff --git a/func/Module_SA_label.py b/func/Module_SA_label.py index 53c6a72..8f4c466 100644 --- a/func/Module_SA_label.py +++ b/func/Module_SA_label.py @@ -1266,7 +1266,7 @@ class Data: def open_file(self): if Path(Config["Path"]["Input_OrgBCG"]).is_file(): - Config["Path"]["Input_OrgBCG"] = str(Path(Config["Path"]["Input_orgBcg"]).parent) + Config["Path"]["Input_OrgBCG"] = str(Path(Config["Path"]["Input_OrgBCG"]).parent) if Path(Config["Path"]["Input_Tho"]).is_file(): Config["Path"]["Input_Tho"] = str(Path(Config["Path"]["Input_Tho"]).parent) if Path(Config["Path"]["Input_Abd"]).is_file(): @@ -1282,16 +1282,6 @@ class Data: if Path(Config["Path"]["Input_Label"]).is_file(): Config["Path"]["Input_Label"] = str(Path(Config["Path"]["Input_Label"]).parent) - if ((not Path(Config["Path"]["Input_OrgBCG"]).exists()) - or (not Path(Config["Path"]["Input_Tho"]).exists()) - or (not Path(Config["Path"]["Input_Abd"]).exists()) - or (not Path(Config["Path"]["Input_FlowT"]).exists()) - or (not Path(Config["Path"]["Input_FlowP"]).exists()) - or (not Path(Config["Path"]["Input_SpO2"]).exists()) - or (not Path(Config["Path"]["Input_Artifact"]).exists())): - return Result().failure(info=Constants.INPUT_FAILURE + - Constants.FAILURE_REASON["Path_Not_Exist"]) - result = PublicFunc.examine_file(Config["Path"]["Input_OrgBCG"], ConfigParams.ORGBCG_SYNC) if result.status: Config["Path"]["Input_OrgBCG"] = result.data["path"] @@ -1338,6 +1328,17 @@ class Data: Config["Path"]["Save_2"] = str( Path(Config["Path"]["Save_2"]) / Path(ConfigParams.SA_LABEL_ADD + ConfigParams.ENDSWITH_CSV)) + if not Path(Config["Path"]["Input_Artifact"]).exists(): + return Result().failure(info=Constants.INPUT_FAILURE + "\n" + + ConfigParams.ARTIFACT_A + ":" + + Config["Path"]["Input_Artifact"] + + Constants.FAILURE_REASON["Path_Not_Exist"]) + if not Path(Config["Path"]["Input_Label"]).exists(): + return Result().failure(info=Constants.INPUT_FAILURE + "\n" + + ConfigParams.SA_LABEL_SYNC + ":" + + Config["Path"]["Input_Label"] + + Constants.FAILURE_REASON["Path_Not_Exist"]) + try: self.OrgBCG = read_csv(Config["Path"]["Input_OrgBCG"], encoding=ConfigParams.UTF8_ENCODING, diff --git a/func/Module_artifact_label.py b/func/Module_artifact_label.py index f79f52b..e0ce628 100644 --- a/func/Module_artifact_label.py +++ b/func/Module_artifact_label.py @@ -1209,9 +1209,6 @@ class Data: if Path(Config["Path"]["Input_BCG"]).is_file(): Config["Path"]["Input_BCG"] = str(Path(Config["Path"]["Input_BCG"]).parent) - if (not Path(Config["Path"]["Input_orgBcg"]).exists()) or (not Path(Config["Path"]["Input_BCG"]).exists()): - return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Path_Not_Exist"]) - result = PublicFunc.examine_file(Config["Path"]["Input_orgBcg"], ConfigParams.ORGBCG_SYNC) if result.status: Config["Path"]["Input_orgBcg"] = result.data["path"] diff --git a/func/Module_detect_Jpeak.py b/func/Module_detect_Jpeak.py index 6f6c5b0..d8b8710 100644 --- a/func/Module_detect_Jpeak.py +++ b/func/Module_detect_Jpeak.py @@ -398,9 +398,6 @@ class Data: if Path(Config["Path"]["Input"]).is_file(): Config["Path"]["Input"] = str(Path(Config["Path"]["Input"]).parent) - if not Path(Config["Path"]["Input"]).exists(): - return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Path_Not_Exist"]) - result = PublicFunc.examine_file(Config["Path"]["Input"], ConfigParams.BCG_FILTER) if result.status: Config["Path"]["Input"] = result.data["path"] diff --git a/func/Module_detect_Rpeak.py b/func/Module_detect_Rpeak.py index 9b73f7d..7100d16 100644 --- a/func/Module_detect_Rpeak.py +++ b/func/Module_detect_Rpeak.py @@ -399,9 +399,6 @@ class Data: if Path(Config["Path"]["Input"]).is_file(): Config["Path"]["Input"] = str(Path(Config["Path"]["Input"]).parent) - if not Path(Config["Path"]["Input"]).exists(): - return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Path_Not_Exist"]) - result = PublicFunc.examine_file(Config["Path"]["Input"], ConfigParams.ECG_FILTER) if result.status: Config["Path"]["Input"] = result.data["path"] diff --git a/func/Module_label_check.py b/func/Module_label_check.py index ec22501..962c031 100644 --- a/func/Module_label_check.py +++ b/func/Module_label_check.py @@ -933,18 +933,28 @@ class Data: result = PublicFunc.examine_file(Config["Path"]["Input_Signal"], signal) if result.status: Config["Path"]["Input_Signal"] = result.data["path"] - Config["Path"]["Input_Peak"] = str( - Path(Config["Path"]["Input_Peak"]) / Path(peak + str(Config["InputConfig"]["Freq"]) + ConfigParams.ENDSWITH_TXT)) Config["InputConfig"]["Freq"] = result.data["freq"] - Config["Path"]["Input_Approximately_Align"] = str( - Path(Config["Path"]["Input_Approximately_Align"]) / Path(ConfigParams.APPROXIMATELY_ALIGN_INFO + ConfigParams.ENDSWITH_CSV)) - Config["Path"]["Save"] = str( - Path(Config["Path"]["Save"]) / Path(save + str(Config["InputConfig"]["Freq"]) + ConfigParams.ENDSWITH_TXT)) else: return result - if (not Path(Config["Path"]["Input_Signal"]).exists()) or (not Path(Config["Path"]["Input_Peak"]).exists()): - return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Path_Not_Exist"]) + Config["Path"]["Input_Peak"] = str( + Path(Config["Path"]["Input_Peak"]) / Path(peak + str(Config["InputConfig"]["Freq"]) + ConfigParams.ENDSWITH_TXT)) + Config["Path"]["Input_Approximately_Align"] = str( + Path(Config["Path"]["Input_Approximately_Align"]) / Path( + ConfigParams.APPROXIMATELY_ALIGN_INFO + ConfigParams.ENDSWITH_CSV)) + Config["Path"]["Save"] = str( + Path(Config["Path"]["Save"]) / Path(save + str(Config["InputConfig"]["Freq"]) + ConfigParams.ENDSWITH_TXT)) + + if not Path(Config["Path"]["Input_Peak"]).exists(): + return Result().failure(info=Constants.INPUT_FAILURE + "\n" + + peak + ":" + + Config["Path"]["Input_Peak"] + + Constants.FAILURE_REASON["Path_Not_Exist"]) + if not Path(Config["Path"]["Input_Approximately_Align"]).exists(): + return Result().failure(info=Constants.INPUT_FAILURE + "\n" + + ConfigParams.APPROXIMATELY_ALIGN_INFO + ":" + + Config["Path"]["Input_Approximately_Align"] + + Constants.FAILURE_REASON["Path_Not_Exist"]) try: self.raw_data = read_csv(Config["Path"]["Input_Signal"], diff --git a/func/Module_precisely_align.py b/func/Module_precisely_align.py index 44e9af2..41f67ad 100644 --- a/func/Module_precisely_align.py +++ b/func/Module_precisely_align.py @@ -687,7 +687,7 @@ class MainWindow_precisely_align(QMainWindow): PublicFunc.finish_operation(self, ButtonState) def __slot_btn_calculate_correlation__(self, test1=None, shift_front=None, shift_back=None): - # TODO:这里有个未知的问BUG,虽然不影响功能,但会影响代码整洁性,第一个形参赋值为None时,之后使用变量时将会变成False,不知道为什么 + # TODO:这里有个未知的BUG,虽然不影响功能,但会影响代码整洁性,第一个形参赋值为None时,之后使用变量时将会变成False,不知道为什么 PublicFunc.__disableAllButton__(self, ButtonState) sender = self.sender() @@ -1458,52 +1458,63 @@ class Data: if result.status: Config["Path"]["Input_OrgBCG"] = result.data["path"] Config["InputConfig"]["orgBcgFreq"] = result.data["freq"] - Config["Path"]["Input_Approximately_Align"] = str( - Path(Config["Path"]["Input_Approximately_Align"]) / Path( - ConfigParams.APPROXIMATELY_ALIGN_INFO + ConfigParams.ENDSWITH_CSV)) - Config["Path"]["Save_AlignInfo"] = str( - Path(Config["Path"]["Save_AlignInfo"]) / Path( - ConfigParams.PRECISELY_ALIGN_INFO + ConfigParams.ENDSWITH_TXT)) - Config["Path"]["Save_OrgBCG"] = str( - Path(Config["Path"]["Save_OrgBCG"]) / Path( - ConfigParams.ORGBCG_SYNC + str(Config["InputConfig"]["orgBcgFreq"]) + ConfigParams.ENDSWITH_TXT)) else: return result + Config["Path"]["Input_Approximately_Align"] = str( + Path(Config["Path"]["Input_Approximately_Align"]) / Path( + ConfigParams.APPROXIMATELY_ALIGN_INFO + ConfigParams.ENDSWITH_CSV)) + Config["Path"]["Save_AlignInfo"] = str( + Path(Config["Path"]["Save_AlignInfo"]) / Path( + ConfigParams.PRECISELY_ALIGN_INFO + ConfigParams.ENDSWITH_TXT)) + Config["Path"]["Save_OrgBCG"] = str( + Path(Config["Path"]["Save_OrgBCG"]) / Path( + ConfigParams.ORGBCG_SYNC + str(Config["InputConfig"]["orgBcgFreq"]) + ConfigParams.ENDSWITH_TXT)) result = PublicFunc.examine_file(Config["Path"]["Input_BCG"], ConfigParams.BCG_FILTER) if result.status: Config["Path"]["Input_BCG"] = result.data["path"] Config["InputConfig"]["BCGFreq"] = result.data["freq"] - Config["Path"]["Input_Jpeak"] = str( - Path(Config["Path"]["Input_Jpeak"]) / Path(ConfigParams.JPEAK_REVISE_CORRECTED + str(Config["InputConfig"]["BCGFreq"]) + ConfigParams.ENDSWITH_TXT)) - Config["Path"]["Save_BCG"] = str( - Path(Config["Path"]["Save_BCG"]) / Path( - ConfigParams.BCG_SYNC + str(Config["InputConfig"]["BCGFreq"]) + ConfigParams.ENDSWITH_TXT)) - Config["Path"]["Save_Jpeak"] = str( - Path(Config["Path"]["Save_Jpeak"]) / Path( - ConfigParams.JPEAK_SYNC + str(Config["InputConfig"]["BCGFreq"]) + ConfigParams.ENDSWITH_TXT)) else: return result + Config["Path"]["Input_Jpeak"] = str( + Path(Config["Path"]["Input_Jpeak"]) / Path(ConfigParams.JPEAK_REVISE_CORRECTED + str( + Config["InputConfig"]["BCGFreq"]) + ConfigParams.ENDSWITH_TXT)) + Config["Path"]["Save_BCG"] = str( + Path(Config["Path"]["Save_BCG"]) / Path( + ConfigParams.BCG_SYNC + str(Config["InputConfig"]["BCGFreq"]) + ConfigParams.ENDSWITH_TXT)) + Config["Path"]["Save_Jpeak"] = str( + Path(Config["Path"]["Save_Jpeak"]) / Path( + ConfigParams.JPEAK_SYNC + str(Config["InputConfig"]["BCGFreq"]) + ConfigParams.ENDSWITH_TXT)) result = PublicFunc.examine_file(Config["Path"]["Input_ECG"], ConfigParams.ECG_FILTER) if result.status: Config["Path"]["Input_ECG"] = result.data["path"] Config["InputConfig"]["ECGFreq"] = result.data["freq"] - Config["Path"]["Input_Rpeak"] = str( - Path(Config["Path"]["Input_Rpeak"]) / Path(ConfigParams.RPEAK_FINAL_CORRECTED + str(Config["InputConfig"]["ECGFreq"]) + ConfigParams.ENDSWITH_TXT)) - Config["Path"]["Save_ECG"] = str( - Path(Config["Path"]["Save_ECG"]) / Path( - ConfigParams.ECG_SYNC + str(Config["InputConfig"]["ECGFreq"]) + ConfigParams.ENDSWITH_TXT)) - Config["Path"]["Save_Rpeak"] = str( - Path(Config["Path"]["Save_Rpeak"]) / Path( - ConfigParams.RPEAK_SYNC + str(Config["InputConfig"]["ECGFreq"]) + ConfigParams.ENDSWITH_TXT)) else: return result + Config["Path"]["Input_Rpeak"] = str( + Path(Config["Path"]["Input_Rpeak"]) / Path( + ConfigParams.RPEAK_FINAL_CORRECTED + str(Config["InputConfig"]["ECGFreq"]) + ConfigParams.ENDSWITH_TXT)) + Config["Path"]["Save_ECG"] = str( + Path(Config["Path"]["Save_ECG"]) / Path( + ConfigParams.ECG_SYNC + str(Config["InputConfig"]["ECGFreq"]) + ConfigParams.ENDSWITH_TXT)) + Config["Path"]["Save_Rpeak"] = str( + Path(Config["Path"]["Save_Rpeak"]) / Path( + ConfigParams.RPEAK_SYNC + str(Config["InputConfig"]["ECGFreq"]) + ConfigParams.ENDSWITH_TXT)) - if ((not Path(Config["Path"]["Input_OrgBCG"]).exists()) - or (not Path(Config["Path"]["Input_BCG"]).exists()) - or (not Path(Config["Path"]["Input_Jpeak"]).exists()) - or (not Path(Config["Path"]["Input_ECG"]).exists()) - or (not Path(Config["Path"]["Input_Rpeak"]).exists())): - return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + if not Path(Config["Path"]["Input_Jpeak"]).exists(): + return Result().failure(info=Constants.INPUT_FAILURE + "\n" + + ConfigParams.JPEAK_REVISE_CORRECTED + ":" + + Config["Path"]["Input_Jpeak"] + + Constants.FAILURE_REASON["Path_Not_Exist"]) + if not Path(Config["Path"]["Input_Rpeak"]).exists(): + return Result().failure(info=Constants.INPUT_FAILURE + "\n" + + ConfigParams.RPEAK_FINAL_CORRECTED + ":" + + Config["Path"]["Input_Rpeak"] + + Constants.FAILURE_REASON["Path_Not_Exist"]) + if not Path(Config["Path"]["Input_Approximately_Align"]).exists(): + return Result().failure(info=Constants.INPUT_FAILURE + "\n" + + ConfigParams.APPROXIMATELY_ALIGN_INFO + ":" + + Config["Path"]["Input_Approximately_Align"] + + Constants.FAILURE_REASON["Path_Not_Exist"]) try: self.raw_orgBcg = read_csv(Config["Path"]["Input_OrgBCG"], diff --git a/func/Module_preprocess.py b/func/Module_preprocess.py index dbf6921..8e37866 100644 --- a/func/Module_preprocess.py +++ b/func/Module_preprocess.py @@ -410,9 +410,6 @@ class Data: if Path(Config["Path"]["Input"]).is_file(): Config["Path"]["Input"] = str(Path(Config["Path"]["Input"]).parent) - if not Path(Config["Path"]["Input"]).exists(): - return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Path_Not_Exist"]) - result = PublicFunc.examine_file(Config["Path"]["Input"], signal) if result.status: Config["Path"]["Input"] = result.data["path"] diff --git a/func/utils/ConfigParams.py b/func/utils/ConfigParams.py index 254fa36..04582c6 100644 --- a/func/utils/ConfigParams.py +++ b/func/utils/ConfigParams.py @@ -68,6 +68,8 @@ class ConfigParams: SA_LABEL_SYNC: str = "SA Label_Sync" SA_LABEL_CORRECTED: str = "SA Label_corrected" SA_LABEL_ADD: str = "SA Label_add" + RESP_QUALITY_LABEL: str = "Resp_quality_label" + THO_PEAK: str = "Tho_peak_" # 数据粗同步 APPROXIMATELY_ALIGN_CONFIG_FILE_PATH: str = "./config/Config_approximately_align.yaml" @@ -250,6 +252,32 @@ class ConfigParams: ARTIFACT_LABEL_LABEL_TRANSPARENCY: float = 0.3 ARTIFACT_LABEL_ACTION_LABEL_ARTIFACT_SHORTCUT_KEY: str = "Z" + # 呼吸可用性及间期标注 + RESP_QUALITY_LABEL_CONFIG_FILE_PATH: str = "./config/Config_resp_quality_label.yaml" + RESP_QUALITY_LABEL_CONFIG_NEW_CONTENT: dict = { + "InputConfig": { + "OrgBCGFreq": 1000, + "ThoFreq": 100, + "OrgBCGUseFreq": 1000, + "ThoUseFreq": 100 + }, + "Threshold": { + "Low": 0.65, + "High": 0.8 + }, + "FindPeaks" : { + "MinInterval": 300, + "MinHeight": 0.1 + }, + "Filter": { + "BandPassLow": 0.1, + "BandPassHigh": 1 + } + } + RESP_QUALITY_LABEL_PREPROCESS_FC: int = 1 + RESP_QUALITY_LABEL_LABEL_TRANSPARENCY: float = 0.2 + RESP_QUALITY_LABEL_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY: str = "Z" + # 睡眠呼吸暂停事件标注 SA_LABEL_CONFIG_FILE_PATH: str = "./config/Config_SA_label.yaml" SA_LABEL_CONFIG_NEW_CONTENT: dict = { @@ -314,7 +342,7 @@ class ConfigParams: RESP_QUALITY_LABEL_INPUT_THO_DEFAULT_FS: int = 200 RESP_QUALITY_LABEL_PARTS_TIME_SEC: int = 30 - RESP_QUALITY_LABEL_PREPROCESS_FC: int = 1 + RESP_QUALITY_LABEL_THRESHOLD1_DEFAULT: float = 0.65 RESP_QUALITY_LABEL_THRESHOLD2_DEFAULT: float = 0.8 @@ -323,9 +351,9 @@ class ConfigParams: RESP_QUALITY_LABEL_CUSTOM_LOW_DEFAULT: float = 0.1 RESP_QUALITY_LABEL_CUSTOM_HIGH_DEFAULT: float = 1 - RESP_QUALITY_LABEL_LABEL_TRANSPARENCY: float = 0.2 - RESP_QUALITY_LABEL_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY: str = "Z" + + # 睡眠呼吸暂停事件打标 diff --git a/func/utils/Constants.py b/func/utils/Constants.py index 717a91b..ad4749a 100644 --- a/func/utils/Constants.py +++ b/func/utils/Constants.py @@ -133,6 +133,7 @@ class Constants: "Update_tableWidget_Exception": "(更新表格异常)", "Update_Info_Exception": "(更新信息异常)", "Label_Format_Exception": "(获取标签格式异常)", + "Calculate_Peak_Exception": "(计算峰值异常)", "res_orgBcg_Not_Exist": "(切割后orgBcg不存在)", "res_BCG_Not_Exist": "(切割后BCG不存在)", @@ -377,6 +378,23 @@ class Constants: background-color: #00ff00; /* 鼠标悬停时的背景颜色 */ }""" + # 呼吸可用性及间期标注 + RESP_QUALITY_LABEL_CALCULATING_PEAK: str = "正在计算峰值" + RESP_QUALITY_LABEL_CALCULATE_FINISHED: str = "计算完成" + RESP_QUALITY_LABEL_CALCULATE_FAILURE: str = "计算失败" + + RESP_QUALITY_LABEL_PLOT_LABEL_ORGBCG: str = "BDR_Sync by filter OrgBCG_Sync" + RESP_QUALITY_LABEL_PLOT_LABEL_THO: str = "THO_Sync after preprocess" + RESP_QUALITY_LABEL_PLOT_LABEL_THO_PEAKS: str = "Tho_peak" + RESP_QUALITY_LABEL_PLOT_LABEL_ARTIFACT: str = "Artifact" + RESP_QUALITY_LABEL_SPECTRUM_BDR_TITLE: str = "Spectrum of BDR_sync by filter OrgBCG_Sync" + RESP_QUALITY_LABEL_SPECTRUM_THO_TITLE: str = "Spectrum of THO_sync after preprocess" + RESP_QUALITY_LABEL_SPECTRUM_ORGBCG_LABEL: str = "orgBcg" + RESP_QUALITY_LABEL_SPECTRUM_BDR_LABEL: str = "BDR" + RESP_QUALITY_LABEL_SPECTRUM_THO_LABEL: str = "THO" + + RESP_QUALITY_LABEL_ACTION_LABEL_MULTIPLE_NAME: str = f"批量更改标签({ConfigParams.RESP_QUALITY_LABEL_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY})" + # 睡眠呼吸暂停事件标注 SA_LABEL_JUMP: str = "跳转到事件" SA_LABEL_VIEWING_FIRST: str = "你正在查看第1个事件" @@ -477,14 +495,8 @@ class Constants: RESP_QUALITY_LABEL_INPUT_ARTIFACT_FAILURE_FORMAT: str = "导入体动失败,请检查体动标签格式" RESP_QUALITY_LABEL_INPUT_ARTIFACT_FAILURE_LENGTH: str = "导入体动失败,请检查体动长度是否为4的倍数" - RESP_QUALITY_LABEL_RUNNING: str = "开始执行任务<呼吸可用性及间期标注>" - RESP_QUALITY_LABEL_PLOT_LABEL_ORGBCG: str = "BDR_sync by filter orgBcg_sync" - RESP_QUALITY_LABEL_PLOT_LABEL_THO: str = "THO_sync after preprocess" - RESP_QUALITY_LABEL_PLOT_LABEL_THO_PEAKS: str = "THO_peak" - RESP_QUALITY_LABEL_PLOT_LABEL_ARTIFACT: str = "Artifact" RESP_QUALITY_LABEL_VIEWING_THE_FIRST_PART: str = "你正在查看第1段信号" RESP_QUALITY_LABEL_VIEWING_THE_LAST_PART: str = "你正在查看最后1段信号" - RESP_QUALITY_LABEL_ACTION_LABEL_MULTIPLE_NAME: str = f"批量更改标签({ConfigParams.RESP_QUALITY_LABEL_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY})" RESP_QUALITY_LABEL_CUSTOM_NAVIGATIONTOOLBAR_WIDGET_NAME: str = "MainWindow" RESP_QUALITY_LABEL_BUTTON_PRESS_EVENT: str = "button_press_event" RESP_QUALITY_LABEL_BUTTON_RELEASE_EVENT: str = "button_release_event" @@ -503,11 +515,7 @@ class Constants: RESP_QUALITY_LABEL_C_QUALITY: int = -1 RESP_QUALITY_LABEL_LABELED: str = "已标注" RESP_QUALITY_LABEL_TOBELABELED: str = "未标注" - RESP_QUALITY_LABEL_SPECTRUM_BDR_TITLE: str = "Spectrum of BDR_sync by filter orgBcg_sync" - RESP_QUALITY_LABEL_SPECTRUM_THO_TITLE: str = "Spectrum of THO_sync after preprocess" - RESP_QUALITY_LABEL_SPECTRUM_ORGBCG_LABEL: str = "orgBcg" - RESP_QUALITY_LABEL_SPECTRUM_BDR_LABEL: str = "BDR" - RESP_QUALITY_LABEL_SPECTRUM_THO_LABEL: str = "THO" + RESP_QUALITY_LABEL_CUSTOM_FILTER_ARGS_ERROR: str = "orgBcg带通滤波频率设置范围应为数字,范围是0~1" RESP_QUALITY_LABEL_AUTOLABEL_ARGS_ERROR: str = "人工标注阈值设置范围应为数字,范围是0~1" RESP_QUALITY_LABEL_CHECK_ARGS_QUESTION_CONTENT: str = "你确定要执行此操作吗,请确保参数输入正确" From 17b896e49dfa9953bbfcd5dbc2c8103315d3956a Mon Sep 17 00:00:00 2001 From: Yorusora <2944763079@qq.com> Date: Thu, 22 May 2025 10:50:51 +0800 Subject: [PATCH 04/26] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BA=86=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=E4=BD=93=E5=8A=A8=E6=A0=87=E7=AD=BE=E6=AD=A3=E7=A1=AE?= =?UTF-8?q?=E6=80=A7=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- func/Module_SA_label.py | 8 +------- func/utils/PublicFunc.py | 13 ++++++++++++- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 76d5310..8ef99de 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ 2、体动选取区域的判别尚未做的很完整,选中多个已有的体动的区域时可能会出现问题 -3、部分模块在导入失败后重新导入时会出现问题,已知模块有<人工纠正>、<体动标注>、<呼吸可用性及间期标注>、<睡眠呼吸暂停事件标注>,主要是涉及到按钮状态的设置,有待后续优化 +3、部分模块在导入失败后重新导入时会出现问题,已知模块有<人工纠正>、<体动标注>、<呼吸可用性及间期标注>、<睡眠呼吸暂停事件标注>,主要是涉及到按钮状态的设置,有待后续优化。当前将这些有涉及到的功能,禁止了导入数据后在不关闭界面的情况下直接重新导入 ## 1、主菜单 diff --git a/func/Module_SA_label.py b/func/Module_SA_label.py index 8f4c466..e02be1a 100644 --- a/func/Module_SA_label.py +++ b/func/Module_SA_label.py @@ -1368,13 +1368,7 @@ class Data: try: # 检查体动标签正确性,长度 - if len(self.Artifact) % 4 != 0: - return Result().failure(info=Constants.INPUT_FAILURE + - Constants.FAILURE_REASON["Artifact_Format_Not_Correct"]) - for i in range(0, len(self.Artifact), 4): - unit_data = self.Artifact[i:i + 4] - if len(unit_data) < 4: - break + PublicFunc.examine_artifact(self.Artifact) self.Artifact = self.Artifact.reshape(-1, 4) except Exception as e: return Result().failure(info=Constants.INPUT_FAILURE + diff --git a/func/utils/PublicFunc.py b/func/utils/PublicFunc.py index 8a33394..4de4878 100644 --- a/func/utils/PublicFunc.py +++ b/func/utils/PublicFunc.py @@ -205,4 +205,15 @@ class PublicFunc: "path": str(path), "freq": int(freq) } - return Result().success(data=data) \ No newline at end of file + return Result().success(data=data) + + @staticmethod + def examine_artifact(artifact): + # 检查体动标签正确性,长度 + if len(artifact) % 4 != 0: + return Result().failure(info=Constants.INPUT_FAILURE + + Constants.FAILURE_REASON["Artifact_Format_Not_Correct"]) + for i in range(0, len(artifact), 4): + unit_data = artifact[i:i + 4] + if len(unit_data) < 4: + break \ No newline at end of file From b57bd9e7fae781e532e3660331683962991374a3 Mon Sep 17 00:00:00 2001 From: Yorusora <2944763079@qq.com> Date: Thu, 22 May 2025 15:58:29 +0800 Subject: [PATCH 05/26] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BA=86<=E5=91=BC?= =?UTF-8?q?=E5=90=B8=E5=8F=AF=E7=94=A8=E6=80=A7=E5=8F=8A=E9=97=B4=E6=9C=9F?= =?UTF-8?q?=E6=A0=87=E6=B3=A8>=E7=9A=84=E4=BB=A3=E7=A0=81=E9=87=8D?= =?UTF-8?q?=E6=9E=84=20=E4=BF=AE=E5=A4=8D=E4=BA=86<=E4=BA=BA=E5=B7=A5?= =?UTF-8?q?=E7=BA=A0=E6=AD=A3>=E4=B8=AD=E5=A4=9A=E6=AC=A1=E5=AF=BB?= =?UTF-8?q?=E5=B3=B0=E6=97=B6=E4=BC=9A=E4=BF=9D=E5=AD=98=E5=A4=9A=E4=B8=AA?= =?UTF-8?q?=E7=9B=B8=E5=90=8C=E5=B3=B0=E5=80=BC=E6=A8=AA=E5=9D=90=E6=A0=87?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_label_check.py | 3 +- func/Module_resp_quality_label.py | 1552 +++++++++++++++++ func/utils/ConfigParams.py | 3 +- func/utils/Constants.py | 89 +- .../MainWindow_resp_quality_label.py | 27 +- .../MainWindow_resp_quality_label.ui | 25 +- .../resp_quality_label_input_setting.py | 10 +- .../resp_quality_label_input_setting.ui | 2 +- 8 files changed, 1637 insertions(+), 74 deletions(-) create mode 100644 func/Module_resp_quality_label.py diff --git a/func/Module_label_check.py b/func/Module_label_check.py index 962c031..0a7cbf2 100644 --- a/func/Module_label_check.py +++ b/func/Module_label_check.py @@ -9,7 +9,7 @@ from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication, QTableWidg 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 numpy import append, delete, arange, setdiff1d from overrides import overrides from pandas import read_csv, DataFrame from scipy.signal import find_peaks @@ -818,6 +818,7 @@ class MainWindow_label_check(QMainWindow): height=Config["FindPeaks"]["MinHeight"], distance=Config["FindPeaks"]["MinInterval"]) peaks_idx = peaks_idx + int(rect_left) + peaks_idx = setdiff1d(peaks_idx, self.data.corrected_peak) if len(peaks_idx) != 0: PublicFunc.text_output(self.ui, f"{Constants.LABEL_CHECK_ADD_POINTS_SUCCESSFULLY}{peaks_idx}", Constants.TIPS_TYPE_INFO) diff --git a/func/Module_resp_quality_label.py b/func/Module_resp_quality_label.py new file mode 100644 index 0000000..38d21b7 --- /dev/null +++ b/func/Module_resp_quality_label.py @@ -0,0 +1,1552 @@ +from gc import collect +from pathlib import Path +from traceback import format_exc + +import matplotlib.pyplot as plt +from PySide6.QtCore import QCoreApplication +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 import array, full, int64, append, zeros, where, arange, float64, nan, place, delete, setdiff1d +from overrides import overrides +from pandas import read_csv, DataFrame +from scipy.signal import find_peaks, resample +from yaml import dump, load, FullLoader + +from func.utils.PublicFunc import PublicFunc +from func.utils.Constants import Constants, ConfigParams +from func.Filters.Preprocessing import Butterworth_for_BCG_PreProcess, Butterworth_for_ECG_PreProcess +from func.utils.Result import Result +from func.utils.resp_quality_label import pre_process, get_slice, evaluate_quality +from func.utils.resp_quality_label_filter import get_bandpass_bcgsignal + +from ui.MainWindow.MainWindow_resp_quality_label import Ui_MainWindow_resp_quality_label +from ui.setting.resp_quality_label_input_setting import Ui_MainWindow_resp_quality_label_input_setting + + +Config = { + +} + +ButtonState = { + "Default": { + "pushButton_input_setting": True, + "pushButton_input_and_calculate_peaks": True, + "pushButton_calculate_peaks": False, + "pushButton_calculate_peaks_save": False, + "pushButton_input_data_and_label": True, + "pushButton_autoqualitylabel_recalculate": False, + "pushButton_refilter_orgBcg": False, + "pushButton_valid": False, + "pushButton_invalid": False, + "pushButton_reset": False, + "pushButton_prev": False, + "pushButton_next": False, + "pushButton_save": False + }, + "Current": { + "pushButton_input_setting": True, + "pushButton_input_and_calculate_peaks": True, + "pushButton_calculate_peaks": False, + "pushButton_calculate_peaks_save": False, + "pushButton_input_data_and_label": True, + "pushButton_autoqualitylabel_recalculate": False, + "pushButton_refilter_orgBcg": False, + "pushButton_valid": False, + "pushButton_invalid": False, + "pushButton_reset": False, + "pushButton_prev": False, + "pushButton_next": False, + "pushButton_save": False + } +} + + +class SettingWindow(QMainWindow): + + def __init__(self, root_path, sampID): + super(SettingWindow, self).__init__() + self.ui = Ui_MainWindow_resp_quality_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_signal_OrgBCG.valueChanged.connect(self.__update_ui__) + self.ui.spinBox_input_freq_signal_Tho.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.RESP_QUALITY_LABEL_CONFIG_FILE_PATH).exists(): + with open(ConfigParams.RESP_QUALITY_LABEL_CONFIG_FILE_PATH, "w") as f: + dump(ConfigParams.RESP_QUALITY_LABEL_CONFIG_NEW_CONTENT, f) + + with open(ConfigParams.RESP_QUALITY_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)))), + "Input_Tho": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + Path(str(self.sampID)))), + "Input_Artifact": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + Path(str(self.sampID)))), + "Save_Resp_quality_label": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + Path(str(self.sampID)))), + "Save_Tho_peak": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + Path(str(self.sampID)))) + }, + "CurrentPartNum": 1, + "DataPartNum": 0, + "CurrentOrgBCGIndex": 0, + "CurrentThoIndex": 0 + }) + + # 数据回显 + self.ui.spinBox_input_freq_signal_OrgBCG.setValue(Config["InputConfig"]["OrgBCGFreq"]) + self.ui.spinBox_input_freq_signal_Tho.setValue(Config["InputConfig"]["ThoFreq"]) + self.ui.plainTextEdit_file_path_input_signal_OrgBCG.setPlainText(Config["Path"]["Input_OrgBCG"]) + self.ui.plainTextEdit_file_path_input_signal_Tho.setPlainText(Config["Path"]["Input_Tho"]) + self.ui.plainTextEdit_file_path_input_artifact.setPlainText(Config["Path"]["Input_Artifact"]) + self.ui.plainTextEdit_file_path_save_Resp_quality_label.setPlainText(Config["Path"]["Save_Resp_quality_label"]) + self.ui.plainTextEdit_file_path_save_Tho_peak.setPlainText(Config["Path"]["Save_Tho_peak"]) + + def __write_config__(self): + # 从界面写入配置 + Config["InputConfig"]["OrgBCGFreq"] = self.ui.spinBox_input_freq_signal_OrgBCG.value() + Config["InputConfig"]["ThoFreq"] = self.ui.spinBox_input_freq_signal_Tho.value() + Config["Path"]["Input_OrgBCG"] = self.ui.plainTextEdit_file_path_input_signal_OrgBCG.toPlainText() + Config["Path"]["Input_Tho"] = self.ui.plainTextEdit_file_path_input_signal_Tho.toPlainText() + Config["Path"]["Input_Artifact"] = self.ui.plainTextEdit_file_path_input_artifact.toPlainText() + Config["Path"]["Save_Resp_quality_label"] = self.ui.plainTextEdit_file_path_save_Resp_quality_label.toPlainText() + Config["Path"]["Save_Tho_peak"] = self.ui.plainTextEdit_file_path_save_Tho_peak.toPlainText() + + # 保存配置到文件 + self.config["InputConfig"]["OrgBCGFreq"] = self.ui.spinBox_input_freq_signal_OrgBCG.value() + self.config["InputConfig"]["ThoFreq"] = self.ui.spinBox_input_freq_signal_Tho.value() + + with open(ConfigParams.RESP_QUALITY_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_signal_OrgBCG.setPlainText( + str((Path(self.root_path) / + ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + Path(str(self.sampID)) / + Path(ConfigParams.ORGBCG_SYNC + + str(self.ui.spinBox_input_freq_signal_OrgBCG.value()) + + ConfigParams.ENDSWITH_TXT)))) + self.ui.plainTextEdit_file_path_input_signal_Tho.setPlainText( + str((Path(self.root_path) / + ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + Path(str(self.sampID)) / + Path(ConfigParams.THO_SYNC + + str(self.ui.spinBox_input_freq_signal_Tho.value()) + + ConfigParams.ENDSWITH_TXT)))) + + +class MainWindow_resp_quality_label(QMainWindow): + + def __init__(self): + super(MainWindow_resp_quality_label, self).__init__() + self.ui = Ui_MainWindow_resp_quality_label() + self.ui.setupUi(self) + + self.mode = None + 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.fig_spectrum = None + self.canvas_spectrum = None + self.figToolbar_spectrum = None + self.gs_spectrum = None + self.ax0_spectrum = None + self.ax1_spectrum = None + self.is_left_button_pressed = None + self.is_right_button_pressed = None + + self.tho_peak_point = None + + self.cid1 = None + self.cid2 = None + + self.msgBox = QMessageBox() + self.msgBox.setWindowTitle(Constants.MAINWINDOW_MSGBOX_TITLE) + + @overrides + def show(self, root_path, sampID): + super().show() + self.root_path = root_path + self.sampID = sampID + + self.setting = SettingWindow(root_path, sampID) + + # 初始化画框 + self.fig = plt.figure(figsize=(12, 9), dpi=100) + self.canvas = FigureCanvasQTAgg(self.fig) + self.figToolbar = CustomNavigationToolbar(self.canvas, self) + self.figToolbar.action_Label_Multiple.setEnabled(False) + for action in self.figToolbar._actions.values(): + action.setEnabled(False) + for action in self.figToolbar.actions(): + if action.text() == "Subplots" or action.text() == "Customize": + self.figToolbar.removeAction(action) + self.figToolbar._actions['home'].triggered.connect(self.toggle_home) + self.figToolbar.action_Label_Multiple.triggered.connect(self.toggle_changeLabel_Multiple_mode) + 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.1, wspace=0) + self.ax0 = self.fig.add_subplot(self.gs[0]) + self.ax0.grid(True) + self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax1 = self.fig.add_subplot(self.gs[1]) + self.ax1.grid(True) + self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + + # 初始化频谱画框 + self.fig_spectrum = plt.figure(figsize=(12, 9), dpi=100) + self.canvas_spectrum = FigureCanvasQTAgg(self.fig_spectrum) + self.figToolbar_spectrum = NavigationToolbar2QT(self.canvas_spectrum) + self.figToolbar_spectrum.setStyleSheet(Constants.RESP_QUALITY_LABEL_FIGTOOLBAR_SPECTRUM_STYLESHEET) + for action in self.figToolbar_spectrum._actions.values(): + action.setEnabled(False) + for action in self.figToolbar_spectrum.actions(): + if action.text() == "Subplots" or action.text() == "Customize": + self.figToolbar_spectrum.removeAction(action) + self.ui.verticalLayout_spectrum_display.addWidget(self.canvas_spectrum) + self.ui.verticalLayout_spectrum_display.addWidget(self.figToolbar_spectrum) + self.gs_spectrum = gridspec.GridSpec(2, 1, height_ratios=[1, 1]) + self.fig_spectrum.subplots_adjust(top=0.95, bottom=0.05, right=0.98, left=0.1, hspace=0.2, wspace=0) + self.ax0_spectrum = self.fig_spectrum.add_subplot(self.gs_spectrum[0]) + self.ax0_spectrum.grid(True) + self.ax0_spectrum.set_title(Constants.RESP_QUALITY_LABEL_SPECTRUM_BDR_TITLE, fontsize=8) + self.ax1_spectrum = self.fig_spectrum.add_subplot(self.gs_spectrum[1]) + self.ax1_spectrum.grid(True) + self.ax1_spectrum.set_title(Constants.RESP_QUALITY_LABEL_SPECTRUM_THO_TITLE, fontsize=8) + + PublicFunc.__resetAllButton__(self, ButtonState) + + self.ui.doubleSpinBox_quality_threshold1.setValue(Config["Threshold"]["Low"]) + self.ui.doubleSpinBox_quality_threshold2.setValue(Config["Threshold"]["High"]) + self.ui.doubleSpinBox_findpeaks_min_interval.setValue(Config["FindPeaks"]["MinInterval"]) + self.ui.doubleSpinBox_findpeaks_min_height.setValue(Config["FindPeaks"]["MinHeight"]) + self.ui.doubleSpinBox_fillterMode_custom_low.setValue(Config["Filter"]["BandPassLow"]) + self.ui.doubleSpinBox_fillterMode_custom_high.setValue(Config["Filter"]["BandPassHigh"]) + + self.ui.tableWidget_labeled.setHorizontalHeaderLabels(['信号片段', '质量类型']) + self.ui.tableWidget_tobelabeled.setHorizontalHeaderLabels(['信号片段', '质量类型']) + self.ui.tableWidget_labeled.setEditTriggers(QTableWidget.NoEditTriggers) + self.ui.tableWidget_tobelabeled.setEditTriggers(QTableWidget.NoEditTriggers) + self.ui.tableWidget_labeled.horizontalHeader().setStretchLastSection(True) + self.ui.tableWidget_tobelabeled.horizontalHeader().setStretchLastSection(True) + + self.ui.pushButton_input_setting.clicked.connect(self.setting.show) + self.ui.pushButton_input_and_calculate_peaks.clicked.connect(self.__slot_btn_input_and_calculate_peaks__) + self.ui.pushButton_calculate_peaks.clicked.connect(self.__slot_btn_calculate_peaks__) + self.ui.pushButton_calculate_peaks_save.clicked.connect(self.__slot_btn_save_calculate_peak__) + self.ui.pushButton_input_and_label.clicked.connect(self.__slot_btn_input_and_label__) + self.ui.pushButton_autoqualitylabel_recalculate.clicked.connect(self.__slot_btn_autoqualitylabel_recalculate__) + self.ui.pushButton_refilter_orgBcg.clicked.connect(self.__slot_btn_refilter_orgBcg__) + self.ui.pushButton_prev.clicked.connect(self.__slot_btn_move__) + self.ui.pushButton_next.clicked.connect(self.__slot_btn_move__) + self.ui.tableWidget_labeled.cellDoubleClicked.connect(self.__slot_tableWidget_on_cell_double_clicked__) + self.ui.tableWidget_tobelabeled.cellDoubleClicked.connect(self.__slot_tableWidget_on_cell_double_clicked__) + self.ui.pushButton_valid.clicked.connect(self.__slot_btn_label__) + self.ui.pushButton_invalid.clicked.connect(self.__slot_btn_label__) + self.ui.pushButton_reset.clicked.connect(self.__slot_btn_label__) + self.ui.pushButton_save.clicked.connect(self.__slot_btn_save__) + + self.ui.lineEdit_filter_labeled.textChanged.connect(self.__slot_lineEdit_filter__) + self.ui.lineEdit_filter_tobelabeled.textChanged.connect(self.__slot_lineEdit_filter__) + self.ui.doubleSpinBox_quality_threshold1.valueChanged.connect(self.update_config) + self.ui.doubleSpinBox_quality_threshold2.valueChanged.connect(self.update_config) + self.ui.doubleSpinBox_findpeaks_min_interval.valueChanged.connect(self.update_config) + self.ui.doubleSpinBox_findpeaks_min_height.valueChanged.connect(self.update_config) + self.ui.doubleSpinBox_fillterMode_custom_low.valueChanged.connect(self.update_config) + self.ui.doubleSpinBox_fillterMode_custom_high.valueChanged.connect(self.update_config) + + @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.tho_peak_point + if self.ax0 is not None: + self.ax0.clear() + if self.ax1 is not None: + self.ax1.clear() + if self.ax0_spectrum is not None: + self.ax0_spectrum.clear() + if self.ax1_spectrum is not None: + self.ax1_spectrum.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): + # 清空画框 + self.reset_axes() + + sender = self.sender() + + if sender == self.ui.pushButton_calculate_peaks: + try: + self.ax1.plot(self.data.Tho_Processed, + label=Constants.RESP_QUALITY_LABEL_PLOT_LABEL_THO, color=Constants.PLOT_COLOR_BLUE) + self.tho_peak_point, = self.ax1.plot(self.data.Tho_peak, self.data.Tho_peak_y, 'ro', + label=Constants.RESP_QUALITY_LABEL_PLOT_LABEL_THO_PEAKS) + self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT) + self.canvas.draw() + except Exception as e: + return Result().failure(info=Constants.DRAW_FAILURE + "\n" + format_exc()) + return Result().success(info=Constants.DRAW_FINISHED) + elif (sender == self.ui.pushButton_input_and_label or + sender == self.ui.pushButton_refilter_orgBcg or + sender == self.ui.pushButton_prev or + sender == self.ui.pushButton_next or + sender == self.ui.tableWidget_labeled or + sender == self.ui.tableWidget_tobelabeled): + try: + if Config["CurrentPartNum"] != Config["DataPartNum"]: + begin_OrgBCG = Config["CurrentOrgBCGIndex"] + end_OrgBCG = (Config["CurrentOrgBCGIndex"] + ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["OrgBCGUseFreq"])) + begin_Tho = Config["CurrentThoIndex"] + end_Tho = (Config["CurrentThoIndex"] + ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])) + else: + begin_OrgBCG = Config["CurrentOrgBCGIndex"] + end_OrgBCG = len(self.data.OrgBCG_Processed) + begin_Tho = Config["CurrentThoIndex"] + end_Tho = len(self.data.Tho_Processed) + + if self.ui.radioButton_orgBcg_fillterMode_preset.isChecked(): + mode = "preset" + elif self.ui.radioButton_orgBcg_fillterMode_custom.isChecked(): + mode = "custom" + else: + raise ValueError("模式不存在") + BDR, band_low, band_high, bcg_spectrum, bcg_freq, tho_spectrum, tho_freq = ( + self.data.preprocess_getBDR(self.data.OrgBCG_Processed[begin_OrgBCG:end_OrgBCG], + self.data.Tho_Processed[begin_Tho:end_Tho], mode)) + # 绘制数据 + self.ax0.plot(arange(begin_OrgBCG, end_OrgBCG), BDR, + label=Constants.RESP_QUALITY_LABEL_PLOT_LABEL_ORGBCG, + color=Constants.PLOT_COLOR_BLUE) + self.ax1.plot(arange(begin_Tho, end_Tho), self.data.Tho_Processed[begin_Tho:end_Tho], + label=Constants.RESP_QUALITY_LABEL_PLOT_LABEL_THO, + color=Constants.PLOT_COLOR_BLUE) + self.tho_peak_point, = self.ax1.plot( + [value for value in self.data.Tho_peak if begin_Tho <= value <= end_Tho], + [self.data.Tho_peak_y[x] for x in + [index for index, value in enumerate(self.data.Tho_peak) if begin_Tho <= value <= end_Tho]], 'ro', + label=Constants.RESP_QUALITY_LABEL_PLOT_LABEL_THO_PEAKS) + self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) + self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT) + # 绘制体动 + mask = self.data.artifact_mask[begin_OrgBCG: end_OrgBCG] == 1 + mask = (BDR * mask).astype(float64) + place(mask, mask == 0, nan) + self.ax0.plot(arange(begin_OrgBCG, end_OrgBCG), mask, + label=f"{Constants.RESP_QUALITY_LABEL_PLOT_LABEL_ARTIFACT}", + color=Constants.PLOT_COLOR_PINK, linestyle="-") + # 绘制频谱 + self.ax0_spectrum.plot(bcg_freq, bcg_spectrum, + label=Constants.RESP_QUALITY_LABEL_SPECTRUM_ORGBCG_LABEL, + color=Constants.PLOT_COLOR_BLUE) + self.ax0_spectrum.axvline(x=band_low, + label=Constants.RESP_QUALITY_LABEL_SPECTRUM_BDR_LABEL, + color=Constants.PLOT_COLOR_ORANGE, + linestyle='--') + self.ax0_spectrum.axvline(x=band_high, + color=Constants.PLOT_COLOR_ORANGE, + linestyle='--') + self.ax1_spectrum.plot(tho_freq, tho_spectrum, + label=Constants.RESP_QUALITY_LABEL_SPECTRUM_THO_LABEL, + color=Constants.PLOT_COLOR_BLUE) + self.ax0_spectrum.legend(loc=Constants.PLOT_UPPER_RIGHT) + self.ax1_spectrum.legend(loc=Constants.PLOT_UPPER_RIGHT) + + self.canvas.draw() + self.canvas_spectrum.draw() + self.cid1 = self.ax0.callbacks.connect('xlim_changed', self.on_xlim_changed) + self.cid2 = self.ax1.callbacks.connect('xlim_changed', self.on_xlim_changed) + except Exception as e: + return Result().failure(info=Constants.DRAW_FAILURE + "\n" + format_exc()) + return Result().success(info=Constants.DRAW_FINISHED) + else: + self.canvas.draw() + self.ax0.autoscale(False) + self.ax1.autoscale(False) + return Result().failure(info=Constants.DRAW_FAILURE) + + def __redraw_peaks__(self): + try: + if Config["CurrentPartNum"] != Config["DataPartNum"]: + begin_Tho = Config["CurrentThoIndex"] + end_Tho = (Config["CurrentThoIndex"] + ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])) + elif Config["CurrentPartNum"] == Config["DataPartNum"]: + begin_Tho = Config["CurrentThoIndex"] + end_Tho = len(self.data.Tho_Processed) + + self.tho_peak_point.remove() + self.tho_peak_point, = self.ax1.plot( + [value for value in self.data.Tho_peak if begin_Tho <= value <= end_Tho], + [self.data.Tho_peak_y[x] for x in + [index for index, value in enumerate(self.data.Tho_peak) if begin_Tho <= value <= end_Tho]], 'ro', + label=Constants.RESP_QUALITY_LABEL_PLOT_LABEL_THO_PEAKS) + + self.ax1.autoscale(False) + self.canvas.draw() + return Result().success(info=Constants.DRAW_FINISHED) + except Exception as e: + self.canvas.draw() + self.ax0.autoscale(False) + self.ax1.autoscale(False) + return Result().failure(info=Constants.DRAW_FAILURE) + + def update_tableWidget(self): + label_list = { + "已标注": + where((self.data.resp_quality_label == Constants.RESP_QUALITY_LABEL_A_QUALITY) | + (self.data.resp_quality_label == Constants.RESP_QUALITY_LABEL_B_QUALITY))[0] + 1, + "未标注": + where(self.data.resp_quality_label == Constants.RESP_QUALITY_LABEL_C_QUALITY)[0] + 1 + } + self.ui.tableWidget_labeled.setRowCount( + label_list["已标注"].__len__()) + self.ui.tableWidget_tobelabeled.setRowCount( + label_list["未标注"].__len__()) + for label_name, label in label_list.items(): + if label_name == "已标注": + tableWidget = self.ui.tableWidget_labeled + elif label_name == "未标注": + tableWidget = self.ui.tableWidget_tobelabeled + else: + raise ValueError("label_name不存在") + for row, value in enumerate(label): + item = QTableWidgetItem(str(value).strip()) + tableWidget.setItem(row, 0, item) + item = QTableWidgetItem(Constants.RESP_QUALITY_LABEL_KEY_VALUE[self.data.resp_quality_label[value - 1]]) + tableWidget.setItem(row, 1, item) + self.ui.tableWidget_labeled.verticalScrollBar().setValue(self.ui.tableWidget_labeled.verticalScrollBar().maximum()) + self.ui.tableWidget_tobelabeled.verticalScrollBar().setValue(self.ui.tableWidget_tobelabeled.verticalScrollBar().maximum()) + + def update_info(self): + try: + self.ui.lineEdit_current_part_num.setText("{} / {}".format(Config["CurrentPartNum"], Config["DataPartNum"])) + self.ui.lineEdit_current_part_label.setText( + str(Constants.RESP_QUALITY_LABEL_KEY_VALUE[self.data.resp_quality_label[Config["CurrentPartNum"] - 1]])) + except Exception as e: + return Result().failure(info=Constants.UPDATE_FAILURE + + Constants.FAILURE_REASON["Update_Info_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.UPDATE_FINISHED) + + def __slot_btn_input_and_calculate_peaks__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + + self.reset_axes() + self.canvas.draw() + + self.data = Data() + + # 导入数据 + PublicFunc.progressbar_update(self, 1, 3, Constants.INPUTTING_DATA, 0) + result = self.data.open_file_calculate_peaks() + if not result.status: + PublicFunc.text_output(self.ui, "(1/3)" + 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/3)" + result.info, Constants.TIPS_TYPE_INFO) + + # 重采样 + PublicFunc.progressbar_update(self, 2, 3, Constants.RESAMPLING_DATA, 40) + result = self.data.resample_tho() + if not result.status: + PublicFunc.text_output(self.ui, "(2/3)" + 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/3)" + result.info, Constants.TIPS_TYPE_INFO) + + # 数据预处理 + PublicFunc.progressbar_update(self, 3, 3, Constants.PREPROCESSING_DATA, 70) + result = self.data.preprocess_tho() + if not result.status: + PublicFunc.text_output(self.ui, "(3/3)" + 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/3)" + result.info, Constants.TIPS_TYPE_INFO) + + self.__reset__() + ButtonState["Current"]["pushButton_input_setting"] = True + ButtonState["Current"]["pushButton_input_and_calculate_peaks"] = True + ButtonState["Current"]["pushButton_calculate_peaks"] = True + ButtonState["Current"]["pushButton_calculate_peaks_save"] = True + ButtonState["Current"]["pushButton_input_data_and_label"] = True + ButtonState["Current"]["pushButton_autoqualitylabel_recalculate"] = False + ButtonState["Current"]["pushButton_refilter_orgBcg"]: False + ButtonState["Current"]["pushButton_valid"] = False + ButtonState["Current"]["pushButton_invalid"] = False + ButtonState["Current"]["pushButton_reset"] = False + ButtonState["Current"]["pushButton_prev"] = False + ButtonState["Current"]["pushButton_next"] = False + ButtonState["Current"]["pushButton_save"] = False + for action in self.figToolbar._actions.values(): + action.setEnabled(True) + self.figToolbar.action_Label_Multiple.setEnabled(False) + + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_calculate_peaks__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + + self.reset_axes() + self.canvas.draw() + + # 计算峰值 + PublicFunc.progressbar_update(self, 1, 2, Constants.RESP_QUALITY_LABEL_CALCULATING_PEAK, 0) + result = self.data.calculate_tho_peak() + if not result.status: + PublicFunc.text_output(self.ui, "(1/2)" + 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/2)" + result.info, Constants.TIPS_TYPE_INFO) + + # 绘图 + PublicFunc.progressbar_update(self, 2, 2, Constants.DRAWING_DATA, 50) + result = self.__plot__() + if not result.status: + PublicFunc.text_output(self.ui, "(2/2)" + 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/2)" + result.info, Constants.TIPS_TYPE_INFO) + + ButtonState["Current"]["pushButton_input_setting"] = True + ButtonState["Current"]["pushButton_input_and_calculate_peaks"] = True + ButtonState["Current"]["pushButton_calculate_peaks"] = True + ButtonState["Current"]["pushButton_calculate_peaks_save"] = True + ButtonState["Current"]["pushButton_input_data_and_label"] = True + ButtonState["Current"]["pushButton_autoqualitylabel_recalculate"] = False + ButtonState["Current"]["pushButton_refilter_orgBcg"]: False + ButtonState["Current"]["pushButton_valid"] = False + ButtonState["Current"]["pushButton_invalid"] = False + ButtonState["Current"]["pushButton_reset"] = False + ButtonState["Current"]["pushButton_prev"] = False + ButtonState["Current"]["pushButton_next"] = False + ButtonState["Current"]["pushButton_save"] = False + + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_save_calculate_peak__(self): + reply = QMessageBox.question(self, Constants.QUESTION_TITLE, + Constants.QUESTION_CONTENT + Config["Path"]["Save_Tho_peak"], + QMessageBox.Yes | QMessageBox.No, + QMessageBox.Yes) + if reply == QMessageBox.Yes: + PublicFunc.__disableAllButton__(self, ButtonState) + + # 保存 + PublicFunc.progressbar_update(self, 1, 1, Constants.SAVING_DATA, 0) + result = self.data.save_tho_peak() + 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.msgbox_output(self, result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_input_and_label__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + + self.reset_axes() + self.canvas.draw() + + self.data = Data() + + # 导入数据 + PublicFunc.progressbar_update(self, 1, 6, Constants.INPUTTING_DATA, 0) + result = self.data.open_file_label() + if not result.status: + PublicFunc.text_output(self.ui, "(1/6)" + 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/6)" + result.info, Constants.TIPS_TYPE_INFO) + + # 获取标签存档 + PublicFunc.progressbar_update(self, 2, 6, Constants.LOADING_ARCHIVE, 30) + result = self.data.get_archive_resp_quality() + if not result.status: + PublicFunc.text_output(self.ui, "(2/6)" + 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/6)" + result.info, Constants.TIPS_TYPE_INFO) + + # 获取峰值存档 + PublicFunc.progressbar_update(self, 3, 6, Constants.LOADING_ARCHIVE, 30) + result = self.data.get_archive_tho_peak() + if not result.status: + PublicFunc.text_output(self.ui, "(3/6)" + 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/6)" + result.info, Constants.TIPS_TYPE_INFO) + + # 重采样 + PublicFunc.progressbar_update(self, 4, 6, Constants.RESAMPLING_DATA, 40) + result = self.data.resample_tho_and_OrgBCG() + if not result.status: + PublicFunc.text_output(self.ui, "(4/6)" + 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/6)" + result.info, Constants.TIPS_TYPE_INFO) + + # 数据预处理 + PublicFunc.progressbar_update(self, 5, 6, Constants.PREPROCESSING_DATA, 70) + result = self.data.preprocess_tho_and_OrgBCG() + if not result.status: + PublicFunc.text_output(self.ui, "(5/6)" + 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/6)" + result.info, Constants.TIPS_TYPE_INFO) + + # 绘图 + PublicFunc.progressbar_update(self, 6, 6, Constants.DRAWING_DATA, 90) + self.ax0.autoscale(True) + self.ax1.autoscale(True) + self.ax1.relim() + self.ax1.autoscale_view() + result = self.__plot__() + self.ax0.autoscale(False) + self.ax1.autoscale(False) + if not result.status: + PublicFunc.text_output(self.ui, "(6/6)" + 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, "(6/6)" + result.info, Constants.TIPS_TYPE_INFO) + + Config["CurrentPartNum"] = 1 + self.update_info() + self.update_tableWidget() + self.__reset__() + ButtonState["Current"]["pushButton_input_setting"] = False + ButtonState["Current"]["pushButton_input_and_calculate_peaks"] = False + ButtonState["Current"]["pushButton_calculate_peaks"] = False + ButtonState["Current"]["pushButton_calculate_peaks_save"] = False + ButtonState["Current"]["pushButton_input_data_and_label"] = False + ButtonState["Current"]["pushButton_autoqualitylabel_recalculate"] = True + ButtonState["Current"]["pushButton_refilter_orgBcg"] = True + ButtonState["Current"]["pushButton_valid"] = True + ButtonState["Current"]["pushButton_invalid"] = True + ButtonState["Current"]["pushButton_reset"] = True + ButtonState["Current"]["pushButton_prev"] = True + ButtonState["Current"]["pushButton_next"] = True + ButtonState["Current"]["pushButton_save"] = True + for action in self.figToolbar._actions.values(): + action.setEnabled(True) + for action in self.figToolbar_spectrum._actions.values(): + action.setEnabled(True) + self.figToolbar.action_Label_Multiple.setEnabled(True) + + PublicFunc.finish_operation(self, ButtonState) + + def __slot_btn_autoqualitylabel_recalculate__(self): + reply = QMessageBox.question(self, '确认', Constants.RESP_QUALITY_LABEL_CHECK_ARGS_QUESTION_CONTENT, + QMessageBox.Yes | QMessageBox.No, QMessageBox.No) + if reply == QMessageBox.Yes: + if self.check_autolabel_args() is False: + PublicFunc.msgbox_output(self, Constants.RESP_QUALITY_LABEL_AUTOLABEL_ARGS_ERROR, Constants.MSGBOX_TYPE_ERROR) + return + + try: + # 确定带体动的片段 + artifact_indices = [] + for i in range(0, len(self.data.Artifact_a)): + if i + 3 < len(self.data.Artifact_a): # 防止索引越界 + index0 = self.data.Artifact_a[i + 2] // (Config["InputConfig"]["OrgBCGUseFreq"] * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC) # 第三行(索引+2) + index1 = self.data.Artifact_a[i + 3] // (Config["InputConfig"]["OrgBCGUseFreq"] * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC) # 第四行(索引+3) + if index0 == index1: + artifact_indices.append(index0) + else: + artifact_indices.append(index0) + artifact_indices.append(index1) + artifact_indices = list(dict.fromkeys(artifact_indices)) + for seg_idx in range(1, Config["DataPartNum"] - 1): + # 数据切片预处理 + BCG = pre_process( + get_slice( + self.data.OrgBCG_Processed, seg_idx, ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC, Config["InputConfig"]["OrgBCGUseFreq"]), Config["InputConfig"]["OrgBCGUseFreq"], ConfigParams.RESP_QUALITY_LABEL_PREPROCESS_FC) + THO = pre_process( + get_slice( + self.data.Tho_Processed, seg_idx, ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC, Config["InputConfig"]["ThoUseFreq"]), Config["InputConfig"]["ThoUseFreq"], ConfigParams.RESP_QUALITY_LABEL_PREPROCESS_FC) + + # 质量评估 + # 有体动:1 无体动:0 + artifact_flag = 1 if (seg_idx - 1) in artifact_indices else 0 + + quality = evaluate_quality( + BCG, THO, Config["InputConfig"]["OrgBCGUseFreq"], Config["InputConfig"]["ThoUseFreq"] + , artifact_flag, [float(Config["Threshold"]["Low"]), float(Config["Threshold"]["High"])] + ) + self.data.resp_quality_label[seg_idx - 1] = quality + + self.update_tableWidget() + result = self.update_info() + if not result.status: + PublicFunc.text_output(self.ui, 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, result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, Constants.OPERATION_FINISHED, Constants.TIPS_TYPE_INFO) + PublicFunc.msgbox_output(self, Constants.OPERATION_FINISHED, Constants.MSGBOX_TYPE_INFO) + except Exception as e: + PublicFunc.text_output(self.ui, Constants.OPERATION_FAILURE, Constants.TIPS_TYPE_ERROR) + PublicFunc.msgbox_output(self, Constants.OPERATION_FAILURE, Constants.MSGBOX_TYPE_ERROR) + + def __slot_btn_refilter_orgBcg__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + if len(self.data.OrgBCG_Processed) == 0: + Result().failure(info=Constants.RESAMPLE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + return + + if self.ui.radioButton_orgBcg_fillterMode_custom.isChecked(): + if self.check_filter_args() is False: + PublicFunc.msgbox_output(self, Constants.RESP_QUALITY_LABEL_CUSTOM_FILTER_ARGS_ERROR, Constants.MSGBOX_TYPE_ERROR) + return + result = self.__plot__() + if not result.status: + PublicFunc.text_output(self.ui, 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, result.info, Constants.TIPS_TYPE_INFO) + + def __slot_btn_move__(self): + sender = self.sender() + + if sender == self.ui.pushButton_prev: + if self.check_filter_args() is False: + PublicFunc.msgbox_output(self, Constants.RESP_QUALITY_LABEL_CUSTOM_FILTER_ARGS_ERROR, Constants.MSGBOX_TYPE_ERROR) + return + if Config["CurrentPartNum"] == 1: + PublicFunc.text_output(self.ui, Constants.RESP_QUALITY_LABEL_VIEWING_THE_FIRST_PART, Constants.MSGBOX_TYPE_INFO) + PublicFunc.msgbox_output(self, Constants.RESP_QUALITY_LABEL_VIEWING_THE_FIRST_PART, Constants.MSGBOX_TYPE_INFO) + return + Config["CurrentPartNum"] = Config["CurrentPartNum"] - 1 + Config["CurrentOrgBCGIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["OrgBCGUseFreq"])) + Config["CurrentThoIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])) + result = self.__plot__() + if not result.status: + PublicFunc.text_output(self.ui, 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, result.info, Constants.TIPS_TYPE_INFO) + result = self.update_info() + if not result.status: + PublicFunc.text_output(self.ui, 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, result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, Constants.RESP_QUALITY_LABEL_PREV_PART + str(Config["CurrentPartNum"]), + Constants.TIPS_TYPE_INFO) + elif sender == self.ui.pushButton_next: + if self.check_filter_args() is False: + PublicFunc.msgbox_output(self, Constants.RESP_QUALITY_LABEL_CUSTOM_FILTER_ARGS_ERROR, Constants.MSGBOX_TYPE_ERROR) + return + if Config["CurrentPartNum"] == Config["DataPartNum"]: + PublicFunc.text_output(self.ui, Constants.RESP_QUALITY_LABEL_VIEWING_THE_LAST_PART, Constants.MSGBOX_TYPE_INFO) + PublicFunc.msgbox_output(self, Constants.RESP_QUALITY_LABEL_VIEWING_THE_LAST_PART, Constants.MSGBOX_TYPE_INFO) + return + Config["CurrentPartNum"] = Config["CurrentPartNum"] + 1 + Config["CurrentOrgBCGIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["OrgBCGUseFreq"])) + Config["CurrentThoIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])) + result = self.__plot__() + if not result.status: + PublicFunc.text_output(self.ui, 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, result.info, Constants.TIPS_TYPE_INFO) + result = self.update_info() + if not result.status: + PublicFunc.text_output(self.ui, 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, result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, Constants.RESP_QUALITY_LABEL_NEXT_PART + str(Config["CurrentPartNum"]), + Constants.TIPS_TYPE_INFO) + else: + raise ValueError("发射信号不存在") + + def __slot_tableWidget_on_cell_double_clicked__(self, row, column): + sender = self.sender() + + if self.check_filter_args() is False: + PublicFunc.msgbox_output(self, Constants.RESP_QUALITY_LABEL_CUSTOM_FILTER_ARGS_ERROR, Constants.MSGBOX_TYPE_ERROR) + return + if sender == self.ui.tableWidget_labeled: + Config["CurrentPartNum"] = int( + self.ui.tableWidget_labeled.item(row, 0).text()) + Config["CurrentOrgBCGIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["OrgBCGUseFreq"])) + Config["CurrentThoIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])) + elif sender == self.ui.tableWidget_tobelabeled: + Config["CurrentPartNum"] = int( + self.ui.tableWidget_tobelabeled.item(row, 0).text()) + Config["CurrentOrgBCGIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["OrgBCGUseFreq"])) + Config["CurrentThoIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])) + else: + raise ValueError("发射信号不存在") + result = self.__plot__() + if not result.status: + PublicFunc.text_output(self.ui, 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, result.info, Constants.TIPS_TYPE_INFO) + result = self.update_info() + if not result.status: + PublicFunc.text_output(self.ui, 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, result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, Constants.RESP_QUALITY_LABEL_JUMP + str(Config["CurrentPartNum"]), + Constants.TIPS_TYPE_INFO) + + def __slot_btn_label__(self): + sender = self.sender() + + if sender == self.ui.pushButton_valid: + self.data.resp_quality_label[Config["CurrentPartNum"] - 1] = 1 + elif sender == self.ui.pushButton_invalid: + self.data.resp_quality_label[Config["CurrentPartNum"] - 1] = 0 + elif sender == self.ui.pushButton_reset: + self.data.resp_quality_label[Config["CurrentPartNum"] - 1] = -1 + else: + raise ValueError("发射信号不存在") + result = self.data.save_resp_quality_label() + self.update_tableWidget() + if not result.status: + PublicFunc.text_output(self.ui, 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, result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, str(Config["CurrentPartNum"]) + + Constants.RESP_QUALITY_LABEL_LABEL_SUCCESSFULLY + + "," + Constants.RESP_QUALITY_LABEL_LABEL_TYPE + + Constants.RESP_QUALITY_LABEL_KEY_VALUE[self.data.resp_quality_label[Config["CurrentPartNum"] - 1]], + Constants.TIPS_TYPE_INFO) + + def __slot_btn_save__(self): + PublicFunc.__disableAllButton__(self, ButtonState) + + # 保存 + PublicFunc.progressbar_update(self, 1, 2, Constants.SAVING_DATA + ConfigParams.RESP_QUALITY_LABEL, 0) + result = self.data.save_resp_quality_label() + if not result.status: + PublicFunc.text_output(self.ui, "(1/2)" + 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/2)" + result.info, Constants.TIPS_TYPE_INFO) + + PublicFunc.progressbar_update(self, 2, 2, Constants.SAVING_DATA + ConfigParams.THO_PEAK, 50) + result = self.data.save_tho_peak() + if not result.status: + PublicFunc.text_output(self.ui, "(2/2)" + 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/2)" + result.info, Constants.TIPS_TYPE_INFO) + + PublicFunc.msgbox_output(self, Constants.SAVE_FINISHED, Constants.TIPS_TYPE_INFO) + PublicFunc.finish_operation(self, ButtonState) + + def __slot_lineEdit_filter__(self, filter_text): + sender = self.sender() + + if sender == self.ui.lineEdit_filter_labeled: + for row in range(self.ui.tableWidget_labeled.rowCount()): + match = False + for col in range(self.ui.tableWidget_labeled.columnCount()): + item = self.ui.tableWidget_labeled.item(row, col) + if filter_text.lower() in item.text().lower(): + match = True + break + self.ui.tableWidget_labeled.setRowHidden(row, not match) + elif sender == self.ui.lineEdit_filter_tobelabeled: + for row in range(self.ui.tableWidget_tobelabeled.rowCount()): + match = False + for col in range(self.ui.tableWidget_tobelabeled.columnCount()): + item = self.ui.tableWidget_tobelabeled.item(row, col) + if filter_text.lower() in item.text().lower(): + match = True + break + self.ui.tableWidget_tobelabeled.setRowHidden(row, not match) + else: + raise ValueError("发生信号不存在") + + def reset_axes(self): + if self.ax0 is not None: + self.ax0.clear() + self.ax0.grid(True) + self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + if self.ax1 is not None: + self.ax1.clear() + self.ax1.grid(True) + self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + if self.ax0_spectrum is not None: + self.ax0_spectrum.clear() + self.ax0_spectrum.grid(True) + self.ax0_spectrum.set_title(Constants.RESP_QUALITY_LABEL_SPECTRUM_BDR_TITLE, fontsize=8) + if self.ax1_spectrum is not None: + self.ax1_spectrum.clear() + self.ax1_spectrum.grid(True) + self.ax1_spectrum.set_title(Constants.RESP_QUALITY_LABEL_SPECTRUM_THO_TITLE, fontsize=8) + + def check_filter_args(self): + if (float(Config["Filter"]["BandPassLow"]) >= float(Config["Filter"]["BandPassHigh"])): + return False + return True + + def check_autolabel_args(self): + if (float(Config["Threshold"]["Low"]) >= float(Config["Threshold"]["High"])): + return False + return True + + def on_xlim_changed(self, ax): + # 获取触发事件的轴 + if ax == self.ax0: + # 获取第一个子图的X轴范围 + xlim1 = self.ax0.get_xlim() + # 计算对应的第二个子图的X轴范围 + ratio = (int(Config["InputConfig"]["ThoUseFreq"]) / + int(Config["InputConfig"]["OrgBCGUseFreq"])) # 信号B的样本点数与信号A的样本点数的比例 + xlim2 = (xlim1[0] * ratio, xlim1[1] * ratio) + + # 禁用事件监听 + self.ax0.callbacks.disconnect(self.cid2) + # 设置第二个子图的X轴范围 + self.ax1.set_xlim(xlim2) + # 重新启用事件监听 + self.cid2 = self.ax1.callbacks.connect('xlim_changed', self.on_xlim_changed) + + elif ax == self.ax1: + # 获取第二个子图的X轴范围 + xlim2 = self.ax1.get_xlim() + # 计算对应的第一个子图的X轴范围 + ratio = (int(Config["InputConfig"]["OrgBCGUseFreq"]) / + int(Config["InputConfig"]["ThoUseFreq"])) # 信号A的样本点数与信号B的样本点数的比例 + xlim1 = (xlim2[0] * ratio, xlim2[1] * ratio) + + # 禁用事件监听 + self.ax0.callbacks.disconnect(self.cid1) + # 设置第一个子图的X轴范围 + self.ax0.set_xlim(xlim1) + # 重新启用事件监听 + self.cid1 = self.ax0.callbacks.connect('xlim_changed', self.on_xlim_changed) + + def update_config(self): + Config["Threshold"]["Low"] = self.ui.doubleSpinBox_quality_threshold1.value() + Config["Threshold"]["High"] = self.ui.doubleSpinBox_quality_threshold2.value() + Config["FindPeaks"]["MinInterval"] = self.ui.doubleSpinBox_findpeaks_min_interval.value() + Config["FindPeaks"]["MinHeight"] = self.ui.doubleSpinBox_findpeaks_min_height.value() + Config["Filter"]["BandPassLow"] = self.ui.doubleSpinBox_fillterMode_custom_low.value() + Config["Filter"]["BandPassHigh"] = self.ui.doubleSpinBox_fillterMode_custom_high.value() + + def toggle_home(self): + if Config["CurrentPartNum"] is None: + self.ax1.autoscale(True) + self.ax1.relim() + self.ax1.autoscale_view() + self.canvas.draw() + self.ax1.autoscale(False) + + def toggle_changeLabel_Multiple_mode(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_ax1 is not 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 < Config["CurrentThoIndex"]: + rect_left = Config["CurrentThoIndex"] + elif rect_left >= (Config["CurrentThoIndex"] + ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])): + rect_left = 0 + rect_right = 0 + if (rect_right >= Config["CurrentThoIndex"] + ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])): + rect_right = (Config["CurrentThoIndex"] + ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"]) - 1) + elif rect_right < Config["CurrentThoIndex"]: + rect_left = 0 + rect_right = 0 + selected_area_for_add_points = self.data.Tho_Processed[int(rect_left):int(rect_right)] + peaks_idx, _ = find_peaks(selected_area_for_add_points, + height=float(Config["FindPeaks"]["MinHeight"]), + distance=float(Config["FindPeaks"]["MinInterval"])) + peaks_idx = peaks_idx + int(rect_left) + peaks_idx = setdiff1d(peaks_idx, self.data.Tho_peak) + if len(peaks_idx) != 0: + PublicFunc.text_output(self.ui, + f"{Constants.RESP_QUALITY_LABEL_ADD_POINTS_SUCCESSFULLY}{peaks_idx}", + Constants.TIPS_TYPE_INFO) + else: + PublicFunc.text_output(self.ui, + Constants.RESP_QUALITY_LABEL_NO_POINT_IN_THE_INTERVAL, + Constants.TIPS_TYPE_INFO) + self.data.Tho_peak = append(self.data.Tho_peak, peaks_idx) + self.data.Tho_peak_y = append(self.data.Tho_peak_y, self.data.Tho_Processed[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.Tho_peak - rect_left + right_label2_to_delete = self.data.Tho_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.RESP_QUALITY_LABEL_REMOVE_POINTS_SUCCESSFULLY}{self.data.Tho_peak[left_label2_to_delete_idx:right_label2_to_delete_idx]}", + Constants.TIPS_TYPE_INFO) + else: + PublicFunc.text_output(self.ui, + Constants.RESP_QUALITY_LABEL_NO_POINT_IN_THE_INTERVAL, + Constants.TIPS_TYPE_INFO) + self.data.Tho_peak = delete(self.data.Tho_peak, + arange(left_label2_to_delete_idx, right_label2_to_delete_idx)) + self.data.Tho_peak_y = delete(self.data.Tho_peak_y, arange(left_label2_to_delete_idx, right_label2_to_delete_idx)) + self.__redraw_peaks__() + self.data.Tho_peak.sort() + self.data.Tho_peak_y = [self.data.Tho_Processed[x] for x in self.data.Tho_peak] + self.figToolbar.rect_start_x = None + self.figToolbar.rect_end_x = None + + result = self.data.save_tho_peak() + if not result.status: + PublicFunc.text_output(self.ui, 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, result.info, Constants.TIPS_TYPE_INFO) + + # 移除矩形patch + if self.figToolbar.rect_patch_ax1 is not 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_ax1 is None: + if self.is_left_button_pressed: + self.figToolbar.rect_patch_ax1 = patches.Rectangle((0, 0), 1, 1, fill=True, + alpha=ConfigParams.RESP_QUALITY_LABEL_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.RESP_QUALITY_LABEL_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 = self.ax1.get_ylim()[0] - 1000 + rect_up = self.ax1.get_ylim()[1] + 1000 + 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(): + + def __init__(self): + self.OrgBCG = None + self.Tho = None + self.OrgBCG_Processed = None + self.Tho_Processed = None + self.Tho_peak = None + self.resp_quality_label = None + self.Artifact_a = None + self.Tho_peak_y = None + + self.artifact_number = array([]).astype(int64) + self.artifact_type = array([]).astype(int64) + self.artifact_mask = array([]).astype(int64) + + def open_file_calculate_peaks(self): + if Path(Config["Path"]["Input_OrgBCG"]).is_file(): + Config["Path"]["Input_OrgBCG"] = str(Path(Config["Path"]["Input_OrgBCG"]).parent) + if Path(Config["Path"]["Input_Tho"]).is_file(): + Config["Path"]["Input_Tho"] = str(Path(Config["Path"]["Input_Tho"]).parent) + if Path(Config["Path"]["Input_Artifact"]).is_file(): + Config["Path"]["Input_Artifact"] = str(Path(Config["Path"]["Input_Artifact"]).parent) + if Path(Config["Path"]["Save_Resp_quality_label"]).is_file(): + Config["Path"]["Save_Resp_quality_label"] = str(Path(Config["Path"]["Save_Resp_quality_label"]).parent) + if Path(Config["Path"]["Save_Tho_peak"]).is_file(): + Config["Path"]["Save_Tho_peak"] = str(Path(Config["Path"]["Save_Tho_peak"]).parent) + + result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], ConfigParams.THO_SYNC) + if result.status: + Config["Path"]["Input_Tho"] = result.data["path"] + Config["InputConfig"]["ThoFreq"] = result.data["freq"] + else: + return result + + Config["Path"]["Save_Tho_peak"] = str( + Path(Config["Path"]["Save_Tho_peak"]) / Path(ConfigParams.THO_PEAK + str(Config["InputConfig"]["ThoUseFreq"]) + ConfigParams.ENDSWITH_TXT)) + + try: + self.Tho = read_csv(Config["Path"]["Input_Tho"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + except Exception as e: + return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Open_Data_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.INPUT_FINISHED) + + def resample_tho(self): + if self.Tho is None: + Result().failure(info=Constants.RESAMPLE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + + try: + if Config["InputConfig"]["ThoFreq"] != Config["InputConfig"]["ThoUseFreq"]: + self.Tho = resample(self.Tho, + int(len(self.Tho) * + (Config["InputConfig"]["ThoUseFreq"] / Config["InputConfig"]["ThoFreq"]))) + else: + return Result().success(info=Constants.RESAMPLE_NO_NEED) + except Exception as e: + Result().failure(info=Constants.RESAMPLE_FAILURE + + Constants.FAILURE_REASON["Resample_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.RESAMPLE_FINISHED) + + def preprocess_tho(self): + if self.Tho is None: + return Result().failure(info=Constants.PREPROCESS_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + + try: + self.Tho_Processed = pre_process(self.Tho, Config["InputConfig"]["ThoUseFreq"], ConfigParams.RESP_QUALITY_LABEL_PREPROCESS_FC) + except Exception as e: + return Result().failure(info=Constants.PREPROCESS_FAILURE + + Constants.FAILURE_REASON["Preprocess_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.PREPROCESS_FINISHED) + + def calculate_tho_peak(self): + if self.Tho_Processed is None: + return Result().failure(info=Constants.RESP_QUALITY_LABEL_CALCULATE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + + try: + self.Tho_peak, _ = find_peaks(self.Tho_Processed, + height=float(Config["FindPeaks"]["MinHeight"]), + distance=float(Config["FindPeaks"]["MinInterval"])) + self.Tho_peak_y = [self.Tho_Processed[x] for x in (self.Tho_peak)] + except Exception as e: + return Result().failure(info=Constants.RESP_QUALITY_LABEL_CALCULATE_FAILURE + + Constants.FAILURE_REASON["Calculate_Peak_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.RESP_QUALITY_LABEL_CALCULATE_FINISHED) + + def save_tho_peak(self): + if (not Path(Config["Path"]["Save_Tho_peak"]).parent.exists()) or (not Path(Config["Path"]["Save_Tho_peak"]).parent.is_dir()): + Path(Config["Path"]["Save_Tho_peak"]).parent.mkdir(parents=True, exist_ok=True) + + if self.Tho_peak is None: + + return Result().failure(info=ConfigParams.THO_PEAK + Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + + try: + DataFrame(self.Tho_peak).to_csv(Path(Config["Path"]["Save_Tho_peak"]), mode='w', index=False, header=False) + except Exception as e: + return Result().failure(info=ConfigParams.THO_PEAK + Constants.SAVE_FAILURE + + Constants.FAILURE_REASON["Save_Exception"] + "\n" + format_exc()) + + return Result().success(info=ConfigParams.THO_PEAK + Constants.SAVE_FINISHED) + + def open_file_label(self): + if Path(Config["Path"]["Input_OrgBCG"]).is_file(): + Config["Path"]["Input_OrgBCG"] = str(Path(Config["Path"]["Input_OrgBCG"]).parent) + if Path(Config["Path"]["Input_Tho"]).is_file(): + Config["Path"]["Input_Tho"] = str(Path(Config["Path"]["Input_Tho"]).parent) + if Path(Config["Path"]["Input_Artifact"]).is_file(): + Config["Path"]["Input_Artifact"] = str(Path(Config["Path"]["Input_Artifact"]).parent) + if Path(Config["Path"]["Save_Resp_quality_label"]).is_file(): + Config["Path"]["Save_Resp_quality_label"] = str(Path(Config["Path"]["Save_Resp_quality_label"]).parent) + if Path(Config["Path"]["Save_Tho_peak"]).is_file(): + Config["Path"]["Save_Tho_peak"] = str(Path(Config["Path"]["Save_Tho_peak"]).parent) + + result = PublicFunc.examine_file(Config["Path"]["Input_OrgBCG"], ConfigParams.ORGBCG_SYNC) + if result.status: + Config["Path"]["Input_OrgBCG"] = result.data["path"] + Config["InputConfig"]["OrgBCGFreq"] = result.data["freq"] + else: + return result + + result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], ConfigParams.THO_SYNC) + if result.status: + Config["Path"]["Input_Tho"] = result.data["path"] + Config["InputConfig"]["ThoFreq"] = result.data["freq"] + else: + return result + + Config["Path"]["Input_Artifact"] = str( + Path(Config["Path"]["Input_Artifact"]) / Path(ConfigParams.ARTIFACT_A + ConfigParams.ENDSWITH_TXT)) + Config["Path"]["Save_Resp_quality_label"] = str( + Path(Config["Path"]["Save_Resp_quality_label"]) / Path( + ConfigParams.RESP_QUALITY_LABEL + ConfigParams.ENDSWITH_TXT)) + Config["Path"]["Save_Tho_peak"] = str( + Path(Config["Path"]["Save_Tho_peak"]) / Path( + ConfigParams.THO_PEAK + str(Config["InputConfig"]["ThoUseFreq"]) + ConfigParams.ENDSWITH_TXT)) + + try: + self.OrgBCG = read_csv(Config["Path"]["Input_OrgBCG"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + self.Tho = read_csv(Config["Path"]["Input_Tho"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + self.Artifact_a = read_csv(Config["Path"]["Input_Artifact"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + except Exception as e: + return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Open_Data_Exception"] + "\n" + format_exc()) + + try: + Config["DataPartNum"] = len(self.OrgBCG) // (ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + Config["InputConfig"]["OrgBCGFreq"]) + 1 + if Config["DataPartNum"] == 0: + return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Data_Length_Not_Correct"]) + except Exception as e: + return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Open_Data_Exception"] + "\n" + format_exc()) + + try: + # 检查体动标签正确性,长度 + PublicFunc.examine_artifact(self.Artifact_a) + # 定义绘制体动所需要的数组 + artifact_start = array([]) + artifact_start = artifact_start.astype(int64) + artifact_end = array([]) + artifact_end = artifact_end.astype(int64) + for i in range(0, len(self.Artifact_a), 4): + self.artifact_number = append(self.artifact_number, self.Artifact_a[i]) + for i in range(1, len(self.Artifact_a), 4): + self.artifact_type = append(self.artifact_type, self.Artifact_a[i]) + for i in range(2, len(self.Artifact_a), 4): + artifact_start = append(artifact_start, self.Artifact_a[i]) + for i in range(3, len(self.Artifact_a), 4): + artifact_end = append(artifact_end, self.Artifact_a[i]) + self.artifact_mask = zeros(len(self.OrgBCG)) + for i in range(0, len(self.artifact_number)): + self.artifact_mask[artifact_start[i]: artifact_end[i] + 1] = 1 + except Exception as e: + return Result().failure(info=Constants.INPUT_FAILURE + + Constants.FAILURE_REASON["Get_Artifact_Format_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.INPUT_FINISHED) + + def get_archive_resp_quality(self): + if not Path(Config["Path"]["Save_Resp_quality_label"]).exists(): + self.resp_quality_label = full(Config["DataPartNum"], -1) + return Result().success(info=ConfigParams.RESP_QUALITY_LABEL + ":" + Constants.ARCHIVE_NOT_EXIST) + else: + self.resp_quality_label = read_csv(Config["Path"]["Save_Resp_quality_label"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + return Result().success(info=ConfigParams.RESP_QUALITY_LABEL + ":" + Constants.ARCHIVE_EXIST) + + def get_archive_tho_peak(self): + if not Path(Config["Path"]["Save_Tho_peak"]).exists(): + self.Tho_peak = array([]).astype(int) + self.Tho_peak_y = array([]).astype(int) + return Result().success(info=ConfigParams.RESP_QUALITY_LABEL + ":" + Constants.ARCHIVE_NOT_EXIST) + else: + self.Tho_peak = read_csv(Config["Path"]["Save_Tho_peak"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + + return Result().success(info=ConfigParams.THO_PEAK + ":" + Constants.ARCHIVE_EXIST) + + def resample_tho_and_OrgBCG(self): + if (self.OrgBCG is None) or (self.Tho is None): + Result().failure(info=Constants.RESAMPLE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + + try: + if ((Config["InputConfig"]["OrgBCGFreq"] != Config["InputConfig"]["OrgBCGUseFreq"]) + or (Config["InputConfig"]["ThoFreq"] != Config["InputConfig"]["ThoUseFreq"])): + + if Config["InputConfig"]["OrgBCGFreq"] != Config["InputConfig"]["OrgBCGUseFreq"]: + self.OrgBCG = resample(self.OrgBCG, + int(len(self.OrgBCG) * + (Config["InputConfig"]["OrgBCGUseFreq"] / Config["InputConfig"]["OrgBCGFreq"]))) + if Config["InputConfig"]["ThoFreq"] != Config["InputConfig"]["ThoUseFreq"]: + self.Tho = resample(self.Tho, + int(len(self.Tho) * + (Config["InputConfig"]["ThoUseFreq"] / Config["InputConfig"]["ThoFreq"]))) + else: + return Result().success(info=Constants.RESAMPLE_NO_NEED) + except Exception as e: + Result().failure(info=Constants.RESAMPLE_FAILURE + + Constants.FAILURE_REASON["Resample_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.RESAMPLE_FINISHED) + + def preprocess_tho_and_OrgBCG(self): + if (self.OrgBCG is None) or (self.Tho is None): + return Result().failure(info=Constants.PREPROCESS_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + + try: + self.OrgBCG_Processed = self.OrgBCG.copy() + self.Tho_Processed = pre_process(self.Tho, Config["InputConfig"]["ThoUseFreq"], ConfigParams.RESP_QUALITY_LABEL_PREPROCESS_FC) + self.Tho_peak_y = [self.Tho_Processed[x] for x in (self.Tho_peak)] + except Exception as e: + return Result().failure(info=Constants.PREPROCESS_FAILURE + + Constants.FAILURE_REASON["Preprocess_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.PREPROCESS_FINISHED) + + def preprocess_getBDR(self, orgBcg_slice, THO_slice, mode): + orgBcg = pre_process(orgBcg_slice, int(Config["InputConfig"]["OrgBCGUseFreq"]), + ConfigParams.RESP_QUALITY_LABEL_PREPROCESS_FC) + if mode == "preset": + BDR, band_low, band_high, bcg_spectrum, bcg_freq, tho_spectrum, tho_freq = ( + get_bandpass_bcgsignal(orgBcg, THO_slice, int(Config["InputConfig"]["OrgBCGUseFreq"]), + int(Config["InputConfig"]["ThoUseFreq"]), use_custom_band=False)) + elif mode == "custom": + BDR, band_low, band_high, bcg_spectrum, bcg_freq, tho_spectrum, tho_freq = ( + get_bandpass_bcgsignal(orgBcg, THO_slice, int(Config["InputConfig"]["OrgBCGUseFreq"]), + int(Config["InputConfig"]["ThoUseFreq"]), + use_custom_band=True, + low_cutoff=float(Config["Filter"]["BandPassLow"]), + high_cutoff=float(Config["Filter"]["BandPassHigh"]))) + else: + raise ValueError("模式不存在") + return BDR, band_low, band_high, bcg_spectrum, bcg_freq, tho_spectrum, tho_freq + + def save_resp_quality_label(self): + if (not Path(Config["Path"]["Save_Resp_quality_label"]).parent.exists()) or (not Path(Config["Path"]["Save_Resp_quality_label"]).parent.is_dir()): + Path(Config["Path"]["Save_Resp_quality_label"]).parent.mkdir(parents=True, exist_ok=True) + + if self.resp_quality_label is None: + + return Result().failure(info=ConfigParams.RESP_QUALITY_LABEL + Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + + try: + DataFrame(self.resp_quality_label).to_csv(Path(Config["Path"]["Save_Resp_quality_label"]), mode='w', index=False, header=False) + except Exception as e: + return Result().failure(info=ConfigParams.RESP_QUALITY_LABEL + Constants.SAVE_FAILURE + + Constants.FAILURE_REASON["Save_Exception"] + "\n" + format_exc()) + + return Result().success(info=ConfigParams.RESP_QUALITY_LABEL + Constants.SAVE_FINISHED) + + +class CustomNavigationToolbar(NavigationToolbar2QT): + + def __init__(self, canvas, parent): + super().__init__(canvas, parent) + # 初始化画框工具栏 + self.action_Label_Multiple = QAction(Constants.RESP_QUALITY_LABEL_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.RESP_QUALITY_LABEL_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_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 \ No newline at end of file diff --git a/func/utils/ConfigParams.py b/func/utils/ConfigParams.py index 04582c6..404ada5 100644 --- a/func/utils/ConfigParams.py +++ b/func/utils/ConfigParams.py @@ -275,6 +275,7 @@ class ConfigParams: } } RESP_QUALITY_LABEL_PREPROCESS_FC: int = 1 + RESP_QUALITY_LABEL_PARTS_TIME_SEC: int = 30 RESP_QUALITY_LABEL_LABEL_TRANSPARENCY: float = 0.2 RESP_QUALITY_LABEL_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY: str = "Z" @@ -341,7 +342,7 @@ class ConfigParams: RESP_QUALITY_LABEL_INPUT_XINXIAO_DEFAULT_FS: int = 1000 RESP_QUALITY_LABEL_INPUT_THO_DEFAULT_FS: int = 200 - RESP_QUALITY_LABEL_PARTS_TIME_SEC: int = 30 + RESP_QUALITY_LABEL_THRESHOLD1_DEFAULT: float = 0.65 diff --git a/func/utils/Constants.py b/func/utils/Constants.py index ad4749a..f8a2a0e 100644 --- a/func/utils/Constants.py +++ b/func/utils/Constants.py @@ -103,7 +103,7 @@ class Constants: "Method_Not_Exist": "(检测方法不存在)", "Data_Length_not_Correct": "(orgBcg和BCG长度不匹配)", "Artifact_Format_Not_Correct": "(体动长度或格式不正确)", - "Get_Artifact_Format_Exception": "(获取体动长度或格式异常)", + "Data_Length_Not_Correct": "(信号长度不正确)", "Open_Data_Exception": "(打开数据异常)", "Process_Exception": "(处理异常)", @@ -132,6 +132,7 @@ class Constants: "Get_File_and_Freq_Excepetion": "(检查文件是否存在并获取其数据采样率异常)", "Update_tableWidget_Exception": "(更新表格异常)", "Update_Info_Exception": "(更新信息异常)", + "Get_Artifact_Format_Exception": "(获取体动长度或格式异常)", "Label_Format_Exception": "(获取标签格式异常)", "Calculate_Peak_Exception": "(计算峰值异常)", @@ -389,11 +390,45 @@ class Constants: RESP_QUALITY_LABEL_PLOT_LABEL_ARTIFACT: str = "Artifact" RESP_QUALITY_LABEL_SPECTRUM_BDR_TITLE: str = "Spectrum of BDR_sync by filter OrgBCG_Sync" RESP_QUALITY_LABEL_SPECTRUM_THO_TITLE: str = "Spectrum of THO_sync after preprocess" - RESP_QUALITY_LABEL_SPECTRUM_ORGBCG_LABEL: str = "orgBcg" + RESP_QUALITY_LABEL_SPECTRUM_ORGBCG_LABEL: str = "OrgBCG" RESP_QUALITY_LABEL_SPECTRUM_BDR_LABEL: str = "BDR" - RESP_QUALITY_LABEL_SPECTRUM_THO_LABEL: str = "THO" - + RESP_QUALITY_LABEL_SPECTRUM_THO_LABEL: str = "Tho" + RESP_QUALITY_LABEL_VIEWING_THE_FIRST_PART: str = "你正在查看第1段信号" + RESP_QUALITY_LABEL_VIEWING_THE_LAST_PART: str = "你正在查看最后1段信号" + RESP_QUALITY_LABEL_PREV_PART: str = "上一个片段,index " + RESP_QUALITY_LABEL_NEXT_PART: str = "下一个片段,index " + RESP_QUALITY_LABEL_JUMP: str = "跳转到片段,index " + RESP_QUALITY_LABEL_LABEL_SUCCESSFULLY: str = "片段标注成功" + RESP_QUALITY_LABEL_LABEL_TYPE: str = "标注类型为:" + RESP_QUALITY_LABEL_ADD_POINTS_SUCCESSFULLY: str = "成功新增点,横坐标:" + RESP_QUALITY_LABEL_REMOVE_POINTS_SUCCESSFULLY: str = "成功删除点,横坐标:" + RESP_QUALITY_LABEL_NO_POINT_IN_THE_INTERVAL: str = "所选区间内无新增或删除点" + RESP_QUALITY_LABEL_CUSTOM_FILTER_ARGS_ERROR: str = "OrgBCG带通滤波频率设置范围应为数字,范围是0~1" + RESP_QUALITY_LABEL_AUTOLABEL_ARGS_ERROR: str = "人工标注阈值设置范围应为数字,范围是0~1" + RESP_QUALITY_LABEL_CHECK_ARGS_QUESTION_CONTENT: str = "你确定要执行此操作吗,请确保参数输入正确" RESP_QUALITY_LABEL_ACTION_LABEL_MULTIPLE_NAME: str = f"批量更改标签({ConfigParams.RESP_QUALITY_LABEL_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY})" + RESP_QUALITY_LABEL_A_QUALITY: int = 1 + RESP_QUALITY_LABEL_B_QUALITY: int = 0 + RESP_QUALITY_LABEL_C_QUALITY: int = -1 + RESP_QUALITY_LABEL_KEY_VALUE = { + 1: "Good", + 0: "Bad", + -1: "None" + } + RESP_QUALITY_LABEL_FIGTOOLBAR_SPECTRUM_STYLESHEET: str = """ + QToolBar { + border: 1px; + spacing: 2px; /* 设置工具栏按钮之间的间距 */ + } + QToolButton { + height: 20px; /* 设置工具栏按钮的高度 */ + width: 20px; /* 设置工具栏按钮的宽度 */ + font-size: 8px; /* 设置按钮文字大小 */ + } + QToolButton::menu-button { + width: 0px; /* 隐藏下拉菜单按钮 */ + } + """ # 睡眠呼吸暂停事件标注 SA_LABEL_JUMP: str = "跳转到事件" @@ -483,52 +518,6 @@ class Constants: background-color: yellow; /* 鼠标悬停时的背景颜色 */ }""" - - # 呼吸可用性及间期标注 - RESP_QUALITY_LABEL_FILES_NOT_FOUND: str = f"无法找到{ConfigParams.RESP_QUALITY_LABEL_INPUT_XINXIAO_FILENAME}{ConfigParams.ENDSWITH_TXT}或{ConfigParams.RESP_QUALITY_LABEL_INPUT_THO_FILENAME}{ConfigParams.ENDSWITH_TXT}或{ConfigParams.RESP_QUALITY_LABEL_INPUT_ARTIFACT_FILENAME}{ConfigParams.ENDSWITH_TXT},无法执行<呼吸可用性及间期标注>" - RESP_QUALITY_LABEL_FILES_FOUND: str = f"找到{ConfigParams.RESP_QUALITY_LABEL_INPUT_XINXIAO_FILENAME}{ConfigParams.ENDSWITH_TXT}和{ConfigParams.RESP_QUALITY_LABEL_INPUT_THO_FILENAME}{ConfigParams.ENDSWITH_TXT}和{ConfigParams.RESP_QUALITY_LABEL_INPUT_ARTIFACT_FILENAME}{ConfigParams.ENDSWITH_TXT}" - RESP_QUALITY_LABEL_HISTORICAL_SAVE1_FOUND: str = f"找到历史存档文件{ConfigParams.RESP_QUALITY_LABEL_SAVE_RESP_QUALITY_LABNEL_FILENAME}{ConfigParams.ENDSWITH_TXT},已成功读取" - RESP_QUALITY_LABEL_HISTORICAL_SAVE2_FOUND: str = f"找到历史存档文件{ConfigParams.RESP_QUALITY_LABEL_SAVE_THO_PEAK_FILENAME}{ConfigParams.ENDSWITH_TXT},已成功读取" - RESP_QUALITY_LABEL_INPUT_SIGNAL_FAILURE: str = "导入信号失败,请检查信号长度" - RESP_QUALITY_LABEL_INPUT_SUCCESSFULLY: str = "导入数据成功" - RESP_QUALITY_LABEL_PREPROCESS_SUCCESSFULLY: str = "导入数据成功" - RESP_QUALITY_LABEL_INPUT_ARTIFACT_FAILURE_FORMAT: str = "导入体动失败,请检查体动标签格式" - RESP_QUALITY_LABEL_INPUT_ARTIFACT_FAILURE_LENGTH: str = "导入体动失败,请检查体动长度是否为4的倍数" - - RESP_QUALITY_LABEL_VIEWING_THE_FIRST_PART: str = "你正在查看第1段信号" - RESP_QUALITY_LABEL_VIEWING_THE_LAST_PART: str = "你正在查看最后1段信号" - RESP_QUALITY_LABEL_CUSTOM_NAVIGATIONTOOLBAR_WIDGET_NAME: str = "MainWindow" - RESP_QUALITY_LABEL_BUTTON_PRESS_EVENT: str = "button_press_event" - RESP_QUALITY_LABEL_BUTTON_RELEASE_EVENT: str = "button_release_event" - RESP_QUALITY_LABEL_MOTION_NOTIFY_EVENT: str = "motion_notify_event" - RESP_QUALITY_LABEL_ADD_POINTS_SUCCESSFULLY: str = "成功新增点,横坐标:" - RESP_QUALITY_LABEL_REMOVE_POINTS_SUCCESSFULLY: str = "成功删除点,横坐标:" - RESP_QUALITY_LABEL_NO_POINT_IN_THE_INTERVAL: str = "所选区间内无新增或删除点" - RESP_QUALITY_LABEL_SAVE_PEAKS_SUCCESSFULLY: str = "保存峰值成功" - RESP_QUALITY_LABEL_DATA_NOT_FOUND: str = "数据未导入" - RESP_QUALITY_LABEL_LABEL_SUCCESSFULLY: str = "片段标注并保存成功" - RESP_QUALITY_LABEL_RESET_SUCCESSFULLY: str = "片段重置并保存成功" - RESP_QUALITY_LABEL_PLOT_LABEL_VLINE: str = "vline" - RESP_QUALITY_LABEL_PLOT_LABEL_HLINE: str = "hline" - RESP_QUALITY_LABEL_A_QUALITY: int = 1 - RESP_QUALITY_LABEL_B_QUALITY: int = 0 - RESP_QUALITY_LABEL_C_QUALITY: int = -1 - RESP_QUALITY_LABEL_LABELED: str = "已标注" - RESP_QUALITY_LABEL_TOBELABELED: str = "未标注" - - RESP_QUALITY_LABEL_CUSTOM_FILTER_ARGS_ERROR: str = "orgBcg带通滤波频率设置范围应为数字,范围是0~1" - RESP_QUALITY_LABEL_AUTOLABEL_ARGS_ERROR: str = "人工标注阈值设置范围应为数字,范围是0~1" - RESP_QUALITY_LABEL_CHECK_ARGS_QUESTION_CONTENT: str = "你确定要执行此操作吗,请确保参数输入正确" - RESP_QUALITY_LABEL_KEY_VALUE = { - 1: "Good", - 0: "Bad", - -1: "None" - } - - - - - # 禁止实例化 def __new__(cls): raise TypeError("Constants class cannot be instantiated") diff --git a/ui/MainWindow/MainWindow_resp_quality_label.py b/ui/MainWindow/MainWindow_resp_quality_label.py index 4367465..146c77c 100644 --- a/ui/MainWindow/MainWindow_resp_quality_label.py +++ b/ui/MainWindow/MainWindow_resp_quality_label.py @@ -94,13 +94,13 @@ class Ui_MainWindow_resp_quality_label(object): self.gridLayout_5.addWidget(self.pushButton_calculate_peaks_save, 2, 0, 1, 1) - self.pushButton_input_data_and_label = QPushButton(self.groupBox_left) - self.pushButton_input_data_and_label.setObjectName(u"pushButton_input_data_and_label") - sizePolicy.setHeightForWidth(self.pushButton_input_data_and_label.sizePolicy().hasHeightForWidth()) - self.pushButton_input_data_and_label.setSizePolicy(sizePolicy) - self.pushButton_input_data_and_label.setFont(font1) + self.pushButton_input_and_label = QPushButton(self.groupBox_left) + self.pushButton_input_and_label.setObjectName(u"pushButton_input_and_label") + sizePolicy.setHeightForWidth(self.pushButton_input_and_label.sizePolicy().hasHeightForWidth()) + self.pushButton_input_and_label.setSizePolicy(sizePolicy) + self.pushButton_input_and_label.setFont(font1) - self.gridLayout_5.addWidget(self.pushButton_input_data_and_label, 0, 1, 3, 1) + self.gridLayout_5.addWidget(self.pushButton_input_and_label, 0, 1, 3, 1) self.verticalLayout_2.addLayout(self.gridLayout_5) @@ -135,14 +135,16 @@ class Ui_MainWindow_resp_quality_label(object): self.doubleSpinBox_quality_threshold1 = QDoubleSpinBox(self.groupBox_autoqualitylabel_options) self.doubleSpinBox_quality_threshold1.setObjectName(u"doubleSpinBox_quality_threshold1") self.doubleSpinBox_quality_threshold1.setFont(font1) - self.doubleSpinBox_quality_threshold1.setMaximum(10000.000000000000000) + self.doubleSpinBox_quality_threshold1.setMaximum(1.000000000000000) + self.doubleSpinBox_quality_threshold1.setSingleStep(0.100000000000000) self.gridLayout_3.addWidget(self.doubleSpinBox_quality_threshold1, 0, 1, 1, 1) self.doubleSpinBox_quality_threshold2 = QDoubleSpinBox(self.groupBox_autoqualitylabel_options) self.doubleSpinBox_quality_threshold2.setObjectName(u"doubleSpinBox_quality_threshold2") self.doubleSpinBox_quality_threshold2.setFont(font1) - self.doubleSpinBox_quality_threshold2.setMaximum(10000.000000000000000) + self.doubleSpinBox_quality_threshold2.setMaximum(1.000000000000000) + self.doubleSpinBox_quality_threshold2.setSingleStep(0.100000000000000) self.gridLayout_3.addWidget(self.doubleSpinBox_quality_threshold2, 1, 1, 1, 1) @@ -201,14 +203,16 @@ class Ui_MainWindow_resp_quality_label(object): self.doubleSpinBox_fillterMode_custom_low = QDoubleSpinBox(self.groupBox_threshold_setting) self.doubleSpinBox_fillterMode_custom_low.setObjectName(u"doubleSpinBox_fillterMode_custom_low") self.doubleSpinBox_fillterMode_custom_low.setFont(font1) - self.doubleSpinBox_fillterMode_custom_low.setMaximum(10000.000000000000000) + self.doubleSpinBox_fillterMode_custom_low.setMaximum(1.000000000000000) + self.doubleSpinBox_fillterMode_custom_low.setSingleStep(0.100000000000000) self.gridLayout_6.addWidget(self.doubleSpinBox_fillterMode_custom_low, 3, 1, 1, 1) self.doubleSpinBox_fillterMode_custom_high = QDoubleSpinBox(self.groupBox_threshold_setting) self.doubleSpinBox_fillterMode_custom_high.setObjectName(u"doubleSpinBox_fillterMode_custom_high") self.doubleSpinBox_fillterMode_custom_high.setFont(font1) - self.doubleSpinBox_fillterMode_custom_high.setMaximum(10000.000000000000000) + self.doubleSpinBox_fillterMode_custom_high.setMaximum(1.000000000000000) + self.doubleSpinBox_fillterMode_custom_high.setSingleStep(0.100000000000000) self.gridLayout_6.addWidget(self.doubleSpinBox_fillterMode_custom_high, 3, 3, 1, 1) @@ -229,6 +233,7 @@ class Ui_MainWindow_resp_quality_label(object): self.radioButton_orgBcg_fillterMode_preset = QRadioButton(self.groupBox_threshold_setting) self.radioButton_orgBcg_fillterMode_preset.setObjectName(u"radioButton_orgBcg_fillterMode_preset") self.radioButton_orgBcg_fillterMode_preset.setFont(font1) + self.radioButton_orgBcg_fillterMode_preset.setChecked(True) self.gridLayout_6.addWidget(self.radioButton_orgBcg_fillterMode_preset, 0, 0, 1, 1) @@ -471,7 +476,7 @@ class Ui_MainWindow_resp_quality_label(object): self.pushButton_calculate_peaks.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u8ba1\u7b97\u5cf0\u503c\u5e76\u7ed8\u5236", None)) self.pushButton_input_and_calculate_peaks.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u5bfc\u5165\u5e76\u7b97\u6cd5\u5b9a\u4f4d\u5cf0\u503c", None)) self.pushButton_calculate_peaks_save.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u4fdd\u5b58\u5cf0\u503c\u7ed3\u679c", None)) - self.pushButton_input_data_and_label.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u5bfc\u5165\u5e76\u5f00\u59cb\u6807\u6ce8", None)) + self.pushButton_input_and_label.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u5bfc\u5165\u5e76\u5f00\u59cb\u6807\u6ce8", None)) self.groupBox_autoqualitylabel_options.setTitle(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u4eba\u5de5\u6807\u6ce8\u9608\u503c\u8bbe\u7f6e", None)) self.label_6.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"threshold[1]", None)) self.label_5.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"threshold[0]", None)) diff --git a/ui/MainWindow/MainWindow_resp_quality_label.ui b/ui/MainWindow/MainWindow_resp_quality_label.ui index a0213a7..c65e326 100644 --- a/ui/MainWindow/MainWindow_resp_quality_label.ui +++ b/ui/MainWindow/MainWindow_resp_quality_label.ui @@ -122,7 +122,7 @@ - + 0 @@ -204,7 +204,10 @@ - 10000.000000000000000 + 1.000000000000000 + + + 0.100000000000000 @@ -216,7 +219,10 @@ - 10000.000000000000000 + 1.000000000000000 + + + 0.100000000000000 @@ -324,7 +330,10 @@ - 10000.000000000000000 + 1.000000000000000 + + + 0.100000000000000 @@ -336,7 +345,10 @@ - 10000.000000000000000 + 1.000000000000000 + + + 0.100000000000000 @@ -380,6 +392,9 @@ 预设 + + true + diff --git a/ui/setting/resp_quality_label_input_setting.py b/ui/setting/resp_quality_label_input_setting.py index b8f4b5d..fc6b9b3 100644 --- a/ui/setting/resp_quality_label_input_setting.py +++ b/ui/setting/resp_quality_label_input_setting.py @@ -100,10 +100,10 @@ class Ui_MainWindow_resp_quality_label_input_setting(object): self.verticalLayout_3.addLayout(self.horizontalLayout_3) - self.plainTextEdit_file_path_input_Tho = QPlainTextEdit(self.groupBox_file_path_input_Tho) - self.plainTextEdit_file_path_input_Tho.setObjectName(u"plainTextEdit_file_path_input_Tho") + self.plainTextEdit_file_path_input_signal_Tho = QPlainTextEdit(self.groupBox_file_path_input_Tho) + self.plainTextEdit_file_path_input_signal_Tho.setObjectName(u"plainTextEdit_file_path_input_signal_Tho") - self.verticalLayout_3.addWidget(self.plainTextEdit_file_path_input_Tho) + self.verticalLayout_3.addWidget(self.plainTextEdit_file_path_input_signal_Tho) self.verticalLayout_3.setStretch(0, 1) self.verticalLayout_3.setStretch(1, 2) @@ -181,8 +181,8 @@ class Ui_MainWindow_resp_quality_label_input_setting(object): self.plainTextEdit_file_path_input_signal_OrgBCG.setPlaceholderText(QCoreApplication.translate("MainWindow_resp_quality_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None)) self.groupBox_file_path_input_Tho.setTitle(QCoreApplication.translate("MainWindow_resp_quality_label_input_setting", u"\u540c\u6b65\u540e\u7684Effort Tho\u8def\u5f84", None)) self.label_3.setText(QCoreApplication.translate("MainWindow_resp_quality_label_input_setting", u"\u91c7\u6837\u7387(Hz)\uff1a", None)) - self.plainTextEdit_file_path_input_Tho.setPlainText("") - self.plainTextEdit_file_path_input_Tho.setPlaceholderText(QCoreApplication.translate("MainWindow_resp_quality_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None)) + self.plainTextEdit_file_path_input_signal_Tho.setPlainText("") + self.plainTextEdit_file_path_input_signal_Tho.setPlaceholderText(QCoreApplication.translate("MainWindow_resp_quality_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None)) self.groupBox_file_path_input_artifact.setTitle(QCoreApplication.translate("MainWindow_resp_quality_label_input_setting", u"\u4f53\u52a8Artifact_a\u8def\u5f84", None)) self.plainTextEdit_file_path_input_artifact.setPlainText("") self.plainTextEdit_file_path_input_artifact.setPlaceholderText(QCoreApplication.translate("MainWindow_resp_quality_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None)) diff --git a/ui/setting/resp_quality_label_input_setting.ui b/ui/setting/resp_quality_label_input_setting.ui index cb34972..9b91416 100644 --- a/ui/setting/resp_quality_label_input_setting.ui +++ b/ui/setting/resp_quality_label_input_setting.ui @@ -126,7 +126,7 @@ - + From 94b883032dd1566081d83d158600905a832cd5c5 Mon Sep 17 00:00:00 2001 From: Yorusora <2944763079@qq.com> Date: Thu, 22 May 2025 16:59:52 +0800 Subject: [PATCH 06/26] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E4=BA=86=E4=BD=93?= =?UTF-8?q?=E5=8A=A8=E7=9A=84=E4=BF=9D=E5=AD=98=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_SA_label.py | 8 ++- func/Module_artifact_label.py | 8 +-- func/Module_bcg_quality_label.py | 89 +++++++++++++++++++++++++++++++ func/Module_mainwindow.py | 16 +++++- func/Module_resp_quality_label.py | 8 ++- func/utils/ConfigParams.py | 46 ++-------------- func/utils/Constants.py | 3 ++ 7 files changed, 128 insertions(+), 50 deletions(-) create mode 100644 func/Module_bcg_quality_label.py diff --git a/func/Module_SA_label.py b/func/Module_SA_label.py index e02be1a..71b2fb9 100644 --- a/func/Module_SA_label.py +++ b/func/Module_SA_label.py @@ -1318,9 +1318,13 @@ class Data: Config["InputConfig"]["SpO2Freq"] = result.data["freq"] else: return result + result = PublicFunc.examine_file(Config["Path"]["Input_Artifact"], ConfigParams.ARTIFACT_A) + if result.status: + Config["Path"]["Input_Artifact"] = result.data["path"] + else: + return result + - Config["Path"]["Input_Artifact"] = str( - Path(Config["Path"]["Input_Artifact"]) / Path(ConfigParams.ARTIFACT_A + ConfigParams.ENDSWITH_TXT)) Config["Path"]["Input_Label"] = str( Path(Config["Path"]["Input_Label"]) / Path(ConfigParams.SA_LABEL_SYNC + ConfigParams.ENDSWITH_CSV)) Config["Path"]["Save"] = str( diff --git a/func/Module_artifact_label.py b/func/Module_artifact_label.py index e0ce628..17aa1cf 100644 --- a/func/Module_artifact_label.py +++ b/func/Module_artifact_label.py @@ -562,7 +562,7 @@ class MainWindow_artifact_label(QMainWindow): except Exception as e: return Result().failure(info=Constants.UPDATE_FAILURE + Constants.FAILURE_REASON["Update_Info_Exception"] + "\n" + format_exc()) - return Result().success(info=Constants.UPDATE_FAILURE) + return Result().success(info=Constants.UPDATE_FINISHED) def __slot_btn_input__(self): PublicFunc.__disableAllButton__(self, ButtonState) @@ -1224,11 +1224,11 @@ class Data: return result Config["Path"]["Save_a"] = str( - Path(Config["Path"]["Save_a"]) / Path(ConfigParams.ARTIFACT_A + ConfigParams.ENDSWITH_TXT)) + Path(Config["Path"]["Save_a"]) / Path(ConfigParams.ARTIFACT_A + str(Config["InputConfig"]["UseFreq"]) + ConfigParams.ENDSWITH_TXT)) Config["Path"]["Save_b"] = str( - Path(Config["Path"]["Save_b"]) / Path(ConfigParams.ARTIFACT_B + ConfigParams.ENDSWITH_TXT)) + Path(Config["Path"]["Save_b"]) / Path(ConfigParams.ARTIFACT_B + str(Config["InputConfig"]["UseFreq"]) + ConfigParams.ENDSWITH_TXT)) Config["Path"]["Save_c"] = str( - Path(Config["Path"]["Save_c"]) / Path(ConfigParams.ARTIFACT_C + ConfigParams.ENDSWITH_CSV)) + Path(Config["Path"]["Save_c"]) / Path(ConfigParams.ARTIFACT_C + str(Config["InputConfig"]["UseFreq"]) + ConfigParams.ENDSWITH_CSV)) try: self.orgBcg = read_csv(Config["Path"]["Input_orgBcg"], diff --git a/func/Module_bcg_quality_label.py b/func/Module_bcg_quality_label.py new file mode 100644 index 0000000..ee26e8a --- /dev/null +++ b/func/Module_bcg_quality_label.py @@ -0,0 +1,89 @@ +from gc import collect +from pathlib import Path +from traceback import format_exc + +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 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_bcg_quality_label import Ui_MainWindow_bcg_quality_label +from ui.setting.bcg_quality_label_input_setting import Ui_MainWindow_bcg_quality_label_input_setting + + +Config = { + +} + +ButtonState = { + "Default": { + "pushButton_input_setting": True, + "pushButton_input": True, + "pushButton_invalid_signal_label": False, + "pushButton_Ctype_signal_label": False, + "pushButton_prev": False, + "pushButton_next": False, + "pushButton_save": False, + "pushButton_a1": False, + "pushButton_a2": False, + "pushButton_b1": False, + "pushButton_b2": False, + "pushButton_c": False, + "pushButton_f": False + }, + "Current": { + "pushButton_input_setting": True, + "pushButton_input": True, + "pushButton_invalid_signal_label": False, + "pushButton_Ctype_signal_label": False, + "pushButton_prev": False, + "pushButton_next": False, + "pushButton_save": False, + "pushButton_a1": False, + "pushButton_a2": False, + "pushButton_b1": False, + "pushButton_b2": False, + "pushButton_c": False, + "pushButton_f": False + } +} + + +class SettingWindow(QMainWindow): + + def __init__(self, root_path, sampID): + super(SettingWindow, self).__init__() + self.ui = Ui_MainWindow_bcg_quality_label_input_setting() + self.ui.setupUi(self) + + self.root_path = root_path + self.sampID = sampID + + self.config = None + + +class MainWindow_bcg_quality_label(QMainWindow): + + def __init__(self): + super(MainWindow_bcg_quality_label, self).__init__() + self.ui = Ui_MainWindow_bcg_quality_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) \ No newline at end of file diff --git a/func/Module_mainwindow.py b/func/Module_mainwindow.py index b5d294a..a8ceee9 100644 --- a/func/Module_mainwindow.py +++ b/func/Module_mainwindow.py @@ -16,6 +16,7 @@ from func.Module_label_check import MainWindow_label_check from func.Module_precisely_align import MainWindow_precisely_align from func.Module_cut_PSG import MainWindow_cut_PSG from func.Module_artifact_label import MainWindow_artifact_label +from func.Module_bcg_quality_label import MainWindow_bcg_quality_label from func.Module_resp_quality_label import MainWindow_resp_quality_label from func.Module_SA_label import MainWindow_SA_label @@ -63,6 +64,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.precisely_align = None self.cut_PSG = None self.artifact_label = None + self.bcg_quality_label = None self.resp_quality_label = None self.SA_label = None @@ -78,6 +80,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.ui.pushButton_precisely_align.clicked.connect(self.__slot_btn_precisely_align__) self.ui.pushButton_cut_PSG.clicked.connect(self.__slot_btn_cut_PSG__) self.ui.pushButton_artifact_label.clicked.connect(self.__slot_btn_artifact_label__) + self.ui.pushButton_bcg_quality_label.clicked.connect(self.__slot_btn_bcg_quality_label__) self.ui.pushButton_resp_quality_label.clicked.connect(self.__slot_btn_resp_quality_label__) self.ui.pushButton_SA_label.clicked.connect(self.__slot_btn_SA_label__) @@ -189,7 +192,6 @@ class MainWindow(QMainWindow, Ui_Signal_Label): # 默认最大化显示而非固定分辨率 self.label_check.showMaximized() - def __slot_btn_precisely_align__(self): self.precisely_align = MainWindow_precisely_align() root_path = self.ui.plainTextEdit_root_path.toPlainText() @@ -224,6 +226,18 @@ class MainWindow(QMainWindow, Ui_Signal_Label): # 默认最大化显示而非固定分辨率 self.artifact_label.showMaximized() + def __slot_btn_bcg_quality_label__(self): + self.bcg_quality_label = MainWindow_bcg_quality_label() + root_path = self.ui.plainTextEdit_root_path.toPlainText() + sampID = self.ui.comboBox_sampID.currentText() + if not self.check_root_path(): + return + if not self.check_sampID(): + return + self.bcg_quality_label.show(root_path, int(sampID)) + # 默认最大化显示而非固定分辨率 + self.bcg_quality_label.showMaximized() + def __slot_btn_resp_quality_label__(self): self.resp_quality_label = MainWindow_resp_quality_label() root_path = self.ui.plainTextEdit_root_path.toPlainText() diff --git a/func/Module_resp_quality_label.py b/func/Module_resp_quality_label.py index 38d21b7..86ada06 100644 --- a/func/Module_resp_quality_label.py +++ b/func/Module_resp_quality_label.py @@ -1352,8 +1352,12 @@ class Data(): else: return result - Config["Path"]["Input_Artifact"] = str( - Path(Config["Path"]["Input_Artifact"]) / Path(ConfigParams.ARTIFACT_A + ConfigParams.ENDSWITH_TXT)) + result = PublicFunc.examine_file(Config["Path"]["Input_Artifact"], ConfigParams.ARTIFACT_A) + if result.status: + Config["Path"]["Input_Artifact"] = result.data["path"] + else: + return result + Config["Path"]["Save_Resp_quality_label"] = str( Path(Config["Path"]["Save_Resp_quality_label"]) / Path( ConfigParams.RESP_QUALITY_LABEL + ConfigParams.ENDSWITH_TXT)) diff --git a/func/utils/ConfigParams.py b/func/utils/ConfigParams.py index 404ada5..899488d 100644 --- a/func/utils/ConfigParams.py +++ b/func/utils/ConfigParams.py @@ -50,9 +50,9 @@ class ConfigParams: RPEAK_FINAL_CORRECTED: str = "Rpeak_final_corrected_" APPROXIMATELY_ALIGN_INFO: str = "Approximately_Align_Info" PRECISELY_ALIGN_INFO: str = "Precisely_Align_Info" - ARTIFACT_A: str = "Artifact_a" - ARTIFACT_B: str = "Artifact_b" - ARTIFACT_C: str = "Artifact_c" + ARTIFACT_A: str = "Artifact_a_" + ARTIFACT_B: str = "Artifact_b_" + ARTIFACT_C: str = "Artifact_c_" BCG_SYNC: str = "BCG_Sync_" ECG_SYNC: str = "ECG_Sync_" JPEAK_SYNC: str = "Jpeak_Sync_" @@ -252,6 +252,8 @@ class ConfigParams: ARTIFACT_LABEL_LABEL_TRANSPARENCY: float = 0.3 ARTIFACT_LABEL_ACTION_LABEL_ARTIFACT_SHORTCUT_KEY: str = "Z" + # BCG质量标注 + # 呼吸可用性及间期标注 RESP_QUALITY_LABEL_CONFIG_FILE_PATH: str = "./config/Config_resp_quality_label.yaml" RESP_QUALITY_LABEL_CONFIG_NEW_CONTENT: dict = { @@ -309,16 +311,6 @@ class ConfigParams: SA_LABEL_RADIOBUTTON_2_CLASS_SHORTCUT_KEY: str = "I" SA_LABEL_RADIOBUTTON_3_CLASS_SHORTCUT_KEY: str = "O" - - - - - - - - - - # 质量打标 BCG_QUALITY_LABEL_INPUT_BCG_FILENAME: str = "BCG_sync_" BCG_QUALITY_LABEL_INPUT_ARTIFACT_FILENAME: str = "Artifact_a" @@ -332,34 +324,6 @@ class ConfigParams: BCG_QUALITY_LABEL_MODE_10S_LENGTH = 10 * BCG_QUALITY_LABEL_INPUT_DEFAULT_FS BCG_QUALITY_LABEL_MODE_30S_LENGTH = 30 * BCG_QUALITY_LABEL_INPUT_DEFAULT_FS - # 呼吸可用性及间期标注 - RESP_QUALITY_LABEL_INPUT_XINXIAO_FILENAME: str = "orgBcg_sync_" - RESP_QUALITY_LABEL_INPUT_THO_FILENAME: str = "Effort_Tho_sync_" - RESP_QUALITY_LABEL_INPUT_ARTIFACT_FILENAME: str = "Artifact_a" - RESP_QUALITY_LABEL_SAVE_RESP_QUALITY_LABNEL_FILENAME: str = "Resp_quality_label" - RESP_QUALITY_LABEL_SAVE_THO_PEAK_FILENAME: str = "Tho_peak" - - RESP_QUALITY_LABEL_INPUT_XINXIAO_DEFAULT_FS: int = 1000 - RESP_QUALITY_LABEL_INPUT_THO_DEFAULT_FS: int = 200 - - - - - RESP_QUALITY_LABEL_THRESHOLD1_DEFAULT: float = 0.65 - RESP_QUALITY_LABEL_THRESHOLD2_DEFAULT: float = 0.8 - RESP_QUALITY_LABEL_FINDPEAKS_MIN_INTERVAL_DEFAULT: int = 300 - RESP_QUALITY_LABEL_FINDPEAKS_MIN_HEIGHT_DEFAULT: float = 0.1 - RESP_QUALITY_LABEL_CUSTOM_LOW_DEFAULT: float = 0.1 - RESP_QUALITY_LABEL_CUSTOM_HIGH_DEFAULT: float = 1 - - - - - - - # 睡眠呼吸暂停事件打标 - - # 禁止实例化 def __new__(cls): raise TypeError("Constants class cannot be instantiated") diff --git a/func/utils/Constants.py b/func/utils/Constants.py index f8a2a0e..ade8a2b 100644 --- a/func/utils/Constants.py +++ b/func/utils/Constants.py @@ -379,6 +379,9 @@ class Constants: background-color: #00ff00; /* 鼠标悬停时的背景颜色 */ }""" + # BCG质量标注 + + # 呼吸可用性及间期标注 RESP_QUALITY_LABEL_CALCULATING_PEAK: str = "正在计算峰值" RESP_QUALITY_LABEL_CALCULATE_FINISHED: str = "计算完成" From a321dc5bd45363aad562efbbf37b0e076e09d9b0 Mon Sep 17 00:00:00 2001 From: Yorusora <2944763079@qq.com> Date: Thu, 22 May 2025 17:12:58 +0800 Subject: [PATCH 07/26] =?UTF-8?q?=E5=9C=A8=E5=AF=BC=E5=85=A5=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=97=B6=EF=BC=8C=E5=B0=86=E6=A0=A1=E9=AA=8C=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E7=9A=84=E6=89=A9=E5=B1=95=E5=90=8D=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E5=90=88=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_SA_label.py | 15 +++++++-------- func/Module_approximately_align.py | 6 +++--- func/Module_artifact_label.py | 4 ++-- func/Module_cut_PSG.py | 2 +- func/Module_detect_Jpeak.py | 2 +- func/Module_detect_Rpeak.py | 2 +- func/Module_label_check.py | 2 +- func/Module_precisely_align.py | 6 +++--- func/Module_preprocess.py | 2 +- func/Module_resp_quality_label.py | 8 ++++---- func/utils/Constants.py | 2 ++ func/utils/PublicFunc.py | 7 ++++++- 12 files changed, 32 insertions(+), 26 deletions(-) diff --git a/func/Module_SA_label.py b/func/Module_SA_label.py index 71b2fb9..1e51b97 100644 --- a/func/Module_SA_label.py +++ b/func/Module_SA_label.py @@ -1282,49 +1282,48 @@ class Data: if Path(Config["Path"]["Input_Label"]).is_file(): Config["Path"]["Input_Label"] = str(Path(Config["Path"]["Input_Label"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input_OrgBCG"], ConfigParams.ORGBCG_SYNC) + result = PublicFunc.examine_file(Config["Path"]["Input_OrgBCG"], ConfigParams.ORGBCG_SYNC, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_OrgBCG"] = result.data["path"] Config["InputConfig"]["OrgBCGFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], ConfigParams.THO_SYNC) + result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], ConfigParams.THO_SYNC, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Tho"] = result.data["path"] Config["InputConfig"]["ThoFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_Abd"], ConfigParams.ABD_SYNC) + result = PublicFunc.examine_file(Config["Path"]["Input_Abd"], ConfigParams.ABD_SYNC, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Abd"] = result.data["path"] Config["InputConfig"]["AbdFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_FlowT"], ConfigParams.FLOWT_SYNC) + result = PublicFunc.examine_file(Config["Path"]["Input_FlowT"], ConfigParams.FLOWT_SYNC, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_FlowT"] = result.data["path"] Config["InputConfig"]["FlowTFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_FlowP"], ConfigParams.FLOWP_SYNC) + result = PublicFunc.examine_file(Config["Path"]["Input_FlowP"], ConfigParams.FLOWP_SYNC, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_FlowP"] = result.data["path"] Config["InputConfig"]["FlowPFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_SpO2"], ConfigParams.SPO2_SYNC) + result = PublicFunc.examine_file(Config["Path"]["Input_SpO2"], ConfigParams.SPO2_SYNC, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_SpO2"] = result.data["path"] Config["InputConfig"]["SpO2Freq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_Artifact"], ConfigParams.ARTIFACT_A) + result = PublicFunc.examine_file(Config["Path"]["Input_Artifact"], ConfigParams.ARTIFACT_A, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Artifact"] = result.data["path"] else: return result - Config["Path"]["Input_Label"] = str( Path(Config["Path"]["Input_Label"]) / Path(ConfigParams.SA_LABEL_SYNC + ConfigParams.ENDSWITH_CSV)) Config["Path"]["Save"] = str( diff --git a/func/Module_approximately_align.py b/func/Module_approximately_align.py index 0c85386..97e8209 100644 --- a/func/Module_approximately_align.py +++ b/func/Module_approximately_align.py @@ -933,19 +933,19 @@ class Data: if Path(Config["Path"]["Input_Abd"]).is_file(): Config["Path"]["Input_Abd"] = str(Path(Config["Path"]["Input_Abd"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input_orgBcg"], ConfigParams.ORGBCG_RAW) + result = PublicFunc.examine_file(Config["Path"]["Input_orgBcg"], ConfigParams.ORGBCG_RAW, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_orgBcg"] = result.data["path"] Config["InputConfig"]["orgBcgFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], ConfigParams.THO_RAW) + result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], ConfigParams.THO_RAW, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Tho"] = result.data["path"] Config["InputConfig"]["ThoFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_Abd"], ConfigParams.ABD_RAW) + result = PublicFunc.examine_file(Config["Path"]["Input_Abd"], ConfigParams.ABD_RAW, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Abd"] = result.data["path"] Config["InputConfig"]["AbdFreq"] = result.data["freq"] diff --git a/func/Module_artifact_label.py b/func/Module_artifact_label.py index 17aa1cf..4417057 100644 --- a/func/Module_artifact_label.py +++ b/func/Module_artifact_label.py @@ -1209,14 +1209,14 @@ class Data: if Path(Config["Path"]["Input_BCG"]).is_file(): Config["Path"]["Input_BCG"] = str(Path(Config["Path"]["Input_BCG"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input_orgBcg"], ConfigParams.ORGBCG_SYNC) + result = PublicFunc.examine_file(Config["Path"]["Input_orgBcg"], ConfigParams.ORGBCG_SYNC, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_orgBcg"] = result.data["path"] Config["InputConfig"]["orgBcgFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_BCG"], ConfigParams.BCG_SYNC) + result = PublicFunc.examine_file(Config["Path"]["Input_BCG"], ConfigParams.BCG_SYNC, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_BCG"] = result.data["path"] Config["InputConfig"]["BCGFreq"] = result.data["freq"] diff --git a/func/Module_cut_PSG.py b/func/Module_cut_PSG.py index 10739cd..ea39ece 100644 --- a/func/Module_cut_PSG.py +++ b/func/Module_cut_PSG.py @@ -233,7 +233,7 @@ class Data: def open_file(self): path = str(Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / Path(str(self.sampID))) for value in Config["ChannelInput"].values(): - result = PublicFunc.examine_file(path, value) + result = PublicFunc.examine_file(path, value, ConfigParams.ENDSWITH_TXT) if not result.status: return result diff --git a/func/Module_detect_Jpeak.py b/func/Module_detect_Jpeak.py index d8b8710..d97eac6 100644 --- a/func/Module_detect_Jpeak.py +++ b/func/Module_detect_Jpeak.py @@ -398,7 +398,7 @@ class Data: if Path(Config["Path"]["Input"]).is_file(): Config["Path"]["Input"] = str(Path(Config["Path"]["Input"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input"], ConfigParams.BCG_FILTER) + result = PublicFunc.examine_file(Config["Path"]["Input"], ConfigParams.BCG_FILTER, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input"] = result.data["path"] Config["InputConfig"]["Freq"] = result.data["freq"] diff --git a/func/Module_detect_Rpeak.py b/func/Module_detect_Rpeak.py index 7100d16..69e58ca 100644 --- a/func/Module_detect_Rpeak.py +++ b/func/Module_detect_Rpeak.py @@ -399,7 +399,7 @@ class Data: if Path(Config["Path"]["Input"]).is_file(): Config["Path"]["Input"] = str(Path(Config["Path"]["Input"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input"], ConfigParams.ECG_FILTER) + result = PublicFunc.examine_file(Config["Path"]["Input"], ConfigParams.ECG_FILTER, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input"] = result.data["path"] Config["InputConfig"]["Freq"] = result.data["freq"] diff --git a/func/Module_label_check.py b/func/Module_label_check.py index 0a7cbf2..1a16c04 100644 --- a/func/Module_label_check.py +++ b/func/Module_label_check.py @@ -931,7 +931,7 @@ class Data: if Path(Config["Path"]["Save"]).is_file(): Config["Path"]["Save"] = str(Path(Config["Path"]["Save"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input_Signal"], signal) + result = PublicFunc.examine_file(Config["Path"]["Input_Signal"], signal, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Signal"] = result.data["path"] Config["InputConfig"]["Freq"] = result.data["freq"] diff --git a/func/Module_precisely_align.py b/func/Module_precisely_align.py index 41f67ad..c15a7fc 100644 --- a/func/Module_precisely_align.py +++ b/func/Module_precisely_align.py @@ -1454,7 +1454,7 @@ class Data: if Path(Config["Path"]["Input_Approximately_Align"]).is_file(): Config["Path"]["Input_Approximately_Align"] = str(Path(Config["Path"]["Input_Approximately_Align"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input_OrgBCG"], ConfigParams.ORGBCG_RAW) + result = PublicFunc.examine_file(Config["Path"]["Input_OrgBCG"], ConfigParams.ORGBCG_RAW, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_OrgBCG"] = result.data["path"] Config["InputConfig"]["orgBcgFreq"] = result.data["freq"] @@ -1469,7 +1469,7 @@ class Data: Config["Path"]["Save_OrgBCG"] = str( Path(Config["Path"]["Save_OrgBCG"]) / Path( ConfigParams.ORGBCG_SYNC + str(Config["InputConfig"]["orgBcgFreq"]) + ConfigParams.ENDSWITH_TXT)) - result = PublicFunc.examine_file(Config["Path"]["Input_BCG"], ConfigParams.BCG_FILTER) + result = PublicFunc.examine_file(Config["Path"]["Input_BCG"], ConfigParams.BCG_FILTER, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_BCG"] = result.data["path"] Config["InputConfig"]["BCGFreq"] = result.data["freq"] @@ -1484,7 +1484,7 @@ class Data: Config["Path"]["Save_Jpeak"] = str( Path(Config["Path"]["Save_Jpeak"]) / Path( ConfigParams.JPEAK_SYNC + str(Config["InputConfig"]["BCGFreq"]) + ConfigParams.ENDSWITH_TXT)) - result = PublicFunc.examine_file(Config["Path"]["Input_ECG"], ConfigParams.ECG_FILTER) + result = PublicFunc.examine_file(Config["Path"]["Input_ECG"], ConfigParams.ECG_FILTER, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_ECG"] = result.data["path"] Config["InputConfig"]["ECGFreq"] = result.data["freq"] diff --git a/func/Module_preprocess.py b/func/Module_preprocess.py index 8e37866..7be9aaa 100644 --- a/func/Module_preprocess.py +++ b/func/Module_preprocess.py @@ -410,7 +410,7 @@ class Data: if Path(Config["Path"]["Input"]).is_file(): Config["Path"]["Input"] = str(Path(Config["Path"]["Input"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input"], signal) + result = PublicFunc.examine_file(Config["Path"]["Input"], signal, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input"] = result.data["path"] Config["InputConfig"]["Freq"] = result.data["freq"] diff --git a/func/Module_resp_quality_label.py b/func/Module_resp_quality_label.py index 86ada06..9c2e1ff 100644 --- a/func/Module_resp_quality_label.py +++ b/func/Module_resp_quality_label.py @@ -1247,7 +1247,7 @@ class Data(): if Path(Config["Path"]["Save_Tho_peak"]).is_file(): Config["Path"]["Save_Tho_peak"] = str(Path(Config["Path"]["Save_Tho_peak"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], ConfigParams.THO_SYNC) + result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], ConfigParams.THO_SYNC, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Tho"] = result.data["path"] Config["InputConfig"]["ThoFreq"] = result.data["freq"] @@ -1338,21 +1338,21 @@ class Data(): if Path(Config["Path"]["Save_Tho_peak"]).is_file(): Config["Path"]["Save_Tho_peak"] = str(Path(Config["Path"]["Save_Tho_peak"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input_OrgBCG"], ConfigParams.ORGBCG_SYNC) + result = PublicFunc.examine_file(Config["Path"]["Input_OrgBCG"], ConfigParams.ORGBCG_SYNC, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_OrgBCG"] = result.data["path"] Config["InputConfig"]["OrgBCGFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], ConfigParams.THO_SYNC) + result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], ConfigParams.THO_SYNC, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Tho"] = result.data["path"] Config["InputConfig"]["ThoFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_Artifact"], ConfigParams.ARTIFACT_A) + result = PublicFunc.examine_file(Config["Path"]["Input_Artifact"], ConfigParams.ARTIFACT_A, ConfigParams.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Artifact"] = result.data["path"] else: diff --git a/func/utils/Constants.py b/func/utils/Constants.py index ade8a2b..1696396 100644 --- a/func/utils/Constants.py +++ b/func/utils/Constants.py @@ -94,6 +94,8 @@ class Constants: "Path_Not_Exist": "(路径不存在)", "File_Not_Exist": "(数据文件不存在)", "File_More_Than_One": "(数据文件超过一个)", + "Data_Frequency_Not_In_Filename": "(无法找到文件名中的数据频率信息)", + "Suffix_Not_Correct": "(文件扩展名不正确)", "Frequency_Not_In_Filename": "(数据频率不在文件名中)", "Data_Not_Exist": "(数据不存在)", "Model_File_Not_Exist": "(模型文件不存在)", diff --git a/func/utils/PublicFunc.py b/func/utils/PublicFunc.py index 4de4878..003ef6f 100644 --- a/func/utils/PublicFunc.py +++ b/func/utils/PublicFunc.py @@ -177,7 +177,7 @@ class PublicFunc: QApplication.processEvents() @staticmethod - def examine_file(path_str, filename): + def examine_file(path_str, filename, suffix): temp_path = list( Path(path_str).glob(f"{filename}*")) if len(temp_path) == 0: @@ -201,6 +201,11 @@ class PublicFunc: info=Constants.INPUT_FAILURE + "\n" + filename + ":" + Constants.FAILURE_REASON["Data_Frequency_Not_In_Filename"]) + if Path(path).suffix != suffix: + return Result().failure( + info=Constants.INPUT_FAILURE + "\n" + + filename + ":" + + Constants.FAILURE_REASON["Suffix_Not_Correct"]) data = { "path": str(path), "freq": int(freq) From 196ee81a6f3c9dfd97e4515ac468a160163e70ff Mon Sep 17 00:00:00 2001 From: Yorusora <2944763079@qq.com> Date: Thu, 22 May 2025 19:30:28 +0800 Subject: [PATCH 08/26] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BA=86=E7=9A=84UI=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_bcg_quality_label.py | 666 +++++++++++++- func/Module_resp_quality_label.py | 1 - func/utils/ConfigParams.py | 24 +- func/utils/Constants.py | 51 +- ui/MainWindow/MainWindow_bcg_quality_label.py | 552 ++++++++++++ ui/MainWindow/MainWindow_bcg_quality_label.ui | 853 ++++++++++++++++++ ui/setting/bcg_quality_label_input_setting.py | 177 ++++ ui/setting/bcg_quality_label_input_setting.ui | 219 +++++ 8 files changed, 2491 insertions(+), 52 deletions(-) create mode 100644 ui/MainWindow/MainWindow_bcg_quality_label.py create mode 100644 ui/MainWindow/MainWindow_bcg_quality_label.ui create mode 100644 ui/setting/bcg_quality_label_input_setting.py create mode 100644 ui/setting/bcg_quality_label_input_setting.ui diff --git a/func/Module_bcg_quality_label.py b/func/Module_bcg_quality_label.py index ee26e8a..3c6ab0e 100644 --- a/func/Module_bcg_quality_label.py +++ b/func/Module_bcg_quality_label.py @@ -3,12 +3,15 @@ from pathlib import Path from traceback import format_exc import matplotlib.pyplot as plt -from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication +from PySide6.QtGui import QColor +from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication, QTableWidget, QTableWidgetItem from matplotlib import gridspec from matplotlib.backends.backend_qt import NavigationToolbar2QT from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg +from numpy import array, int64, append, zeros, full, where, nan, arange, float64, isnan, place, count_nonzero, all as np_all from overrides import overrides from pandas import read_csv, DataFrame +from scipy.signal import resample, iirfilter, lfilter from yaml import dump, load, FullLoader from func.utils.PublicFunc import PublicFunc @@ -68,6 +71,80 @@ class SettingWindow(QMainWindow): self.sampID = sampID self.config = None + self.__read_config__() + + self.ui.spinBox_input_freq_signal_BCG.valueChanged.connect(self.__update_ui__) + self.ui.radioButton_30s_mode.clicked.connect(self.__update_mode__) + self.ui.radioButton_10s_mode.clicked.connect(self.__update_mode__) + 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.BCG_QUALITY_LABEL_CONFIG_FILE_PATH).exists(): + with open(ConfigParams.BCG_QUALITY_LABEL_CONFIG_FILE_PATH, "w") as f: + dump(ConfigParams.BCG_QUALITY_LABEL_CONFIG_NEW_CONTENT, f) + + with open(ConfigParams.BCG_QUALITY_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_BCG": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + Path(str(self.sampID)))), + "Input_Artifact": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + Path(str(self.sampID)))), + "Save": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + Path(str(self.sampID)))), + }, + "Mode": "Undefined", + "DataPartNum": 0, + "CurrentDataIdx": 0, + "CurrentPartNum": 1, + "LongestContinuousTime": 0, + "ArtifactTimePercentage": 0 + }) + + # 数据回显 + self.ui.spinBox_input_freq_signal_BCG.setValue(Config["InputConfig"]["BCGFreq"]) + self.ui.plainTextEdit_file_path_input_signal_BCG.setPlainText(Config["Path"]["Input_BCG"]) + self.ui.plainTextEdit_file_path_input_artifact.setPlainText(Config["Path"]["Input_Artifact"]) + self.ui.plainTextEdit_file_path_save.setPlainText(Config["Path"]["Save"]) + + def __write_config__(self): + # 从界面写入配置 + Config["InputConfig"]["BCGFreq"] = self.ui.spinBox_input_freq_signal_BCG.value() + Config["Path"]["Input_BCG"] = self.ui.plainTextEdit_file_path_input_signal_BCG.toPlainText() + Config["Path"]["Input_Artifact"] = self.ui.plainTextEdit_file_path_input_artifact.toPlainText() + Config["Path"]["Save"] = self.ui.plainTextEdit_file_path_save.toPlainText() + + # 保存配置到文件 + self.config["InputConfig"]["BCGFreq"] = self.ui.spinBox_input_freq_signal_BCG.value() + + with open(ConfigParams.BCG_QUALITY_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_signal_BCG.setPlainText( + str((Path(self.root_path) / + ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + Path(str(self.sampID)) / + Path(ConfigParams.BCG_SYNC + + str(self.ui.spinBox_input_freq_signal_BCG.value()) + + ConfigParams.ENDSWITH_TXT)))) + + def __update_mode__(self): + if self.ui.radioButton_30s_mode.isChecked(): + Config["Mode"] = "30s" + elif self.ui.radioButton_10s_mode.isChecked(): + Config["Mode"] = "10s" class MainWindow_bcg_quality_label(QMainWindow): @@ -86,4 +163,589 @@ class MainWindow_bcg_quality_label(QMainWindow): # 初始化进度条 self.progressbar = None - PublicFunc.add_progressbar(self) \ No newline at end of file + PublicFunc.add_progressbar(self) + + #初始化画框 + self.fig = None + self.canvas = None + self.figToolbar = None + self.gs = None + self.ax0 = None + + self.line_data = None + + self.msgBox = QMessageBox() + self.msgBox.setWindowTitle(Constants.MAINWINDOW_MSGBOX_TITLE) + + @overrides + def show(self, root_path, sampID): + super().show() + self.root_path = root_path + self.sampID = sampID + + self.setting = SettingWindow(root_path, sampID) + + # 初始化画框 + self.fig = plt.figure(figsize=(12, 9), dpi=100) + self.canvas = FigureCanvasQTAgg(self.fig) + self.figToolbar = NavigationToolbar2QT(self.canvas) + 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.ui.verticalLayout_canvas.addWidget(self.canvas) + self.ui.verticalLayout_canvas.addWidget(self.figToolbar) + self.gs = gridspec.GridSpec(1, 1, height_ratios=[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) + + PublicFunc.__resetAllButton__(self, ButtonState) + + self.ui.tableWidget_a1.setEditTriggers(QTableWidget.NoEditTriggers) + self.ui.tableWidget_a2.setEditTriggers(QTableWidget.NoEditTriggers) + self.ui.tableWidget_b1.setEditTriggers(QTableWidget.NoEditTriggers) + self.ui.tableWidget_b2.setEditTriggers(QTableWidget.NoEditTriggers) + self.ui.tableWidget_c.setEditTriggers(QTableWidget.NoEditTriggers) + self.ui.tableWidget_f.setEditTriggers(QTableWidget.NoEditTriggers) + self.ui.tableWidget_a1.horizontalHeader().setStretchLastSection(True) + self.ui.tableWidget_a2.horizontalHeader().setStretchLastSection(True) + self.ui.tableWidget_b1.horizontalHeader().setStretchLastSection(True) + self.ui.tableWidget_b2.horizontalHeader().setStretchLastSection(True) + self.ui.tableWidget_c.horizontalHeader().setStretchLastSection(True) + self.ui.tableWidget_f.horizontalHeader().setStretchLastSection(True) + self.ui.tableWidget_a1.setHorizontalHeaderLabels(['a1']) + self.ui.tableWidget_a2.setHorizontalHeaderLabels(['a2']) + self.ui.tableWidget_b1.setHorizontalHeaderLabels(['b1']) + self.ui.tableWidget_b2.setHorizontalHeaderLabels(['b2']) + self.ui.tableWidget_c.setHorizontalHeaderLabels(['c']) + self.ui.tableWidget_f.setHorizontalHeaderLabels(['None']) + + self.ui.pushButton_input_setting.clicked.connect(self.setting.show) + self.ui.pushButton_input.clicked.connect(self.__slot_btn_input__) + + @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() + + # 清空画框 + if self.ax0 is not None: + self.ax0.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): + # 清空画框 + self.reset_axes() + + sender = self.sender() + + if sender == self.ui.pushButton_input: + try: + artifact_type_seq = array([]) + artifact_type_seq = artifact_type_seq.astype(int64) + if self.ui.checkBox_type1.isChecked(): + artifact_type_seq = append(artifact_type_seq, 1) + if self.ui.checkBox_type2.isChecked(): + artifact_type_seq = append(artifact_type_seq, 2) + if self.ui.checkBox_type3.isChecked(): + artifact_type_seq = append(artifact_type_seq, 3) + if self.ui.checkBox_type4.isChecked(): + artifact_type_seq = append(artifact_type_seq, 4) + if self.ui.checkBox_type5.isChecked(): + artifact_type_seq = append(artifact_type_seq, 5) + + # 是否显示去除工频噪声 + if self.ui.checkBox_display_afterfilter.isChecked(): + display_data = self.data.BCG_without_industrialFrequencyNoise + else: + display_data = self.data.BCG + + if Config["Mode"] == "30s": + length = Config["InputConfig"]["UseFreq"] * 30 + elif Config["Mode"] == "10s": + length = Config["InputConfig"]["UseFreq"] * 10 + else: + raise ValueError("模式不存在") + + # 绘制数据和体动 + mask = array([arange(length), arange(length), arange(length), arange(length), arange(length), arange(length)]) + mask = mask.astype(float64) + self.ax0.plot( + arange(Config["CurrentDataIdx"], Config["CurrentDataIdx"] + length), + display_data[Config["CurrentDataIdx"]: Config["CurrentDataIdx"] + length], + label=Constants.BCG_QUALITY_LABEL_PLOT_LABEL_SIGNAL, color=Constants.PLOT_COLOR_BLUE) + for i in artifact_type_seq: + mask[i] = self.data.artifact_mask[Config["CurrentDataIdx"]: Config["CurrentDataIdx"] + length] == i + mask[i] = (display_data[Config["CurrentDataIdx"]: Config["CurrentDataIdx"] + length] * + mask[i]).astype(float64) + place(mask[i], mask[i] == 0, nan) + self.ax0.plot(arange(Config["CurrentDataIdx"], Config["CurrentDataIdx"] + length), mask[i], + label=f"{Constants.BCG_QUALITY_LABEL_PLOT_LABEL_ARTIFACT}{i}", color=Constants.PLOT_COLOR_RED, + linestyle="-") + + isArtifact = mask[~np_all(mask == range(0, length), axis=1)] + isArtifact = ~isnan(isArtifact).all(axis=0) + + # 计算最长连续时间并更新信息 + longest_continuous_max_length = 0 + longest_continuous_current_length = 0 + longest_continuous_end = 0 + for index, value in enumerate(isArtifact): + if value == False: + longest_continuous_current_length += 1 + if longest_continuous_current_length > longest_continuous_max_length: + longest_continuous_end = index + longest_continuous_max_length = max(longest_continuous_max_length, + longest_continuous_current_length) + else: + longest_continuous_current_length = 0 + longest_continuous_start = longest_continuous_end - longest_continuous_max_length + 1 + if self.ui.checkBox_highlight_longest_continuous.isChecked(): + self.ax0.plot( + arange(Config["CurrentDataIdx"] + longest_continuous_start, + Config["CurrentDataIdx"] + longest_continuous_end), + display_data[ + Config["CurrentDataIdx"] + longest_continuous_start: Config["CurrentDataIdx"] + longest_continuous_end], + label=Constants.BCG_QUALITY_LABEL_PLOT_LABEL_LONGEST_CONTINUOUS, + color=Constants.PLOT_COLOR_PURPLE, linestyle="-", zorder=3) + self.ui.lineEdit_longest_continuous_time.setText( + str(round(longest_continuous_max_length / int(Config["InputConfig"]["UseFreq"]), 2)) + "秒") + + # 计算体动时间占比并更新信息 + self.ui.lineEdit_artifact_time_percentage.setText( + str(round(100 * count_nonzero(isArtifact) / len(isArtifact), 2)) + "%") + + self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) + self.canvas.draw() + except Exception as e: + return Result().failure(info=Constants.DRAW_FAILURE + "\n" + format_exc()) + return Result().success(info=Constants.DRAW_FINISHED) + else: + self.canvas.draw() + self.ax0.autoscale(False) + return Result().failure(info=Constants.DRAW_FAILURE) + + 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.LOADING_ARCHIVE, 30) + 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.RESAMPLING_DATA, 40) + result = self.data.resample() + 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.PREPROCESSING_DATA, 70) + result = self.data.preprocess() + 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.DRAWING_DATA, 90) + result = self.__plot__() + 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.change_tablewidget_mode() + self.update_tableWidget() + self.update_status() + ButtonState["Current"]["pushButton_input_setting"] = True + ButtonState["Current"]["pushButton_input"] = True + ButtonState["Current"]["pushButton_invalid_signal_label"] = True + ButtonState["Current"]["pushButton_Ctype_signal_label"] = True + ButtonState["Current"]["pushButton_prev"] = True + ButtonState["Current"]["pushButton_next"] = True + ButtonState["Current"]["pushButton_save"] = True + ButtonState["Current"]["pushButton_a1"] = True + ButtonState["Current"]["pushButton_a2"] = True + ButtonState["Current"]["pushButton_b1"] = True + ButtonState["Current"]["pushButton_b2"] = True + ButtonState["Current"]["pushButton_c"] = True + ButtonState["Current"]["pushButton_f"] = True + for action in self.figToolbar._actions.values(): + action.setEnabled(True) + + PublicFunc.finish_operation(self, ButtonState) + + def update_status(self): + if Config["Mode"] == "30s": + hour = int(((Config["CurrentDataIdx"] + (Config["InputConfig"]["UseFreq"] * 30)) / int(Config["InputConfig"]["UseFreq"])) // 3600) + min = int((((Config["CurrentDataIdx"] + (Config["InputConfig"]["UseFreq"] * 30)) / int(Config["InputConfig"]["UseFreq"])) % 3600) // 60) + sec = int((((Config["CurrentDataIdx"] + (Config["InputConfig"]["UseFreq"] * 30)) / int(Config["InputConfig"]["UseFreq"])) % 3600) % 60) + elif Config["Mode"] == "10s": + hour = int(((Config["CurrentDataIdx"] + (Config["InputConfig"]["UseFreq"] * 10)) / int(Config["InputConfig"]["UseFreq"])) // 3600) + min = int((((Config["CurrentDataIdx"] + (Config["InputConfig"]["UseFreq"] * 10)) / int(Config["InputConfig"]["UseFreq"])) % 3600) // 60) + sec = int((((Config["CurrentDataIdx"] + (Config["InputConfig"]["UseFreq"] * 10)) / int(Config["InputConfig"]["UseFreq"])) % 3600) % 60) + else: + raise ValueError("模式不存在") + self.ui.lineEdit_current_part_time.setText(str(hour) + "时" + str(min) + "分" + str(sec) + "秒") + self.ui.lineEdit_data_part_num.setText(str(Config["CurrentPartNum"]) + "/" + str(Config["DataPartNum"])) + + def update_tableWidget(self): + if Config["Mode"] == "30s": + label_list = { + "label_a1": where(self.data.label == Constants.BCG_QUALITY_LABEL_30S_A1)[0] + 1, + "label_a2": where(self.data.label == Constants.BCG_QUALITY_LABEL_30S_A2)[0] + 1, + "label_b1": where(self.data.label == Constants.BCG_QUALITY_LABEL_30S_B1)[0] + 1, + "label_b2": where(self.data.label == Constants.BCG_QUALITY_LABEL_30S_B2)[0] + 1, + "label_c": where(self.data.label == Constants.BCG_QUALITY_LABEL_30S_C)[0] + 1, + "label_tobeLabeled": where(self.data.label == Constants.BCG_QUALITY_LABEL_TOBELABELED)[0] + 1 + } + self.ui.tableWidget_a1.setRowCount(label_list["label_a1"].__len__()) + self.ui.tableWidget_a2.setRowCount(label_list["label_a2"].__len__()) + self.ui.tableWidget_b1.setRowCount(label_list["label_b1"].__len__()) + self.ui.tableWidget_b2.setRowCount(label_list["label_b2"].__len__()) + self.ui.tableWidget_c.setRowCount(label_list["label_c"].__len__()) + self.ui.tableWidget_f.setRowCount(label_list["label_tobeLabeled"].__len__()) + for label_name, label in label_list.items(): + if label_name == "label_a1": + tableWidget = self.ui.tableWidget_a1 + elif label_name == "label_a2": + tableWidget = self.ui.tableWidget_a2 + elif label_name == "label_b1": + tableWidget = self.ui.tableWidget_b1 + elif label_name == "label_b2": + tableWidget = self.ui.tableWidget_b2 + elif label_name == "label_c": + tableWidget = self.ui.tableWidget_c + elif label_name == "label_tobeLabeled": + tableWidget = self.ui.tableWidget_f + else: + raise ValueError("标签名不存在") + for row, value in enumerate(label): + item = QTableWidgetItem(str(value).strip()) + tableWidget.setItem(row, 0, item) + if (self.data.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_REMARK][ + value - 1] != Constants.STRING_IS_EMPTY and + self.data.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_REMARK][value - 1] is not nan): + item = tableWidget.item(row, 0) + item.setBackground(QColor(255, 200, 200)) + else: + item = tableWidget.item(row, 0) + item.setBackground(QColor(255, 255, 255)) + self.ui.tableWidget_a1.verticalScrollBar().setValue(self.ui.tableWidget_a1.verticalScrollBar().maximum()) + self.ui.tableWidget_a2.verticalScrollBar().setValue(self.ui.tableWidget_a2.verticalScrollBar().maximum()) + self.ui.tableWidget_b1.verticalScrollBar().setValue(self.ui.tableWidget_b2.verticalScrollBar().maximum()) + self.ui.tableWidget_c.verticalScrollBar().setValue(self.ui.tableWidget_c.verticalScrollBar().maximum()) + self.ui.tableWidget_f.verticalScrollBar().setValue(self.ui.tableWidget_f.verticalScrollBar().maximum()) + elif Config["Mode"] == "10s": + label_list = { + "label_a": where(self.data.label == Constants.BCG_QUALITY_LABEL_10S_A)[0] + 1, + "label_b": where(self.data.label == Constants.BCG_QUALITY_LABEL_10S_B)[0] + 1, + "label_c": where(self.data.label == Constants.BCG_QUALITY_LABEL_10S_C)[0] + 1, + "label_tobeLabeled": where(self.data.label == Constants.BCG_QUALITY_LABEL_TOBELABELED)[0] + 1 + } + self.ui.tableWidget_a1.setRowCount(label_list["label_a"].__len__()) + self.ui.tableWidget_b1.setRowCount(label_list["label_b"].__len__()) + self.ui.tableWidget_c.setRowCount(label_list["label_c"].__len__()) + self.ui.tableWidget_f.setRowCount(label_list["label_tobeLabeled"].__len__()) + for label_name, label in label_list.items(): + if label_name == "label_a": + tableWidget = self.ui.tableWidget_a1 + elif label_name == "label_b": + tableWidget = self.ui.tableWidget_b1 + elif label_name == "label_c": + tableWidget = self.ui.tableWidget_c + elif label_name == "label_tobeLabeled": + tableWidget = self.ui.tableWidget_f + else: + raise ValueError("标签名不存在") + for row, value in enumerate(label): + item = QTableWidgetItem(str(value).strip()) + tableWidget.setItem(row, 0, item) + if (self.data.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_REMARK][ + value - 1] != Constants.STRING_IS_EMPTY and + self.data.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_REMARK][value - 1] is not nan): + item = tableWidget.item(row, 0) + item.setBackground(QColor(255, 200, 200)) + else: + item = tableWidget.item(row, 0) + item.setBackground(QColor(255, 255, 255)) + self.ui.tableWidget_a1.verticalScrollBar().setValue(self.ui.tableWidget_a1.verticalScrollBar().maximum()) + self.ui.tableWidget_b1.verticalScrollBar().setValue(self.ui.tableWidget_b1.verticalScrollBar().maximum()) + self.ui.tableWidget_c.verticalScrollBar().setValue(self.ui.tableWidget_c.verticalScrollBar().maximum()) + else: + raise ValueError("模式不存在") + + def reset_axes(self): + if self.ax0 is not None: + self.ax0.clear() + self.ax0.grid(True) + self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + + def change_tablewidget_mode(self): + if Config["Mode"] == "10s": + self.ui.pushButton_a1.show() + self.ui.pushButton_a2.hide() + self.ui.pushButton_b1.show() + self.ui.pushButton_b2.hide() + self.ui.pushButton_c.show() + self.ui.pushButton_f.show() + self.ui.pushButton_a1.setText("a") + self.ui.pushButton_a2.setText("a2") + self.ui.pushButton_b1.setText("b") + self.ui.pushButton_b2.setText("b2") + self.ui.pushButton_c.setText("c") + self.ui.pushButton_f.setText("删除") + self.ui.tableWidget_a1.show() + self.ui.tableWidget_a2.hide() + self.ui.tableWidget_b1.show() + self.ui.tableWidget_b2.hide() + self.ui.tableWidget_c.show() + self.ui.tableWidget_f.show() + self.ui.tableWidget_a1.setHorizontalHeaderLabels(['a']) + self.ui.tableWidget_a2.setHorizontalHeaderLabels(['a2']) + self.ui.tableWidget_b1.setHorizontalHeaderLabels(['b']) + self.ui.tableWidget_b2.setHorizontalHeaderLabels(['b2']) + self.ui.tableWidget_c.setHorizontalHeaderLabels(['c']) + self.ui.tableWidget_f.setHorizontalHeaderLabels(['None']) + elif Config["Mode"] == "30s": + self.ui.pushButton_a1.show() + self.ui.pushButton_a2.show() + self.ui.pushButton_b1.show() + self.ui.pushButton_b2.show() + self.ui.pushButton_c.show() + self.ui.pushButton_f.show() + self.ui.pushButton_a1.setText("a1") + self.ui.pushButton_a2.setText("a2") + self.ui.pushButton_b1.setText("b1") + self.ui.pushButton_b2.setText("b2") + self.ui.pushButton_c.setText("c") + self.ui.pushButton_f.setText("删除") + self.ui.tableWidget_a1.show() + self.ui.tableWidget_a2.show() + self.ui.tableWidget_b1.show() + self.ui.tableWidget_b2.show() + self.ui.tableWidget_c.show() + self.ui.tableWidget_f.show() + self.ui.tableWidget_a1.setHorizontalHeaderLabels(['a1']) + self.ui.tableWidget_a2.setHorizontalHeaderLabels(['a2']) + self.ui.tableWidget_b1.setHorizontalHeaderLabels(['b1']) + self.ui.tableWidget_b2.setHorizontalHeaderLabels(['b2']) + self.ui.tableWidget_c.setHorizontalHeaderLabels(['c']) + self.ui.tableWidget_f.setHorizontalHeaderLabels(['None']) + elif Config["Mode"] == "Undefined": + return False + else: + raise ValueError("模式不存在") + return True + + +class Data(): + + def __init__(self): + self.BCG = None + self.BCG_without_industrialFrequencyNoise = None + self.Artifact_a = None + self.df_label = None + self.label = None + + self.artifact_number = array([]).astype(int64) + self.artifact_type = array([]).astype(int64) + self.artifact_mask = array([]).astype(int64) + + def open_file(self): + if Path(Config["Path"]["Input_BCG"]).is_file(): + Config["Path"]["Input_BCG"] = str(Path(Config["Path"]["Input_BCG"]).parent) + if Path(Config["Path"]["Input_Artifact"]).is_file(): + Config["Path"]["Input_Artifact"] = str(Path(Config["Path"]["Input_Artifact"]).parent) + if Path(Config["Path"]["Save"]).is_file(): + Config["Path"]["Save"] = str(Path(Config["Path"]["Save"]).parent) + + result = PublicFunc.examine_file(Config["Path"]["Input_BCG"], ConfigParams.BCG_SYNC, ConfigParams.ENDSWITH_TXT) + if result.status: + Config["Path"]["Input_BCG"] = result.data["path"] + Config["InputConfig"]["ThoFreq"] = result.data["freq"] + else: + return result + + result = PublicFunc.examine_file(Config["Path"]["Input_Artifact"], ConfigParams.ARTIFACT_A, ConfigParams.ENDSWITH_TXT) + if result.status: + Config["Path"]["Input_Artifact"] = result.data["path"] + else: + return result + + if Config["Mode"] == "30s": + Config["Path"]["Save"] = str( + Path(Config["Path"]["Save"]) / Path(ConfigParams.SQ_LABEL_30S + ConfigParams.ENDSWITH_CSV)) + elif Config["Mode"] == "10s": + Config["Path"]["Save"] = str( + Path(Config["Path"]["Save"]) / Path(ConfigParams.SQ_LABEL_10S + ConfigParams.ENDSWITH_CSV)) + elif Config["Mode"] == "Undefined": + return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Mode_Undefined"]) + else: + raise ValueError("模式不存在") + + try: + self.BCG = read_csv(Config["Path"]["Input_BCG"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + self.Artifact_a = read_csv(Config["Path"]["Input_Artifact"], + encoding=ConfigParams.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) + except Exception as e: + return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Open_Data_Exception"] + "\n" + format_exc()) + + try: + if Config["Mode"] == "30s": + Config["DataPartNum"] = len(self.BCG) // (Config["InputConfig"]["UseFreq"] * 30) + elif Config["Mode"] == "10s": + Config["DataPartNum"] = len(self.BCG) // (Config["InputConfig"]["UseFreq"] * 10) + else: + raise ValueError("模式不存在") + if Config["DataPartNum"] == 0: + return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Data_Length_Not_Correct"]) + except Exception as e: + return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Open_Data_Exception"] + "\n" + format_exc()) + + try: + # 检查体动标签正确性,长度 + PublicFunc.examine_artifact(self.Artifact_a) + # 定义绘制体动所需要的数组 + artifact_start = array([]) + artifact_start = artifact_start.astype(int64) + artifact_end = array([]) + artifact_end = artifact_end.astype(int64) + for i in range(0, len(self.Artifact_a), 4): + self.artifact_number = append(self.artifact_number, self.Artifact_a[i]) + for i in range(1, len(self.Artifact_a), 4): + self.artifact_type = append(self.artifact_type, self.Artifact_a[i]) + for i in range(2, len(self.Artifact_a), 4): + artifact_start = append(artifact_start, self.Artifact_a[i]) + for i in range(3, len(self.Artifact_a), 4): + artifact_end = append(artifact_end, self.Artifact_a[i]) + self.artifact_mask = zeros(len(self.BCG)) + for i in range(0, len(self.artifact_number)): + self.artifact_mask[artifact_start[i]: artifact_end[i] + 1] = 1 + except Exception as e: + return Result().failure(info=Constants.INPUT_FAILURE + + Constants.FAILURE_REASON["Get_Artifact_Format_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.INPUT_FINISHED) + + def get_archive(self): + if Config["Mode"] == "30s": + filename = ConfigParams.SQ_LABEL_30S + elif Config["Mode"] == "10s": + filename = ConfigParams.SQ_LABEL_10S + else: + raise ValueError("模式不存在") + + if not Path(Config["Path"]["Save"]).exists(): + self.label = full(Config["DataPartNum"], Constants.BCG_QUALITY_LABEL_TOBELABELED) + self.df_label = DataFrame(columns=[Constants.BCG_QUALITY_LABEL_COLUMN_LABEL, Constants.BCG_QUALITY_LABEL_COLUMN_REMARK]) + self.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_LABEL] = self.label + self.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_REMARK] = Constants.STRING_IS_EMPTY + self.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_LABEL] = self.df_label[ + Constants.BCG_QUALITY_LABEL_COLUMN_LABEL].astype(str) + self.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_REMARK] = self.df_label[ + Constants.BCG_QUALITY_LABEL_COLUMN_REMARK].astype(str) + return Result().success(info=filename + ":" + Constants.ARCHIVE_NOT_EXIST) + else: + self.df_label = read_csv(Config["Path"]["Save"], + encoding=ConfigParams.GBK_ENCODING) + self.label = self.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_LABEL].astype(str) + return Result().success(info=filename + ":" + Constants.ARCHIVE_EXIST) + + def resample(self): + if self.BCG is None: + Result().failure(info=Constants.RESAMPLE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + + try: + if Config["InputConfig"]["BCGFreq"] != Config["InputConfig"]["UseFreq"]: + self.BCG = resample(self.BCG, + int(len(self.BCG) * + (Config["InputConfig"]["UseFreq"] / Config["InputConfig"]["BCGFreq"]))) + else: + return Result().success(info=Constants.RESAMPLE_NO_NEED) + except Exception as e: + Result().failure(info=Constants.RESAMPLE_FAILURE + + Constants.FAILURE_REASON["Resample_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.RESAMPLE_FINISHED) + + def preprocess(self): + if self.BCG is None: + return Result().failure(info=Constants.PREPROCESS_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + + try: + self.BCG_without_industrialFrequencyNoise = Data.wipe_industrialFrequencyNoise(self.BCG, int(Config["InputConfig"]["UseFreq"])) + except Exception as e: + return Result().failure(info=Constants.PREPROCESS_FAILURE + + Constants.FAILURE_REASON["Preprocess_Exception"] + "\n" + format_exc()) + + return Result().success(info=Constants.PREPROCESS_FINISHED) + + + @staticmethod + def wipe_industrialFrequencyNoise(data, fs): + # 设计带阻滤波器(Notch Filter)来滤除49-51Hz的噪声 + nyq = 0.5 * fs # 奈奎斯特频率 + low = 49 / nyq + high = 51 / nyq + b, a = iirfilter(4, [low, high], btype='bandstop', ftype='butter') # 4阶巴特沃斯带阻滤波器 + return lfilter(b, a, data) \ No newline at end of file diff --git a/func/Module_resp_quality_label.py b/func/Module_resp_quality_label.py index 9c2e1ff..2f1049d 100644 --- a/func/Module_resp_quality_label.py +++ b/func/Module_resp_quality_label.py @@ -286,7 +286,6 @@ class MainWindow_resp_quality_label(QMainWindow): self.ui.pushButton_invalid.clicked.connect(self.__slot_btn_label__) self.ui.pushButton_reset.clicked.connect(self.__slot_btn_label__) self.ui.pushButton_save.clicked.connect(self.__slot_btn_save__) - self.ui.lineEdit_filter_labeled.textChanged.connect(self.__slot_lineEdit_filter__) self.ui.lineEdit_filter_tobelabeled.textChanged.connect(self.__slot_lineEdit_filter__) self.ui.doubleSpinBox_quality_threshold1.valueChanged.connect(self.update_config) diff --git a/func/utils/ConfigParams.py b/func/utils/ConfigParams.py index 899488d..ee06548 100644 --- a/func/utils/ConfigParams.py +++ b/func/utils/ConfigParams.py @@ -70,6 +70,8 @@ class ConfigParams: SA_LABEL_ADD: str = "SA Label_add" RESP_QUALITY_LABEL: str = "Resp_quality_label" THO_PEAK: str = "Tho_peak_" + SQ_LABEL_10S: str = "SQ_label_10s" + SQ_LABEL_30S: str = "SQ_label_30s" # 数据粗同步 APPROXIMATELY_ALIGN_CONFIG_FILE_PATH: str = "./config/Config_approximately_align.yaml" @@ -252,7 +254,14 @@ class ConfigParams: ARTIFACT_LABEL_LABEL_TRANSPARENCY: float = 0.3 ARTIFACT_LABEL_ACTION_LABEL_ARTIFACT_SHORTCUT_KEY: str = "Z" - # BCG质量标注 + # BCG的质量标注 + BCG_QUALITY_LABEL_CONFIG_FILE_PATH: str = "./config/Config_bcg_quality_label.yaml" + BCG_QUALITY_LABEL_CONFIG_NEW_CONTENT: dict = { + "InputConfig": { + "BCGFreq": 1000, + "UseFreq": 1000 + } + } # 呼吸可用性及间期标注 RESP_QUALITY_LABEL_CONFIG_FILE_PATH: str = "./config/Config_resp_quality_label.yaml" @@ -311,19 +320,6 @@ class ConfigParams: SA_LABEL_RADIOBUTTON_2_CLASS_SHORTCUT_KEY: str = "I" SA_LABEL_RADIOBUTTON_3_CLASS_SHORTCUT_KEY: str = "O" - # 质量打标 - BCG_QUALITY_LABEL_INPUT_BCG_FILENAME: str = "BCG_sync_" - BCG_QUALITY_LABEL_INPUT_ARTIFACT_FILENAME: str = "Artifact_a" - BCG_QUALITY_LABEL_SAVE_FILENAME: str = "SQ_label_" - - BCG_QUALITY_LABEL_INPUT_DEFAULT_FS: int = 1000 - - BCG_QUALITY_LABEL_SAVE_MODE_10S: str = "10s" - BCG_QUALITY_LABEL_SAVE_MODE_30S: str = "30s" - - BCG_QUALITY_LABEL_MODE_10S_LENGTH = 10 * BCG_QUALITY_LABEL_INPUT_DEFAULT_FS - BCG_QUALITY_LABEL_MODE_30S_LENGTH = 30 * BCG_QUALITY_LABEL_INPUT_DEFAULT_FS - # 禁止实例化 def __new__(cls): raise TypeError("Constants class cannot be instantiated") diff --git a/func/utils/Constants.py b/func/utils/Constants.py index 1696396..7300484 100644 --- a/func/utils/Constants.py +++ b/func/utils/Constants.py @@ -106,6 +106,7 @@ class Constants: "Data_Length_not_Correct": "(orgBcg和BCG长度不匹配)", "Artifact_Format_Not_Correct": "(体动长度或格式不正确)", "Data_Length_Not_Correct": "(信号长度不正确)", + "Mode_Undefined": "(模式未选择)", "Open_Data_Exception": "(打开数据异常)", "Process_Exception": "(处理异常)", @@ -381,7 +382,21 @@ class Constants: background-color: #00ff00; /* 鼠标悬停时的背景颜色 */ }""" - # BCG质量标注 + # BCG的质量标注 + BCG_QUALITY_LABEL_COLUMN_LABEL: str = "label" + BCG_QUALITY_LABEL_COLUMN_REMARK: str = "remark" + BCG_QUALITY_LABEL_PLOT_LABEL_SIGNAL: str = "BCG" + BCG_QUALITY_LABEL_PLOT_LABEL_ARTIFACT: str = "Artifact" + BCG_QUALITY_LABEL_PLOT_LABEL_LONGEST_CONTINUOUS: str = "Longest_Continuous" + BCG_QUALITY_LABEL_10S_A: str = "a" + BCG_QUALITY_LABEL_10S_B: str = "b" + BCG_QUALITY_LABEL_10S_C: str = "c" + BCG_QUALITY_LABEL_30S_A1: str = "a" + BCG_QUALITY_LABEL_30S_A2: str = "b" + BCG_QUALITY_LABEL_30S_B1: str = "c" + BCG_QUALITY_LABEL_30S_B2: str = "d" + BCG_QUALITY_LABEL_30S_C: str = "e" + BCG_QUALITY_LABEL_TOBELABELED: str = "f" # 呼吸可用性及间期标注 @@ -464,19 +479,6 @@ class Constants: # 质量打标 - BCG_QUALITY_LABEL_FILES_NOT_FOUND: str = f"无法找到{ConfigParams.BCG_QUALITY_LABEL_INPUT_BCG_FILENAME}{ConfigParams.ENDSWITH_TXT}或{ConfigParams.BCG_QUALITY_LABEL_INPUT_ARTIFACT_FILENAME}{ConfigParams.ENDSWITH_TXT},无法执行" - BCG_QUALITY_LABEL_FILES_FOUND: str = f"找到{ConfigParams.BCG_QUALITY_LABEL_INPUT_BCG_FILENAME}{ConfigParams.ENDSWITH_TXT}和{ConfigParams.BCG_QUALITY_LABEL_INPUT_ARTIFACT_FILENAME}{ConfigParams.ENDSWITH_TXT}" - BCG_QUALITY_LABEL_HISTORICAL_SAVE_FOUND: str = f"找到历史存档文件{ConfigParams.BCG_QUALITY_LABEL_SAVE_FILENAME}{ConfigParams.BCG_QUALITY_LABEL_SAVE_MODE_10S}{ConfigParams.ENDSWITH_CSV}或{ConfigParams.BCG_QUALITY_LABEL_SAVE_FILENAME}{ConfigParams.BCG_QUALITY_LABEL_SAVE_MODE_30S}{ConfigParams.ENDSWITH_CSV},已成功读取" - BCG_QUALITY_LABEL_MODE_UNSELECTED: str = "显示模式未选择" - BCG_QUALITY_LABEL_INPUT_SIGNAL_FAILURE: str = "导入信号失败,请检查信号长度" - BCG_QUALITY_LABEL_INPUT_ARTIFACT_FAILURE_FORMAT: str = "导入体动失败,请检查体动标签格式" - BCG_QUALITY_LABEL_INPUT_ARTIFACT_FAILURE_LENGTH: str = "导入体动失败,请检查体动长度是否为4的倍数" - - BCG_QUALITY_LABEL_RUNNING: str = "开始执行任务" - BCG_QUALITY_LABEL_10S_MODE: str = f"{ConfigParams.BCG_QUALITY_LABEL_SAVE_MODE_10S}_MODE" - BCG_QUALITY_LABEL_30S_MODE: str = f"{ConfigParams.BCG_QUALITY_LABEL_SAVE_MODE_30S}_MODE" - BCG_QUALITY_LABEL_COLUMN_LABEL: str = "label" - BCG_QUALITY_LABEL_COLUMN_REMARK: str = "remark" BCG_QUALITY_LABEL_VIEWING_THE_FIRST_PART: str = "你正在查看第1段信号" BCG_QUALITY_LABEL_VIEWING_THE_LAST_PART: str = "你正在查看最后1段信号" BCG_QUALITY_LABEL_VIEWING_THE_FIRST_PART_UNLABELED: str = "前面的片段都被打标,将跳转至第1段信号" @@ -491,27 +493,6 @@ class Constants: BCG_QUALITY_LABEL_LABEL_ALL_TO_TYPE_C: str = "已将所有片段标记为类型C" BCG_QUALITY_LABEL_LABEL_ARTIFACT_TO_TYPE_C_QUESTION_CONTENT: str = "你确定要将所有带有体动的片段标记为类型C" BCG_QUALITY_LABEL_LABEL_ARTIFACT_TO_TYPE_C: str = "已将所有带有体动的片段标记为类型C" - BCG_QUALITY_LABEL_PLOT_LABEL_SIGNAL: str = "BCG" - BCG_QUALITY_LABEL_PLOT_LABEL_ARTIFACT: str = "Artifact" - BCG_QUALITY_LABEL_PLOT_LABEL_LONGEST_CONTINUOUS: str = "Longest_Continuous" - BCG_QUALITY_LABEL_10S_A: str = "a" - BCG_QUALITY_LABEL_10S_B: str = "b" - BCG_QUALITY_LABEL_10S_C: str = "c" - BCG_QUALITY_LABEL_10S_A_LIST: str = "label_a" - BCG_QUALITY_LABEL_10S_B_LIST: str = "label_b" - BCG_QUALITY_LABEL_10S_C_LIST: str = "label_c" - BCG_QUALITY_LABEL_30S_A1: str = "a" - BCG_QUALITY_LABEL_30S_A2: str = "b" - BCG_QUALITY_LABEL_30S_B1: str = "c" - BCG_QUALITY_LABEL_30S_B2: str = "d" - BCG_QUALITY_LABEL_30S_C: str = "e" - BCG_QUALITY_LABEL_30S_A1_LIST: str = "label_a1" - BCG_QUALITY_LABEL_30S_A2_LIST: str = "label_a2" - BCG_QUALITY_LABEL_30S_B1_LIST: str = "label_b1" - BCG_QUALITY_LABEL_30S_B2_LIST: str = "label_b2" - BCG_QUALITY_LABEL_30S_C_LIST: str = "label_c" - BCG_QUALITY_LABEL_tobeLabeled: str = "f" - BCG_QUALITY_LABEL_tobeLabeled_LIST: str = "label_tobeLabeled" BCG_QUALITY_LABEL_LABELBTN_STYLE: str = """ QPushButton { background-color: orange; /* 设置背景颜色 */ diff --git a/ui/MainWindow/MainWindow_bcg_quality_label.py b/ui/MainWindow/MainWindow_bcg_quality_label.py new file mode 100644 index 0000000..df857d5 --- /dev/null +++ b/ui/MainWindow/MainWindow_bcg_quality_label.py @@ -0,0 +1,552 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'MainWindow_bcg_quality_label.ui' +## +## Created by: Qt User Interface Compiler version 6.8.2 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, + QMetaObject, QObject, QPoint, QRect, + QSize, QTime, QUrl, Qt) +from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, + QFont, QFontDatabase, QGradient, QIcon, + QImage, QKeySequence, QLinearGradient, QPainter, + QPalette, QPixmap, QRadialGradient, QTransform) +from PySide6.QtWidgets import (QApplication, QCheckBox, QGridLayout, QGroupBox, + QHBoxLayout, QHeaderView, QLabel, QLineEdit, + QMainWindow, QPushButton, QSizePolicy, QSpacerItem, + QStatusBar, QTableWidget, QTableWidgetItem, QTextBrowser, + QVBoxLayout, QWidget) + +class Ui_MainWindow_bcg_quality_label(object): + def setupUi(self, MainWindow_bcg_quality_label): + if not MainWindow_bcg_quality_label.objectName(): + MainWindow_bcg_quality_label.setObjectName(u"MainWindow_bcg_quality_label") + MainWindow_bcg_quality_label.resize(1920, 1080) + self.centralwidget = QWidget(MainWindow_bcg_quality_label) + self.centralwidget.setObjectName(u"centralwidget") + self.gridLayout = QGridLayout(self.centralwidget) + self.gridLayout.setObjectName(u"gridLayout") + self.groupBox_canvas = QGroupBox(self.centralwidget) + self.groupBox_canvas.setObjectName(u"groupBox_canvas") + font = QFont() + font.setPointSize(10) + self.groupBox_canvas.setFont(font) + self.verticalLayout = QVBoxLayout(self.groupBox_canvas) + self.verticalLayout.setObjectName(u"verticalLayout") + self.verticalLayout_canvas = QVBoxLayout() + self.verticalLayout_canvas.setObjectName(u"verticalLayout_canvas") + + self.verticalLayout.addLayout(self.verticalLayout_canvas) + + + self.gridLayout.addWidget(self.groupBox_canvas, 0, 1, 1, 1) + + self.groupBox_left = QGroupBox(self.centralwidget) + self.groupBox_left.setObjectName(u"groupBox_left") + self.groupBox_left.setFont(font) + self.verticalLayout_2 = QVBoxLayout(self.groupBox_left) + self.verticalLayout_2.setObjectName(u"verticalLayout_2") + self.horizontalLayout = QHBoxLayout() + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.pushButton_input_setting = QPushButton(self.groupBox_left) + self.pushButton_input_setting.setObjectName(u"pushButton_input_setting") + sizePolicy = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.pushButton_input_setting.sizePolicy().hasHeightForWidth()) + self.pushButton_input_setting.setSizePolicy(sizePolicy) + font1 = QFont() + font1.setPointSize(12) + self.pushButton_input_setting.setFont(font1) + + self.horizontalLayout.addWidget(self.pushButton_input_setting) + + self.pushButton_input = QPushButton(self.groupBox_left) + self.pushButton_input.setObjectName(u"pushButton_input") + sizePolicy.setHeightForWidth(self.pushButton_input.sizePolicy().hasHeightForWidth()) + self.pushButton_input.setSizePolicy(sizePolicy) + self.pushButton_input.setFont(font1) + + self.horizontalLayout.addWidget(self.pushButton_input) + + + self.verticalLayout_2.addLayout(self.horizontalLayout) + + self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + + self.verticalLayout_2.addItem(self.verticalSpacer) + + self.groupBox_status = QGroupBox(self.groupBox_left) + self.groupBox_status.setObjectName(u"groupBox_status") + self.gridLayout_3 = QGridLayout(self.groupBox_status) + self.gridLayout_3.setObjectName(u"gridLayout_3") + self.label_5 = QLabel(self.groupBox_status) + self.label_5.setObjectName(u"label_5") + sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed) + sizePolicy1.setHorizontalStretch(0) + sizePolicy1.setVerticalStretch(0) + sizePolicy1.setHeightForWidth(self.label_5.sizePolicy().hasHeightForWidth()) + self.label_5.setSizePolicy(sizePolicy1) + self.label_5.setFont(font1) + + self.gridLayout_3.addWidget(self.label_5, 0, 0, 1, 1) + + self.label_6 = QLabel(self.groupBox_status) + self.label_6.setObjectName(u"label_6") + sizePolicy1.setHeightForWidth(self.label_6.sizePolicy().hasHeightForWidth()) + self.label_6.setSizePolicy(sizePolicy1) + self.label_6.setFont(font1) + + self.gridLayout_3.addWidget(self.label_6, 1, 0, 1, 1) + + self.label_12 = QLabel(self.groupBox_status) + self.label_12.setObjectName(u"label_12") + sizePolicy1.setHeightForWidth(self.label_12.sizePolicy().hasHeightForWidth()) + self.label_12.setSizePolicy(sizePolicy1) + self.label_12.setFont(font1) + + self.gridLayout_3.addWidget(self.label_12, 2, 0, 1, 1) + + self.label_13 = QLabel(self.groupBox_status) + self.label_13.setObjectName(u"label_13") + sizePolicy1.setHeightForWidth(self.label_13.sizePolicy().hasHeightForWidth()) + self.label_13.setSizePolicy(sizePolicy1) + self.label_13.setFont(font1) + + self.gridLayout_3.addWidget(self.label_13, 3, 0, 1, 1) + + self.lineEdit_artifact_time_percentage = QLineEdit(self.groupBox_status) + self.lineEdit_artifact_time_percentage.setObjectName(u"lineEdit_artifact_time_percentage") + self.lineEdit_artifact_time_percentage.setEnabled(False) + self.lineEdit_artifact_time_percentage.setFont(font1) + + self.gridLayout_3.addWidget(self.lineEdit_artifact_time_percentage, 3, 1, 1, 1) + + self.lineEdit_longest_continuous_time = QLineEdit(self.groupBox_status) + self.lineEdit_longest_continuous_time.setObjectName(u"lineEdit_longest_continuous_time") + self.lineEdit_longest_continuous_time.setEnabled(False) + self.lineEdit_longest_continuous_time.setFont(font1) + + self.gridLayout_3.addWidget(self.lineEdit_longest_continuous_time, 2, 1, 1, 1) + + self.lineEdit_data_part_num = QLineEdit(self.groupBox_status) + self.lineEdit_data_part_num.setObjectName(u"lineEdit_data_part_num") + self.lineEdit_data_part_num.setEnabled(False) + self.lineEdit_data_part_num.setFont(font1) + + self.gridLayout_3.addWidget(self.lineEdit_data_part_num, 1, 1, 1, 1) + + self.lineEdit_current_part_time = QLineEdit(self.groupBox_status) + self.lineEdit_current_part_time.setObjectName(u"lineEdit_current_part_time") + self.lineEdit_current_part_time.setEnabled(False) + self.lineEdit_current_part_time.setFont(font1) + + self.gridLayout_3.addWidget(self.lineEdit_current_part_time, 0, 1, 1, 1) + + + self.verticalLayout_2.addWidget(self.groupBox_status) + + self.verticalSpacer_5 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + + self.verticalLayout_2.addItem(self.verticalSpacer_5) + + self.horizontalLayout_2 = QHBoxLayout() + self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") + self.groupBox_artifact_type = QGroupBox(self.groupBox_left) + self.groupBox_artifact_type.setObjectName(u"groupBox_artifact_type") + self.gridLayout_6 = QGridLayout(self.groupBox_artifact_type) + self.gridLayout_6.setObjectName(u"gridLayout_6") + self.checkBox_allin = QCheckBox(self.groupBox_artifact_type) + self.checkBox_allin.setObjectName(u"checkBox_allin") + font2 = QFont() + font2.setPointSize(20) + self.checkBox_allin.setFont(font2) + self.checkBox_allin.setChecked(True) + + self.gridLayout_6.addWidget(self.checkBox_allin, 0, 1, 1, 1) + + self.checkBox_type1 = QCheckBox(self.groupBox_artifact_type) + self.checkBox_type1.setObjectName(u"checkBox_type1") + self.checkBox_type1.setFont(font1) + self.checkBox_type1.setChecked(True) + + self.gridLayout_6.addWidget(self.checkBox_type1, 0, 2, 1, 1) + + self.checkBox_type2 = QCheckBox(self.groupBox_artifact_type) + self.checkBox_type2.setObjectName(u"checkBox_type2") + self.checkBox_type2.setFont(font1) + self.checkBox_type2.setChecked(True) + + self.gridLayout_6.addWidget(self.checkBox_type2, 1, 1, 1, 1) + + self.checkBox_type3 = QCheckBox(self.groupBox_artifact_type) + self.checkBox_type3.setObjectName(u"checkBox_type3") + self.checkBox_type3.setFont(font1) + self.checkBox_type3.setChecked(True) + + self.gridLayout_6.addWidget(self.checkBox_type3, 1, 2, 1, 1) + + self.checkBox_type4 = QCheckBox(self.groupBox_artifact_type) + self.checkBox_type4.setObjectName(u"checkBox_type4") + self.checkBox_type4.setFont(font1) + self.checkBox_type4.setChecked(True) + + self.gridLayout_6.addWidget(self.checkBox_type4, 2, 1, 1, 1) + + self.checkBox_type5 = QCheckBox(self.groupBox_artifact_type) + self.checkBox_type5.setObjectName(u"checkBox_type5") + self.checkBox_type5.setFont(font1) + self.checkBox_type5.setChecked(True) + + self.gridLayout_6.addWidget(self.checkBox_type5, 2, 2, 1, 1) + + + self.horizontalLayout_2.addWidget(self.groupBox_artifact_type) + + self.groupBox_function = QGroupBox(self.groupBox_left) + self.groupBox_function.setObjectName(u"groupBox_function") + self.gridLayout_13 = QGridLayout(self.groupBox_function) + self.gridLayout_13.setObjectName(u"gridLayout_13") + self.pushButton_invalid_signal_label = QPushButton(self.groupBox_function) + self.pushButton_invalid_signal_label.setObjectName(u"pushButton_invalid_signal_label") + sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Preferred) + sizePolicy2.setHorizontalStretch(0) + sizePolicy2.setVerticalStretch(0) + sizePolicy2.setHeightForWidth(self.pushButton_invalid_signal_label.sizePolicy().hasHeightForWidth()) + self.pushButton_invalid_signal_label.setSizePolicy(sizePolicy2) + self.pushButton_invalid_signal_label.setFont(font1) + + self.gridLayout_13.addWidget(self.pushButton_invalid_signal_label, 0, 0, 1, 1) + + self.pushButton_Ctype_signal_label = QPushButton(self.groupBox_function) + self.pushButton_Ctype_signal_label.setObjectName(u"pushButton_Ctype_signal_label") + sizePolicy2.setHeightForWidth(self.pushButton_Ctype_signal_label.sizePolicy().hasHeightForWidth()) + self.pushButton_Ctype_signal_label.setSizePolicy(sizePolicy2) + self.pushButton_Ctype_signal_label.setFont(font1) + + self.gridLayout_13.addWidget(self.pushButton_Ctype_signal_label, 1, 0, 1, 1) + + + self.horizontalLayout_2.addWidget(self.groupBox_function) + + self.horizontalLayout_2.setStretch(0, 2) + self.horizontalLayout_2.setStretch(1, 1) + + self.verticalLayout_2.addLayout(self.horizontalLayout_2) + + self.verticalSpacer_4 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + + self.verticalLayout_2.addItem(self.verticalSpacer_4) + + self.groupBox_operation = QGroupBox(self.groupBox_left) + self.groupBox_operation.setObjectName(u"groupBox_operation") + self.gridLayout_7 = QGridLayout(self.groupBox_operation) + self.gridLayout_7.setObjectName(u"gridLayout_7") + self.pushButton_prev = QPushButton(self.groupBox_operation) + self.pushButton_prev.setObjectName(u"pushButton_prev") + sizePolicy2.setHeightForWidth(self.pushButton_prev.sizePolicy().hasHeightForWidth()) + self.pushButton_prev.setSizePolicy(sizePolicy2) + self.pushButton_prev.setFont(font1) + + self.gridLayout_7.addWidget(self.pushButton_prev, 4, 0, 1, 1) + + self.checkBox_examine_tobeLabeled = QCheckBox(self.groupBox_operation) + self.checkBox_examine_tobeLabeled.setObjectName(u"checkBox_examine_tobeLabeled") + self.checkBox_examine_tobeLabeled.setFont(font1) + + self.gridLayout_7.addWidget(self.checkBox_examine_tobeLabeled, 1, 0, 1, 1) + + self.checkBox_highlight_longest_continuous = QCheckBox(self.groupBox_operation) + self.checkBox_highlight_longest_continuous.setObjectName(u"checkBox_highlight_longest_continuous") + self.checkBox_highlight_longest_continuous.setFont(font1) + + self.gridLayout_7.addWidget(self.checkBox_highlight_longest_continuous, 0, 0, 1, 1) + + self.pushButton_next = QPushButton(self.groupBox_operation) + self.pushButton_next.setObjectName(u"pushButton_next") + sizePolicy2.setHeightForWidth(self.pushButton_next.sizePolicy().hasHeightForWidth()) + self.pushButton_next.setSizePolicy(sizePolicy2) + self.pushButton_next.setFont(font1) + + self.gridLayout_7.addWidget(self.pushButton_next, 4, 1, 1, 1) + + self.label = QLabel(self.groupBox_operation) + self.label.setObjectName(u"label") + self.label.setFont(font1) + self.label.setAlignment(Qt.AlignmentFlag.AlignCenter) + + self.gridLayout_7.addWidget(self.label, 2, 0, 1, 1) + + self.checkBox_display_afterfilter = QCheckBox(self.groupBox_operation) + self.checkBox_display_afterfilter.setObjectName(u"checkBox_display_afterfilter") + self.checkBox_display_afterfilter.setFont(font1) + + self.gridLayout_7.addWidget(self.checkBox_display_afterfilter, 0, 1, 1, 1) + + self.lineEdit_remark = QLineEdit(self.groupBox_operation) + self.lineEdit_remark.setObjectName(u"lineEdit_remark") + self.lineEdit_remark.setEnabled(True) + self.lineEdit_remark.setFont(font1) + + self.gridLayout_7.addWidget(self.lineEdit_remark, 2, 1, 1, 1) + + self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + + self.gridLayout_7.addItem(self.verticalSpacer_2, 3, 0, 1, 2) + + self.gridLayout_7.setRowStretch(0, 1) + self.gridLayout_7.setRowStretch(1, 1) + self.gridLayout_7.setRowStretch(2, 1) + self.gridLayout_7.setRowStretch(3, 1) + self.gridLayout_7.setRowStretch(4, 3) + self.gridLayout_7.setColumnStretch(0, 1) + self.gridLayout_7.setColumnStretch(1, 1) + + self.verticalLayout_2.addWidget(self.groupBox_operation) + + self.verticalSpacer_3 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + + self.verticalLayout_2.addItem(self.verticalSpacer_3) + + self.horizontalLayout_3 = QHBoxLayout() + self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") + self.pushButton_save = QPushButton(self.groupBox_left) + self.pushButton_save.setObjectName(u"pushButton_save") + sizePolicy.setHeightForWidth(self.pushButton_save.sizePolicy().hasHeightForWidth()) + self.pushButton_save.setSizePolicy(sizePolicy) + self.pushButton_save.setFont(font1) + + self.horizontalLayout_3.addWidget(self.pushButton_save) + + + self.verticalLayout_2.addLayout(self.horizontalLayout_3) + + self.groupBox_4 = QGroupBox(self.groupBox_left) + self.groupBox_4.setObjectName(u"groupBox_4") + self.verticalLayout_6 = QVBoxLayout(self.groupBox_4) + self.verticalLayout_6.setObjectName(u"verticalLayout_6") + self.textBrowser_info = QTextBrowser(self.groupBox_4) + self.textBrowser_info.setObjectName(u"textBrowser_info") + + self.verticalLayout_6.addWidget(self.textBrowser_info) + + + self.verticalLayout_2.addWidget(self.groupBox_4) + + self.verticalLayout_2.setStretch(0, 2) + self.verticalLayout_2.setStretch(1, 1) + self.verticalLayout_2.setStretch(2, 4) + self.verticalLayout_2.setStretch(3, 1) + self.verticalLayout_2.setStretch(4, 6) + self.verticalLayout_2.setStretch(5, 1) + self.verticalLayout_2.setStretch(6, 6) + self.verticalLayout_2.setStretch(7, 1) + self.verticalLayout_2.setStretch(8, 2) + self.verticalLayout_2.setStretch(9, 5) + + self.gridLayout.addWidget(self.groupBox_left, 0, 0, 1, 1) + + self.groupBox_right = QGroupBox(self.centralwidget) + self.groupBox_right.setObjectName(u"groupBox_right") + self.groupBox_right.setFont(font) + self.gridLayout_4 = QGridLayout(self.groupBox_right) + self.gridLayout_4.setObjectName(u"gridLayout_4") + self.verticalSpacer_9 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + + self.gridLayout_4.addItem(self.verticalSpacer_9, 7, 0, 1, 2) + + self.verticalSpacer_7 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + + self.gridLayout_4.addItem(self.verticalSpacer_7, 3, 0, 1, 2) + + self.pushButton_b1 = QPushButton(self.groupBox_right) + self.pushButton_b1.setObjectName(u"pushButton_b1") + sizePolicy2.setHeightForWidth(self.pushButton_b1.sizePolicy().hasHeightForWidth()) + self.pushButton_b1.setSizePolicy(sizePolicy2) + font3 = QFont() + font3.setPointSize(24) + self.pushButton_b1.setFont(font3) + + self.gridLayout_4.addWidget(self.pushButton_b1, 4, 0, 1, 1) + + self.tableWidget_c = QTableWidget(self.groupBox_right) + if (self.tableWidget_c.columnCount() < 1): + self.tableWidget_c.setColumnCount(1) + self.tableWidget_c.setObjectName(u"tableWidget_c") + self.tableWidget_c.setFont(font1) + self.tableWidget_c.setColumnCount(1) + + self.gridLayout_4.addWidget(self.tableWidget_c, 8, 1, 1, 1) + + self.tableWidget_a1 = QTableWidget(self.groupBox_right) + if (self.tableWidget_a1.columnCount() < 1): + self.tableWidget_a1.setColumnCount(1) + self.tableWidget_a1.setObjectName(u"tableWidget_a1") + self.tableWidget_a1.setFont(font1) + self.tableWidget_a1.setColumnCount(1) + self.tableWidget_a1.horizontalHeader().setMinimumSectionSize(33) + self.tableWidget_a1.horizontalHeader().setDefaultSectionSize(75) + self.tableWidget_a1.verticalHeader().setMinimumSectionSize(32) + + self.gridLayout_4.addWidget(self.tableWidget_a1, 0, 1, 1, 1) + + self.pushButton_b2 = QPushButton(self.groupBox_right) + self.pushButton_b2.setObjectName(u"pushButton_b2") + sizePolicy2.setHeightForWidth(self.pushButton_b2.sizePolicy().hasHeightForWidth()) + self.pushButton_b2.setSizePolicy(sizePolicy2) + self.pushButton_b2.setFont(font3) + + self.gridLayout_4.addWidget(self.pushButton_b2, 6, 0, 1, 1) + + self.pushButton_f = QPushButton(self.groupBox_right) + self.pushButton_f.setObjectName(u"pushButton_f") + sizePolicy2.setHeightForWidth(self.pushButton_f.sizePolicy().hasHeightForWidth()) + self.pushButton_f.setSizePolicy(sizePolicy2) + self.pushButton_f.setFont(font3) + + self.gridLayout_4.addWidget(self.pushButton_f, 10, 0, 1, 1) + + self.tableWidget_f = QTableWidget(self.groupBox_right) + if (self.tableWidget_f.columnCount() < 1): + self.tableWidget_f.setColumnCount(1) + self.tableWidget_f.setObjectName(u"tableWidget_f") + self.tableWidget_f.setFont(font1) + self.tableWidget_f.setColumnCount(1) + + self.gridLayout_4.addWidget(self.tableWidget_f, 10, 1, 1, 1) + + self.pushButton_a2 = QPushButton(self.groupBox_right) + self.pushButton_a2.setObjectName(u"pushButton_a2") + sizePolicy2.setHeightForWidth(self.pushButton_a2.sizePolicy().hasHeightForWidth()) + self.pushButton_a2.setSizePolicy(sizePolicy2) + self.pushButton_a2.setFont(font3) + + self.gridLayout_4.addWidget(self.pushButton_a2, 2, 0, 1, 1) + + self.verticalSpacer_6 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + + self.gridLayout_4.addItem(self.verticalSpacer_6, 1, 0, 1, 2) + + self.tableWidget_b1 = QTableWidget(self.groupBox_right) + if (self.tableWidget_b1.columnCount() < 1): + self.tableWidget_b1.setColumnCount(1) + self.tableWidget_b1.setObjectName(u"tableWidget_b1") + self.tableWidget_b1.setFont(font1) + self.tableWidget_b1.setColumnCount(1) + + self.gridLayout_4.addWidget(self.tableWidget_b1, 4, 1, 1, 1) + + self.pushButton_a1 = QPushButton(self.groupBox_right) + self.pushButton_a1.setObjectName(u"pushButton_a1") + sizePolicy2.setHeightForWidth(self.pushButton_a1.sizePolicy().hasHeightForWidth()) + self.pushButton_a1.setSizePolicy(sizePolicy2) + self.pushButton_a1.setFont(font3) + + self.gridLayout_4.addWidget(self.pushButton_a1, 0, 0, 1, 1) + + self.tableWidget_b2 = QTableWidget(self.groupBox_right) + if (self.tableWidget_b2.columnCount() < 1): + self.tableWidget_b2.setColumnCount(1) + self.tableWidget_b2.setObjectName(u"tableWidget_b2") + self.tableWidget_b2.setFont(font1) + self.tableWidget_b2.setColumnCount(1) + + self.gridLayout_4.addWidget(self.tableWidget_b2, 6, 1, 1, 1) + + self.tableWidget_a2 = QTableWidget(self.groupBox_right) + if (self.tableWidget_a2.columnCount() < 1): + self.tableWidget_a2.setColumnCount(1) + self.tableWidget_a2.setObjectName(u"tableWidget_a2") + self.tableWidget_a2.setFont(font1) + self.tableWidget_a2.setColumnCount(1) + + self.gridLayout_4.addWidget(self.tableWidget_a2, 2, 1, 1, 1) + + self.verticalSpacer_8 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + + self.gridLayout_4.addItem(self.verticalSpacer_8, 5, 0, 1, 2) + + self.pushButton_c = QPushButton(self.groupBox_right) + self.pushButton_c.setObjectName(u"pushButton_c") + sizePolicy2.setHeightForWidth(self.pushButton_c.sizePolicy().hasHeightForWidth()) + self.pushButton_c.setSizePolicy(sizePolicy2) + self.pushButton_c.setFont(font3) + + self.gridLayout_4.addWidget(self.pushButton_c, 8, 0, 1, 1) + + self.verticalSpacer_10 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + + self.gridLayout_4.addItem(self.verticalSpacer_10, 9, 0, 1, 2) + + self.gridLayout_4.setRowStretch(0, 5) + self.gridLayout_4.setRowStretch(1, 1) + self.gridLayout_4.setRowStretch(2, 5) + self.gridLayout_4.setRowStretch(3, 1) + self.gridLayout_4.setRowStretch(4, 5) + self.gridLayout_4.setRowStretch(5, 1) + self.gridLayout_4.setRowStretch(6, 5) + self.gridLayout_4.setRowStretch(7, 1) + self.gridLayout_4.setRowStretch(8, 5) + self.gridLayout_4.setRowStretch(9, 1) + self.gridLayout_4.setRowStretch(10, 5) + self.gridLayout_4.setColumnStretch(0, 1) + self.gridLayout_4.setColumnStretch(1, 2) + + self.gridLayout.addWidget(self.groupBox_right, 0, 2, 1, 1) + + self.gridLayout.setColumnStretch(0, 4) + self.gridLayout.setColumnStretch(1, 15) + self.gridLayout.setColumnStretch(2, 4) + MainWindow_bcg_quality_label.setCentralWidget(self.centralwidget) + self.statusbar = QStatusBar(MainWindow_bcg_quality_label) + self.statusbar.setObjectName(u"statusbar") + MainWindow_bcg_quality_label.setStatusBar(self.statusbar) + + self.retranslateUi(MainWindow_bcg_quality_label) + + QMetaObject.connectSlotsByName(MainWindow_bcg_quality_label) + # setupUi + + def retranslateUi(self, MainWindow_bcg_quality_label): + MainWindow_bcg_quality_label.setWindowTitle(QCoreApplication.translate("MainWindow_bcg_quality_label", u"BCG\u7684\u8d28\u91cf\u6807\u6ce8", None)) + self.groupBox_canvas.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u7ed8\u56fe\u533a", None)) + self.groupBox_left.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label", u"BCG\u7684\u8d28\u91cf\u6807\u6ce8", None)) + self.pushButton_input_setting.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u5bfc\u5165\u8bbe\u7f6e", None)) + self.pushButton_input.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u5f00\u59cb\u5bfc\u5165", None)) + self.groupBox_status.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u8fd0\u884c\u72b6\u6001", None)) + self.label_5.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u5f53\u524d\u7247\u6bb5\u65f6\u95f4", None)) + self.label_6.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u5f53\u524d\u7247\u6bb5/\u7247\u6bb5\u603b\u6570", None)) + self.label_12.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u6700\u957f\u8fde\u7eed\u65f6\u95f4", None)) + self.label_13.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u4f53\u52a8\u65f6\u95f4\u5360\u6bd4", None)) + self.groupBox_artifact_type.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u4f53\u52a8\u7c7b\u578b", None)) + self.checkBox_allin.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u5168\u9009", None)) + self.checkBox_type1.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u7c7b\u578b1", None)) + self.checkBox_type2.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u7c7b\u578b2", None)) + self.checkBox_type3.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u7c7b\u578b3", None)) + self.checkBox_type4.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u7c7b\u578b4", None)) + self.checkBox_type5.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u7c7b\u578b5", None)) + self.groupBox_function.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u529f\u80fd", None)) + self.pushButton_invalid_signal_label.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u65e0\u6548\u4fe1\u53f7\u6253\u6807", None)) + self.pushButton_Ctype_signal_label.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"C\u7c7b\u4fe1\u53f7\u6253\u6807", None)) + self.groupBox_operation.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u64cd\u4f5c", None)) + self.pushButton_prev.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"<(A)", None)) + self.checkBox_examine_tobeLabeled.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u4ec5\u67e5\u672a\u6807\u7247\u6bb5", None)) + self.checkBox_highlight_longest_continuous.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u9ad8\u4eae\u6700\u957f\u8fde\u7eed", None)) + self.pushButton_next.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u">(D)", None)) + self.label.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u8f93\u5165\u5907\u6ce8", None)) + self.checkBox_display_afterfilter.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u53bb\u9664\u5de5\u9891\u566a\u58f0", None)) + self.pushButton_save.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u5bfc\u51fa\u6807\u7b7e", None)) + self.groupBox_4.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u65e5\u5fd7", None)) + self.groupBox_right.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u6807\u7b7e\u8bb0\u5f55", None)) + self.pushButton_b1.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"b1", None)) + self.pushButton_b2.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"b2", None)) + self.pushButton_f.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u5220\u9664", None)) + self.pushButton_a2.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"a2", None)) + self.pushButton_a1.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"a1", None)) + self.pushButton_c.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"c", None)) + # retranslateUi + diff --git a/ui/MainWindow/MainWindow_bcg_quality_label.ui b/ui/MainWindow/MainWindow_bcg_quality_label.ui new file mode 100644 index 0000000..e196086 --- /dev/null +++ b/ui/MainWindow/MainWindow_bcg_quality_label.ui @@ -0,0 +1,853 @@ + + + MainWindow_bcg_quality_label + + + + 0 + 0 + 1920 + 1080 + + + + BCG的质量标注 + + + + + + + + 10 + + + + 绘图区 + + + + + + + + + + + + + 10 + + + + BCG的质量标注 + + + + + + + + + 0 + 0 + + + + + 12 + + + + 导入设置 + + + + + + + + 0 + 0 + + + + + 12 + + + + 开始导入 + + + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + 运行状态 + + + + + + + 0 + 0 + + + + + 12 + + + + 当前片段时间 + + + + + + + + 0 + 0 + + + + + 12 + + + + 当前片段/片段总数 + + + + + + + + 0 + 0 + + + + + 12 + + + + 最长连续时间 + + + + + + + + 0 + 0 + + + + + 12 + + + + 体动时间占比 + + + + + + + false + + + + 12 + + + + + + + + false + + + + 12 + + + + + + + + false + + + + 12 + + + + + + + + false + + + + 12 + + + + + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + + + 体动类型 + + + + + + + 20 + + + + 全选 + + + true + + + + + + + + 12 + + + + 类型1 + + + true + + + + + + + + 12 + + + + 类型2 + + + true + + + + + + + + 12 + + + + 类型3 + + + true + + + + + + + + 12 + + + + 类型4 + + + true + + + + + + + + 12 + + + + 类型5 + + + true + + + + + + + + + + 功能 + + + + + + + 0 + 0 + + + + + 12 + + + + 无效信号打标 + + + + + + + + 0 + 0 + + + + + 12 + + + + C类信号打标 + + + + + + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + 操作 + + + + + + + 0 + 0 + + + + + 12 + + + + <(A) + + + + + + + + 12 + + + + 仅查未标片段 + + + + + + + + 12 + + + + 高亮最长连续 + + + + + + + + 0 + 0 + + + + + 12 + + + + >(D) + + + + + + + + 12 + + + + 输入备注 + + + Qt::AlignmentFlag::AlignCenter + + + + + + + + 12 + + + + 去除工频噪声 + + + + + + + true + + + + 12 + + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + + + + 0 + 0 + + + + + 12 + + + + 导出标签 + + + + + + + + + 日志 + + + + + + + + + + + + + + + + 10 + + + + 标签记录 + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + 24 + + + + b1 + + + + + + + + 12 + + + + 1 + + + + + + + + + 12 + + + + 1 + + + 33 + + + 75 + + + 32 + + + + + + + + + 0 + 0 + + + + + 24 + + + + b2 + + + + + + + + 0 + 0 + + + + + 24 + + + + 删除 + + + + + + + + 12 + + + + 1 + + + + + + + + + 0 + 0 + + + + + 24 + + + + a2 + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + + 12 + + + + 1 + + + + + + + + + 0 + 0 + + + + + 24 + + + + a1 + + + + + + + + 12 + + + + 1 + + + + + + + + + 12 + + + + 1 + + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + 24 + + + + c + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + diff --git a/ui/setting/bcg_quality_label_input_setting.py b/ui/setting/bcg_quality_label_input_setting.py new file mode 100644 index 0000000..735b15c --- /dev/null +++ b/ui/setting/bcg_quality_label_input_setting.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'bcg_quality_label_input_setting.ui' +## +## Created by: Qt User Interface Compiler version 6.8.2 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, + QMetaObject, QObject, QPoint, QRect, + QSize, QTime, QUrl, Qt) +from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, + QFont, QFontDatabase, QGradient, QIcon, + QImage, QKeySequence, QLinearGradient, QPainter, + QPalette, QPixmap, QRadialGradient, QTransform) +from PySide6.QtWidgets import (QApplication, QGridLayout, QGroupBox, QHBoxLayout, + QLabel, QMainWindow, QPlainTextEdit, QPushButton, + QRadioButton, QSizePolicy, QSpacerItem, QSpinBox, + QStatusBar, QVBoxLayout, QWidget) + +class Ui_MainWindow_bcg_quality_label_input_setting(object): + def setupUi(self, MainWindow_bcg_quality_label_input_setting): + if not MainWindow_bcg_quality_label_input_setting.objectName(): + MainWindow_bcg_quality_label_input_setting.setObjectName(u"MainWindow_bcg_quality_label_input_setting") + MainWindow_bcg_quality_label_input_setting.resize(540, 540) + self.centralwidget = QWidget(MainWindow_bcg_quality_label_input_setting) + self.centralwidget.setObjectName(u"centralwidget") + self.gridLayout = QGridLayout(self.centralwidget) + self.gridLayout.setObjectName(u"gridLayout") + self.pushButton_cancel = QPushButton(self.centralwidget) + self.pushButton_cancel.setObjectName(u"pushButton_cancel") + font = QFont() + font.setPointSize(12) + self.pushButton_cancel.setFont(font) + + self.gridLayout.addWidget(self.pushButton_cancel, 1, 3, 1, 1) + + self.groupBox = QGroupBox(self.centralwidget) + self.groupBox.setObjectName(u"groupBox") + font1 = QFont() + font1.setPointSize(10) + self.groupBox.setFont(font1) + self.verticalLayout_2 = QVBoxLayout(self.groupBox) + self.verticalLayout_2.setObjectName(u"verticalLayout_2") + self.groupBox_file_path_input_signal_BCG = QGroupBox(self.groupBox) + self.groupBox_file_path_input_signal_BCG.setObjectName(u"groupBox_file_path_input_signal_BCG") + self.verticalLayout_5 = QVBoxLayout(self.groupBox_file_path_input_signal_BCG) + self.verticalLayout_5.setObjectName(u"verticalLayout_5") + self.horizontalLayout_2 = QHBoxLayout() + self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") + self.label_2 = QLabel(self.groupBox_file_path_input_signal_BCG) + self.label_2.setObjectName(u"label_2") + self.label_2.setFont(font) + + self.horizontalLayout_2.addWidget(self.label_2) + + self.spinBox_input_freq_signal_BCG = QSpinBox(self.groupBox_file_path_input_signal_BCG) + self.spinBox_input_freq_signal_BCG.setObjectName(u"spinBox_input_freq_signal_BCG") + self.spinBox_input_freq_signal_BCG.setFont(font) + self.spinBox_input_freq_signal_BCG.setMinimum(1) + self.spinBox_input_freq_signal_BCG.setMaximum(1000000) + + self.horizontalLayout_2.addWidget(self.spinBox_input_freq_signal_BCG) + + + self.verticalLayout_5.addLayout(self.horizontalLayout_2) + + self.plainTextEdit_file_path_input_signal_BCG = QPlainTextEdit(self.groupBox_file_path_input_signal_BCG) + self.plainTextEdit_file_path_input_signal_BCG.setObjectName(u"plainTextEdit_file_path_input_signal_BCG") + + self.verticalLayout_5.addWidget(self.plainTextEdit_file_path_input_signal_BCG) + + self.verticalLayout_5.setStretch(0, 1) + self.verticalLayout_5.setStretch(1, 2) + + self.verticalLayout_2.addWidget(self.groupBox_file_path_input_signal_BCG) + + self.groupBox_file_path_input_artifact = QGroupBox(self.groupBox) + self.groupBox_file_path_input_artifact.setObjectName(u"groupBox_file_path_input_artifact") + self.verticalLayout_6 = QVBoxLayout(self.groupBox_file_path_input_artifact) + self.verticalLayout_6.setObjectName(u"verticalLayout_6") + self.plainTextEdit_file_path_input_artifact = QPlainTextEdit(self.groupBox_file_path_input_artifact) + self.plainTextEdit_file_path_input_artifact.setObjectName(u"plainTextEdit_file_path_input_artifact") + + self.verticalLayout_6.addWidget(self.plainTextEdit_file_path_input_artifact) + + self.verticalLayout_6.setStretch(0, 2) + + self.verticalLayout_2.addWidget(self.groupBox_file_path_input_artifact) + + self.groupBox_file_path_save = QGroupBox(self.groupBox) + self.groupBox_file_path_save.setObjectName(u"groupBox_file_path_save") + self.verticalLayout_4 = QVBoxLayout(self.groupBox_file_path_save) + self.verticalLayout_4.setObjectName(u"verticalLayout_4") + self.plainTextEdit_file_path_save = QPlainTextEdit(self.groupBox_file_path_save) + self.plainTextEdit_file_path_save.setObjectName(u"plainTextEdit_file_path_save") + + self.verticalLayout_4.addWidget(self.plainTextEdit_file_path_save) + + + self.verticalLayout_2.addWidget(self.groupBox_file_path_save) + + self.groupBox_display_mode = QGroupBox(self.groupBox) + self.groupBox_display_mode.setObjectName(u"groupBox_display_mode") + self.horizontalLayout = QHBoxLayout(self.groupBox_display_mode) + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) + + self.horizontalLayout.addItem(self.horizontalSpacer) + + self.radioButton_30s_mode = QRadioButton(self.groupBox_display_mode) + self.radioButton_30s_mode.setObjectName(u"radioButton_30s_mode") + self.radioButton_30s_mode.setFont(font) + + self.horizontalLayout.addWidget(self.radioButton_30s_mode) + + self.horizontalSpacer_3 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) + + self.horizontalLayout.addItem(self.horizontalSpacer_3) + + self.radioButton_10s_mode = QRadioButton(self.groupBox_display_mode) + self.radioButton_10s_mode.setObjectName(u"radioButton_10s_mode") + self.radioButton_10s_mode.setFont(font) + + self.horizontalLayout.addWidget(self.radioButton_10s_mode) + + self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) + + self.horizontalLayout.addItem(self.horizontalSpacer_2) + + + self.verticalLayout_2.addWidget(self.groupBox_display_mode) + + self.verticalLayout_2.setStretch(0, 3) + self.verticalLayout_2.setStretch(1, 2) + self.verticalLayout_2.setStretch(2, 2) + self.verticalLayout_2.setStretch(3, 2) + + self.gridLayout.addWidget(self.groupBox, 0, 0, 1, 4) + + self.pushButton_confirm = QPushButton(self.centralwidget) + self.pushButton_confirm.setObjectName(u"pushButton_confirm") + self.pushButton_confirm.setFont(font) + + self.gridLayout.addWidget(self.pushButton_confirm, 1, 2, 1, 1) + + MainWindow_bcg_quality_label_input_setting.setCentralWidget(self.centralwidget) + self.statusbar = QStatusBar(MainWindow_bcg_quality_label_input_setting) + self.statusbar.setObjectName(u"statusbar") + MainWindow_bcg_quality_label_input_setting.setStatusBar(self.statusbar) + + self.retranslateUi(MainWindow_bcg_quality_label_input_setting) + + QMetaObject.connectSlotsByName(MainWindow_bcg_quality_label_input_setting) + # setupUi + + def retranslateUi(self, MainWindow_bcg_quality_label_input_setting): + MainWindow_bcg_quality_label_input_setting.setWindowTitle(QCoreApplication.translate("MainWindow_bcg_quality_label_input_setting", u"\u5bfc\u5165\u8bbe\u7f6e", None)) + self.pushButton_cancel.setText(QCoreApplication.translate("MainWindow_bcg_quality_label_input_setting", u"\u53d6\u6d88", None)) + self.groupBox.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None)) + self.groupBox_file_path_input_signal_BCG.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label_input_setting", u"\u540c\u6b65\u540e\u7684BCG\u8def\u5f84", None)) + self.label_2.setText(QCoreApplication.translate("MainWindow_bcg_quality_label_input_setting", u"\u91c7\u6837\u7387(Hz)\uff1a", None)) + self.plainTextEdit_file_path_input_signal_BCG.setPlainText("") + self.plainTextEdit_file_path_input_signal_BCG.setPlaceholderText(QCoreApplication.translate("MainWindow_bcg_quality_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None)) + self.groupBox_file_path_input_artifact.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label_input_setting", u"\u4f53\u52a8Artifact_a\u8def\u5f84", None)) + self.plainTextEdit_file_path_input_artifact.setPlainText("") + self.plainTextEdit_file_path_input_artifact.setPlaceholderText(QCoreApplication.translate("MainWindow_bcg_quality_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None)) + self.groupBox_file_path_save.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label_input_setting", u"BCG\u8d28\u91cf\u6807\u7b7e\u4fdd\u5b58\u8def\u5f84", None)) + self.plainTextEdit_file_path_save.setPlaceholderText(QCoreApplication.translate("MainWindow_bcg_quality_label_input_setting", u"\u4fdd\u5b58\u8def\u5f84", None)) + self.groupBox_display_mode.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label_input_setting", u"\u663e\u793a\u6a21\u5f0f", None)) + self.radioButton_30s_mode.setText(QCoreApplication.translate("MainWindow_bcg_quality_label_input_setting", u"30s\u6a21\u5f0f", None)) + self.radioButton_10s_mode.setText(QCoreApplication.translate("MainWindow_bcg_quality_label_input_setting", u"10s\u6a21\u5f0f", None)) + self.pushButton_confirm.setText(QCoreApplication.translate("MainWindow_bcg_quality_label_input_setting", u"\u786e\u5b9a", None)) + # retranslateUi + diff --git a/ui/setting/bcg_quality_label_input_setting.ui b/ui/setting/bcg_quality_label_input_setting.ui new file mode 100644 index 0000000..c3bf273 --- /dev/null +++ b/ui/setting/bcg_quality_label_input_setting.ui @@ -0,0 +1,219 @@ + + + MainWindow_bcg_quality_label_input_setting + + + + 0 + 0 + 540 + 540 + + + + 导入设置 + + + + + + + + 12 + + + + 取消 + + + + + + + + 10 + + + + 文件路径 + + + + + + 同步后的BCG路径 + + + + + + + + + 12 + + + + 采样率(Hz): + + + + + + + + 12 + + + + 1 + + + 1000000 + + + + + + + + + + + + 文件路径 + + + + + + + + + + 体动Artifact_a路径 + + + + + + + + + 文件路径 + + + + + + + + + + BCG质量标签保存路径 + + + + + + 保存路径 + + + + + + + + + + 显示模式 + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + 12 + + + + 30s模式 + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + 12 + + + + 10s模式 + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 12 + + + + 确定 + + + + + + + + + + From 54f3852b017892cfcfcf238024e04b4b78b6bee1 Mon Sep 17 00:00:00 2001 From: Yorusora <2944763079@qq.com> Date: Thu, 22 May 2025 21:15:13 +0800 Subject: [PATCH 09/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86<=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E7=B2=97=E5=90=8C=E6=AD=A5>=E7=9A=84=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E8=B7=AF=E5=BE=84=E9=94=99=E8=AF=AF=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_approximately_align.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/func/Module_approximately_align.py b/func/Module_approximately_align.py index 97e8209..298cf75 100644 --- a/func/Module_approximately_align.py +++ b/func/Module_approximately_align.py @@ -114,7 +114,7 @@ class SettingWindow(QMainWindow): Path(str(self.sampID)))), "Input_Abd": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / Path(str(self.sampID)))), - "Save": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / + "Save": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / Path(str(self.sampID)) / Path(ConfigParams.APPROXIMATELY_ALIGN_INFO + ConfigParams.ENDSWITH_CSV))) }, @@ -190,7 +190,7 @@ class SettingWindow(QMainWindow): ConfigParams.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_save.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + ConfigParams.PUBLIC_PATH_LABEL / Path(str(self.sampID)) / Path(ConfigParams.APPROXIMATELY_ALIGN_INFO + ConfigParams.ENDSWITH_CSV)))) From 6a325ba95ba68f1c559b99e0505e914323278932 Mon Sep 17 00:00:00 2001 From: Yorusora <2944763079@qq.com> Date: Fri, 23 May 2025 10:25:25 +0800 Subject: [PATCH 10/26] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BA=86=E7=9A=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_SA_label.py | 2 +- func/Module_approximately_align.py | 6 - func/Module_bcg_quality_label.py | 399 +++++++++++++++++- func/utils/ConfigParams.py | 2 + func/utils/Constants.py | 75 ++-- ui/MainWindow/MainWindow_bcg_quality_label.py | 21 +- ui/MainWindow/MainWindow_bcg_quality_label.ui | 28 +- ui/setting/bcg_quality_label_input_setting.py | 1 + ui/setting/bcg_quality_label_input_setting.ui | 3 + 9 files changed, 423 insertions(+), 114 deletions(-) diff --git a/func/Module_SA_label.py b/func/Module_SA_label.py index 1e51b97..0e32da6 100644 --- a/func/Module_SA_label.py +++ b/func/Module_SA_label.py @@ -609,7 +609,7 @@ class MainWindow_SA_label(QMainWindow): item = QTableWidgetItem(str(correct_End)) self.ui.tableWidget_label_add.setItem(index, 3, item) remark = row.get("remark", None) - if str(remark) != "" and str(remark) != "nan" and row.get("isLabeled", None) == 1: + if str(remark) != Constants.STRING_IS_EMPTY and str(remark) != Constants.STRING_IS_NAN and row.get("isLabeled", None) == 1: for col in range(self.ui.tableWidget_label_add.columnCount()): item = self.ui.tableWidget_label_add.item(index, col) item.setBackground(QColor(255, 200, 200)) diff --git a/func/Module_approximately_align.py b/func/Module_approximately_align.py index 298cf75..3b8a84e 100644 --- a/func/Module_approximately_align.py +++ b/func/Module_approximately_align.py @@ -188,12 +188,6 @@ class SettingWindow(QMainWindow): Path(ConfigParams.ABD_RAW + str(self.ui.spinBox_input_Abd_freq.value()) + ConfigParams.ENDSWITH_TXT)))) - self.ui.plainTextEdit_file_path_save.setPlainText( - str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_LABEL / - Path(str(self.sampID)) / - Path(ConfigParams.APPROXIMATELY_ALIGN_INFO + - ConfigParams.ENDSWITH_CSV)))) class MainWindow_approximately_align(QMainWindow): diff --git a/func/Module_bcg_quality_label.py b/func/Module_bcg_quality_label.py index 3c6ab0e..9fa62be 100644 --- a/func/Module_bcg_quality_label.py +++ b/func/Module_bcg_quality_label.py @@ -3,12 +3,14 @@ from pathlib import Path from traceback import format_exc import matplotlib.pyplot as plt +from PySide6.QtCore import QCoreApplication from PySide6.QtGui import QColor from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication, QTableWidget, QTableWidgetItem from matplotlib import gridspec from matplotlib.backends.backend_qt import NavigationToolbar2QT from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg -from numpy import array, int64, append, zeros, full, where, nan, arange, float64, isnan, place, count_nonzero, all as np_all +from numpy import array, int64, append, zeros, full, where, nan, arange, float64, isnan, place, count_nonzero, \ + all as np_all, split from overrides import overrides from pandas import read_csv, DataFrame from scipy.signal import resample, iirfilter, lfilter @@ -99,7 +101,7 @@ class SettingWindow(QMainWindow): "Save": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / Path(str(self.sampID)))), }, - "Mode": "Undefined", + "Mode": "30s", "DataPartNum": 0, "CurrentDataIdx": 0, "CurrentPartNum": 1, @@ -225,6 +227,33 @@ class MainWindow_bcg_quality_label(QMainWindow): self.ui.pushButton_input_setting.clicked.connect(self.setting.show) self.ui.pushButton_input.clicked.connect(self.__slot_btn_input__) + self.ui.pushButton_prev.clicked.connect(self.__slot_btn_move__) + self.ui.pushButton_next.clicked.connect(self.__slot_btn_move__) + self.ui.tableWidget_a1.cellDoubleClicked.connect(self.__slot_tablewidget_on_cell_double_clicked__) + self.ui.tableWidget_a2.cellDoubleClicked.connect(self.__slot_tablewidget_on_cell_double_clicked__) + self.ui.tableWidget_b1.cellDoubleClicked.connect(self.__slot_tablewidget_on_cell_double_clicked__) + self.ui.tableWidget_b2.cellDoubleClicked.connect(self.__slot_tablewidget_on_cell_double_clicked__) + self.ui.tableWidget_c.cellDoubleClicked.connect(self.__slot_tablewidget_on_cell_double_clicked__) + self.ui.tableWidget_f.cellDoubleClicked.connect(self.__slot_tablewidget_on_cell_double_clicked__) + self.ui.checkBox_highlight_longest_continuous.clicked.connect(self.__slot_checkBox_highlight_longest_continuous__) + self.ui.checkBox_display_afterfilter.clicked.connect(self.__slot_checkBox_display_afterfilter__) + self.ui.pushButton_invalid_signal_label.clicked.connect(self.__slot_btn_invalid_signal_label__) + self.ui.pushButton_Ctype_signal_label.clicked.connect(self.__slot_btn_Ctype_signal_label__) + self.ui.pushButton_a1.clicked.connect(self.__slot_btn_label__) + self.ui.pushButton_a2.clicked.connect(self.__slot_btn_label__) + self.ui.pushButton_b1.clicked.connect(self.__slot_btn_label__) + self.ui.pushButton_b2.clicked.connect(self.__slot_btn_label__) + self.ui.pushButton_c.clicked.connect(self.__slot_btn_label__) + self.ui.pushButton_f.clicked.connect(self.__slot_btn_label__) + self.ui.checkBox_allin.clicked.connect(self.__slot_checkBox__) + self.ui.checkBox_type1.clicked.connect(self.__slot_checkBox__) + self.ui.checkBox_type2.clicked.connect(self.__slot_checkBox__) + self.ui.checkBox_type3.clicked.connect(self.__slot_checkBox__) + self.ui.checkBox_type4.clicked.connect(self.__slot_checkBox__) + self.ui.checkBox_type5.clicked.connect(self.__slot_checkBox__) + + self.ui.pushButton_prev.setShortcut(QCoreApplication.translate("MainWindow", ConfigParams.BCG_QUALITY_LABEL_BTN_PREV_SHORTCUT_KEY)) + self.ui.pushButton_next.setShortcut(QCoreApplication.translate("MainWindow", ConfigParams.BCG_QUALITY_LABEL_BTN_NEXT_SHORTCUT_KEY)) @overrides def closeEvent(self, event): @@ -260,7 +289,17 @@ class MainWindow_bcg_quality_label(QMainWindow): sender = self.sender() - if sender == self.ui.pushButton_input: + if (sender == self.ui.pushButton_input or + sender == self.ui.pushButton_prev or + sender == self.ui.pushButton_next or + self.ui.tableWidget_a1 or + self.ui.tableWidget_a2 or + self.ui.tableWidget_b1 or + self.ui.tableWidget_b2 or + self.ui.tableWidget_c or + self.ui.tableWidget_f or + self.ui.checkBox_highlight_longest_continuous or + self.ui.checkBox_display_afterfilter): try: artifact_type_seq = array([]) artifact_type_seq = artifact_type_seq.astype(int64) @@ -413,10 +452,16 @@ class MainWindow_bcg_quality_label(QMainWindow): self.change_tablewidget_mode() self.update_tableWidget() self.update_status() - ButtonState["Current"]["pushButton_input_setting"] = True - ButtonState["Current"]["pushButton_input"] = True + self.change_labelBtn_color() + ButtonState["Current"]["pushButton_input_setting"] = False + ButtonState["Current"]["pushButton_input"] = False ButtonState["Current"]["pushButton_invalid_signal_label"] = True - ButtonState["Current"]["pushButton_Ctype_signal_label"] = True + if Config["Mode"] == "10s": + ButtonState["Current"]["pushButton_Ctype_signal_label"] = True + elif Config["Mode"] == "30s": + ButtonState["Current"]["pushButton_Ctype_signal_label"] = False + else: + raise ValueError("模式不存在") ButtonState["Current"]["pushButton_prev"] = True ButtonState["Current"]["pushButton_next"] = True ButtonState["Current"]["pushButton_save"] = True @@ -431,6 +476,270 @@ class MainWindow_bcg_quality_label(QMainWindow): PublicFunc.finish_operation(self, ButtonState) + def __slot_btn_move__(self): + sender = self.sender() + + if sender == self.ui.pushButton_prev: + if Config["CurrentPartNum"] == 1: + PublicFunc.text_output(self.ui, Constants.BCG_QUALITY_LABEL_VIEWING_THE_FIRST_PART, Constants.MSGBOX_TYPE_INFO) + PublicFunc.msgbox_output(self, Constants.BCG_QUALITY_LABEL_VIEWING_THE_FIRST_PART, Constants.MSGBOX_TYPE_INFO) + return + Config["CurrentPartNum"] -= 1 + if Config["Mode"] == "10s": + Config["CurrentDataIdx"] -= Config["InputConfig"]["UseFreq"] * 10 + elif Config["Mode"] == "30s": + Config["CurrentDataIdx"] -= Config["InputConfig"]["UseFreq"] * 30 + else: + raise ValueError("模式不存在") + while (self.ui.checkBox_examine_tobeLabeled.isChecked() and + self.data.df_label.at[ + Config["CurrentPartNum"] - 1, Constants.BCG_QUALITY_LABEL_COLUMN_LABEL] != Constants.BCG_QUALITY_LABEL_TOBELABELED): + Config["CurrentPartNum"] -= 1 + if Config["Mode"] == "10s": + Config["CurrentDataIdx"] -= Config["InputConfig"]["UseFreq"] * 10 + elif Config["Mode"] == "30s": + Config["CurrentDataIdx"] -= Config["InputConfig"]["UseFreq"] * 30 + if Config["CurrentPartNum"] == 0: + Config["CurrentPartNum"] = 1 + Config["CurrentDataIdx"] = 0 + PublicFunc.text_output(self.ui, Constants.BCG_QUALITY_LABEL_VIEWING_THE_FIRST_PART_UNLABELED, + Constants.MSGBOX_TYPE_INFO) + PublicFunc.msgbox_output(self, Constants.BCG_QUALITY_LABEL_VIEWING_THE_FIRST_PART_UNLABELED, + Constants.MSGBOX_TYPE_INFO) + break + elif sender == self.ui.pushButton_next: + if Config["CurrentPartNum"] == Config["DataPartNum"]: + PublicFunc.text_output(self.ui, Constants.BCG_QUALITY_LABEL_VIEWING_THE_LAST_PART, Constants.MSGBOX_TYPE_INFO) + PublicFunc.msgbox_output(self, Constants.BCG_QUALITY_LABEL_VIEWING_THE_LAST_PART, Constants.MSGBOX_TYPE_INFO) + return + Config["CurrentPartNum"] += 1 + if Config["Mode"] == "10s": + Config["CurrentDataIdx"] += Config["InputConfig"]["UseFreq"] * 10 + elif Config["Mode"] == "30s": + Config["CurrentDataIdx"] += Config["InputConfig"]["UseFreq"] * 30 + while (self.ui.checkBox_examine_tobeLabeled.isChecked() and + self.data.df_label.at[ + Config["CurrentPartNum"] - 1, Constants.BCG_QUALITY_LABEL_COLUMN_LABEL] != Constants.BCG_QUALITY_LABEL_TOBELABELED): + Config["CurrentPartNum"] += 1 + if Config["Mode"] == "10s": + Config["CurrentDataIdx"] += Config["InputConfig"]["UseFreq"] * 10 + elif Config["Mode"] == "30s": + Config["CurrentDataIdx"] += Config["InputConfig"]["UseFreq"] * 30 + if Config["CurrentPartNum"] == Config["DataPartNum"] + 1: + Config["CurrentPartNum"] = Config["DataPartNum"] + if Config["Mode"] == "10s": + Config["CurrentDataIdx"] = (Config["DataPartNum"] - 1) * Config["InputConfig"]["UseFreq"] * 10 + elif Config["Mode"] == "30s": + Config["CurrentDataIdx"] = (Config["DataPartNum"] - 1) * Config["InputConfig"]["UseFreq"] * 30 + PublicFunc.text_output(self.ui, Constants.BCG_QUALITY_LABEL_VIEWING_THE_LAST_PART_UNLABELED, + Constants.MSGBOX_TYPE_INFO) + PublicFunc.msgbox_output(self, Constants.BCG_QUALITY_LABEL_VIEWING_THE_LAST_PART_UNLABELED, + Constants.MSGBOX_TYPE_INFO) + break + else: + raise ValueError("发射信号不存在") + + # 更新备注内容 + if not (str(self.data.df_label.at[Config["CurrentPartNum"] - 1, Constants.BCG_QUALITY_LABEL_COLUMN_REMARK]) == + Constants.STRING_IS_NAN): + self.ui.lineEdit_remark.setText( + str(self.data.df_label.at[Config["CurrentPartNum"] - 1, Constants.BCG_QUALITY_LABEL_COLUMN_REMARK])) + else: + self.ui.lineEdit_remark.setText(Constants.STRING_IS_EMPTY) + + # 更新按钮颜色 + self.change_labelBtn_color() + + if (self.data.df_label[ + Constants.BCG_QUALITY_LABEL_COLUMN_LABEL] != Constants.BCG_QUALITY_LABEL_TOBELABELED).all(): + PublicFunc.text_output(self.ui, Constants.BCG_QUALITY_LABEL_LABELED_FINISHED, + Constants.MSGBOX_TYPE_INFO) + self.update_status() + self.update_tableWidget() + self.__plot__() + PublicFunc.text_output(self.ui, Constants.BCG_QUALITY_LABEL_VIEWING_PART + str(Config["CurrentPartNum"]), + Constants.MSGBOX_TYPE_INFO) + + def __slot_tablewidget_on_cell_double_clicked__(self, row, column): + sender = self.sender() + + if Config["Mode"] == "30s": + length = Config["InputConfig"]["UseFreq"] * 30 + elif Config["Mode"] == "10s": + length = Config["InputConfig"]["UseFreq"] * 10 + else: + raise ValueError("模式不存在") + + if sender == self.ui.tableWidget_a1: + Config["CurrentPartNum"] = int(self.ui.tableWidget_a1.item(row, column).text()) + Config["CurrentDataIdx"] = (Config["CurrentPartNum"] - 1) * length + elif sender == self.ui.tableWidget_a2: + Config["CurrentPartNum"] = int(self.ui.tableWidget_a2.item(row, column).text()) + Config["CurrentDataIdx"] = (Config["CurrentPartNum"] - 1) * length + elif sender == self.ui.tableWidget_b1: + Config["CurrentPartNum"] = int(self.ui.tableWidget_b1.item(row, column).text()) + Config["CurrentDataIdx"] = (Config["CurrentPartNum"] - 1) * length + elif sender == self.ui.tableWidget_b2: + Config["CurrentPartNum"] = int(self.ui.tableWidget_b2.item(row, column).text()) + Config["CurrentDataIdx"] = (Config["CurrentPartNum"] - 1) * length + elif sender == self.ui.tableWidget_c: + Config["CurrentPartNum"] = int(self.ui.tableWidget_c.item(row, column).text()) + Config["CurrentDataIdx"] = (Config["CurrentPartNum"] - 1) * length + elif sender == self.ui.tableWidget_f: + Config["CurrentPartNum"] = int(self.ui.tableWidget_f.item(row, column).text()) + Config["CurrentDataIdx"] = (Config["CurrentPartNum"] - 1) * length + else: + raise ValueError("发射信号不存在") + + # 更新备注内容 + if not (str(self.data.df_label.at[Config["CurrentPartNum"] - 1, Constants.BCG_QUALITY_LABEL_COLUMN_REMARK]) == + Constants.STRING_IS_NAN): + self.ui.lineEdit_remark.setText(str(self.data.df_label.at[Config["CurrentPartNum"] - 1, Constants.BCG_QUALITY_LABEL_COLUMN_REMARK])) + else: + self.ui.lineEdit_remark.setText(Constants.STRING_IS_EMPTY) + + # 更新按钮颜色 + self.change_labelBtn_color() + + self.update_status() + self.__plot__() + PublicFunc.text_output(self.ui, Constants.BCG_QUALITY_LABEL_JUMP_PART + str(Config["CurrentPartNum"]), + Constants.MSGBOX_TYPE_INFO) + + def __slot_btn_label__(self): + sender = self.sender() + + if sender == self.ui.pushButton_a1: + if Config["Mode"] == "30s": + label = Constants.BCG_QUALITY_LABEL_30S_A1 + elif Config["Mode"] == "10s": + label = Constants.BCG_QUALITY_LABEL_10S_A + else: + raise ValueError("模式不存在") + elif sender == self.ui.pushButton_a2: + label = Constants.BCG_QUALITY_LABEL_30S_A2 + elif sender == self.ui.pushButton_b1: + if Config["Mode"] == "30s": + label = Constants.BCG_QUALITY_LABEL_30S_B1 + elif Config["Mode"] == "10s": + label = Constants.BCG_QUALITY_LABEL_10S_B + else: + raise ValueError("模式不存在") + elif sender == self.ui.pushButton_b2: + label = Constants.BCG_QUALITY_LABEL_30S_B2 + elif sender == self.ui.pushButton_c: + if Config["Mode"] == "30s": + label = Constants.BCG_QUALITY_LABEL_30S_C + elif Config["Mode"] == "10s": + label = Constants.BCG_QUALITY_LABEL_10S_C + else: + raise ValueError("模式不存在") + elif sender == self.ui.pushButton_f: + label = Constants.BCG_QUALITY_LABEL_TOBELABELED + else: + raise ValueError("发射信号不存在") + + self.data.label[Config["CurrentPartNum"] - 1] = label + self.data.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_LABEL] = self.data.label + self.data.df_label.at[Config["CurrentPartNum"] - 1, Constants.BCG_QUALITY_LABEL_COLUMN_REMARK] = ( + self.ui.lineEdit_remark.text()) + self.change_labelBtn_color() + self.update_tableWidget() + result = self.data.save(label) + if not result.status: + PublicFunc.text_output(self.ui, 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, result.info, Constants.TIPS_TYPE_INFO) + + def __slot_btn_invalid_signal_label__(self): + reply = QMessageBox.question(self, Constants.QUESTION_TITLE, + Constants.BCG_QUALITY_LABEL_LABEL_ALL_TO_TYPE_C_QUESTION_CONTENT, + QMessageBox.Yes | QMessageBox.No, QMessageBox.No) + if reply == QMessageBox.Yes: + if Config["Mode"] == "30s": + self.data.label = full(self.data.label.shape, Constants.BCG_QUALITY_LABEL_30S_C).astype(str) + elif Config["Mode"] == "10s": + self.data.label = full(self.data.label.shape, Constants.BCG_QUALITY_LABEL_10S_C).astype(str) + else: + raise ValueError("模式不存在") + self.data.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_LABEL] = self.data.label + self.change_labelBtn_color() + self.update_tableWidget() + result = self.data.save("无效信号标注") + if not result.status: + PublicFunc.text_output(self.ui, 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, result.info, Constants.TIPS_TYPE_INFO) + + def __slot_btn_Ctype_signal_label__(self): + reply = QMessageBox.question(self, Constants.QUESTION_TITLE, + Constants.BCG_QUALITY_LABEL_LABEL_ARTIFACT_TO_TYPE_C_QUESTION_CONTENT, + QMessageBox.Yes | QMessageBox.No, QMessageBox.No) + if reply == QMessageBox.Yes: + artifact_mask = self.data.artifact_mask[:Config["InputConfig"]["UseFreq"] * 10 * + int(len(self.data.BCG) // (Config["InputConfig"]["UseFreq"] * 10))] + sub_artifact_mask = split(artifact_mask, len(artifact_mask) // (Config["InputConfig"]["UseFreq"] * 10)) + for index, array in enumerate(sub_artifact_mask): + if 1 in array or 2 in array or 3 in array or 4 in array or 5 in array: + self.data.label[index] = Constants.BCG_QUALITY_LABEL_10S_C + self.data.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_LABEL] = self.data.label + self.change_labelBtn_color() + self.update_tableWidget() + result = self.data.save("C类信号标注") + if not result.status: + PublicFunc.text_output(self.ui, 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, result.info, Constants.TIPS_TYPE_INFO) + + def __slot_checkBox_highlight_longest_continuous__(self): + self.__plot__() + + def __slot_checkBox_display_afterfilter__(self): + self.__plot__() + + def __slot_checkBox__(self): + sender = self.sender() + + if sender == self.ui.checkBox_allin: + if self.ui.checkBox_allin.isChecked(): + self.ui.checkBox_type1.setChecked(True) + self.ui.checkBox_type2.setChecked(True) + self.ui.checkBox_type3.setChecked(True) + self.ui.checkBox_type4.setChecked(True) + self.ui.checkBox_type5.setChecked(True) + else: + self.ui.checkBox_type1.setChecked(False) + self.ui.checkBox_type2.setChecked(False) + self.ui.checkBox_type3.setChecked(False) + self.ui.checkBox_type4.setChecked(False) + self.ui.checkBox_type5.setChecked(False) + elif (sender == self.ui.checkBox_type1 or + sender == self.ui.checkBox_type2 or + sender == self.ui.checkBox_type3 or + sender == self.ui.checkBox_type4 or + sender == self.ui.checkBox_type5): + if (self.ui.checkBox_type1.isChecked() and + self.ui.checkBox_type2.isChecked() and + self.ui.checkBox_type3.isChecked() and + self.ui.checkBox_type4.isChecked() and + self.ui.checkBox_type5.isChecked()): + self.ui.checkBox_allin.setChecked(True) + else: + self.ui.checkBox_allin.setChecked(False) + else: + raise ValueError("发射信号不存在") + + self.__plot__() + def update_status(self): if Config["Mode"] == "30s": hour = int(((Config["CurrentDataIdx"] + (Config["InputConfig"]["UseFreq"] * 30)) / int(Config["InputConfig"]["UseFreq"])) // 3600) @@ -479,9 +788,9 @@ class MainWindow_bcg_quality_label(QMainWindow): for row, value in enumerate(label): item = QTableWidgetItem(str(value).strip()) tableWidget.setItem(row, 0, item) - if (self.data.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_REMARK][ - value - 1] != Constants.STRING_IS_EMPTY and - self.data.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_REMARK][value - 1] is not nan): + if (str(self.data.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_REMARK][ + value - 1]) != Constants.STRING_IS_EMPTY and + str(self.data.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_REMARK][value - 1]) != Constants.STRING_IS_NAN): item = tableWidget.item(row, 0) item.setBackground(QColor(255, 200, 200)) else: @@ -517,9 +826,9 @@ class MainWindow_bcg_quality_label(QMainWindow): for row, value in enumerate(label): item = QTableWidgetItem(str(value).strip()) tableWidget.setItem(row, 0, item) - if (self.data.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_REMARK][ - value - 1] != Constants.STRING_IS_EMPTY and - self.data.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_REMARK][value - 1] is not nan): + if (str(self.data.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_REMARK][ + value - 1]) != Constants.STRING_IS_EMPTY and + str(self.data.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_REMARK][value - 1]) != Constants.STRING_IS_NAN): item = tableWidget.item(row, 0) item.setBackground(QColor(255, 200, 200)) else: @@ -588,12 +897,48 @@ class MainWindow_bcg_quality_label(QMainWindow): self.ui.tableWidget_b2.setHorizontalHeaderLabels(['b2']) self.ui.tableWidget_c.setHorizontalHeaderLabels(['c']) self.ui.tableWidget_f.setHorizontalHeaderLabels(['None']) - elif Config["Mode"] == "Undefined": - return False else: raise ValueError("模式不存在") return True + def change_labelBtn_color(self): + if self.data.df_label.at[Config["CurrentPartNum"] - 1, Constants.BCG_QUALITY_LABEL_COLUMN_LABEL] == "a1": + self.ui.pushButton_a1.setStyleSheet(Constants.BCG_QUALITY_LABEL_LABELBTN_STYLE) + self.ui.pushButton_a2.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_b1.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_b2.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_c.setStyleSheet(Constants.STRING_IS_EMPTY) + elif self.data.df_label.at[Config["CurrentPartNum"] - 1, Constants.BCG_QUALITY_LABEL_COLUMN_LABEL] == "a2": + self.ui.pushButton_a1.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_a2.setStyleSheet(Constants.BCG_QUALITY_LABEL_LABELBTN_STYLE) + self.ui.pushButton_b1.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_b2.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_c.setStyleSheet(Constants.STRING_IS_EMPTY) + elif self.data.df_label.at[Config["CurrentPartNum"] - 1, Constants.BCG_QUALITY_LABEL_COLUMN_LABEL] == "b1": + self.ui.pushButton_a1.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_a2.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_b1.setStyleSheet(Constants.BCG_QUALITY_LABEL_LABELBTN_STYLE) + self.ui.pushButton_b2.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_c.setStyleSheet(Constants.STRING_IS_EMPTY) + elif self.data.df_label.at[Config["CurrentPartNum"] - 1, Constants.BCG_QUALITY_LABEL_COLUMN_LABEL] == "b2": + self.ui.pushButton_a1.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_a2.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_b1.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_b2.setStyleSheet(Constants.BCG_QUALITY_LABEL_LABELBTN_STYLE) + self.ui.pushButton_c.setStyleSheet(Constants.STRING_IS_EMPTY) + elif self.data.df_label.at[Config["CurrentPartNum"] - 1, Constants.BCG_QUALITY_LABEL_COLUMN_LABEL] == "c1": + self.ui.pushButton_a1.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_a2.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_b1.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_b2.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_c.setStyleSheet(Constants.BCG_QUALITY_LABEL_LABELBTN_STYLE) + elif self.data.df_label.at[Config["CurrentPartNum"] - 1, Constants.BCG_QUALITY_LABEL_COLUMN_LABEL] == "f1": + self.ui.pushButton_a1.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_a2.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_b1.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_b2.setStyleSheet(Constants.STRING_IS_EMPTY) + self.ui.pushButton_c.setStyleSheet(Constants.STRING_IS_EMPTY) + class Data(): @@ -635,8 +980,6 @@ class Data(): elif Config["Mode"] == "10s": Config["Path"]["Save"] = str( Path(Config["Path"]["Save"]) / Path(ConfigParams.SQ_LABEL_10S + ConfigParams.ENDSWITH_CSV)) - elif Config["Mode"] == "Undefined": - return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Mode_Undefined"]) else: raise ValueError("模式不存在") @@ -696,7 +1039,7 @@ class Data(): raise ValueError("模式不存在") if not Path(Config["Path"]["Save"]).exists(): - self.label = full(Config["DataPartNum"], Constants.BCG_QUALITY_LABEL_TOBELABELED) + self.label = full(Config["DataPartNum"], Constants.BCG_QUALITY_LABEL_TOBELABELED).astype(str) self.df_label = DataFrame(columns=[Constants.BCG_QUALITY_LABEL_COLUMN_LABEL, Constants.BCG_QUALITY_LABEL_COLUMN_REMARK]) self.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_LABEL] = self.label self.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_REMARK] = Constants.STRING_IS_EMPTY @@ -740,6 +1083,28 @@ class Data(): return Result().success(info=Constants.PREPROCESS_FINISHED) + def save(self, label): + if (not Path(Config["Path"]["Save"]).parent.exists()) or (not Path(Config["Path"]["Save"]).parent.is_dir()): + Path(Config["Path"]["Save"]).parent.mkdir(parents=True, exist_ok=True) + + if self.df_label is None: + return Result().failure(info=ConfigParams.RESP_QUALITY_LABEL + Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + + if Config["Mode"] == "30s": + filename = ConfigParams.SQ_LABEL_30S + elif Config["Mode"] == "10s": + filename = ConfigParams.SQ_LABEL_10S + else: + raise ValueError("模式不存在") + + try: + self.df_label.to_csv(Config["Path"]["Save"], index=False, encoding=ConfigParams.GBK_ENCODING) + except Exception as e: + return Result().failure(info=filename + Constants.SAVE_FAILURE + + Constants.FAILURE_REASON["Save_Exception"] + "\n" + format_exc()) + + return Result().success(info=filename + Constants.SAVE_FINISHED + "标签为:" + str(label)) + @staticmethod def wipe_industrialFrequencyNoise(data, fs): diff --git a/func/utils/ConfigParams.py b/func/utils/ConfigParams.py index ee06548..a45c944 100644 --- a/func/utils/ConfigParams.py +++ b/func/utils/ConfigParams.py @@ -262,6 +262,8 @@ class ConfigParams: "UseFreq": 1000 } } + BCG_QUALITY_LABEL_BTN_PREV_SHORTCUT_KEY: str = "A" + BCG_QUALITY_LABEL_BTN_NEXT_SHORTCUT_KEY: str = "D" # 呼吸可用性及间期标注 RESP_QUALITY_LABEL_CONFIG_FILE_PATH: str = "./config/Config_resp_quality_label.yaml" diff --git a/func/utils/Constants.py b/func/utils/Constants.py index 7300484..a6907e6 100644 --- a/func/utils/Constants.py +++ b/func/utils/Constants.py @@ -106,7 +106,6 @@ class Constants: "Data_Length_not_Correct": "(orgBcg和BCG长度不匹配)", "Artifact_Format_Not_Correct": "(体动长度或格式不正确)", "Data_Length_Not_Correct": "(信号长度不正确)", - "Mode_Undefined": "(模式未选择)", "Open_Data_Exception": "(打开数据异常)", "Process_Exception": "(处理异常)", @@ -388,15 +387,34 @@ class Constants: BCG_QUALITY_LABEL_PLOT_LABEL_SIGNAL: str = "BCG" BCG_QUALITY_LABEL_PLOT_LABEL_ARTIFACT: str = "Artifact" BCG_QUALITY_LABEL_PLOT_LABEL_LONGEST_CONTINUOUS: str = "Longest_Continuous" - BCG_QUALITY_LABEL_10S_A: str = "a" - BCG_QUALITY_LABEL_10S_B: str = "b" - BCG_QUALITY_LABEL_10S_C: str = "c" - BCG_QUALITY_LABEL_30S_A1: str = "a" - BCG_QUALITY_LABEL_30S_A2: str = "b" - BCG_QUALITY_LABEL_30S_B1: str = "c" - BCG_QUALITY_LABEL_30S_B2: str = "d" - BCG_QUALITY_LABEL_30S_C: str = "e" - BCG_QUALITY_LABEL_TOBELABELED: str = "f" + BCG_QUALITY_LABEL_10S_A: str = "a1" + BCG_QUALITY_LABEL_10S_B: str = "b1" + BCG_QUALITY_LABEL_10S_C: str = "c1" + BCG_QUALITY_LABEL_30S_A1: str = "a1" + BCG_QUALITY_LABEL_30S_A2: str = "a2" + BCG_QUALITY_LABEL_30S_B1: str = "b1" + BCG_QUALITY_LABEL_30S_B2: str = "b2" + BCG_QUALITY_LABEL_30S_C: str = "c1" + BCG_QUALITY_LABEL_TOBELABELED: str = "f1" + BCG_QUALITY_LABEL_VIEWING_THE_FIRST_PART: str = "你正在查看第1段信号" + BCG_QUALITY_LABEL_VIEWING_THE_LAST_PART: str = "你正在查看最后1段信号" + BCG_QUALITY_LABEL_VIEWING_THE_FIRST_PART_UNLABELED: str = "前面的片段都被打标,将跳转至第1段信号" + BCG_QUALITY_LABEL_VIEWING_THE_LAST_PART_UNLABELED: str = "后面的片段都被打标,将跳转至最后1段信号" + BCG_QUALITY_LABEL_LABELED_FINISHED: str = "该份数据打标已全部完成" + BCG_QUALITY_LABEL_VIEWING_PART: str = "正在查看信号段" + BCG_QUALITY_LABEL_JUMP_PART: str = "跳转到片段" + BCG_QUALITY_LABEL_LABEL_ALL_TO_TYPE_C_QUESTION_CONTENT: str = "你确定要将所有片段标记为类型C" + BCG_QUALITY_LABEL_LABEL_ARTIFACT_TO_TYPE_C_QUESTION_CONTENT: str = "你确定要将所有带有体动的片段标记为类型C" + BCG_QUALITY_LABEL_LABELBTN_STYLE: str = """ + QPushButton { + background-color: orange; /* 设置背景颜色 */ + padding: 10px; /* 设置内边距 */ + border: 2px solid darkblue; /* 设置边框 */ + border-radius: 10px; /* 设置圆角 */ + } + QPushButton:hover { + background-color: yellow; /* 鼠标悬停时的背景颜色 */ + }""" # 呼吸可用性及间期标注 @@ -467,43 +485,6 @@ class Constants: SA_LABEL_LENGTH_LESS_THEN_10S: str = "当前标注的事件的持续时间小于10秒" SA_LABEL_WRONG_ARGS: str = "起始时间和终止时间输入错误" - - - - - - - - - - - - # 质量打标 - BCG_QUALITY_LABEL_VIEWING_THE_FIRST_PART: str = "你正在查看第1段信号" - BCG_QUALITY_LABEL_VIEWING_THE_LAST_PART: str = "你正在查看最后1段信号" - BCG_QUALITY_LABEL_VIEWING_THE_FIRST_PART_UNLABELED: str = "前面的片段都被打标,将跳转至第1段信号" - BCG_QUALITY_LABEL_VIEWING_THE_LAST_PART_UNLABELED: str = "后面的片段都被打标,将跳转至最后1段信号" - BCG_QUALITY_LABEL_LABELED_FINISHED: str = "该份数据打标已全部完成" - BCG_QUALITY_LABEL_VIEWING_PART: str = "正在查看信号段" - BCG_QUALITY_LABEL_JUMP_PART: str = "跳转到片段" - BCG_QUALITY_LABEL_CLICKED_CHECKBOX_HIGHLIGHT_LONGEST_CONTINUOUS: str = "点击了<高亮最长连续>" - BCG_QUALITY_LABEL_CLICKED_CHECKBOX_DISPLAY_AFTERFILTER: str = "点击了<去除工频噪声>" - BCG_QUALITY_LABEL_CLICKED_CHECKBOX_EXAMINE_TOBOLABELED: str = "点击了<仅查未标片段>" - BCG_QUALITY_LABEL_LABEL_ALL_TO_TYPE_C_QUESTION_CONTENT: str = "你确定要将所有片段标记为类型C" - BCG_QUALITY_LABEL_LABEL_ALL_TO_TYPE_C: str = "已将所有片段标记为类型C" - BCG_QUALITY_LABEL_LABEL_ARTIFACT_TO_TYPE_C_QUESTION_CONTENT: str = "你确定要将所有带有体动的片段标记为类型C" - BCG_QUALITY_LABEL_LABEL_ARTIFACT_TO_TYPE_C: str = "已将所有带有体动的片段标记为类型C" - BCG_QUALITY_LABEL_LABELBTN_STYLE: str = """ - QPushButton { - background-color: orange; /* 设置背景颜色 */ - padding: 10px; /* 设置内边距 */ - border: 2px solid darkblue; /* 设置边框 */ - border-radius: 10px; /* 设置圆角 */ - } - QPushButton:hover { - background-color: yellow; /* 鼠标悬停时的背景颜色 */ - }""" - # 禁止实例化 def __new__(cls): raise TypeError("Constants class cannot be instantiated") diff --git a/ui/MainWindow/MainWindow_bcg_quality_label.py b/ui/MainWindow/MainWindow_bcg_quality_label.py index df857d5..dec5d33 100644 --- a/ui/MainWindow/MainWindow_bcg_quality_label.py +++ b/ui/MainWindow/MainWindow_bcg_quality_label.py @@ -312,19 +312,6 @@ class Ui_MainWindow_bcg_quality_label(object): self.verticalLayout_2.addItem(self.verticalSpacer_3) - self.horizontalLayout_3 = QHBoxLayout() - self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") - self.pushButton_save = QPushButton(self.groupBox_left) - self.pushButton_save.setObjectName(u"pushButton_save") - sizePolicy.setHeightForWidth(self.pushButton_save.sizePolicy().hasHeightForWidth()) - self.pushButton_save.setSizePolicy(sizePolicy) - self.pushButton_save.setFont(font1) - - self.horizontalLayout_3.addWidget(self.pushButton_save) - - - self.verticalLayout_2.addLayout(self.horizontalLayout_3) - self.groupBox_4 = QGroupBox(self.groupBox_left) self.groupBox_4.setObjectName(u"groupBox_4") self.verticalLayout_6 = QVBoxLayout(self.groupBox_4) @@ -345,8 +332,7 @@ class Ui_MainWindow_bcg_quality_label(object): self.verticalLayout_2.setStretch(5, 1) self.verticalLayout_2.setStretch(6, 6) self.verticalLayout_2.setStretch(7, 1) - self.verticalLayout_2.setStretch(8, 2) - self.verticalLayout_2.setStretch(9, 5) + self.verticalLayout_2.setStretch(8, 5) self.gridLayout.addWidget(self.groupBox_left, 0, 0, 1, 1) @@ -530,8 +516,8 @@ class Ui_MainWindow_bcg_quality_label(object): self.checkBox_type4.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u7c7b\u578b4", None)) self.checkBox_type5.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u7c7b\u578b5", None)) self.groupBox_function.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u529f\u80fd", None)) - self.pushButton_invalid_signal_label.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u65e0\u6548\u4fe1\u53f7\u6253\u6807", None)) - self.pushButton_Ctype_signal_label.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"C\u7c7b\u4fe1\u53f7\u6253\u6807", None)) + self.pushButton_invalid_signal_label.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u65e0\u6548\u4fe1\u53f7\u6807\u6ce8", None)) + self.pushButton_Ctype_signal_label.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"C\u7c7b\u4fe1\u53f7\u6807\u6ce8", None)) self.groupBox_operation.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u64cd\u4f5c", None)) self.pushButton_prev.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"<(A)", None)) self.checkBox_examine_tobeLabeled.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u4ec5\u67e5\u672a\u6807\u7247\u6bb5", None)) @@ -539,7 +525,6 @@ class Ui_MainWindow_bcg_quality_label(object): self.pushButton_next.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u">(D)", None)) self.label.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u8f93\u5165\u5907\u6ce8", None)) self.checkBox_display_afterfilter.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u53bb\u9664\u5de5\u9891\u566a\u58f0", None)) - self.pushButton_save.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u5bfc\u51fa\u6807\u7b7e", None)) self.groupBox_4.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u65e5\u5fd7", None)) self.groupBox_right.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u6807\u7b7e\u8bb0\u5f55", None)) self.pushButton_b1.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"b1", None)) diff --git a/ui/MainWindow/MainWindow_bcg_quality_label.ui b/ui/MainWindow/MainWindow_bcg_quality_label.ui index e196086..5be4fb4 100644 --- a/ui/MainWindow/MainWindow_bcg_quality_label.ui +++ b/ui/MainWindow/MainWindow_bcg_quality_label.ui @@ -42,7 +42,7 @@ BCG的质量标注 - + @@ -359,7 +359,7 @@ - 无效信号打标 + 无效信号标注 @@ -377,7 +377,7 @@ - C类信号打标 + C类信号标注 @@ -533,28 +533,6 @@ - - - - - - - 0 - 0 - - - - - 12 - - - - 导出标签 - - - - - diff --git a/ui/setting/bcg_quality_label_input_setting.py b/ui/setting/bcg_quality_label_input_setting.py index 735b15c..a9b6c22 100644 --- a/ui/setting/bcg_quality_label_input_setting.py +++ b/ui/setting/bcg_quality_label_input_setting.py @@ -113,6 +113,7 @@ class Ui_MainWindow_bcg_quality_label_input_setting(object): self.radioButton_30s_mode = QRadioButton(self.groupBox_display_mode) self.radioButton_30s_mode.setObjectName(u"radioButton_30s_mode") self.radioButton_30s_mode.setFont(font) + self.radioButton_30s_mode.setChecked(True) self.horizontalLayout.addWidget(self.radioButton_30s_mode) diff --git a/ui/setting/bcg_quality_label_input_setting.ui b/ui/setting/bcg_quality_label_input_setting.ui index c3bf273..47c971e 100644 --- a/ui/setting/bcg_quality_label_input_setting.ui +++ b/ui/setting/bcg_quality_label_input_setting.ui @@ -152,6 +152,9 @@ 30s模式 + + true + From 0411966ed00f2ad52c9febec9b875bfb06081a2d Mon Sep 17 00:00:00 2001 From: Yorusora <2944763079@qq.com> Date: Fri, 23 May 2025 10:42:01 +0800 Subject: [PATCH 11/26] =?UTF-8?q?=E5=88=A0=E9=99=A4=E4=BA=86=E8=8B=A5?= =?UTF-8?q?=E5=B9=B2=E4=B8=AA=E5=8A=9F=E8=83=BD=E7=9A=84=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E6=A0=87=E7=AD=BE=E6=8C=89=E9=92=AE=EF=BC=8C=E5=9B=A0=E4=B8=BA?= =?UTF-8?q?=E5=85=B6=E7=94=A8=E5=A4=84=E4=B8=8D=E5=A4=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_approximately_align.py | 2 - func/Module_artifact_label.py | 10 +--- func/Module_label_check.py | 60 +++++-------------- func/Module_resp_quality_label.py | 37 +----------- ui/MainWindow/MainWindow_artifact_label.py | 10 ---- ui/MainWindow/MainWindow_artifact_label.ui | 20 +------ ui/MainWindow/MainWindow_label_check.py | 9 --- ui/MainWindow/MainWindow_label_check.ui | 18 ------ .../MainWindow_resp_quality_label.py | 17 +----- .../MainWindow_resp_quality_label.ui | 24 +------- 10 files changed, 23 insertions(+), 184 deletions(-) diff --git a/func/Module_approximately_align.py b/func/Module_approximately_align.py index 3b8a84e..2f1c1dd 100644 --- a/func/Module_approximately_align.py +++ b/func/Module_approximately_align.py @@ -1039,8 +1039,6 @@ class Data: def Standardize_2(self): # 预重采样 try: - # TODO:这里的采样率处理,如果THO和ABD的采样率不同,可能还是会导致之后的ApplyFrequency出问题,最后导致得到的粗同步坐标不正确 - # if Config["InputConfig"]["ThoFreq"] != Config["TempFrequency"]: print(int(Config["InputConfig"]["ThoFreq"]), int(Config["TempFrequency"])) self.processed_Tho = resample(self.processed_Tho, diff --git a/func/Module_artifact_label.py b/func/Module_artifact_label.py index 4417057..bc48a57 100644 --- a/func/Module_artifact_label.py +++ b/func/Module_artifact_label.py @@ -35,7 +35,6 @@ ButtonState = { "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, @@ -49,7 +48,6 @@ ButtonState = { "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, @@ -270,7 +268,6 @@ class MainWindow_artifact_label(QMainWindow): 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__) @@ -647,7 +644,6 @@ class MainWindow_artifact_label(QMainWindow): 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 @@ -737,9 +733,9 @@ class MainWindow_artifact_label(QMainWindow): 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__() + self.save() - def __slot_btn_save__(self): + def save(self): PublicFunc.__disableAllButton__(self, ButtonState) # 保存 @@ -790,7 +786,7 @@ class MainWindow_artifact_label(QMainWindow): self.update_tableWidget() self.update_Info() self.__plot_artifact__() - self.__slot_btn_save__() + self.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) diff --git a/func/Module_label_check.py b/func/Module_label_check.py index 1a16c04..09f957e 100644 --- a/func/Module_label_check.py +++ b/func/Module_label_check.py @@ -34,16 +34,14 @@ ButtonState = { "pushButton_input": True, "pushButton_prev_move": False, "pushButton_pause": False, - "pushButton_next_move": False, - "pushButton_save": False + "pushButton_next_move": False }, "Current": { "pushButton_input_setting": True, "pushButton_input": True, "pushButton_prev_move": False, "pushButton_pause": False, - "pushButton_next_move": False, - "pushButton_save": False + "pushButton_next_move": False } } @@ -307,7 +305,6 @@ class MainWindow_label_check(QMainWindow): 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_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__) @@ -541,42 +538,8 @@ class MainWindow_label_check(QMainWindow): 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) - - 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] - result = self.data.save(chunk) - progress = int((end / total_rows) * 100) - self.progressbar.setValue(progress) - QApplication.processEvents() - - 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.msgbox_output(self, result.info, Constants.TIPS_TYPE_INFO) - PublicFunc.finish_operation(self, ButtonState) - def __slot_btn_move__(self): if self.data is None: return @@ -848,7 +811,14 @@ class MainWindow_label_check(QMainWindow): 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(Config["Path"]["Save"], index=False, header=False) + result = self.data.save() + if not result.status: + PublicFunc.text_output(self.ui, 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, result.info, Constants.TIPS_TYPE_INFO) # 移除矩形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() @@ -989,6 +959,9 @@ class Data: return Result().success(info=Constants.INPUT_FINISHED) def get_archive(self): + if (not Path(Config["Path"]["Save"]).parent.exists()) or (not Path(Config["Path"]["Save"]).parent.is_dir()): + Path(Config["Path"]["Save"]).parent.mkdir(parents=True, exist_ok=True) + if not Path(Config["Path"]["Save"]).exists(): self.corrected_peak = self.original_peak return Result().success(info=Constants.ARCHIVE_NOT_EXIST) @@ -1025,15 +998,12 @@ class Data: return Result().success(info=Constants.PREPROCESS_FINISHED) - def save(self, chunk): - if (not Path(Config["Path"]["Save"]).parent.exists()) or (not Path(Config["Path"]["Save"]).parent.is_dir()): - Path(Config["Path"]["Save"]).parent.mkdir(parents=True, exist_ok=True) - + def save(self): if self.corrected_peak is None: return Result().failure(info=Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) try: - chunk.to_csv(Config["Path"]["Save"], mode='a', index=False, header=False) + DataFrame(self.corrected_peak).to_csv(Config["Path"]["Save"], index=False, header=False) except Exception as e: return Result().failure(info=Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Save_Exception"] + "\n" + format_exc()) diff --git a/func/Module_resp_quality_label.py b/func/Module_resp_quality_label.py index 2f1049d..6577fcd 100644 --- a/func/Module_resp_quality_label.py +++ b/func/Module_resp_quality_label.py @@ -43,8 +43,7 @@ ButtonState = { "pushButton_invalid": False, "pushButton_reset": False, "pushButton_prev": False, - "pushButton_next": False, - "pushButton_save": False + "pushButton_next": False }, "Current": { "pushButton_input_setting": True, @@ -58,8 +57,7 @@ ButtonState = { "pushButton_invalid": False, "pushButton_reset": False, "pushButton_prev": False, - "pushButton_next": False, - "pushButton_save": False + "pushButton_next": False } } @@ -285,7 +283,6 @@ class MainWindow_resp_quality_label(QMainWindow): self.ui.pushButton_valid.clicked.connect(self.__slot_btn_label__) self.ui.pushButton_invalid.clicked.connect(self.__slot_btn_label__) self.ui.pushButton_reset.clicked.connect(self.__slot_btn_label__) - self.ui.pushButton_save.clicked.connect(self.__slot_btn_save__) self.ui.lineEdit_filter_labeled.textChanged.connect(self.__slot_lineEdit_filter__) self.ui.lineEdit_filter_tobelabeled.textChanged.connect(self.__slot_lineEdit_filter__) self.ui.doubleSpinBox_quality_threshold1.valueChanged.connect(self.update_config) @@ -545,7 +542,6 @@ class MainWindow_resp_quality_label(QMainWindow): ButtonState["Current"]["pushButton_reset"] = False ButtonState["Current"]["pushButton_prev"] = False ButtonState["Current"]["pushButton_next"] = False - ButtonState["Current"]["pushButton_save"] = False for action in self.figToolbar._actions.values(): action.setEnabled(True) self.figToolbar.action_Label_Multiple.setEnabled(False) @@ -592,7 +588,6 @@ class MainWindow_resp_quality_label(QMainWindow): ButtonState["Current"]["pushButton_reset"] = False ButtonState["Current"]["pushButton_prev"] = False ButtonState["Current"]["pushButton_next"] = False - ButtonState["Current"]["pushButton_save"] = False PublicFunc.finish_operation(self, ButtonState) @@ -714,7 +709,6 @@ class MainWindow_resp_quality_label(QMainWindow): ButtonState["Current"]["pushButton_reset"] = True ButtonState["Current"]["pushButton_prev"] = True ButtonState["Current"]["pushButton_next"] = True - ButtonState["Current"]["pushButton_save"] = True for action in self.figToolbar._actions.values(): action.setEnabled(True) for action in self.figToolbar_spectrum._actions.values(): @@ -932,33 +926,6 @@ class MainWindow_resp_quality_label(QMainWindow): Constants.RESP_QUALITY_LABEL_KEY_VALUE[self.data.resp_quality_label[Config["CurrentPartNum"] - 1]], Constants.TIPS_TYPE_INFO) - def __slot_btn_save__(self): - PublicFunc.__disableAllButton__(self, ButtonState) - - # 保存 - PublicFunc.progressbar_update(self, 1, 2, Constants.SAVING_DATA + ConfigParams.RESP_QUALITY_LABEL, 0) - result = self.data.save_resp_quality_label() - if not result.status: - PublicFunc.text_output(self.ui, "(1/2)" + 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/2)" + result.info, Constants.TIPS_TYPE_INFO) - - PublicFunc.progressbar_update(self, 2, 2, Constants.SAVING_DATA + ConfigParams.THO_PEAK, 50) - result = self.data.save_tho_peak() - if not result.status: - PublicFunc.text_output(self.ui, "(2/2)" + 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/2)" + result.info, Constants.TIPS_TYPE_INFO) - - PublicFunc.msgbox_output(self, Constants.SAVE_FINISHED, Constants.TIPS_TYPE_INFO) - PublicFunc.finish_operation(self, ButtonState) - def __slot_lineEdit_filter__(self, filter_text): sender = self.sender() diff --git a/ui/MainWindow/MainWindow_artifact_label.py b/ui/MainWindow/MainWindow_artifact_label.py index 588cb13..6354192 100644 --- a/ui/MainWindow/MainWindow_artifact_label.py +++ b/ui/MainWindow/MainWindow_artifact_label.py @@ -389,14 +389,6 @@ class Ui_MainWindow_artifact_label(object): self.verticalLayout_2.addItem(self.verticalSpacer_3) - self.pushButton_save = QPushButton(self.groupBox_left) - self.pushButton_save.setObjectName(u"pushButton_save") - sizePolicy.setHeightForWidth(self.pushButton_save.sizePolicy().hasHeightForWidth()) - self.pushButton_save.setSizePolicy(sizePolicy) - self.pushButton_save.setFont(font1) - - self.verticalLayout_2.addWidget(self.pushButton_save) - self.groupBox_4 = QGroupBox(self.groupBox_left) self.groupBox_4.setObjectName(u"groupBox_4") self.verticalLayout_6 = QVBoxLayout(self.groupBox_4) @@ -415,7 +407,6 @@ class Ui_MainWindow_artifact_label(object): self.verticalLayout_2.setStretch(3, 1) self.verticalLayout_2.setStretch(4, 6) self.verticalLayout_2.setStretch(5, 1) - self.verticalLayout_2.setStretch(6, 1) self.gridLayout.addWidget(self.groupBox_left, 0, 0, 1, 1) @@ -717,7 +708,6 @@ class Ui_MainWindow_artifact_label(object): self.label_7.setText(QCoreApplication.translate("MainWindow_artifact_label", u"\u79fb\u52a8\u8ddd\u79bb", None)) self.label_6.setText(QCoreApplication.translate("MainWindow_artifact_label", u"\u6700\u5927\u8303\u56f4", None)) self.label_8.setText(QCoreApplication.translate("MainWindow_artifact_label", u"\u79fb\u52a8\u95f4\u9694(ms)", None)) - self.pushButton_save.setText(QCoreApplication.translate("MainWindow_artifact_label", u"\u5bfc\u51fa\u6807\u7b7e", None)) self.groupBox_4.setTitle(QCoreApplication.translate("MainWindow_artifact_label", u"\u65e5\u5fd7", None)) self.groupBox_right.setTitle(QCoreApplication.translate("MainWindow_artifact_label", u"\u6807\u6ce8\u64cd\u4f5c\u548c\u4fe1\u606f", None)) self.pushButton_type_1.setText(QCoreApplication.translate("MainWindow_artifact_label", u"\u5267\u70c8\u4f53\u52a8", None)) diff --git a/ui/MainWindow/MainWindow_artifact_label.ui b/ui/MainWindow/MainWindow_artifact_label.ui index 76ccb60..94a987e 100644 --- a/ui/MainWindow/MainWindow_artifact_label.ui +++ b/ui/MainWindow/MainWindow_artifact_label.ui @@ -42,7 +42,7 @@ 体动标注 - + @@ -676,24 +676,6 @@ - - - - - 0 - 0 - - - - - 12 - - - - 导出标签 - - - diff --git a/ui/MainWindow/MainWindow_label_check.py b/ui/MainWindow/MainWindow_label_check.py index a55d8e8..57e444a 100644 --- a/ui/MainWindow/MainWindow_label_check.py +++ b/ui/MainWindow/MainWindow_label_check.py @@ -357,14 +357,6 @@ class Ui_MainWindow_label_check(object): self.horizontalLayout_3.addWidget(self.checkBox_show_reference_line) - self.pushButton_save = QPushButton(self.groupBox_left) - self.pushButton_save.setObjectName(u"pushButton_save") - sizePolicy.setHeightForWidth(self.pushButton_save.sizePolicy().hasHeightForWidth()) - self.pushButton_save.setSizePolicy(sizePolicy) - self.pushButton_save.setFont(font1) - - self.horizontalLayout_3.addWidget(self.pushButton_save) - self.verticalLayout_2.addLayout(self.horizontalLayout_3) @@ -521,7 +513,6 @@ class Ui_MainWindow_label_check(object): self.label_6.setText(QCoreApplication.translate("MainWindow_label_check", u"\u6700\u5927\u8303\u56f4", None)) self.label_8.setText(QCoreApplication.translate("MainWindow_label_check", u"\u79fb\u52a8\u95f4\u9694(ms)", None)) self.checkBox_show_reference_line.setText(QCoreApplication.translate("MainWindow_label_check", u"\u7ed8\u5236\u53c2\u8003\u7ebf", None)) - self.pushButton_save.setText(QCoreApplication.translate("MainWindow_label_check", u"\u5bfc\u51fa\u6807\u7b7e", None)) self.groupBox_4.setTitle(QCoreApplication.translate("MainWindow_label_check", u"\u65e5\u5fd7", None)) self.groupBox_right.setTitle(QCoreApplication.translate("MainWindow_label_check", u"\u5cf0\u503c\u5750\u6807\u548c\u4fe1\u606f", None)) self.label_9.setText(QCoreApplication.translate("MainWindow_label_check", u"\u6570\u636e\u957f\u5ea6(\u70b9\u6570)", None)) diff --git a/ui/MainWindow/MainWindow_label_check.ui b/ui/MainWindow/MainWindow_label_check.ui index 3f1bba6..60bbc3c 100644 --- a/ui/MainWindow/MainWindow_label_check.ui +++ b/ui/MainWindow/MainWindow_label_check.ui @@ -619,24 +619,6 @@ - - - - - 0 - 0 - - - - - 12 - - - - 导出标签 - - - diff --git a/ui/MainWindow/MainWindow_resp_quality_label.py b/ui/MainWindow/MainWindow_resp_quality_label.py index 146c77c..24339c4 100644 --- a/ui/MainWindow/MainWindow_resp_quality_label.py +++ b/ui/MainWindow/MainWindow_resp_quality_label.py @@ -348,19 +348,6 @@ class Ui_MainWindow_resp_quality_label(object): self.verticalLayout_2.addWidget(self.groupBox_label_operation) - self.horizontalLayout_3 = QHBoxLayout() - self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") - self.pushButton_save = QPushButton(self.groupBox_left) - self.pushButton_save.setObjectName(u"pushButton_save") - sizePolicy.setHeightForWidth(self.pushButton_save.sizePolicy().hasHeightForWidth()) - self.pushButton_save.setSizePolicy(sizePolicy) - self.pushButton_save.setFont(font1) - - self.horizontalLayout_3.addWidget(self.pushButton_save) - - - self.verticalLayout_2.addLayout(self.horizontalLayout_3) - self.groupBox_4 = QGroupBox(self.groupBox_left) self.groupBox_4.setObjectName(u"groupBox_4") self.verticalLayout_6 = QVBoxLayout(self.groupBox_4) @@ -381,8 +368,7 @@ class Ui_MainWindow_resp_quality_label(object): self.verticalLayout_2.setStretch(5, 3) self.verticalLayout_2.setStretch(6, 1) self.verticalLayout_2.setStretch(7, 6) - self.verticalLayout_2.setStretch(8, 2) - self.verticalLayout_2.setStretch(9, 5) + self.verticalLayout_2.setStretch(8, 5) self.gridLayout.addWidget(self.groupBox_left, 0, 0, 1, 1) @@ -499,7 +485,6 @@ class Ui_MainWindow_resp_quality_label(object): self.pushButton_valid.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u53ef\u7528\uff08F\uff09", None)) self.pushButton_prev.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u4e0a\u4e00\u6bb5(A)", None)) self.pushButton_next.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u4e0b\u4e00\u6bb5(D)", None)) - self.pushButton_save.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u5bfc\u51fa\u6807\u7b7e", None)) self.groupBox_4.setTitle(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u65e5\u5fd7", None)) self.groupBox_right.setTitle(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u547c\u5438\u53ef\u7528\u6027\u53ca\u95f4\u671f\u6807\u6ce8", None)) self.groupBox.setTitle(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u9891\u8c31", None)) diff --git a/ui/MainWindow/MainWindow_resp_quality_label.ui b/ui/MainWindow/MainWindow_resp_quality_label.ui index c65e326..14af760 100644 --- a/ui/MainWindow/MainWindow_resp_quality_label.ui +++ b/ui/MainWindow/MainWindow_resp_quality_label.ui @@ -42,7 +42,7 @@ 呼吸可用性及间期标注 - + @@ -624,28 +624,6 @@ - - - - - - - 0 - 0 - - - - - 12 - - - - 导出标签 - - - - - From 9d88b6ab37dd0992b4b685e378d597a65d082c51 Mon Sep 17 00:00:00 2001 From: Yorusora <2944763079@qq.com> Date: Fri, 23 May 2025 14:34:48 +0800 Subject: [PATCH 12/26] =?UTF-8?q?=E6=9B=B4=E6=96=B0TODOLIST?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8ef99de..68dbc58 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ 3、部分模块在导入失败后重新导入时会出现问题,已知模块有<人工纠正>、<体动标注>、<呼吸可用性及间期标注>、<睡眠呼吸暂停事件标注>,主要是涉及到按钮状态的设置,有待后续优化。当前将这些有涉及到的功能,禁止了导入数据后在不关闭界面的情况下直接重新导入 +4、在J峰算法定位的时候滤波导致的信号偏移,导致之后的峰值坐标点与实际峰值出现偏移 + ## 1、主菜单 ![](/img/0.png) From 976244b3b43528c1e2f5313c86d202b1d70681cd Mon Sep 17 00:00:00 2001 From: wst Date: Fri, 23 May 2025 16:31:05 +0800 Subject: [PATCH 13/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E5=9C=A8=E4=B8=AD?= =?UTF-8?q?=E7=B2=97=E5=90=8C=E6=AD=A5=E7=BB=93=E6=9E=9C=E5=AF=BC=E5=85=A5?= =?UTF-8?q?=E8=B7=AF=E5=BE=84=E9=94=99=E8=AF=AF=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=20=E4=BF=AE=E5=A4=8D=E4=BA=86=E5=9C=A8=E4=B8=AD=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E8=8E=B7=E5=8F=96=E5=A4=B1=E8=B4=A5=E6=97=B6=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E7=9A=84=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_precisely_align.py | 2 +- func/utils/Constants.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/func/Module_precisely_align.py b/func/Module_precisely_align.py index c15a7fc..009c642 100644 --- a/func/Module_precisely_align.py +++ b/func/Module_precisely_align.py @@ -123,7 +123,7 @@ class SettingWindow(QMainWindow): Path(str(self.sampID)))), "Input_Rpeak": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / Path(str(self.sampID)))), - "Input_Approximately_Align": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / + "Input_Approximately_Align": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / Path(str(self.sampID)))), "Save_AlignInfo": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / Path(str(self.sampID)))), diff --git a/func/utils/Constants.py b/func/utils/Constants.py index a6907e6..56df68d 100644 --- a/func/utils/Constants.py +++ b/func/utils/Constants.py @@ -98,7 +98,7 @@ class Constants: "Suffix_Not_Correct": "(文件扩展名不正确)", "Frequency_Not_In_Filename": "(数据频率不在文件名中)", "Data_Not_Exist": "(数据不存在)", - "Model_File_Not_Exist": "(模型文件不存在)", + "Model_Path_Not_Exist": "(模型文件不存在)", "Cut_Data_Length_not_Correct": "(切割数据时长度不正确)", "Align_Label_SALabel_Format_not_Correct": "(映射标签时SA Label中的文件格式不正确)", "Filename_Format_not_Correct": "(文件名格式不正确)", From fd184c63847a039aed46734aa033d072a4ac94b2 Mon Sep 17 00:00:00 2001 From: Yorusora Date: Tue, 27 May 2025 20:34:59 +0800 Subject: [PATCH 14/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86<=E5=91=BC?= =?UTF-8?q?=E5=90=B8=E5=8F=AF=E7=94=A8=E6=80=A7=E5=8F=8A=E9=97=B4=E6=9C=9F?= =?UTF-8?q?=E6=A0=87=E6=B3=A8>=E4=B8=AD=E7=82=B9=E5=87=BB=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E5=B9=B6=E8=AE=A1=E7=AE=97=E8=BF=9B=E8=A1=8C=E9=87=8D?= =?UTF-8?q?=E6=96=B0=E6=BB=A4=E6=B3=A2=E5=90=8E=E6=8C=89=E9=92=AE=E5=85=A8?= =?UTF-8?q?=E9=83=A8=E8=A2=AB=E7=A6=81=E7=94=A8=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_resp_quality_label.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/func/Module_resp_quality_label.py b/func/Module_resp_quality_label.py index 6577fcd..a041988 100644 --- a/func/Module_resp_quality_label.py +++ b/func/Module_resp_quality_label.py @@ -791,6 +791,8 @@ class MainWindow_resp_quality_label(QMainWindow): else: PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.finish_operation(self, ButtonState) + def __slot_btn_move__(self): sender = self.sender() From 29056a96f33414dbcbd127cf160855712081eeeb Mon Sep 17 00:00:00 2001 From: Yorusora Date: Tue, 27 May 2025 21:12:55 +0800 Subject: [PATCH 15/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86<=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E7=B2=BE=E5=AF=B9=E9=BD=90>=E4=B8=AD=E7=B2=97?= =?UTF-8?q?=E5=AF=B9=E9=BD=90=E8=99=9A=E7=BA=BF=E4=BD=8D=E7=BD=AE=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E9=94=99=E8=AF=AF=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_precisely_align.py | 1 + 1 file changed, 1 insertion(+) diff --git a/func/Module_precisely_align.py b/func/Module_precisely_align.py index 009c642..651cff8 100644 --- a/func/Module_precisely_align.py +++ b/func/Module_precisely_align.py @@ -1547,6 +1547,7 @@ class Data: self.BCG_early = False elif self.approximately_align_pos < 0: self.BCG_early = True + self.approximately_align_pos = - self.approximately_align_pos else: self.approximately_align_pos = 0 self.BCG_early = None From ee4df5ee93a85aa8131d280376b7aadd7c6b0673 Mon Sep 17 00:00:00 2001 From: Yorusora Date: Wed, 28 May 2025 12:59:06 +0800 Subject: [PATCH 16/26] =?UTF-8?q?1=E3=80=81=E4=BF=AE=E5=A4=8D=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E5=A4=84=E6=96=87=E4=BB=B6=E5=91=BD=E5=90=8D=E9=94=99?= =?UTF-8?q?=E8=AF=AF=202=E3=80=81=E6=B7=BB=E5=8A=A0=E4=BA=86=E4=B8=80?= =?UTF-8?q?=E6=9D=A1TODO=20LIST?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 ++ func/utils/ConfigParams.py | 37 +++++++++++++++++++++++-------------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 68dbc58..5b688d9 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ 4、在J峰算法定位的时候滤波导致的信号偏移,导致之后的峰值坐标点与实际峰值出现偏移 +5、写一个脚本,用于直接从ConfigParams.py中读取文件命名规则,并直接自动化写入到一个markdown文件中。目的是方便文件命名的修改。 + ## 1、主菜单 ![](/img/0.png) diff --git a/func/utils/ConfigParams.py b/func/utils/ConfigParams.py index a45c944..5a9e150 100644 --- a/func/utils/ConfigParams.py +++ b/func/utils/ConfigParams.py @@ -31,7 +31,13 @@ class ConfigParams: VALIDATOR_DOUBLE = QDoubleValidator(-1e100, 1e100, 10) # 文件命名 + # Folder: OrgBCG_Text ORGBCG_RAW: str = "OrgBCG_Raw_" + BCG_FILTER: str = "BCG_Filter_" + JPEAK_REVISE: str = "Jpeak_revise_" + JPEAK_REVISE_CORRECTED: str = "Jpeak_revise_corrected_" + + # Folder: PSG_Text ECG_RAW: str = "ECG II_Raw_" THO_RAW: str = "Effort Tho_Raw_" ABD_RAW: str = "Effort Abd_Raw_" @@ -40,24 +46,18 @@ class ConfigParams: SNORE_RAW: str = "Snore_Raw_" SPO2_RAW: str = "SpO2_Raw_" FIVE_CLASS_RAW: str = "5_class_Raw_" - STARTTIME_RAW: str = "StartTime_Raw_" - SA_LABEL_RAW: str = "SA Label_Raw_" - BCG_FILTER: str = "BCG_Filter_" + STARTTIME_RAW: str = "StartTime_Raw" + SA_LABEL_RAW: str = "SA Label_Raw" ECG_FILTER: str = "ECG_Filter_" - JPEAK_REVISE: str = "Jpeak_revise_" RPEAK_FINAL: str = "Rpeak_final_" - JPEAK_REVISE_CORRECTED: str = "Jpeak_revise_corrected_" RPEAK_FINAL_CORRECTED: str = "Rpeak_final_corrected_" - APPROXIMATELY_ALIGN_INFO: str = "Approximately_Align_Info" - PRECISELY_ALIGN_INFO: str = "Precisely_Align_Info" - ARTIFACT_A: str = "Artifact_a_" - ARTIFACT_B: str = "Artifact_b_" - ARTIFACT_C: str = "Artifact_c_" - BCG_SYNC: str = "BCG_Sync_" - ECG_SYNC: str = "ECG_Sync_" - JPEAK_SYNC: str = "Jpeak_Sync_" - RPEAK_SYNC: str = "Rpeak_Sync_" + + # Folder: OrgBCG_Aligned ORGBCG_SYNC: str = "OrgBCG_Sync_" + BCG_SYNC: str = "BCG_Sync_" + + # Folder: PSG_Aligned + ECG_SYNC: str = "ECG_Sync_" THO_SYNC: str = "Effort Tho_Sync_" ABD_SYNC: str = "Effort Abd_Sync_" FLOWT_SYNC: str = "Flow T_Sync_" @@ -66,6 +66,15 @@ class ConfigParams: SPO2_SYNC: str = "SpO2_Sync_" FIVE_CLASS_SYNC: str = "5_class_Sync_" SA_LABEL_SYNC: str = "SA Label_Sync" + JPEAK_SYNC: str = "Jpeak_Sync_" + RPEAK_SYNC: str = "Rpeak_Sync_" + + # Folder: Label + APPROXIMATELY_ALIGN_INFO: str = "Approximately_Align_Info" + PRECISELY_ALIGN_INFO: str = "Precisely_Align_Info" + ARTIFACT_A: str = "Artifact_a_" + ARTIFACT_B: str = "Artifact_b_" + ARTIFACT_C: str = "Artifact_c_" SA_LABEL_CORRECTED: str = "SA Label_corrected" SA_LABEL_ADD: str = "SA Label_add" RESP_QUALITY_LABEL: str = "Resp_quality_label" From 13cf749a9918473893688944ba7fb1e517a1f19b Mon Sep 17 00:00:00 2001 From: Yorusora Date: Wed, 28 May 2025 22:04:49 +0800 Subject: [PATCH 17/26] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=84=9A=E6=9C=ACfilen?= =?UTF-8?q?ame=5Fregulation=5Fgenerator.py=EF=BC=8C=E6=9C=89=E5=91=BD?= =?UTF-8?q?=E5=90=8D=E8=A7=84=E8=8C=83=E9=9C=80=E8=A6=81=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E5=8F=AA=E9=9C=80=E8=A6=81=E4=BF=AE=E6=94=B9?= =?UTF-8?q?ConfigParams.py=E7=9A=84Filename=E7=B1=BB=E9=87=8C=E9=9D=A2?= =?UTF-8?q?=E7=9A=84=E5=8F=98=E9=87=8F=E7=9A=84=E5=80=BC=EF=BC=8C=E4=B9=8B?= =?UTF-8?q?=E5=90=8E=E7=9B=B4=E6=8E=A5=E8=BF=90=E8=A1=8C=E8=84=9A=E6=9C=AC?= =?UTF-8?q?filename=5Fregulation=5Fgenerator.py=E5=8D=B3=E5=8F=AF=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E6=9C=80=E6=96=B0=E7=89=88=E6=9C=AC=E7=9A=84=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E7=BB=93=E6=9E=84=E5=8C=96=E8=BE=93=E5=85=A5=E5=92=8C?= =?UTF-8?q?=E8=BE=93=E5=87=BA=E5=91=BD=E5=90=8D=E8=A7=84=E8=8C=83.html?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- filename_regulation_generator.py | 291 ++++++++++++++++++++++++++++ func/Module_SA_label.py | 187 +++++++++--------- func/Module_approximately_align.py | 61 +++--- func/Module_artifact_label.py | 115 +++++------ func/Module_bcg_quality_label.py | 62 +++--- func/Module_cut_PSG.py | 33 ++-- func/Module_detect_Jpeak.py | 41 ++-- func/Module_detect_Rpeak.py | 45 ++--- func/Module_label_check.py | 133 ++++++------- func/Module_mainwindow.py | 19 +- func/Module_precisely_align.py | 191 +++++++++--------- func/Module_preprocess.py | 65 ++++--- func/Module_resp_quality_label.py | 172 ++++++++--------- func/utils/ConfigParams.py | 98 +++++----- func/utils/Constants.py | 10 +- 数据结构化输入和输出命名规范.html | 168 ++++++++++++++++ 数据结构化输入和输出命名规范.md | 300 ----------------------------- 17 files changed, 1083 insertions(+), 908 deletions(-) create mode 100644 filename_regulation_generator.py create mode 100644 数据结构化输入和输出命名规范.html delete mode 100644 数据结构化输入和输出命名规范.md diff --git a/filename_regulation_generator.py b/filename_regulation_generator.py new file mode 100644 index 0000000..c3e9995 --- /dev/null +++ b/filename_regulation_generator.py @@ -0,0 +1,291 @@ +from markdown import markdown + +from func.utils.ConfigParams import Filename, Params + +markdown_text = f""" +# 文件命名规范 + +### 当一份数据被完整走完标注流程后,数据文件夹目录结构将会是: + + .../{Filename.PATH_LABEL}/{Filename.PATH_SAMPID} + |-{Filename.ARTIFACT_A}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.ARTIFACT_B}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.ARTIFACT_C}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_CSV} + |-{Filename.SQ_LABEL_10S}{Params.ENDSWITH_CSV} + |-{Filename.SQ_LABEL_30S}{Params.ENDSWITH_CSV} + |-{Filename.RESP_QUALITY_LABEL}{Params.ENDSWITH_TXT} + |-{Filename.THO_PEAK}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.SA_LABEL_CORRECTED}{Params.ENDSWITH_CSV} + |-{Filename.SA_LABEL_ADD}{Params.ENDSWITH_CSV} + |-{Filename.PRECISELY_ALIGN_INFO}{Params.ENDSWITH_TXT} + |-{Filename.APPROXIMATELY_ALIGN_INFO}{Params.ENDSWITH_CSV} + .../{Filename.PATH_ORGBCG_ALIGNED}/{Filename.PATH_SAMPID} + |-{Filename.BCG_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.ORGBCG_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.JPEAK_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + .../{Filename.PATH_ORGBCG_TEXT}/{Filename.PATH_SAMPID} + |-{Filename.ORGBCG_RAW}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.BCG_FILTER}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.JPEAK_REVISE}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.JPEAK_REVISE_CORRECTED}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + .../{Filename.PATH_ORGBCG_ORIGIN}/{Filename.PATH_SAMPID} + |-... + .../{Filename.PATH_PSG_ALIGNED}/{Filename.PATH_SAMPID} + |-{Filename.ECG_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.RPEAK_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.FIVE_CLASS_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.SA_LABEL_SYNC}{Params.ENDSWITH_CSV} + |-{Filename.ABD_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.THO_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.FLOWT_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.FLOWP_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.SNORE_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.SPO2_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + .../{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID} + |-{Filename.ECG_RAW}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.ECG_FILTER}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.RPEAK_FINAL}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.RPEAK_FINAL_CORRECTED}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.FIVE_CLASS_RAW}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.SA_LABEL_RAW}{Params.ENDSWITH_CSV} + |-{Filename.ABD_RAW}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.THO_RAW}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.FLOWT_RAW}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.FLOWP_RAW}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.SNORE_RAW}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.SPO2_RAW}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT} + |-{Filename.STARTTIME_RAW}{Params.ENDSWITH_TXT} + .../{Filename.PATH_PSG_ORIGIN}/{Filename.PATH_SAMPID} + |-... + .../{Filename.PATH_REVEIVE_ORIGIN} + |-... + .../{Filename.PATH_REPORT} + |-... + +### 1 数据粗同步 + +输入: + +原始OrgBCG信号:`./{Filename.PATH_ORGBCG_TEXT}/{Filename.PATH_SAMPID}/{Filename.ORGBCG_RAW}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +原始Tho信号:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.THO_RAW}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +原始Abd信号:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.ABD_RAW}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +输出: + +粗同步后的位置索引:`./{Filename.PATH_LABEL}/{Filename.PATH_SAMPID}/{Filename.APPROXIMATELY_ALIGN_INFO}{Params.ENDSWITH_CSV}` + +### 2 预处理 + +输入: + +原始OrgBCG信号:`./{Filename.PATH_ORGBCG_TEXT}/{Filename.PATH_SAMPID}/{Filename.ORGBCG_RAW}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +原始ECG信号:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.ECG_RAW}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +输出: + +滤波后的BCG信号:`./{Filename.PATH_ORGBCG_TEXT}/{Filename.PATH_SAMPID}/{Filename.BCG_FILTER}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +滤波后的ECG信号:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.ECG_FILTER}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +### 3 数据精同步 + +#### 3.1 算法定位 + +#### 3.1.1 R峰算法定位 + +输入: + +滤波后的ECG信号:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.ECG_FILTER}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +输出: + +算法定位的R峰坐标:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.RPEAK_FINAL}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +#### 3.1.2 J峰算法定位 + +输入: + +滤波后的BCG信号:`./{Filename.PATH_ORGBCG_TEXT}/{Filename.PATH_SAMPID}/{Filename.BCG_FILTER}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +输出: + +算法定位的J峰坐标:`./{Filename.PATH_ORGBCG_TEXT}/{Filename.PATH_SAMPID}/{Filename.JPEAK_REVISE}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +#### 3.2 人工纠正 + +#### 3.2.1 R峰人工纠正 + +输入: + +滤波后的ECG信号:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.ECG_FILTER}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +算法定位的R峰坐标:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.RPEAK_FINAL}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +粗同步后的位置索引:`./{Filename.PATH_LABEL}/{Filename.PATH_SAMPID}/{Filename.APPROXIMATELY_ALIGN_INFO}{Params.ENDSWITH_CSV}` + +输出: + +人工纠正后的R峰坐标:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.RPEAK_FINAL_CORRECTED}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +#### 3.2.2 J峰人工纠正* + +输入: + +滤波后的BCG信号:`./{Filename.PATH_ORGBCG_TEXT}/{Filename.PATH_SAMPID}/{Filename.BCG_FILTER}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +算法定位的J峰坐标:`./{Filename.PATH_ORGBCG_TEXT}/{Filename.PATH_SAMPID}/{Filename.JPEAK_REVISE}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +粗同步后的位置索引:`./{Filename.PATH_LABEL}/{Filename.PATH_SAMPID}/{Filename.APPROXIMATELY_ALIGN_INFO}{Params.ENDSWITH_CSV}` + +输出: + +人工纠正后的J峰坐标:`./{Filename.PATH_ORGBCG_TEXT}/{Filename.PATH_SAMPID}/{Filename.JPEAK_REVISE_CORRECTED}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +#### 3.3 数据片段起止对齐、数据采样率同步 + +输入: + +滤波后的ECG信号:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.ECG_FILTER}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +人工纠正后的R峰坐标:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.RPEAK_FINAL_CORRECTED}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +滤波后的BCG信号:`./{Filename.PATH_ORGBCG_TEXT}/{Filename.PATH_SAMPID}/{Filename.BCG_FILTER}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +人工纠正后的J峰坐标:`./{Filename.PATH_ORGBCG_TEXT}/{Filename.PATH_SAMPID}/{Filename.JPEAK_REVISE_CORRECTED}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +原始OrgBCG信号:`./{Filename.PATH_ORGBCG_TEXT}/{Filename.PATH_SAMPID}/{Filename.ORGBCG_RAW}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +粗同步后的位置索引:`./{Filename.PATH_LABEL}/{Filename.PATH_SAMPID}/{Filename.APPROXIMATELY_ALIGN_INFO}{Params.ENDSWITH_CSV}` + +输出: + +精同步对齐信息:`./{Filename.PATH_LABEL}/{Filename.PATH_SAMPID}/{Filename.PRECISELY_ALIGN_INFO}{Params.ENDSWITH_TXT}` + +同步后的ECG信号:`./{Filename.PATH_PSG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.ECG_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的R峰坐标:`./{Filename.PATH_PSG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.RPEAK_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的BCG信号:`./{Filename.PATH_ORGBCG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.BCG_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的OrgBCG信号:`./{Filename.PATH_ORGBCG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.ORGBCG_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的J峰坐标:`./{Filename.PATH_ORGBCG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.JPEAK_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +#### 3.4、冗余数据切割、标签映射 + +输入: + +精同步对齐信息:`./{Filename.PATH_LABEL}/{Filename.PATH_SAMPID}/{Filename.PRECISELY_ALIGN_INFO}{Params.ENDSWITH_TXT}` + +原始的Flow T信号:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.FLOWT_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +原始的Flow P信号:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.FLOWP_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +原始的Tho信号:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.THO_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +原始的Abd信号:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.ABD_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +原始的SpO2信号:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.SPO2_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +原始的Snore信号:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.SNORE_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +原始的睡眠分期标签:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.FIVE_CLASS_RAW}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +原始的睡眠呼吸暂停事件标签:`./{Filename.PATH_PSG_TEXT}/{Filename.PATH_SAMPID}/{Filename.SA_LABEL_RAW}{Params.ENDSWITH_CSV}` + +输出: + +同步后的Flow T信号:`./{Filename.PATH_PSG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.FLOWT_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的Flow P信号:`./{Filename.PATH_PSG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.FLOWP_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的Tho信号:`./{Filename.PATH_PSG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.THO_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的Abd信号:`./{Filename.PATH_PSG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.ABD_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的SpO2信号:`./{Filename.PATH_PSG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.SPO2_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的Snore信号:`./{Filename.PATH_PSG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.SNORE_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的睡眠分期标签:`./{Filename.PATH_PSG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.FIVE_CLASS_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的睡眠呼吸暂停事件标签:`./{Filename.PATH_PSG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.SA_LABEL_SYNC}{Params.ENDSWITH_CSV}` + +### 4 体动标记 + +输入: + +同步后的BCG信号:`./{Filename.PATH_ORGBCG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.BCG_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的OrgBCG信号:`./{Filename.PATH_ORGBCG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.ORGBCG_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +输出: + +txt格式的体动标签:`./{Filename.PATH_LABEL}/{Filename.PATH_SAMPID}/{Filename.ARTIFACT_A}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +体动标签类型数量统计:`./{Filename.PATH_LABEL}/{Filename.PATH_SAMPID}/{Filename.ARTIFACT_B}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +csv格式的体动标签:`./{Filename.PATH_LABEL}/{Filename.PATH_SAMPID}/{Filename.ARTIFACT_C}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_CSV}` + +### 5 质量评估 + +输入: + +同步后的BCG信号:`./{Filename.PATH_ORGBCG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.BCG_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +txt格式的体动标签:`./{Filename.PATH_LABEL}/{Filename.PATH_SAMPID}/{Filename.ARTIFACT_A}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +输出: + +质量标签:`./{Filename.PATH_LABEL}/{Filename.PATH_SAMPID}/{Filename.SQ_LABEL_10S}{Params.ENDSWITH_CSV}`或`./{Filename.PATH_LABEL}/{Filename.PATH_SAMPID}/{Filename.SQ_LABEL_30S}{Params.ENDSWITH_CSV}` + +### 6 呼吸提取 + +输入: + +同步后的OrgBCG信号:`./{Filename.PATH_ORGBCG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.ORGBCG_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的Tho信号:`./{Filename.PATH_PSG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.THO_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +txt格式的体动标签:`./{Filename.PATH_LABEL}/{Filename.PATH_SAMPID}/{Filename.ARTIFACT_A}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +输出: + +呼吸可用性标签:`./{Filename.PATH_LABEL}/{Filename.PATH_SAMPID}/{Filename.RESP_QUALITY_LABEL}{Params.ENDSWITH_TXT}` + +Tho信号呼吸间期标签:`./{Filename.PATH_LABEL}/{Filename.PATH_SAMPID}/{Filename.THO_PEAK}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +### 8 呼吸暂停事件标注 + +输入: + +同步后的OrgBCG信号:`./{Filename.PATH_ORGBCG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.ORGBCG_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +txt格式的体动标签:`./{Filename.PATH_LABEL}/{Filename.PATH_SAMPID}/{Filename.ARTIFACT_A}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的Flow T信号:`./{Filename.PATH_PSG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.FLOWT_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的Flow P信号:`./{Filename.PATH_PSG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.FLOWP_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的Tho信号:`./{Filename.PATH_PSG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.THO_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的Abd信号:`./{Filename.PATH_PSG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.ABD_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的SpO2信号:`./{Filename.PATH_PSG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.SPO2_SYNC}{Filename.SUFFIX_FREQ}{Params.ENDSWITH_TXT}` + +同步后的睡眠呼吸暂停事件标签:`./{Filename.PATH_PSG_ALIGNED}/{Filename.PATH_SAMPID}/{Filename.SA_LABEL_SYNC}{Params.ENDSWITH_CSV}` + +输出: + +修正后的呼吸暂停标签:`./{Filename.PATH_LABEL}/{Filename.PATH_SAMPID}/{Filename.SA_LABEL_CORRECTED}{Params.ENDSWITH_CSV}` + +新增的呼吸暂停标签:`./{Filename.PATH_LABEL}/{Filename.PATH_SAMPID}/{Filename.SA_LABEL_ADD}{Params.ENDSWITH_CSV}` + +""" + +html = markdown(markdown_text) +with open('数据结构化输入和输出命名规范.html', 'w', encoding='utf-8') as file: + file.write(html) diff --git a/func/Module_SA_label.py b/func/Module_SA_label.py index 0e32da6..a92237f 100644 --- a/func/Module_SA_label.py +++ b/func/Module_SA_label.py @@ -15,9 +15,10 @@ from overrides import overrides from pandas import read_csv, DataFrame, Series, concat from yaml import dump, load, FullLoader +from func.utils.ConfigParams import Filename, Params from func.Filters.Preprocessing import Butterworth_for_ECG_PreProcess from func.utils.PublicFunc import PublicFunc -from func.utils.Constants import Constants, ConfigParams +from func.utils.Constants import Constants from func.utils.Result import Result from ui.MainWindow.MainWindow_SA_label import Ui_MainWindow_SA_label @@ -98,36 +99,36 @@ class SettingWindow(QMainWindow): self.ui.pushButton_cancel.clicked.connect(self.close) def __read_config__(self): - if not Path(ConfigParams.SA_LABEL_CONFIG_FILE_PATH).exists(): - with open(ConfigParams.SA_LABEL_CONFIG_FILE_PATH, "w") as f: - dump(ConfigParams.SA_LABEL_CONFIG_NEW_CONTENT, f) + if not Path(Params.SA_LABEL_CONFIG_FILE_PATH).exists(): + with open(Params.SA_LABEL_CONFIG_FILE_PATH, "w") as f: + dump(Params.SA_LABEL_CONFIG_NEW_CONTENT, f) - with open(ConfigParams.SA_LABEL_CONFIG_FILE_PATH, "r") as f: + with open(Params.SA_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 / + "Input_OrgBCG": str((Path(self.root_path) / Filename.PATH_ORGBCG_ALIGNED / Path(str(self.sampID)))), - "Input_Tho": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + "Input_Tho": str((Path(self.root_path) / Filename.PATH_PSG_ALIGNED / Path(str(self.sampID)))), - "Input_Abd": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_ALIGNED / - Path(str(self.sampID)))), - "Input_FlowT": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + "Input_Abd": str((Path(self.root_path) / Filename.PATH_PSG_ALIGNED / Path(str(self.sampID)))), - "Input_FlowP": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + "Input_FlowT": str((Path(self.root_path) / Filename.PATH_PSG_ALIGNED / Path(str(self.sampID)))), - "Input_SpO2": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_ALIGNED / - Path(str(self.sampID)))), - "Input_Artifact": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / - Path(str(self.sampID)))), - "Input_Label": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + "Input_FlowP": str((Path(self.root_path) / Filename.PATH_PSG_ALIGNED / Path(str(self.sampID)))), - "Save": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + "Input_SpO2": str((Path(self.root_path) / Filename.PATH_PSG_ALIGNED / + Path(str(self.sampID)))), + "Input_Artifact": str((Path(self.root_path) / Filename.PATH_LABEL / + Path(str(self.sampID)))), + "Input_Label": str((Path(self.root_path) / Filename.PATH_PSG_ALIGNED / + Path(str(self.sampID)))), + "Save": str((Path(self.root_path) / Filename.PATH_LABEL / Path(str(self.sampID)))), - "Save_2": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + "Save_2": str((Path(self.root_path) / Filename.PATH_LABEL / Path(str(self.sampID)))) }, "PlotEventIndex": 0, @@ -182,7 +183,7 @@ class SettingWindow(QMainWindow): self.config["InputConfig"]["FlowPFreq"] = self.ui.spinBox_input_freq_signal_FlowP.value() self.config["InputConfig"]["SpO2Freq"] = self.ui.spinBox_input_freq_signal_SpO2.value() - with open(ConfigParams.SA_LABEL_CONFIG_FILE_PATH, "w") as f: + with open(Params.SA_LABEL_CONFIG_FILE_PATH, "w") as f: dump(self.config, f) self.close() @@ -193,46 +194,46 @@ class SettingWindow(QMainWindow): def __update_ui__(self): self.ui.plainTextEdit_file_path_input_signal_OrgBCG.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + Filename.PATH_ORGBCG_ALIGNED / Path(str(self.sampID)) / - Path(ConfigParams.ORGBCG_SYNC + + Path(Filename.ORGBCG_SYNC + str(self.ui.spinBox_input_freq_signal_OrgBCG.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_input_signal_Tho.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + Filename.PATH_PSG_ALIGNED / Path(str(self.sampID)) / - Path(ConfigParams.THO_SYNC + + Path(Filename.THO_SYNC + str(self.ui.spinBox_input_freq_signal_Tho.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_input_signal_Abd.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + Filename.PATH_PSG_ALIGNED / Path(str(self.sampID)) / - Path(ConfigParams.ABD_SYNC + + Path(Filename.ABD_SYNC + str(self.ui.spinBox_input_freq_signal_Abd.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_input_signal_FlowT.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + Filename.PATH_PSG_ALIGNED / Path(str(self.sampID)) / - Path(ConfigParams.FLOWT_SYNC + + Path(Filename.FLOWT_SYNC + str(self.ui.spinBox_input_freq_signal_FlowT.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_input_signal_FlowP.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + Filename.PATH_PSG_ALIGNED / Path(str(self.sampID)) / - Path(ConfigParams.FLOWP_SYNC + + Path(Filename.FLOWP_SYNC + str(self.ui.spinBox_input_freq_signal_FlowP.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_input_signal_SpO2.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + Filename.PATH_PSG_ALIGNED / Path(str(self.sampID)) / - Path(ConfigParams.SPO2_SYNC + + Path(Filename.SPO2_SYNC + str(self.ui.spinBox_input_freq_signal_SpO2.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) class MainWindow_SA_label(QMainWindow): @@ -305,31 +306,31 @@ class MainWindow_SA_label(QMainWindow): 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.xaxis.set_major_formatter(Params.FORMATTER) self.ax0.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) self.ax1 = self.fig.add_subplot(self.gs[1], sharex=self.ax0) self.ax1.grid(True) - self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax1.xaxis.set_major_formatter(Params.FORMATTER) self.ax1.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) self.ax2 = self.fig.add_subplot(self.gs[2], sharex=self.ax0) self.ax2.grid(True) - self.ax2.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax2.xaxis.set_major_formatter(Params.FORMATTER) self.ax2.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) self.ax3 = self.fig.add_subplot(self.gs[3], sharex=self.ax0) self.ax3.grid(True) - self.ax3.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax3.xaxis.set_major_formatter(Params.FORMATTER) self.ax3.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) self.ax4 = self.fig.add_subplot(self.gs[4], sharex=self.ax0) self.ax4.grid(True) - self.ax4.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax4.xaxis.set_major_formatter(Params.FORMATTER) self.ax4.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) self.ax5 = self.fig.add_subplot(self.gs[5], sharex=self.ax0) self.ax5.grid(True) - self.ax5.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax5.xaxis.set_major_formatter(Params.FORMATTER) self.ax5.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) self.ax6 = self.fig.add_subplot(self.gs[6], sharex=self.ax0) self.ax6.grid(True) - self.ax6.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax6.xaxis.set_major_formatter(Params.FORMATTER) PublicFunc.__resetAllButton__(self, ButtonState) @@ -378,17 +379,17 @@ class MainWindow_SA_label(QMainWindow): self.ui.checkBox_examineBySecond.clicked.connect(self.__slot_checkBox_examineBySecond__) self.ui.checkBox_examineLabeled.clicked.connect(self.__slot_checkBox_examineLabeled__) - self.ui.pushButton_prev.setShortcut(QCoreApplication.translate("MainWindow", ConfigParams.SA_LABEL_BTN_PREV_SHORTCUT_KEY)) - self.ui.pushButton_confirmLabel.setShortcut(QCoreApplication.translate("MainWindow", ConfigParams.SA_LABEL_BTN_CONFIRMLABEL_SHORTCUT_KEY)) - self.ui.pushButton_next.setShortcut(QCoreApplication.translate("MainWindow", ConfigParams.SA_LABEL_BTN_NEXT_SHORTCUT_KEY)) - self.ui.radioButton_OSA.setShortcut(QCoreApplication.translate("MainWindow", ConfigParams.SA_LABEL_RADIOBUTTON_OSA_SHORTCUT_KEY)) - self.ui.radioButton_CSA.setShortcut(QCoreApplication.translate("MainWindow", ConfigParams.SA_LABEL_RADIOBUTTON_CSA_SHORTCUT_KEY)) - self.ui.radioButton_MSA.setShortcut(QCoreApplication.translate("MainWindow", ConfigParams.SA_LABEL_RADIOBUTTON_MSA_SHORTCUT_KEY)) - self.ui.radioButton_HPY.setShortcut(QCoreApplication.translate("MainWindow", ConfigParams.SA_LABEL_RADIOBUTTON_HPY_SHORTCUT_KEY)) - self.ui.radioButton_1_class.setShortcut(QCoreApplication.translate("MainWindow", ConfigParams.SA_LABEL_RADIOBUTTON_1_CLASS_SHORTCUT_KEY)) - self.ui.radioButton_2_class.setShortcut(QCoreApplication.translate("MainWindow", ConfigParams.SA_LABEL_RADIOBUTTON_2_CLASS_SHORTCUT_KEY)) - self.ui.radioButton_3_class.setShortcut(QCoreApplication.translate("MainWindow", ConfigParams.SA_LABEL_RADIOBUTTON_3_CLASS_SHORTCUT_KEY)) - self.ui.pushButton_quick_remark_input_waitingForTalk.setShortcut(QCoreApplication.translate("MainWindow", ConfigParams.SA_LABEL_BTN_QUICK_REMARK_WAITINGFORTALK_SHORTCUT_KEY)) + self.ui.pushButton_prev.setShortcut(QCoreApplication.translate("MainWindow", Params.SA_LABEL_BTN_PREV_SHORTCUT_KEY)) + self.ui.pushButton_confirmLabel.setShortcut(QCoreApplication.translate("MainWindow", Params.SA_LABEL_BTN_CONFIRMLABEL_SHORTCUT_KEY)) + self.ui.pushButton_next.setShortcut(QCoreApplication.translate("MainWindow", Params.SA_LABEL_BTN_NEXT_SHORTCUT_KEY)) + self.ui.radioButton_OSA.setShortcut(QCoreApplication.translate("MainWindow", Params.SA_LABEL_RADIOBUTTON_OSA_SHORTCUT_KEY)) + self.ui.radioButton_CSA.setShortcut(QCoreApplication.translate("MainWindow", Params.SA_LABEL_RADIOBUTTON_CSA_SHORTCUT_KEY)) + self.ui.radioButton_MSA.setShortcut(QCoreApplication.translate("MainWindow", Params.SA_LABEL_RADIOBUTTON_MSA_SHORTCUT_KEY)) + self.ui.radioButton_HPY.setShortcut(QCoreApplication.translate("MainWindow", Params.SA_LABEL_RADIOBUTTON_HPY_SHORTCUT_KEY)) + self.ui.radioButton_1_class.setShortcut(QCoreApplication.translate("MainWindow", Params.SA_LABEL_RADIOBUTTON_1_CLASS_SHORTCUT_KEY)) + self.ui.radioButton_2_class.setShortcut(QCoreApplication.translate("MainWindow", Params.SA_LABEL_RADIOBUTTON_2_CLASS_SHORTCUT_KEY)) + self.ui.radioButton_3_class.setShortcut(QCoreApplication.translate("MainWindow", Params.SA_LABEL_RADIOBUTTON_3_CLASS_SHORTCUT_KEY)) + self.ui.pushButton_quick_remark_input_waitingForTalk.setShortcut(QCoreApplication.translate("MainWindow", Params.SA_LABEL_BTN_QUICK_REMARK_WAITINGFORTALK_SHORTCUT_KEY)) @overrides def closeEvent(self, event): @@ -1003,37 +1004,37 @@ class MainWindow_SA_label(QMainWindow): if self.ax0 is not None: self.ax0.clear() self.ax0.grid(True) - self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax0.xaxis.set_major_formatter(Params.FORMATTER) self.ax0.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) if self.ax1 is not None: self.ax1.clear() self.ax1.grid(True) - self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax1.xaxis.set_major_formatter(Params.FORMATTER) self.ax1.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) if self.ax2 is not None: self.ax2.clear() self.ax2.grid(True) - self.ax2.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax2.xaxis.set_major_formatter(Params.FORMATTER) self.ax2.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) if self.ax3 is not None: self.ax3.clear() self.ax3.grid(True) - self.ax3.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax3.xaxis.set_major_formatter(Params.FORMATTER) self.ax3.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) if self.ax4 is not None: self.ax4.clear() self.ax4.grid(True) - self.ax4.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax4.xaxis.set_major_formatter(Params.FORMATTER) self.ax4.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) if self.ax5 is not None: self.ax5.clear() self.ax5.grid(True) - self.ax5.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax5.xaxis.set_major_formatter(Params.FORMATTER) self.ax5.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) if self.ax6 is not None: self.ax6.clear() self.ax6.grid(True) - self.ax6.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax6.xaxis.set_major_formatter(Params.FORMATTER) def on_xlim_change(self, event_ax): # 获取当前x轴范围 @@ -1162,7 +1163,7 @@ class MainWindow_SA_label(QMainWindow): self.data.df_corrected.at[Config["EventLabelIndexList"][Config["PlotEventIndex"]], "correct_Start"], self.data.df_corrected.at[Config["EventLabelIndexList"][Config["PlotEventIndex"]], "correct_End"], color='red', - alpha=ConfigParams.SA_LABEL_TRANSPARENCY) + alpha=Params.SA_LABEL_TRANSPARENCY) elif self.data.df_corrected.at[ Config["EventLabelIndexList"][Config["PlotEventIndex"]], "correct_EventsType"] == "Central apnea": for ax in ax_: @@ -1170,7 +1171,7 @@ class MainWindow_SA_label(QMainWindow): self.data.df_corrected.at[Config["EventLabelIndexList"][Config["PlotEventIndex"]], "correct_Start"], self.data.df_corrected.at[Config["EventLabelIndexList"][Config["PlotEventIndex"]], "correct_End"], color='blue', - alpha=ConfigParams.SA_LABEL_TRANSPARENCY) + alpha=Params.SA_LABEL_TRANSPARENCY) elif self.data.df_corrected.at[ Config["EventLabelIndexList"][Config["PlotEventIndex"]], "correct_EventsType"] == "Mixed apnea": for ax in ax_: @@ -1178,7 +1179,7 @@ class MainWindow_SA_label(QMainWindow): self.data.df_corrected.at[Config["EventLabelIndexList"][Config["PlotEventIndex"]], "correct_Start"], self.data.df_corrected.at[Config["EventLabelIndexList"][Config["PlotEventIndex"]], "correct_End"], color='gray', - alpha=ConfigParams.SA_LABEL_TRANSPARENCY) + alpha=Params.SA_LABEL_TRANSPARENCY) elif self.data.df_corrected.at[ Config["EventLabelIndexList"][Config["PlotEventIndex"]], "correct_EventsType"] == "Hypopnea": for ax in ax_: @@ -1186,7 +1187,7 @@ class MainWindow_SA_label(QMainWindow): self.data.df_corrected.at[Config["EventLabelIndexList"][Config["PlotEventIndex"]], "correct_Start"], self.data.df_corrected.at[Config["EventLabelIndexList"][Config["PlotEventIndex"]], "correct_End"], color='pink', - alpha=ConfigParams.SA_LABEL_TRANSPARENCY) + alpha=Params.SA_LABEL_TRANSPARENCY) else: if self.data.df_corrected.at[ Config["EventLabelIndexList"][Config["PlotEventIndex"]], "Event type"] == "Obstructive apnea": @@ -1194,28 +1195,28 @@ class MainWindow_SA_label(QMainWindow): ax.axvspan(self.data.df_corrected.at[Config["EventLabelIndexList"][Config["PlotEventIndex"]], "Start"], self.data.df_corrected.at[Config["EventLabelIndexList"][Config["PlotEventIndex"]], "End"], color='red', - alpha=ConfigParams.SA_LABEL_TRANSPARENCY) + alpha=Params.SA_LABEL_TRANSPARENCY) elif self.data.df_corrected.at[ Config["EventLabelIndexList"][Config["PlotEventIndex"]], "Event type"] == "Central apnea": for ax in ax_: ax.axvspan(self.data.df_corrected.at[Config["EventLabelIndexList"][Config["PlotEventIndex"]], "Start"], self.data.df_corrected.at[Config["EventLabelIndexList"][Config["PlotEventIndex"]], "End"], color='blue', - alpha=ConfigParams.SA_LABEL_TRANSPARENCY) + alpha=Params.SA_LABEL_TRANSPARENCY) elif self.data.df_corrected.at[ Config["EventLabelIndexList"][Config["PlotEventIndex"]], "Event type"] == "Mixed apnea": for ax in ax_: ax.axvspan(self.data.df_corrected.at[Config["EventLabelIndexList"][Config["PlotEventIndex"]], "Start"], self.data.df_corrected.at[Config["EventLabelIndexList"][Config["PlotEventIndex"]], "End"], color='gray', - alpha=ConfigParams.SA_LABEL_TRANSPARENCY) + alpha=Params.SA_LABEL_TRANSPARENCY) elif self.data.df_corrected.at[ Config["EventLabelIndexList"][Config["PlotEventIndex"]], "Event type"] == "Hypopnea": for ax in ax_: ax.axvspan(self.data.df_corrected.at[Config["EventLabelIndexList"][Config["PlotEventIndex"]], "Start"], self.data.df_corrected.at[Config["EventLabelIndexList"][Config["PlotEventIndex"]], "End"], color='pink', - alpha=ConfigParams.SA_LABEL_TRANSPARENCY) + alpha=Params.SA_LABEL_TRANSPARENCY) def pd_add_new_row(self, df, score: int, remark: str, correct_Start: int, correct_End: int, correct_EventsType: str, isLabeled: int): @@ -1282,88 +1283,88 @@ class Data: if Path(Config["Path"]["Input_Label"]).is_file(): Config["Path"]["Input_Label"] = str(Path(Config["Path"]["Input_Label"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input_OrgBCG"], ConfigParams.ORGBCG_SYNC, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_OrgBCG"], Filename.ORGBCG_SYNC, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_OrgBCG"] = result.data["path"] Config["InputConfig"]["OrgBCGFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], ConfigParams.THO_SYNC, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], Filename.THO_SYNC, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Tho"] = result.data["path"] Config["InputConfig"]["ThoFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_Abd"], ConfigParams.ABD_SYNC, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_Abd"], Filename.ABD_SYNC, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Abd"] = result.data["path"] Config["InputConfig"]["AbdFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_FlowT"], ConfigParams.FLOWT_SYNC, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_FlowT"], Filename.FLOWT_SYNC, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_FlowT"] = result.data["path"] Config["InputConfig"]["FlowTFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_FlowP"], ConfigParams.FLOWP_SYNC, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_FlowP"], Filename.FLOWP_SYNC, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_FlowP"] = result.data["path"] Config["InputConfig"]["FlowPFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_SpO2"], ConfigParams.SPO2_SYNC, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_SpO2"], Filename.SPO2_SYNC, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_SpO2"] = result.data["path"] Config["InputConfig"]["SpO2Freq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_Artifact"], ConfigParams.ARTIFACT_A, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_Artifact"], Filename.ARTIFACT_A, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Artifact"] = result.data["path"] else: return result Config["Path"]["Input_Label"] = str( - Path(Config["Path"]["Input_Label"]) / Path(ConfigParams.SA_LABEL_SYNC + ConfigParams.ENDSWITH_CSV)) + Path(Config["Path"]["Input_Label"]) / Path(Filename.SA_LABEL_SYNC + Params.ENDSWITH_CSV)) Config["Path"]["Save"] = str( - Path(Config["Path"]["Save"]) / Path(ConfigParams.SA_LABEL_CORRECTED + ConfigParams.ENDSWITH_CSV)) + Path(Config["Path"]["Save"]) / Path(Filename.SA_LABEL_CORRECTED + Params.ENDSWITH_CSV)) Config["Path"]["Save_2"] = str( - Path(Config["Path"]["Save_2"]) / Path(ConfigParams.SA_LABEL_ADD + ConfigParams.ENDSWITH_CSV)) + Path(Config["Path"]["Save_2"]) / Path(Filename.SA_LABEL_ADD + Params.ENDSWITH_CSV)) if not Path(Config["Path"]["Input_Artifact"]).exists(): return Result().failure(info=Constants.INPUT_FAILURE + "\n" + - ConfigParams.ARTIFACT_A + ":" + + Filename.ARTIFACT_A + ":" + Config["Path"]["Input_Artifact"] + Constants.FAILURE_REASON["Path_Not_Exist"]) if not Path(Config["Path"]["Input_Label"]).exists(): return Result().failure(info=Constants.INPUT_FAILURE + "\n" + - ConfigParams.SA_LABEL_SYNC + ":" + + Filename.SA_LABEL_SYNC + ":" + Config["Path"]["Input_Label"] + Constants.FAILURE_REASON["Path_Not_Exist"]) try: self.OrgBCG = read_csv(Config["Path"]["Input_OrgBCG"], - encoding=ConfigParams.UTF8_ENCODING, - header=None).to_numpy().reshape(-1) + encoding=Params.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) self.Tho = read_csv(Config["Path"]["Input_Tho"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.Abd = read_csv(Config["Path"]["Input_Abd"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.FlowT = read_csv(Config["Path"]["Input_FlowT"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.FlowP = read_csv(Config["Path"]["Input_FlowP"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.SpO2 = read_csv(Config["Path"]["Input_SpO2"], - encoding=ConfigParams.UTF8_ENCODING, - header=None).to_numpy().reshape(-1) + encoding=Params.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) self.Artifact = read_csv(Config["Path"]["Input_Artifact"], - encoding=ConfigParams.UTF8_ENCODING, - header=None).to_numpy().reshape(-1) + encoding=Params.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) self.event_label = zeros(len(self.OrgBCG) + (int(Config["AddSecond"]["Front"] + int(Config["AddSecond"]["Back"])) * Config["InputConfig"]["PlotFreq"])) except Exception as e: return Result().failure(info=Constants.INPUT_FAILURE + @@ -1623,6 +1624,6 @@ class CustomNavigationToolbar(NavigationToolbar2QT): def __init__(self, canvas, parent): super().__init__(canvas, parent) self.action_Reset_Signal_and_Time = QAction('复原视图和时间', self) - self.action_Reset_Signal_and_Time.setFont(QFont(ConfigParams.FONT, 14)) + self.action_Reset_Signal_and_Time.setFont(QFont(Params.FONT, 14)) self.action_Reset_Signal_and_Time.setCheckable(True) self.insertAction(self._actions['home'], self.action_Reset_Signal_and_Time) \ No newline at end of file diff --git a/func/Module_approximately_align.py b/func/Module_approximately_align.py index 2f1c1dd..3b64623 100644 --- a/func/Module_approximately_align.py +++ b/func/Module_approximately_align.py @@ -13,8 +13,9 @@ from pandas import read_csv, DataFrame from scipy.signal import find_peaks, resample, butter, sosfiltfilt, correlate from yaml import dump, load, FullLoader +from func.utils.ConfigParams import Filename, Params from func.utils.PublicFunc import PublicFunc -from func.utils.Constants import Constants, ConfigParams +from func.utils.Constants import Constants from func.utils.Result import Result from ui.MainWindow.MainWindow_approximately_align import Ui_MainWindow_approximately_align @@ -95,11 +96,11 @@ class SettingWindow(QMainWindow): self.ui.pushButton_cancel.clicked.connect(self.close) def __read_config__(self): - if not Path(ConfigParams.APPROXIMATELY_ALIGN_CONFIG_FILE_PATH).exists(): - with open(ConfigParams.APPROXIMATELY_ALIGN_CONFIG_FILE_PATH, "w") as f: - dump(ConfigParams.APPROXIMATELY_ALIGN_CONFIG_NEW_CONTENT, f) + if not Path(Params.APPROXIMATELY_ALIGN_CONFIG_FILE_PATH).exists(): + with open(Params.APPROXIMATELY_ALIGN_CONFIG_FILE_PATH, "w") as f: + dump(Params.APPROXIMATELY_ALIGN_CONFIG_NEW_CONTENT, f) - with open(ConfigParams.APPROXIMATELY_ALIGN_CONFIG_FILE_PATH, "r") as f: + with open(Params.APPROXIMATELY_ALIGN_CONFIG_FILE_PATH, "r") as f: file_config = load(f.read(), Loader=FullLoader) Config.update(file_config) self.config = file_config @@ -108,15 +109,15 @@ class SettingWindow(QMainWindow): Config.update({ "Path": { - "Input_orgBcg": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + "Input_orgBcg": str((Path(self.root_path) / Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)))), - "Input_Tho": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / + "Input_Tho": str((Path(self.root_path) / Filename.PATH_PSG_TEXT / Path(str(self.sampID)))), - "Input_Abd": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / + "Input_Abd": str((Path(self.root_path) / Filename.PATH_PSG_TEXT / Path(str(self.sampID)))), - "Save": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / - Path(str(self.sampID)) / Path(ConfigParams.APPROXIMATELY_ALIGN_INFO + - ConfigParams.ENDSWITH_CSV))) + "Save": str((Path(self.root_path) / Filename.PATH_LABEL / + Path(str(self.sampID)) / Path(Filename.APPROXIMATELY_ALIGN_INFO + + Params.ENDSWITH_CSV))) }, "orgBcgConfig": {}, "PSGConfig": {} @@ -158,7 +159,7 @@ class SettingWindow(QMainWindow): self.config["Filter"]["BandPassLow"] = self.ui.doubleSpinBox_bandpassLow.value() self.config["Filter"]["BandPassHigh"] = self.ui.doubleSpinBox_bandpassHigh.value() - with open(ConfigParams.APPROXIMATELY_ALIGN_CONFIG_FILE_PATH, "w") as f: + with open(Params.APPROXIMATELY_ALIGN_CONFIG_FILE_PATH, "w") as f: dump(self.config, f) self.close() @@ -169,25 +170,25 @@ class SettingWindow(QMainWindow): def __update_ui__(self): self.ui.plainTextEdit_file_path_input_orgBcg.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.ORGBCG_RAW + + Path(Filename.ORGBCG_RAW + str(self.ui.spinBox_input_orgBcg_freq.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_input_Tho.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_TEXT / + Filename.PATH_PSG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.THO_RAW + + Path(Filename.THO_RAW + str(self.ui.spinBox_input_Tho_freq.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_input_Abd.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_TEXT / + Filename.PATH_PSG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.ABD_RAW + + Path(Filename.ABD_RAW + str(self.ui.spinBox_input_Abd_freq.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) class MainWindow_approximately_align(QMainWindow): @@ -927,19 +928,19 @@ class Data: if Path(Config["Path"]["Input_Abd"]).is_file(): Config["Path"]["Input_Abd"] = str(Path(Config["Path"]["Input_Abd"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input_orgBcg"], ConfigParams.ORGBCG_RAW, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_orgBcg"], Filename.ORGBCG_RAW, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_orgBcg"] = result.data["path"] Config["InputConfig"]["orgBcgFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], ConfigParams.THO_RAW, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], Filename.THO_RAW, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Tho"] = result.data["path"] Config["InputConfig"]["ThoFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_Abd"], ConfigParams.ABD_RAW, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_Abd"], Filename.ABD_RAW, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Abd"] = result.data["path"] Config["InputConfig"]["AbdFreq"] = result.data["freq"] @@ -948,13 +949,13 @@ class Data: try: self.raw_orgBcg = read_csv(Config["Path"]["Input_orgBcg"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.raw_Tho = read_csv(Config["Path"]["Input_Tho"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.raw_Abd = read_csv(Config["Path"]["Input_Abd"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) except Exception as e: return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON[ @@ -1115,7 +1116,7 @@ class Data: # 计算互相关1/2 try: # 计算因子 - MULTIPLE_FACTOER = ConfigParams.APPROXIMATELY_ALIGN_CONFIG_NEW_CONTENT["Multiple_Factor"] + MULTIPLE_FACTOER = Params.APPROXIMATELY_ALIGN_CONFIG_NEW_CONTENT["Multiple_Factor"] a = self.processed_downsample_Tho[ Config["PSGConfig"]["PreCut"]:len(self.processed_downsample_Tho) - Config["PSGConfig"][ "PostCut"]].copy() @@ -1209,8 +1210,8 @@ class Data: epoch_min = response.data["epoch_min"] epoch_max = response.data["epoch_max"] - temp_freq = ConfigParams.APPROXIMATELY_ALIGN_CONFIG_NEW_CONTENT["TempFrequency"] - window_epoch = ConfigParams.APPROXIMATELY_ALIGN_CONFIG_NEW_CONTENT["CorrByEpoch"]["window_epoch"] + temp_freq = Params.APPROXIMATELY_ALIGN_CONFIG_NEW_CONTENT["TempFrequency"] + window_epoch = Params.APPROXIMATELY_ALIGN_CONFIG_NEW_CONTENT["CorrByEpoch"]["window_epoch"] tho_bias_list = [] abd_bias_list = [] diff --git a/func/Module_artifact_label.py b/func/Module_artifact_label.py index bc48a57..ccd4348 100644 --- a/func/Module_artifact_label.py +++ b/func/Module_artifact_label.py @@ -9,15 +9,16 @@ from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication, QTableWidg from matplotlib import gridspec, patches from matplotlib.backends.backend_qt import NavigationToolbar2QT from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg -from numpy import array, append +from numpy import array from numpy.fft import fft, fftfreq from overrides import overrides from pandas import read_csv, DataFrame, concat from scipy.signal import resample from yaml import dump, load, FullLoader +from func.utils.ConfigParams import Filename, Params from func.utils.PublicFunc import PublicFunc -from func.utils.Constants import Constants, ConfigParams +from func.utils.Constants import Constants from func.utils.Result import Result from ui.MainWindow.MainWindow_artifact_label import Ui_MainWindow_artifact_label @@ -78,26 +79,26 @@ class SettingWindow(QMainWindow): 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) + if not Path(Params.ARTIFACT_LABEL_CONFIG_FILE_PATH).exists(): + with open(Params.ARTIFACT_LABEL_CONFIG_FILE_PATH, "w") as f: + dump(Params.ARTIFACT_LABEL_CONFIG_NEW_CONTENT, f) - with open(ConfigParams.ARTIFACT_LABEL_CONFIG_FILE_PATH, "r") as f: + with open(Params.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 / + "Input_orgBcg": str((Path(self.root_path) / Filename.PATH_ORGBCG_ALIGNED / Path(str(self.sampID)))), - "Input_BCG": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + "Input_BCG": str((Path(self.root_path) / Filename.PATH_ORGBCG_ALIGNED / Path(str(self.sampID)))), - "Save_a": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + "Save_a": str((Path(self.root_path) / Filename.PATH_LABEL / Path(str(self.sampID)))), - "Save_b": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + "Save_b": str((Path(self.root_path) / Filename.PATH_LABEL / Path(str(self.sampID)))), - "Save_c": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + "Save_c": str((Path(self.root_path) / Filename.PATH_LABEL / Path(str(self.sampID)))) } }) @@ -125,7 +126,7 @@ class SettingWindow(QMainWindow): 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: + with open(Params.ARTIFACT_LABEL_CONFIG_FILE_PATH, "w") as f: dump(self.config, f) self.close() @@ -136,18 +137,18 @@ class SettingWindow(QMainWindow): def __update_ui__(self): self.ui.plainTextEdit_file_path_input_orgBcg.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + Filename.PATH_ORGBCG_ALIGNED / Path(str(self.sampID)) / - Path(ConfigParams.ORGBCG_SYNC + + Path(Filename.ORGBCG_SYNC + str(self.ui.spinBox_input_freq_orgBcg.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_input_BCG.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + Filename.PATH_ORGBCG_ALIGNED / Path(str(self.sampID)) / - Path(ConfigParams.BCG_SYNC + + Path(Filename.BCG_SYNC + str(self.ui.spinBox_input_freq_BCG.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) class MainWindow_artifact_label(QMainWindow): @@ -231,11 +232,11 @@ class MainWindow_artifact_label(QMainWindow): 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.xaxis.set_major_formatter(Params.FORMATTER) self.ax0.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) self.ax1 = self.fig.add_subplot(self.gs[1], sharex=self.ax0) self.ax1.grid(True) - self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax1.xaxis.set_major_formatter(Params.FORMATTER) PublicFunc.__resetAllButton__(self, ButtonState) @@ -259,8 +260,8 @@ class MainWindow_artifact_label(QMainWindow): self.ui.tableWidget_type_4.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) self.ui.tableWidget_type_5.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) - self.ui.lineEdit_start_time.setValidator(ConfigParams.VALIDATOR_INTEGER) - self.ui.lineEdit_end_time.setValidator(ConfigParams.VALIDATOR_INTEGER) + self.ui.lineEdit_start_time.setValidator(Params.VALIDATOR_INTEGER) + self.ui.lineEdit_end_time.setValidator(Params.VALIDATOR_INTEGER) self.ui.pushButton_input.clicked.connect(self.__slot_btn_input__) self.ui.pushButton_type_1.clicked.connect(self.__slot_btn_label__) @@ -369,71 +370,71 @@ class MainWindow_artifact_label(QMainWindow): 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]), + 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, + fill=True, alpha=Params.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]), + 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, + fill=True, alpha=Params.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]), + 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, + fill=True, alpha=Params.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]), + 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, + fill=True, alpha=Params.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]), + 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, + fill=True, alpha=Params.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]), + 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, + fill=True, alpha=Params.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]), + 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, + fill=True, alpha=Params.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]), + 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, + fill=True, alpha=Params.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]), + 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, + fill=True, alpha=Params.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]), + 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, + fill=True, alpha=Params.ARTIFACT_LABEL_LABEL_TRANSPARENCY, color=Constants.PLOT_COLOR_DEEP_GREY) self.rectangles_ax1_patches.append(rectangle) for patch in self.rectangles_ax0_patches: @@ -927,12 +928,12 @@ class MainWindow_artifact_label(QMainWindow): if self.ax0 is not None: self.ax0.clear() self.ax0.grid(True) - self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax0.xaxis.set_major_formatter(Params.FORMATTER) self.ax0.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) if self.ax1 is not None: self.ax1.clear() self.ax1.grid(True) - self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax1.xaxis.set_major_formatter(Params.FORMATTER) def on_xlim_change(self, event_ax): try: @@ -1205,14 +1206,14 @@ class Data: if Path(Config["Path"]["Input_BCG"]).is_file(): Config["Path"]["Input_BCG"] = str(Path(Config["Path"]["Input_BCG"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input_orgBcg"], ConfigParams.ORGBCG_SYNC, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_orgBcg"], Filename.ORGBCG_SYNC, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_orgBcg"] = result.data["path"] Config["InputConfig"]["orgBcgFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_BCG"], ConfigParams.BCG_SYNC, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_BCG"], Filename.BCG_SYNC, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_BCG"] = result.data["path"] Config["InputConfig"]["BCGFreq"] = result.data["freq"] @@ -1220,18 +1221,18 @@ class Data: return result Config["Path"]["Save_a"] = str( - Path(Config["Path"]["Save_a"]) / Path(ConfigParams.ARTIFACT_A + str(Config["InputConfig"]["UseFreq"]) + ConfigParams.ENDSWITH_TXT)) + Path(Config["Path"]["Save_a"]) / Path(Filename.ARTIFACT_A + str(Config["InputConfig"]["UseFreq"]) + Params.ENDSWITH_TXT)) Config["Path"]["Save_b"] = str( - Path(Config["Path"]["Save_b"]) / Path(ConfigParams.ARTIFACT_B + str(Config["InputConfig"]["UseFreq"]) + ConfigParams.ENDSWITH_TXT)) + Path(Config["Path"]["Save_b"]) / Path(Filename.ARTIFACT_B + str(Config["InputConfig"]["UseFreq"]) + Params.ENDSWITH_TXT)) Config["Path"]["Save_c"] = str( - Path(Config["Path"]["Save_c"]) / Path(ConfigParams.ARTIFACT_C + str(Config["InputConfig"]["UseFreq"]) + ConfigParams.ENDSWITH_CSV)) + Path(Config["Path"]["Save_c"]) / Path(Filename.ARTIFACT_C + str(Config["InputConfig"]["UseFreq"]) + Params.ENDSWITH_CSV)) try: self.orgBcg = read_csv(Config["Path"]["Input_orgBcg"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.BCG = read_csv(Config["Path"]["Input_BCG"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) except Exception as e: return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Open_Data_Exception"] + "\n" + format_exc()) @@ -1265,7 +1266,7 @@ class Data: return Result().success(info=Constants.ARCHIVE_NOT_EXIST) else: self.Artifact_a = read_csv(Config["Path"]["Save_a"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) try: # 检查体动标签正确性,长度 @@ -1311,7 +1312,7 @@ class Data: 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) + encoding=Params.GBK_ENCODING) except Exception as e: return Result().failure(info=Constants.SAVE_FAILURE + Constants.FAILURE_REASON[ "Save_Exception"] + "\n" + format_exc()) @@ -1325,19 +1326,19 @@ class CustomNavigationToolbar(NavigationToolbar2QT): 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.setFont(QFont(Params.FONT, 14)) self.action_Label_Artifact.setCheckable(True) self.action_Label_Artifact.setShortcut(QCoreApplication.translate( "MainWindow", - ConfigParams.ARTIFACT_LABEL_ACTION_LABEL_ARTIFACT_SHORTCUT_KEY)) + Params.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)) + Params.ACTION_PAN_SHORTCUT_KEY)) self._actions['zoom'].setShortcut(QCoreApplication.translate( "MainWindow", - ConfigParams.ACTION_ZOOM_SHORTCUT_KEY)) + Params.ACTION_ZOOM_SHORTCUT_KEY)) # 用于存储事件连接ID self.cid_mouse_press = None diff --git a/func/Module_bcg_quality_label.py b/func/Module_bcg_quality_label.py index 9fa62be..e6f5217 100644 --- a/func/Module_bcg_quality_label.py +++ b/func/Module_bcg_quality_label.py @@ -16,8 +16,9 @@ from pandas import read_csv, DataFrame from scipy.signal import resample, iirfilter, lfilter from yaml import dump, load, FullLoader +from func.utils.ConfigParams import Filename, Params from func.utils.PublicFunc import PublicFunc -from func.utils.Constants import Constants, ConfigParams +from func.utils.Constants import Constants from func.utils.Result import Result from ui.MainWindow.MainWindow_bcg_quality_label import Ui_MainWindow_bcg_quality_label @@ -83,22 +84,22 @@ class SettingWindow(QMainWindow): self.ui.pushButton_cancel.clicked.connect(self.close) def __read_config__(self): - if not Path(ConfigParams.BCG_QUALITY_LABEL_CONFIG_FILE_PATH).exists(): - with open(ConfigParams.BCG_QUALITY_LABEL_CONFIG_FILE_PATH, "w") as f: - dump(ConfigParams.BCG_QUALITY_LABEL_CONFIG_NEW_CONTENT, f) + if not Path(Params.BCG_QUALITY_LABEL_CONFIG_FILE_PATH).exists(): + with open(Params.BCG_QUALITY_LABEL_CONFIG_FILE_PATH, "w") as f: + dump(Params.BCG_QUALITY_LABEL_CONFIG_NEW_CONTENT, f) - with open(ConfigParams.BCG_QUALITY_LABEL_CONFIG_FILE_PATH, "r") as f: + with open(Params.BCG_QUALITY_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_BCG": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / - Path(str(self.sampID)))), - "Input_Artifact": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + "Input_BCG": str((Path(self.root_path) / Filename.PATH_ORGBCG_ALIGNED / + Path(str(self.sampID)))), + "Input_Artifact": str((Path(self.root_path) / Filename.PATH_LABEL / Path(str(self.sampID)))), - "Save": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + "Save": str((Path(self.root_path) / Filename.PATH_LABEL / Path(str(self.sampID)))), }, "Mode": "30s", @@ -125,7 +126,7 @@ class SettingWindow(QMainWindow): # 保存配置到文件 self.config["InputConfig"]["BCGFreq"] = self.ui.spinBox_input_freq_signal_BCG.value() - with open(ConfigParams.BCG_QUALITY_LABEL_CONFIG_FILE_PATH, "w") as f: + with open(Params.BCG_QUALITY_LABEL_CONFIG_FILE_PATH, "w") as f: dump(self.config, f) self.close() @@ -136,11 +137,11 @@ class SettingWindow(QMainWindow): def __update_ui__(self): self.ui.plainTextEdit_file_path_input_signal_BCG.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + Filename.PATH_ORGBCG_ALIGNED / Path(str(self.sampID)) / - Path(ConfigParams.BCG_SYNC + + Path(Filename.BCG_SYNC + str(self.ui.spinBox_input_freq_signal_BCG.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) def __update_mode__(self): if self.ui.radioButton_30s_mode.isChecked(): @@ -202,7 +203,7 @@ class MainWindow_bcg_quality_label(QMainWindow): 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.xaxis.set_major_formatter(Params.FORMATTER) PublicFunc.__resetAllButton__(self, ButtonState) @@ -252,8 +253,8 @@ class MainWindow_bcg_quality_label(QMainWindow): self.ui.checkBox_type4.clicked.connect(self.__slot_checkBox__) self.ui.checkBox_type5.clicked.connect(self.__slot_checkBox__) - self.ui.pushButton_prev.setShortcut(QCoreApplication.translate("MainWindow", ConfigParams.BCG_QUALITY_LABEL_BTN_PREV_SHORTCUT_KEY)) - self.ui.pushButton_next.setShortcut(QCoreApplication.translate("MainWindow", ConfigParams.BCG_QUALITY_LABEL_BTN_NEXT_SHORTCUT_KEY)) + self.ui.pushButton_prev.setShortcut(QCoreApplication.translate("MainWindow", Params.BCG_QUALITY_LABEL_BTN_PREV_SHORTCUT_KEY)) + self.ui.pushButton_next.setShortcut(QCoreApplication.translate("MainWindow", Params.BCG_QUALITY_LABEL_BTN_NEXT_SHORTCUT_KEY)) @overrides def closeEvent(self, event): @@ -844,7 +845,7 @@ class MainWindow_bcg_quality_label(QMainWindow): if self.ax0 is not None: self.ax0.clear() self.ax0.grid(True) - self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax0.xaxis.set_major_formatter(Params.FORMATTER) def change_tablewidget_mode(self): if Config["Mode"] == "10s": @@ -961,14 +962,14 @@ class Data(): if Path(Config["Path"]["Save"]).is_file(): Config["Path"]["Save"] = str(Path(Config["Path"]["Save"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input_BCG"], ConfigParams.BCG_SYNC, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_BCG"], Filename.BCG_SYNC, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_BCG"] = result.data["path"] Config["InputConfig"]["ThoFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_Artifact"], ConfigParams.ARTIFACT_A, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_Artifact"], Filename.ARTIFACT_A, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Artifact"] = result.data["path"] else: @@ -976,19 +977,19 @@ class Data(): if Config["Mode"] == "30s": Config["Path"]["Save"] = str( - Path(Config["Path"]["Save"]) / Path(ConfigParams.SQ_LABEL_30S + ConfigParams.ENDSWITH_CSV)) + Path(Config["Path"]["Save"]) / Path(Filename.SQ_LABEL_30S + Params.ENDSWITH_CSV)) elif Config["Mode"] == "10s": Config["Path"]["Save"] = str( - Path(Config["Path"]["Save"]) / Path(ConfigParams.SQ_LABEL_10S + ConfigParams.ENDSWITH_CSV)) + Path(Config["Path"]["Save"]) / Path(Filename.SQ_LABEL_10S + Params.ENDSWITH_CSV)) else: raise ValueError("模式不存在") try: self.BCG = read_csv(Config["Path"]["Input_BCG"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.Artifact_a = read_csv(Config["Path"]["Input_Artifact"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) except Exception as e: return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Open_Data_Exception"] + "\n" + format_exc()) @@ -1032,9 +1033,9 @@ class Data(): def get_archive(self): if Config["Mode"] == "30s": - filename = ConfigParams.SQ_LABEL_30S + filename = Filename.SQ_LABEL_30S elif Config["Mode"] == "10s": - filename = ConfigParams.SQ_LABEL_10S + filename = Filename.SQ_LABEL_10S else: raise ValueError("模式不存在") @@ -1050,7 +1051,7 @@ class Data(): return Result().success(info=filename + ":" + Constants.ARCHIVE_NOT_EXIST) else: self.df_label = read_csv(Config["Path"]["Save"], - encoding=ConfigParams.GBK_ENCODING) + encoding=Params.GBK_ENCODING) self.label = self.df_label[Constants.BCG_QUALITY_LABEL_COLUMN_LABEL].astype(str) return Result().success(info=filename + ":" + Constants.ARCHIVE_EXIST) @@ -1088,24 +1089,23 @@ class Data(): Path(Config["Path"]["Save"]).parent.mkdir(parents=True, exist_ok=True) if self.df_label is None: - return Result().failure(info=ConfigParams.RESP_QUALITY_LABEL + Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + return Result().failure(info=Filename.RESP_QUALITY_LABEL + Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) if Config["Mode"] == "30s": - filename = ConfigParams.SQ_LABEL_30S + filename = Filename.SQ_LABEL_30S elif Config["Mode"] == "10s": - filename = ConfigParams.SQ_LABEL_10S + filename = Filename.SQ_LABEL_10S else: raise ValueError("模式不存在") try: - self.df_label.to_csv(Config["Path"]["Save"], index=False, encoding=ConfigParams.GBK_ENCODING) + self.df_label.to_csv(Config["Path"]["Save"], index=False, encoding=Params.GBK_ENCODING) except Exception as e: return Result().failure(info=filename + Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Save_Exception"] + "\n" + format_exc()) return Result().success(info=filename + Constants.SAVE_FINISHED + "标签为:" + str(label)) - @staticmethod def wipe_industrialFrequencyNoise(data, fs): # 设计带阻滤波器(Notch Filter)来滤除49-51Hz的噪声 diff --git a/func/Module_cut_PSG.py b/func/Module_cut_PSG.py index ea39ece..cedb1d6 100644 --- a/func/Module_cut_PSG.py +++ b/func/Module_cut_PSG.py @@ -10,8 +10,9 @@ from overrides import overrides from pandas import read_csv, DataFrame from yaml import dump, load, FullLoader +from func.utils.ConfigParams import Filename, Params from func.utils.PublicFunc import PublicFunc -from func.utils.Constants import Constants, ConfigParams +from func.utils.Constants import Constants from func.utils.Result import Result from ui.MainWindow.MainWindow_cut_PSG import Ui_MainWindow_cut_PSG @@ -62,9 +63,9 @@ class MainWindow_cut_PSG(QMainWindow): Config.update({ "Path": { - "InputFolder": str(Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / Path(str(self.sampID))), - "SaveFolder": str(Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_ALIGNED / Path(str(self.sampID))), - "InputAlignInfo": str(Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / Path(str(self.sampID))) + "InputFolder": str(Path(self.root_path) / Filename.PATH_PSG_TEXT / Path(str(self.sampID))), + "SaveFolder": str(Path(self.root_path) / Filename.PATH_PSG_ALIGNED / Path(str(self.sampID))), + "InputAlignInfo": str(Path(self.root_path) / Filename.PATH_LABEL / Path(str(self.sampID))) } }) @@ -94,11 +95,11 @@ class MainWindow_cut_PSG(QMainWindow): ButtonState["Current"].update(ButtonState["Default"].copy()) def __read_config__(self): - if not Path(ConfigParams.CUT_PSG_CONFIG_FILE_PATH).exists(): - with open(ConfigParams.CUT_PSG_CONFIG_FILE_PATH, "w") as f: - dump(ConfigParams.CUT_PSG_CONFIG_NEW_CONTENT, f) + if not Path(Params.CUT_PSG_CONFIG_FILE_PATH).exists(): + with open(Params.CUT_PSG_CONFIG_FILE_PATH, "w") as f: + dump(Params.CUT_PSG_CONFIG_NEW_CONTENT, f) - with open(ConfigParams.CUT_PSG_CONFIG_FILE_PATH, "r") as f: + with open(Params.CUT_PSG_CONFIG_FILE_PATH, "r") as f: file_config = load(f.read(), Loader=FullLoader) Config.update(file_config) @@ -231,9 +232,9 @@ class Data: return Result().success(info=Constants.CUT_PSG_GET_FILE_AND_FREQ_FINISHED) def open_file(self): - path = str(Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / Path(str(self.sampID))) + path = str(Path(self.root_path) / Filename.PATH_PSG_TEXT / Path(str(self.sampID))) for value in Config["ChannelInput"].values(): - result = PublicFunc.examine_file(path, value, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(path, value, Params.ENDSWITH_TXT) if not result.status: return result @@ -242,20 +243,20 @@ class Data: Config["Path"]["InputAlignInfo"] = str( Path(Config["Path"]["InputAlignInfo"]) / Path( - ConfigParams.PRECISELY_ALIGN_INFO + ConfigParams.ENDSWITH_TXT)) + Filename.PRECISELY_ALIGN_INFO + Params.ENDSWITH_TXT)) try: for key in Config["ChannelInput"].keys(): self.raw[key] = read_csv(Path(Config["Path"]["InputFolder"]) / Path((Config["ChannelInput"][key] + str(self.freq[key]) + Config["EndWith"][key])), - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.SALabel = read_csv(Path(Config["Path"]["InputFolder"]) / Path((Config["LabelInput"]["SA Label"] + Config["EndWith"]["SA Label"])), - encoding=ConfigParams.GBK_ENCODING) + encoding=Params.GBK_ENCODING) self.startTime = read_csv(Path(Config["Path"]["InputFolder"]) / Path((Config["StartTime"] + Config["EndWith"]["StartTime"])), - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.alignInfo = read_csv(Path(Config["Path"]["InputAlignInfo"]), - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.alignInfo = literal_eval(self.alignInfo[0]) except Exception as e: @@ -290,7 +291,7 @@ class Data: try: # 读取SA标签 self.SALabel = self.SALabel.loc[:, ~self.SALabel.columns.str.contains("^Unnamed")] - self.SALabel = self.SALabel[self.SALabel["Event type"].isin(ConfigParams.CUT_PSG_SALABEL_EVENT)] + self.SALabel = self.SALabel[self.SALabel["Event type"].isin(Params.CUT_PSG_SALABEL_EVENT)] self.SALabel["Duration"] = self.SALabel["Duration"].astype(str) self.SALabel["Duration"] = self.SALabel["Duration"].str.replace(r' \(.*?\)', '', regex=True) except Exception: diff --git a/func/Module_detect_Jpeak.py b/func/Module_detect_Jpeak.py index d97eac6..de66a0d 100644 --- a/func/Module_detect_Jpeak.py +++ b/func/Module_detect_Jpeak.py @@ -11,8 +11,9 @@ from overrides import overrides from pandas import read_csv, DataFrame from yaml import dump, load, FullLoader +from func.utils.ConfigParams import Filename, Params from func.utils.PublicFunc import PublicFunc -from func.utils.Constants import Constants, ConfigParams +from func.utils.Constants import Constants from func.utils.Result import Result from func.utils.detect_Jpeak import preprocess, Jpeak_Detection @@ -59,20 +60,20 @@ class SettingWindow(QMainWindow): self.ui.pushButton_cancel.clicked.connect(self.close) def __read_config__(self): - if not Path(ConfigParams.DETECT_JPEAK_CONFIG_FILE_PATH).exists(): - with open(ConfigParams.DETECT_JPEAK_CONFIG_FILE_PATH, "w") as f: - dump(ConfigParams.DETECT_JPEAK_CONFIG_NEW_CONTENT, f) + if not Path(Params.DETECT_JPEAK_CONFIG_FILE_PATH).exists(): + with open(Params.DETECT_JPEAK_CONFIG_FILE_PATH, "w") as f: + dump(Params.DETECT_JPEAK_CONFIG_NEW_CONTENT, f) - with open(ConfigParams.DETECT_JPEAK_CONFIG_FILE_PATH, "r") as f: + with open(Params.DETECT_JPEAK_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": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + "Input": str((Path(self.root_path) / Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)))), - "Save": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + "Save": str((Path(self.root_path) / Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)))) } }) @@ -94,7 +95,7 @@ class SettingWindow(QMainWindow): self.config["InputConfig"]["Freq"] = self.ui.spinBox_input_freq.value() self.config["ModelFolderPath"] = self.ui.plainTextEdit_deepmodel_path.toPlainText() - with open(ConfigParams.DETECT_JPEAK_CONFIG_FILE_PATH, "w") as f: + with open(Params.DETECT_JPEAK_CONFIG_FILE_PATH, "w") as f: dump(self.config, f) self.close() @@ -105,18 +106,18 @@ class SettingWindow(QMainWindow): def __update_ui__(self): self.ui.plainTextEdit_file_path_input.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.BCG_FILTER + + Path(Filename.BCG_FILTER + str(self.ui.spinBox_input_freq.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_save.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_TEXT / + Filename.PATH_PSG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.JPEAK_REVISE + + Path(Filename.JPEAK_REVISE + str(self.ui.spinBox_input_freq.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) class MainWindow_detect_Jpeak(QMainWindow): @@ -169,7 +170,7 @@ class MainWindow_detect_Jpeak(QMainWindow): 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.xaxis.set_major_formatter(Params.FORMATTER) PublicFunc.__resetAllButton__(self, ButtonState) @@ -355,7 +356,7 @@ class MainWindow_detect_Jpeak(QMainWindow): PublicFunc.progressbar_update(self, 1, 1, Constants.SAVING_DATA, 0) total_rows = len(DataFrame(self.data.peak.reshape(-1))) - chunk_size = ConfigParams.DETECT_JPEAK_SAVE_CHUNK_SIZE + chunk_size = Params.DETECT_JPEAK_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) @@ -379,7 +380,7 @@ class MainWindow_detect_Jpeak(QMainWindow): def reset_axes(self): self.ax0.clear() self.ax0.grid(True) - self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax0.xaxis.set_major_formatter(Params.FORMATTER) def update_ui_comboBox_model(self, model_list): self.ui.comboBox_model.clear() @@ -398,18 +399,18 @@ class Data: if Path(Config["Path"]["Input"]).is_file(): Config["Path"]["Input"] = str(Path(Config["Path"]["Input"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input"], ConfigParams.BCG_FILTER, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input"], Filename.BCG_FILTER, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input"] = result.data["path"] Config["InputConfig"]["Freq"] = result.data["freq"] Config["Path"]["Save"] = str( - Path(Config["Path"]["Save"]) / Path(ConfigParams.JPEAK_REVISE + str(Config["InputConfig"]["Freq"]) + ConfigParams.ENDSWITH_TXT)) + Path(Config["Path"]["Save"]) / Path(Filename.JPEAK_REVISE + str(Config["InputConfig"]["Freq"]) + Params.ENDSWITH_TXT)) else: return result try: self.raw_data = read_csv(Config["Path"]["Input"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) except Exception as e: return Result().failure(info=Constants.INPUT_FAILURE + diff --git a/func/Module_detect_Rpeak.py b/func/Module_detect_Rpeak.py index 69e58ca..76d700e 100644 --- a/func/Module_detect_Rpeak.py +++ b/func/Module_detect_Rpeak.py @@ -11,8 +11,9 @@ from overrides import overrides from pandas import read_csv, DataFrame from yaml import dump, load, FullLoader +from func.utils.ConfigParams import Filename, Params from func.utils.PublicFunc import PublicFunc -from func.utils.Constants import Constants, ConfigParams +from func.utils.Constants import Constants from func.utils.Result import Result from func.utils.detect_Rpeak import preprocess, Rpeak_Detection, get_method @@ -59,20 +60,20 @@ class SettingWindow(QMainWindow): self.ui.pushButton_cancel.clicked.connect(self.close) def __read_config__(self): - if not Path(ConfigParams.DETECT_RPEAK_CONFIG_FILE_PATH).exists(): - with open(ConfigParams.DETECT_RPEAK_CONFIG_FILE_PATH, "w") as f: - dump(ConfigParams.DETECT_RPEAK_CONFIG_NEW_CONTENT, f) + if not Path(Params.DETECT_RPEAK_CONFIG_FILE_PATH).exists(): + with open(Params.DETECT_RPEAK_CONFIG_FILE_PATH, "w") as f: + dump(Params.DETECT_RPEAK_CONFIG_NEW_CONTENT, f) - with open(ConfigParams.DETECT_RPEAK_CONFIG_FILE_PATH, "r") as f: + with open(Params.DETECT_RPEAK_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": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / + "Input": str((Path(self.root_path) / Filename.PATH_PSG_TEXT / Path(str(self.sampID)))), - "Save": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / + "Save": str((Path(self.root_path) / Filename.PATH_PSG_TEXT / Path(str(self.sampID)))) } }) @@ -91,7 +92,7 @@ class SettingWindow(QMainWindow): # 保存配置到文件 self.config["InputConfig"]["Freq"] = self.ui.spinBox_input_freq.value() - with open(ConfigParams.DETECT_RPEAK_CONFIG_FILE_PATH, "w") as f: + with open(Params.DETECT_RPEAK_CONFIG_FILE_PATH, "w") as f: dump(self.config, f) self.close() @@ -102,18 +103,18 @@ class SettingWindow(QMainWindow): def __update_ui__(self): self.ui.plainTextEdit_file_path_input.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_TEXT / + Filename.PATH_PSG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.ECG_FILTER + + Path(Filename.ECG_FILTER + str(self.ui.spinBox_input_freq.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_save.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_TEXT / + Filename.PATH_PSG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.RPEAK_FINAL + + Path(Filename.RPEAK_FINAL + str(self.ui.spinBox_input_freq.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) class MainWindow_detect_Rpeak(QMainWindow): @@ -166,11 +167,11 @@ class MainWindow_detect_Rpeak(QMainWindow): 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.xaxis.set_major_formatter(Params.FORMATTER) self.ax0.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) self.ax1 = self.fig.add_subplot(self.gs[1], sharex=self.ax0) self.ax1.grid(True) - self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax1.xaxis.set_major_formatter(Params.FORMATTER) PublicFunc.__resetAllButton__(self, ButtonState) @@ -351,7 +352,7 @@ class MainWindow_detect_Rpeak(QMainWindow): PublicFunc.progressbar_update(self, 1, 1, Constants.SAVING_DATA, 0) total_rows = len(DataFrame(self.data.peak.reshape(-1))) - chunk_size = ConfigParams.DETECT_RPEAK_SAVE_CHUNK_SIZE + chunk_size = Params.DETECT_RPEAK_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) @@ -376,10 +377,10 @@ class MainWindow_detect_Rpeak(QMainWindow): self.ax0.clear() self.ax1.clear() self.ax0.grid(True) - self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax0.xaxis.set_major_formatter(Params.FORMATTER) self.ax0.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) self.ax1.grid(True) - self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax1.xaxis.set_major_formatter(Params.FORMATTER) def update_ui_comboBox_method(self, method_list): self.ui.comboBox_method.clear() @@ -399,18 +400,18 @@ class Data: if Path(Config["Path"]["Input"]).is_file(): Config["Path"]["Input"] = str(Path(Config["Path"]["Input"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input"], ConfigParams.ECG_FILTER, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input"], Filename.ECG_FILTER, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input"] = result.data["path"] Config["InputConfig"]["Freq"] = result.data["freq"] Config["Path"]["Save"] = str( - Path(Config["Path"]["Save"]) / Path(ConfigParams.RPEAK_FINAL + str(Config["InputConfig"]["Freq"]) + ConfigParams.ENDSWITH_TXT)) + Path(Config["Path"]["Save"]) / Path(Filename.RPEAK_FINAL + str(Config["InputConfig"]["Freq"]) + Params.ENDSWITH_TXT)) else: return result try: self.raw_data = read_csv(Config["Path"]["Input"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) except Exception as e: return Result().failure(info=Constants.INPUT_FAILURE + diff --git a/func/Module_label_check.py b/func/Module_label_check.py index 09f957e..14d5517 100644 --- a/func/Module_label_check.py +++ b/func/Module_label_check.py @@ -15,8 +15,9 @@ from pandas import read_csv, DataFrame from scipy.signal import find_peaks from yaml import dump, load, FullLoader +from func.utils.ConfigParams import Filename, Params from func.utils.PublicFunc import PublicFunc -from func.utils.Constants import Constants, ConfigParams +from func.utils.Constants import Constants from func.Filters.Preprocessing import data_preprocess_for_label_check from func.utils.Result import Result @@ -69,11 +70,11 @@ class SettingWindow(QMainWindow): 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) + if not Path(Params.LABEL_CHECK_CONFIG_FILE_PATH).exists(): + with open(Params.LABEL_CHECK_CONFIG_FILE_PATH, "w") as f: + dump(Params.LABEL_CHECK_CONFIG_NEW_CONTENT, f) - with open(ConfigParams.LABEL_CHECK_CONFIG_FILE_PATH, "r") as f: + with open(Params.LABEL_CHECK_CONFIG_FILE_PATH, "r") as f: file_config = load(f.read(), Loader=FullLoader) Config.update(file_config) self.config = file_config @@ -81,13 +82,13 @@ class SettingWindow(QMainWindow): if self.mode == "BCG": Config.update({ "Path": { - "Input_Signal": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / - Path(str(self.sampID)))), - "Input_Peak": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / - Path(str(self.sampID)))), - "Input_Approximately_Align": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + "Input_Signal": str((Path(self.root_path) / Filename.PATH_ORGBCG_TEXT / + Path(str(self.sampID)))), + "Input_Peak": str((Path(self.root_path) / Filename.PATH_ORGBCG_TEXT / + Path(str(self.sampID)))), + "Input_Approximately_Align": str((Path(self.root_path) / Filename.PATH_LABEL / Path(str(self.sampID)))), - "Save": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + "Save": str((Path(self.root_path) / Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)))) }, "Mode": self.mode @@ -95,13 +96,13 @@ class SettingWindow(QMainWindow): elif self.mode == "ECG": Config.update({ "Path": { - "Input_Signal": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / - Path(str(self.sampID)))), - "Input_Peak": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / - Path(str(self.sampID)))), - "Input_Approximately_Align": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + "Input_Signal": str((Path(self.root_path) / Filename.PATH_PSG_TEXT / + Path(str(self.sampID)))), + "Input_Peak": str((Path(self.root_path) / Filename.PATH_PSG_TEXT / + Path(str(self.sampID)))), + "Input_Approximately_Align": str((Path(self.root_path) / Filename.PATH_LABEL / Path(str(self.sampID)))), - "Save": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / + "Save": str((Path(self.root_path) / Filename.PATH_PSG_TEXT / Path(str(self.sampID)))) }, "Mode": self.mode @@ -147,7 +148,7 @@ class SettingWindow(QMainWindow): # 保存配置到文件 self.config["InputConfig"]["Freq"] = self.ui.spinBox_input_freq_signal.value() - with open(ConfigParams.LABEL_CHECK_CONFIG_FILE_PATH, "w") as f: + with open(Params.LABEL_CHECK_CONFIG_FILE_PATH, "w") as f: dump(self.config, f) self.close() @@ -159,47 +160,47 @@ class SettingWindow(QMainWindow): if self.mode == "BCG": self.ui.plainTextEdit_file_path_input_signal.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.BCG_FILTER + + Path(Filename.BCG_FILTER + str(self.ui.spinBox_input_freq_signal.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_input_peak.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.JPEAK_REVISE + + Path(Filename.JPEAK_REVISE + str(self.ui.spinBox_input_freq_signal.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_save.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.JPEAK_REVISE_CORRECTED + + Path(Filename.JPEAK_REVISE_CORRECTED + str(self.ui.spinBox_input_freq_signal.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) elif self.mode == "ECG": self.ui.plainTextEdit_file_path_input_signal.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_TEXT / + Filename.PATH_PSG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.ECG_FILTER + + Path(Filename.ECG_FILTER + str(self.ui.spinBox_input_freq_signal.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_input_peak.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_TEXT / + Filename.PATH_PSG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.RPEAK_FINAL + + Path(Filename.RPEAK_FINAL + str(self.ui.spinBox_input_freq_signal.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_save.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_TEXT / + Filename.PATH_PSG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.RPEAK_FINAL_CORRECTED + + Path(Filename.RPEAK_FINAL_CORRECTED + str(self.ui.spinBox_input_freq_signal.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) else: raise ValueError("模式不存在") @@ -281,11 +282,11 @@ class MainWindow_label_check(QMainWindow): 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.xaxis.set_major_formatter(Params.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) + self.ax1.xaxis.set_major_formatter(Params.FORMATTER) PublicFunc.__resetAllButton__(self, ButtonState) @@ -638,12 +639,12 @@ class MainWindow_label_check(QMainWindow): if self.ax0 is not None: self.ax0.clear() self.ax0.grid(True) - self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax0.xaxis.set_major_formatter(Params.FORMATTER) self.ax0.tick_params(axis='x', colors=Constants.PLOT_COLOR_WHITE) if self.ax1 is not None: self.ax1.clear() self.ax1.grid(True) - self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax1.xaxis.set_major_formatter(Params.FORMATTER) def on_xlim_change(self, event_ax): try: @@ -835,24 +836,24 @@ class MainWindow_label_check(QMainWindow): 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) + alpha=Params.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) + alpha=Params.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) + alpha=Params.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) + alpha=Params.LABEL_CHECK_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_RED) self.ax1.add_patch(self.figToolbar.rect_patch_ax1) # 更新矩形patch的位置和大小 @@ -883,13 +884,13 @@ class Data: def open_file(self): if Config["Mode"] == "BCG": - signal = ConfigParams.BCG_FILTER - peak = ConfigParams.JPEAK_REVISE - save = ConfigParams.JPEAK_REVISE_CORRECTED + signal = Filename.BCG_FILTER + peak = Filename.JPEAK_REVISE + save = Filename.JPEAK_REVISE_CORRECTED elif Config["Mode"] == "ECG": - signal = ConfigParams.ECG_FILTER - peak = ConfigParams.RPEAK_FINAL - save = ConfigParams.RPEAK_FINAL_CORRECTED + signal = Filename.ECG_FILTER + peak = Filename.RPEAK_FINAL + save = Filename.RPEAK_FINAL_CORRECTED else: raise ValueError("模式不存在") if Path(Config["Path"]["Input_Signal"]).is_file(): @@ -901,7 +902,7 @@ class Data: if Path(Config["Path"]["Save"]).is_file(): Config["Path"]["Save"] = str(Path(Config["Path"]["Save"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input_Signal"], signal, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_Signal"], signal, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Signal"] = result.data["path"] Config["InputConfig"]["Freq"] = result.data["freq"] @@ -909,12 +910,12 @@ class Data: return result Config["Path"]["Input_Peak"] = str( - Path(Config["Path"]["Input_Peak"]) / Path(peak + str(Config["InputConfig"]["Freq"]) + ConfigParams.ENDSWITH_TXT)) + Path(Config["Path"]["Input_Peak"]) / Path(peak + str(Config["InputConfig"]["Freq"]) + Params.ENDSWITH_TXT)) Config["Path"]["Input_Approximately_Align"] = str( Path(Config["Path"]["Input_Approximately_Align"]) / Path( - ConfigParams.APPROXIMATELY_ALIGN_INFO + ConfigParams.ENDSWITH_CSV)) + Filename.APPROXIMATELY_ALIGN_INFO + Params.ENDSWITH_CSV)) Config["Path"]["Save"] = str( - Path(Config["Path"]["Save"]) / Path(save + str(Config["InputConfig"]["Freq"]) + ConfigParams.ENDSWITH_TXT)) + Path(Config["Path"]["Save"]) / Path(save + str(Config["InputConfig"]["Freq"]) + Params.ENDSWITH_TXT)) if not Path(Config["Path"]["Input_Peak"]).exists(): return Result().failure(info=Constants.INPUT_FAILURE + "\n" + @@ -923,16 +924,16 @@ class Data: Constants.FAILURE_REASON["Path_Not_Exist"]) if not Path(Config["Path"]["Input_Approximately_Align"]).exists(): return Result().failure(info=Constants.INPUT_FAILURE + "\n" + - ConfigParams.APPROXIMATELY_ALIGN_INFO + ":" + + Filename.APPROXIMATELY_ALIGN_INFO + ":" + Config["Path"]["Input_Approximately_Align"] + Constants.FAILURE_REASON["Path_Not_Exist"]) try: self.raw_data = read_csv(Config["Path"]["Input_Signal"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.original_peak = read_csv(Config["Path"]["Input_Peak"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) except Exception as e: return Result().failure(info=Constants.INPUT_FAILURE + @@ -967,7 +968,7 @@ class Data: return Result().success(info=Constants.ARCHIVE_NOT_EXIST) else: self.corrected_peak = read_csv(Config["Path"]["Save"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) return Result().success(info=Constants.ARCHIVE_EXIST) @@ -1017,19 +1018,19 @@ class CustomNavigationToolbar(NavigationToolbar2QT): 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.setFont(QFont(Params.FONT, 14)) self.action_Label_Multiple.setCheckable(True) self.action_Label_Multiple.setShortcut(QCoreApplication.translate( "MainWindow", - ConfigParams.LABEL_CHECK_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY)) + Params.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)) + Params.ACTION_PAN_SHORTCUT_KEY)) self._actions['zoom'].setShortcut(QCoreApplication.translate( "MainWindow", - ConfigParams.ACTION_ZOOM_SHORTCUT_KEY)) + Params.ACTION_ZOOM_SHORTCUT_KEY)) # 用于存储事件连接ID self.cid_mouse_press = None diff --git a/func/Module_mainwindow.py b/func/Module_mainwindow.py index a8ceee9..3f62ec0 100644 --- a/func/Module_mainwindow.py +++ b/func/Module_mainwindow.py @@ -20,7 +20,8 @@ from func.Module_bcg_quality_label import MainWindow_bcg_quality_label from func.Module_resp_quality_label import MainWindow_resp_quality_label from func.Module_SA_label import MainWindow_SA_label -from func.utils.Constants import Constants, ConfigParams +from func.utils.ConfigParams import Filename, Params +from func.utils.Constants import Constants use("QtAgg") @@ -54,7 +55,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.__read_config__() self.ui.plainTextEdit_root_path.setPlainText(Config["Path"]["Root"]) - self.seek_sampID(Path(Config["Path"]["Root"]) / Path(ConfigParams.PUBLIC_PATH_ORGBCG_TEXT)) + self.seek_sampID(Path(Config["Path"]["Root"]) / Path(Filename.PATH_ORGBCG_TEXT)) self.approximately_align = None self.preprocess = None @@ -86,18 +87,18 @@ class MainWindow(QMainWindow, Ui_Signal_Label): @staticmethod def __read_config__(): - if not Path(ConfigParams.PUBLIC_CONFIG_FILE_PATH).exists(): - Path(ConfigParams.PUBLIC_CONFIG_FILE_PATH).parent.mkdir(parents=True, exist_ok=True) - with open(ConfigParams.PUBLIC_CONFIG_FILE_PATH, "w") as f: - dump(ConfigParams.PUBLIC_CONFIG_NEW_CONTENT, f) + if not Path(Params.PUBLIC_CONFIG_FILE_PATH).exists(): + Path(Params.PUBLIC_CONFIG_FILE_PATH).parent.mkdir(parents=True, exist_ok=True) + with open(Params.PUBLIC_CONFIG_FILE_PATH, "w") as f: + dump(Params.PUBLIC_CONFIG_NEW_CONTENT, f) - with open(ConfigParams.PUBLIC_CONFIG_FILE_PATH, "r") as f: + with open(Params.PUBLIC_CONFIG_FILE_PATH, "r") as f: file_config = load(f.read(), Loader=FullLoader) Config.update(file_config) @staticmethod def __write_config__(): - with open(Path(ConfigParams.PUBLIC_CONFIG_FILE_PATH), "w") as f: + with open(Path(Params.PUBLIC_CONFIG_FILE_PATH), "w") as f: dump(Config, f) def __slot_btn_open__(self): @@ -105,7 +106,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): file_dialog.setFileMode(QFileDialog.Directory) file_dialog.setOption(QFileDialog.ShowDirsOnly, True) if file_dialog.exec_() == QFileDialog.Accepted: - self.seek_sampID(Path(file_dialog.selectedFiles()[0]) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT) + self.seek_sampID(Path(file_dialog.selectedFiles()[0]) / Filename.PATH_ORGBCG_TEXT) self.ui.plainTextEdit_root_path.setPlainText(file_dialog.selectedFiles()[0]) # 修改配置 diff --git a/func/Module_precisely_align.py b/func/Module_precisely_align.py index 651cff8..4093469 100644 --- a/func/Module_precisely_align.py +++ b/func/Module_precisely_align.py @@ -17,8 +17,9 @@ from resampy import resample from scipy.signal import find_peaks from yaml import dump, load, FullLoader +from func.utils.ConfigParams import Filename, Params from func.utils.PublicFunc import PublicFunc -from func.utils.Constants import Constants, ConfigParams +from func.utils.Constants import Constants from func.utils.Result import Result from ui.MainWindow.MainWindow_precisely_align import Ui_MainWindow_precisely_align @@ -102,40 +103,40 @@ class SettingWindow(QMainWindow): self.ui.pushButton_cancel.clicked.connect(self.close) def __read_config__(self): - if not Path(ConfigParams.PRECISELY_ALIGN_CONFIG_FILE_PATH).exists(): - with open(ConfigParams.PRECISELY_ALIGN_CONFIG_FILE_PATH, "w") as f: - dump(ConfigParams.PRECISELY_ALIGN_CONFIG_NEW_CONTENT, f) + if not Path(Params.PRECISELY_ALIGN_CONFIG_FILE_PATH).exists(): + with open(Params.PRECISELY_ALIGN_CONFIG_FILE_PATH, "w") as f: + dump(Params.PRECISELY_ALIGN_CONFIG_NEW_CONTENT, f) - with open(ConfigParams.PRECISELY_ALIGN_CONFIG_FILE_PATH, "r") as f: + with open(Params.PRECISELY_ALIGN_CONFIG_FILE_PATH, "r") as f: file_config = load(f.read(), Loader=FullLoader) Config.update(file_config) self.config = file_config Config.update({ "Path": { - "Input_OrgBCG": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + "Input_OrgBCG": str((Path(self.root_path) / Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)))), - "Input_BCG": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + "Input_BCG": str((Path(self.root_path) / Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)))), - "Input_Jpeak": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + "Input_Jpeak": str((Path(self.root_path) / Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)))), - "Input_ECG": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / + "Input_ECG": str((Path(self.root_path) / Filename.PATH_PSG_TEXT / Path(str(self.sampID)))), - "Input_Rpeak": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / + "Input_Rpeak": str((Path(self.root_path) / Filename.PATH_PSG_TEXT / Path(str(self.sampID)))), - "Input_Approximately_Align": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + "Input_Approximately_Align": str((Path(self.root_path) / Filename.PATH_LABEL / Path(str(self.sampID)))), - "Save_AlignInfo": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / - Path(str(self.sampID)))), - "Save_OrgBCG": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + "Save_AlignInfo": str((Path(self.root_path) / Filename.PATH_LABEL / + Path(str(self.sampID)))), + "Save_OrgBCG": str((Path(self.root_path) / Filename.PATH_ORGBCG_ALIGNED / Path(str(self.sampID)))), - "Save_BCG": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + "Save_BCG": str((Path(self.root_path) / Filename.PATH_ORGBCG_ALIGNED / Path(str(self.sampID)))), - "Save_ECG": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + "Save_ECG": str((Path(self.root_path) / Filename.PATH_PSG_ALIGNED / Path(str(self.sampID)))), - "Save_Jpeak": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / - Path(str(self.sampID)))), - "Save_Rpeak": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + "Save_Jpeak": str((Path(self.root_path) / Filename.PATH_ORGBCG_ALIGNED / + Path(str(self.sampID)))), + "Save_Rpeak": str((Path(self.root_path) / Filename.PATH_PSG_ALIGNED / Path(str(self.sampID)))) }, "Coordinate": { @@ -221,7 +222,7 @@ class SettingWindow(QMainWindow): self.config["InputConfig"]["BCGFreq"] = self.ui.spinBox_input_freq_BCG.value() self.config["InputConfig"]["ECGFreq"] = self.ui.spinBox_input_freq_ECG.value() - with open(ConfigParams.PRECISELY_ALIGN_CONFIG_FILE_PATH, "w") as f: + with open(Params.PRECISELY_ALIGN_CONFIG_FILE_PATH, "w") as f: dump(self.config, f) self.close() @@ -232,60 +233,60 @@ class SettingWindow(QMainWindow): def __update_ui__(self): self.ui.plainTextEdit_file_path_input_orgBcg.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.ORGBCG_RAW + + Path(Filename.ORGBCG_RAW + str(self.ui.spinBox_input_freq_orgBcg.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_input_BCG.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.BCG_FILTER + + Path(Filename.BCG_FILTER + str(self.ui.spinBox_input_freq_BCG.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_input_ECG.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_TEXT / + Filename.PATH_PSG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.ECG_FILTER + + Path(Filename.ECG_FILTER + str(self.ui.spinBox_input_freq_ECG.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_save_orgBcg.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + Filename.PATH_ORGBCG_ALIGNED / Path(str(self.sampID)) / - Path(ConfigParams.ORGBCG_SYNC + + Path(Filename.ORGBCG_SYNC + str(self.ui.spinBox_input_freq_orgBcg.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_save_BCG.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + Filename.PATH_ORGBCG_ALIGNED / Path(str(self.sampID)) / - Path(ConfigParams.BCG_SYNC + + Path(Filename.BCG_SYNC + str(self.ui.spinBox_input_freq_BCG.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_save_ECG.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + Filename.PATH_PSG_ALIGNED / Path(str(self.sampID)) / - Path(ConfigParams.ECG_SYNC + + Path(Filename.ECG_SYNC + str(self.ui.spinBox_input_freq_ECG.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_save_Jpeak.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + Filename.PATH_ORGBCG_ALIGNED / Path(str(self.sampID)) / - Path(ConfigParams.JPEAK_SYNC + + Path(Filename.JPEAK_SYNC + str(self.ui.spinBox_input_freq_BCG.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_save_Rpeak.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + Filename.PATH_PSG_ALIGNED / Path(str(self.sampID)) / - Path(ConfigParams.RPEAK_SYNC + + Path(Filename.RPEAK_SYNC + str(self.ui.spinBox_input_freq_ECG.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) class MainWindow_precisely_align(QMainWindow): @@ -463,10 +464,10 @@ class MainWindow_precisely_align(QMainWindow): self.fig.subplots_adjust(top=0.95, bottom=0.05, right=0.98, left=0.05, hspace=0.15, wspace=0) self.ax0 = self.fig.add_subplot(self.gs[0]) self.ax0.grid(True) - self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax0.xaxis.set_major_formatter(Params.FORMATTER) self.ax1 = self.fig.add_subplot(self.gs[1], sharex=self.ax0, sharey=self.ax0) self.ax1.grid(True) - self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax1.xaxis.set_major_formatter(Params.FORMATTER) Jpeak = self.data.Jpeak[:-2] Rpeak = self.data.Rpeak[:-2] @@ -500,16 +501,16 @@ class MainWindow_precisely_align(QMainWindow): self.fig.subplots_adjust(top=0.88, bottom=0.05, right=0.98, left=0.05, hspace=0.15, wspace=0.15) self.ax0 = self.fig.add_subplot(self.gs[0]) self.ax0.grid(True) - self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax0.xaxis.set_major_formatter(Params.FORMATTER) self.ax1 = self.fig.add_subplot(self.gs[2]) self.ax1.grid(True) - self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax1.xaxis.set_major_formatter(Params.FORMATTER) self.ax2 = self.fig.add_subplot(self.gs[1]) self.ax2.grid(True) - self.ax2.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax2.xaxis.set_major_formatter(Params.FORMATTER) self.ax3 = self.fig.add_subplot(self.gs[3]) self.ax3.grid(True) - self.ax3.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax3.xaxis.set_major_formatter(Params.FORMATTER) self.ax0.set_title( "front\ncorre_IIV: {}, corre_II: {}\nsame_sign_rate:{}, total_time_ratio: {}\nshift: {}, alignment offset: {} seconds\noffset_interval: {}, anchor_J: {}, anchor_R: {}".format( @@ -566,7 +567,7 @@ class MainWindow_precisely_align(QMainWindow): self.fig.subplots_adjust(top=0.95, bottom=0.05, right=0.98, left=0.05, hspace=0, wspace=0) self.ax4 = self.fig.add_subplot(self.gs[0]) self.ax4.grid(True) - self.ax4.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax4.xaxis.set_major_formatter(Params.FORMATTER) self.ax4.set_title("offset correct") self.ax4.plot(plot_element["cut_ECG"], color=Constants.PLOT_COLOR_GREEN, label=Constants.PRECISELY_ALIGN_PLOT_LABEL_ECG) @@ -587,7 +588,7 @@ class MainWindow_precisely_align(QMainWindow): self.fig.subplots_adjust(top=0.95, bottom=0.05, right=0.98, left=0.05, hspace=0, wspace=0) self.ax4 = self.fig.add_subplot(self.gs[0]) self.ax4.grid(True) - self.ax4.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax4.xaxis.set_major_formatter(Params.FORMATTER) self.ax4.set_title("result preview") self.ax4.plot(self.data.cut_ECG, color=Constants.PLOT_COLOR_GREEN, label=Constants.PRECISELY_ALIGN_PLOT_LABEL_ECG) @@ -839,7 +840,7 @@ class MainWindow_precisely_align(QMainWindow): PublicFunc.progressbar_update(self, 2, 6, Constants.PRECISELY_ALIGN_SAVING_RES_ORGBCG, 0) total_rows = len(DataFrame(self.data.res_orgBcg.reshape(-1))) - chunk_size = ConfigParams.PRECISELY_ALIGN_SAVE_CHUNK_SIZE + chunk_size = Params.PRECISELY_ALIGN_SAVE_CHUNK_SIZE with open(Config["Path"]["Save_OrgBCG"], 'w') as f: for start in range(0, total_rows, chunk_size): end = min(start + chunk_size, total_rows) @@ -861,7 +862,7 @@ class MainWindow_precisely_align(QMainWindow): PublicFunc.progressbar_update(self, 3, 6, Constants.PRECISELY_ALIGN_SAVING_RES_BCG, 0) total_rows = len(DataFrame(self.data.res_BCG.reshape(-1))) - chunk_size = ConfigParams.PRECISELY_ALIGN_SAVE_CHUNK_SIZE + chunk_size = Params.PRECISELY_ALIGN_SAVE_CHUNK_SIZE with open(Config["Path"]["Save_BCG"], 'w') as f: for start in range(0, total_rows, chunk_size): end = min(start + chunk_size, total_rows) @@ -883,7 +884,7 @@ class MainWindow_precisely_align(QMainWindow): PublicFunc.progressbar_update(self, 4, 6, Constants.PRECISELY_ALIGN_SAVING_CUT_ECG, 0) total_rows = len(DataFrame(self.data.cut_ECG.reshape(-1))) - chunk_size = ConfigParams.PRECISELY_ALIGN_SAVE_CHUNK_SIZE + chunk_size = Params.PRECISELY_ALIGN_SAVE_CHUNK_SIZE with open(Config["Path"]["Save_ECG"], 'w') as f: for start in range(0, total_rows, chunk_size): end = min(start + chunk_size, total_rows) @@ -905,7 +906,7 @@ class MainWindow_precisely_align(QMainWindow): PublicFunc.progressbar_update(self, 5, 6, Constants.PRECISELY_ALIGN_SAVING_CUT_JPEAK, 0) total_rows = len(DataFrame(self.data.cut_Jpeak.reshape(-1))) - chunk_size = ConfigParams.PRECISELY_ALIGN_SAVE_PEAK_CHUNK_SIZE + chunk_size = Params.PRECISELY_ALIGN_SAVE_PEAK_CHUNK_SIZE with open(Config["Path"]["Save_Jpeak"], 'w') as f: for start in range(0, total_rows, chunk_size): end = min(start + chunk_size, total_rows) @@ -927,7 +928,7 @@ class MainWindow_precisely_align(QMainWindow): PublicFunc.progressbar_update(self, 6, 6, Constants.PRECISELY_ALIGN_SAVING_CUT_RPEAK, 0) total_rows = len(DataFrame(self.data.cut_Rpeak.reshape(-1))) - chunk_size = ConfigParams.PRECISELY_ALIGN_SAVE_PEAK_CHUNK_SIZE + chunk_size = Params.PRECISELY_ALIGN_SAVE_PEAK_CHUNK_SIZE with open(Config["Path"]["Save_Rpeak"], 'w') as f: for start in range(0, total_rows, chunk_size): end = min(start + chunk_size, total_rows) @@ -1014,23 +1015,23 @@ class MainWindow_precisely_align(QMainWindow): if self.ax0 is not None: self.ax0.clear() self.ax0.grid(True) - self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax0.xaxis.set_major_formatter(Params.FORMATTER) if self.ax1 is not None: self.ax1.clear() self.ax1.grid(True) - self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax1.xaxis.set_major_formatter(Params.FORMATTER) if self.ax2 is not None: self.ax2.clear() self.ax2.grid(True) - self.ax2.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax2.xaxis.set_major_formatter(Params.FORMATTER) if self.ax3 is not None: self.ax3.clear() self.ax3.grid(True) - self.ax3.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax3.xaxis.set_major_formatter(Params.FORMATTER) if self.ax4 is not None: self.ax4.clear() self.ax4.grid(True) - self.ax4.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax4.xaxis.set_major_formatter(Params.FORMATTER) def redraw_calculate_coordination(self, plot_element=None): if plot_element is not None and plot_element["mode"] == "select": @@ -1327,26 +1328,26 @@ class MainWindow_precisely_align(QMainWindow): if self.figToolbar.ax0_BCG_rectangle_front is None and self.is_left_button_pressed: self.figToolbar.ax0_BCG_rectangle_front = patches.Rectangle((0, 0), 1, 1, fill=True, - alpha=ConfigParams.PRECISELY_ALIGN_LABEL_TRANSPARENCY, + alpha=Params.PRECISELY_ALIGN_LABEL_TRANSPARENCY, color=Constants.PLOT_COLOR_PINK) self.ax0.add_patch(self.figToolbar.ax0_BCG_rectangle_front) if self.figToolbar.ax0_BCG_rectangle_back is None and self.is_left_button_pressed: self.figToolbar.ax0_BCG_rectangle_back = patches.Rectangle((0, 0), 1, 1, - fill=True, - alpha=ConfigParams.PRECISELY_ALIGN_LABEL_TRANSPARENCY, - color=Constants.PLOT_COLOR_PINK) + fill=True, + alpha=Params.PRECISELY_ALIGN_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_PINK) self.ax0.add_patch(self.figToolbar.ax0_BCG_rectangle_back) if self.figToolbar.ax1_ECG_rectangle_front is None and self.is_left_button_pressed: self.figToolbar.ax1_ECG_rectangle_front = patches.Rectangle((0, 0), 1, 1, fill=True, - alpha=ConfigParams.PRECISELY_ALIGN_LABEL_TRANSPARENCY, + alpha=Params.PRECISELY_ALIGN_LABEL_TRANSPARENCY, color=Constants.PLOT_COLOR_PINK) self.ax1.add_patch(self.figToolbar.ax1_ECG_rectangle_front) if self.figToolbar.ax1_ECG_rectangle_back is None and self.is_left_button_pressed: self.figToolbar.ax1_ECG_rectangle_back = patches.Rectangle((0, 0), 1, 1, - fill=True, - alpha=ConfigParams.PRECISELY_ALIGN_LABEL_TRANSPARENCY, - color=Constants.PLOT_COLOR_PINK) + fill=True, + alpha=Params.PRECISELY_ALIGN_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_PINK) self.ax1.add_patch(self.figToolbar.ax1_ECG_rectangle_back) if self.ui.radioButton_BCG_front.isChecked(): @@ -1454,7 +1455,7 @@ class Data: if Path(Config["Path"]["Input_Approximately_Align"]).is_file(): Config["Path"]["Input_Approximately_Align"] = str(Path(Config["Path"]["Input_Approximately_Align"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input_OrgBCG"], ConfigParams.ORGBCG_RAW, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_OrgBCG"], Filename.ORGBCG_RAW, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_OrgBCG"] = result.data["path"] Config["InputConfig"]["orgBcgFreq"] = result.data["freq"] @@ -1462,29 +1463,29 @@ class Data: return result Config["Path"]["Input_Approximately_Align"] = str( Path(Config["Path"]["Input_Approximately_Align"]) / Path( - ConfigParams.APPROXIMATELY_ALIGN_INFO + ConfigParams.ENDSWITH_CSV)) + Filename.APPROXIMATELY_ALIGN_INFO + Params.ENDSWITH_CSV)) Config["Path"]["Save_AlignInfo"] = str( Path(Config["Path"]["Save_AlignInfo"]) / Path( - ConfigParams.PRECISELY_ALIGN_INFO + ConfigParams.ENDSWITH_TXT)) + Filename.PRECISELY_ALIGN_INFO + Params.ENDSWITH_TXT)) Config["Path"]["Save_OrgBCG"] = str( Path(Config["Path"]["Save_OrgBCG"]) / Path( - ConfigParams.ORGBCG_SYNC + str(Config["InputConfig"]["orgBcgFreq"]) + ConfigParams.ENDSWITH_TXT)) - result = PublicFunc.examine_file(Config["Path"]["Input_BCG"], ConfigParams.BCG_FILTER, ConfigParams.ENDSWITH_TXT) + Filename.ORGBCG_SYNC + str(Config["InputConfig"]["orgBcgFreq"]) + Params.ENDSWITH_TXT)) + result = PublicFunc.examine_file(Config["Path"]["Input_BCG"], Filename.BCG_FILTER, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_BCG"] = result.data["path"] Config["InputConfig"]["BCGFreq"] = result.data["freq"] else: return result Config["Path"]["Input_Jpeak"] = str( - Path(Config["Path"]["Input_Jpeak"]) / Path(ConfigParams.JPEAK_REVISE_CORRECTED + str( - Config["InputConfig"]["BCGFreq"]) + ConfigParams.ENDSWITH_TXT)) + Path(Config["Path"]["Input_Jpeak"]) / Path(Filename.JPEAK_REVISE_CORRECTED + str( + Config["InputConfig"]["BCGFreq"]) + Params.ENDSWITH_TXT)) Config["Path"]["Save_BCG"] = str( Path(Config["Path"]["Save_BCG"]) / Path( - ConfigParams.BCG_SYNC + str(Config["InputConfig"]["BCGFreq"]) + ConfigParams.ENDSWITH_TXT)) + Filename.BCG_SYNC + str(Config["InputConfig"]["BCGFreq"]) + Params.ENDSWITH_TXT)) Config["Path"]["Save_Jpeak"] = str( Path(Config["Path"]["Save_Jpeak"]) / Path( - ConfigParams.JPEAK_SYNC + str(Config["InputConfig"]["BCGFreq"]) + ConfigParams.ENDSWITH_TXT)) - result = PublicFunc.examine_file(Config["Path"]["Input_ECG"], ConfigParams.ECG_FILTER, ConfigParams.ENDSWITH_TXT) + Filename.JPEAK_SYNC + str(Config["InputConfig"]["BCGFreq"]) + Params.ENDSWITH_TXT)) + result = PublicFunc.examine_file(Config["Path"]["Input_ECG"], Filename.ECG_FILTER, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_ECG"] = result.data["path"] Config["InputConfig"]["ECGFreq"] = result.data["freq"] @@ -1492,45 +1493,45 @@ class Data: return result Config["Path"]["Input_Rpeak"] = str( Path(Config["Path"]["Input_Rpeak"]) / Path( - ConfigParams.RPEAK_FINAL_CORRECTED + str(Config["InputConfig"]["ECGFreq"]) + ConfigParams.ENDSWITH_TXT)) + Filename.RPEAK_FINAL_CORRECTED + str(Config["InputConfig"]["ECGFreq"]) + Params.ENDSWITH_TXT)) Config["Path"]["Save_ECG"] = str( Path(Config["Path"]["Save_ECG"]) / Path( - ConfigParams.ECG_SYNC + str(Config["InputConfig"]["ECGFreq"]) + ConfigParams.ENDSWITH_TXT)) + Filename.ECG_SYNC + str(Config["InputConfig"]["ECGFreq"]) + Params.ENDSWITH_TXT)) Config["Path"]["Save_Rpeak"] = str( Path(Config["Path"]["Save_Rpeak"]) / Path( - ConfigParams.RPEAK_SYNC + str(Config["InputConfig"]["ECGFreq"]) + ConfigParams.ENDSWITH_TXT)) + Filename.RPEAK_SYNC + str(Config["InputConfig"]["ECGFreq"]) + Params.ENDSWITH_TXT)) if not Path(Config["Path"]["Input_Jpeak"]).exists(): return Result().failure(info=Constants.INPUT_FAILURE + "\n" + - ConfigParams.JPEAK_REVISE_CORRECTED + ":" + + Filename.JPEAK_REVISE_CORRECTED + ":" + Config["Path"]["Input_Jpeak"] + Constants.FAILURE_REASON["Path_Not_Exist"]) if not Path(Config["Path"]["Input_Rpeak"]).exists(): return Result().failure(info=Constants.INPUT_FAILURE + "\n" + - ConfigParams.RPEAK_FINAL_CORRECTED + ":" + + Filename.RPEAK_FINAL_CORRECTED + ":" + Config["Path"]["Input_Rpeak"] + Constants.FAILURE_REASON["Path_Not_Exist"]) if not Path(Config["Path"]["Input_Approximately_Align"]).exists(): return Result().failure(info=Constants.INPUT_FAILURE + "\n" + - ConfigParams.APPROXIMATELY_ALIGN_INFO + ":" + + Filename.APPROXIMATELY_ALIGN_INFO + ":" + Config["Path"]["Input_Approximately_Align"] + Constants.FAILURE_REASON["Path_Not_Exist"]) try: self.raw_orgBcg = read_csv(Config["Path"]["Input_OrgBCG"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.raw_BCG = read_csv(Config["Path"]["Input_BCG"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.Jpeak = read_csv(Config["Path"]["Input_Jpeak"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.raw_ECG = read_csv(Config["Path"]["Input_ECG"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.Rpeak = read_csv(Config["Path"]["Input_Rpeak"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.argmax_BCG = np_argmax(self.raw_BCG) self.argmax_ECG = np_argmax(self.raw_ECG) @@ -2004,19 +2005,19 @@ class CustomNavigationToolbar(NavigationToolbar2QT): super().__init__(canvas, parent) # 初始化画框工具栏 self.action_Get_Range = QAction(Constants.PRECISELY_ALIGN_ACTION_GET_RANGE_NAME, self) - self.action_Get_Range.setFont(QFont(ConfigParams.FONT, 14)) + self.action_Get_Range.setFont(QFont(Params.FONT, 14)) self.action_Get_Range.setCheckable(True) self.action_Get_Range.setShortcut(QCoreApplication.translate( "MainWindow", - ConfigParams.PRECISELY_ALIGN_ACTION_GET_RANGE_SHORTCUT_KEY)) + Params.PRECISELY_ALIGN_ACTION_GET_RANGE_SHORTCUT_KEY)) self.insertAction(self._actions['pan'], self.action_Get_Range) self._actions['pan'].setShortcut(QCoreApplication.translate( "MainWindow", - ConfigParams.ACTION_PAN_SHORTCUT_KEY)) + Params.ACTION_PAN_SHORTCUT_KEY)) self._actions['zoom'].setShortcut(QCoreApplication.translate( "MainWindow", - ConfigParams.ACTION_ZOOM_SHORTCUT_KEY)) + Params.ACTION_ZOOM_SHORTCUT_KEY)) # 用于存储事件连接ID self.cid_mouse_press = None diff --git a/func/Module_preprocess.py b/func/Module_preprocess.py index 7be9aaa..f751ef5 100644 --- a/func/Module_preprocess.py +++ b/func/Module_preprocess.py @@ -12,8 +12,9 @@ from pandas import read_csv, DataFrame from scipy.signal import resample from yaml import dump, load, FullLoader +from func.utils.ConfigParams import Filename, Params from func.utils.PublicFunc import PublicFunc -from func.utils.Constants import Constants, ConfigParams +from func.utils.Constants import Constants from func.Filters.Preprocessing import Butterworth_for_BCG_PreProcess, Butterworth_for_ECG_PreProcess from func.utils.Result import Result @@ -62,11 +63,11 @@ class SettingWindow(QMainWindow): self.ui.pushButton_cancel.clicked.connect(self.close) def __read_config__(self): - if not Path(ConfigParams.PREPROCESS_CONFIG_FILE_PATH).exists(): - with open(ConfigParams.PREPROCESS_CONFIG_FILE_PATH, "w") as f: - dump(ConfigParams.PREPROCESS_CONFIG_NEW_CONTENT, f) + if not Path(Params.PREPROCESS_CONFIG_FILE_PATH).exists(): + with open(Params.PREPROCESS_CONFIG_FILE_PATH, "w") as f: + dump(Params.PREPROCESS_CONFIG_NEW_CONTENT, f) - with open(ConfigParams.PREPROCESS_CONFIG_FILE_PATH, "r") as f: + with open(Params.PREPROCESS_CONFIG_FILE_PATH, "r") as f: file_config = load(f.read(), Loader=FullLoader) Config.update(file_config) self.config = file_config @@ -74,9 +75,9 @@ class SettingWindow(QMainWindow): if self.mode == "BCG": Config.update({ "Path": { - "Input": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + "Input": str((Path(self.root_path) / Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)))), - "Save": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + "Save": str((Path(self.root_path) / Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)))) }, "Mode": self.mode @@ -84,9 +85,9 @@ class SettingWindow(QMainWindow): elif self.mode == "ECG": Config.update({ "Path": { - "Input": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / + "Input": str((Path(self.root_path) / Filename.PATH_PSG_TEXT / Path(str(self.sampID)))), - "Save": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / + "Save": str((Path(self.root_path) / Filename.PATH_PSG_TEXT / Path(str(self.sampID)))) }, "Mode": self.mode @@ -111,7 +112,7 @@ class SettingWindow(QMainWindow): self.config["InputConfig"]["Freq"] = self.ui.spinBox_input_freq.value() self.config["OutputConfig"]["Freq"] = self.ui.spinBox_output_freq.value() - with open(ConfigParams.PREPROCESS_CONFIG_FILE_PATH, "w") as f: + with open(Params.PREPROCESS_CONFIG_FILE_PATH, "w") as f: dump(self.config, f) self.close() @@ -123,33 +124,33 @@ class SettingWindow(QMainWindow): if self.mode == "BCG": self.ui.plainTextEdit_file_path_input.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.ORGBCG_RAW + + Path(Filename.ORGBCG_RAW + str(self.ui.spinBox_input_freq.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_save.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_ORGBCG_TEXT / + Filename.PATH_ORGBCG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.BCG_FILTER + + Path(Filename.BCG_FILTER + str(self.ui.spinBox_output_freq.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) elif self.mode == "ECG": self.ui.plainTextEdit_file_path_input.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_TEXT / + Filename.PATH_PSG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.ECG_RAW + + Path(Filename.ECG_RAW + str(self.ui.spinBox_input_freq.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_save.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_TEXT / + Filename.PATH_PSG_TEXT / Path(str(self.sampID)) / - Path(ConfigParams.ECG_FILTER + + Path(Filename.ECG_FILTER + str(self.ui.spinBox_output_freq.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) else: raise ValueError("模式不存在") @@ -205,7 +206,7 @@ class MainWindow_preprocess(QMainWindow): 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.xaxis.set_major_formatter(Params.FORMATTER) PublicFunc.__resetAllButton__(self, ButtonState) @@ -364,7 +365,7 @@ class MainWindow_preprocess(QMainWindow): PublicFunc.progressbar_update(self, 1, 1, Constants.SAVING_DATA, 0) total_rows = len(DataFrame(self.data.processed_data.reshape(-1))) - chunk_size = ConfigParams.PREPROCESS_SAVE_CHUNK_SIZE + chunk_size = Params.PREPROCESS_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) @@ -389,7 +390,7 @@ class MainWindow_preprocess(QMainWindow): if self.ax0 is not None: self.ax0.clear() self.ax0.grid(True) - self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax0.xaxis.set_major_formatter(Params.FORMATTER) class Data: @@ -400,28 +401,28 @@ class Data: def open_file(self): if Config["Mode"] == "BCG": - signal = ConfigParams.ORGBCG_RAW - save = ConfigParams.BCG_FILTER + signal = Filename.ORGBCG_RAW + save = Filename.BCG_FILTER elif Config["Mode"] == "ECG": - signal = ConfigParams.ECG_RAW - save = ConfigParams.ECG_FILTER + signal = Filename.ECG_RAW + save = Filename.ECG_FILTER else: raise ValueError("模式不存在") if Path(Config["Path"]["Input"]).is_file(): Config["Path"]["Input"] = str(Path(Config["Path"]["Input"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input"], signal, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input"], signal, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input"] = result.data["path"] Config["InputConfig"]["Freq"] = result.data["freq"] Config["Path"]["Save"] = str( - Path(Config["Path"]["Save"]) / Path(save + str(Config["OutputConfig"]["Freq"]) + ConfigParams.ENDSWITH_TXT)) + Path(Config["Path"]["Save"]) / Path(save + str(Config["OutputConfig"]["Freq"]) + Params.ENDSWITH_TXT)) else: return result try: self.raw_data = read_csv(Config["Path"]["Input"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) except Exception as e: return Result().failure(info=Constants.INPUT_FAILURE + diff --git a/func/Module_resp_quality_label.py b/func/Module_resp_quality_label.py index a041988..e6ab281 100644 --- a/func/Module_resp_quality_label.py +++ b/func/Module_resp_quality_label.py @@ -15,9 +15,9 @@ from pandas import read_csv, DataFrame from scipy.signal import find_peaks, resample from yaml import dump, load, FullLoader +from func.utils.ConfigParams import Filename, Params from func.utils.PublicFunc import PublicFunc -from func.utils.Constants import Constants, ConfigParams -from func.Filters.Preprocessing import Butterworth_for_BCG_PreProcess, Butterworth_for_ECG_PreProcess +from func.utils.Constants import Constants from func.utils.Result import Result from func.utils.resp_quality_label import pre_process, get_slice, evaluate_quality from func.utils.resp_quality_label_filter import get_bandpass_bcgsignal @@ -82,26 +82,26 @@ class SettingWindow(QMainWindow): self.ui.pushButton_cancel.clicked.connect(self.close) def __read_config__(self): - if not Path(ConfigParams.RESP_QUALITY_LABEL_CONFIG_FILE_PATH).exists(): - with open(ConfigParams.RESP_QUALITY_LABEL_CONFIG_FILE_PATH, "w") as f: - dump(ConfigParams.RESP_QUALITY_LABEL_CONFIG_NEW_CONTENT, f) + if not Path(Params.RESP_QUALITY_LABEL_CONFIG_FILE_PATH).exists(): + with open(Params.RESP_QUALITY_LABEL_CONFIG_FILE_PATH, "w") as f: + dump(Params.RESP_QUALITY_LABEL_CONFIG_NEW_CONTENT, f) - with open(ConfigParams.RESP_QUALITY_LABEL_CONFIG_FILE_PATH, "r") as f: + with open(Params.RESP_QUALITY_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 / + "Input_OrgBCG": str((Path(self.root_path) / Filename.PATH_ORGBCG_ALIGNED / Path(str(self.sampID)))), - "Input_Tho": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + "Input_Tho": str((Path(self.root_path) / Filename.PATH_PSG_ALIGNED / Path(str(self.sampID)))), - "Input_Artifact": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + "Input_Artifact": str((Path(self.root_path) / Filename.PATH_LABEL / Path(str(self.sampID)))), - "Save_Resp_quality_label": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / - Path(str(self.sampID)))), - "Save_Tho_peak": str((Path(self.root_path) / ConfigParams.PUBLIC_PATH_LABEL / + "Save_Resp_quality_label": str((Path(self.root_path) / Filename.PATH_LABEL / + Path(str(self.sampID)))), + "Save_Tho_peak": str((Path(self.root_path) / Filename.PATH_LABEL / Path(str(self.sampID)))) }, "CurrentPartNum": 1, @@ -133,7 +133,7 @@ class SettingWindow(QMainWindow): self.config["InputConfig"]["OrgBCGFreq"] = self.ui.spinBox_input_freq_signal_OrgBCG.value() self.config["InputConfig"]["ThoFreq"] = self.ui.spinBox_input_freq_signal_Tho.value() - with open(ConfigParams.RESP_QUALITY_LABEL_CONFIG_FILE_PATH, "w") as f: + with open(Params.RESP_QUALITY_LABEL_CONFIG_FILE_PATH, "w") as f: dump(self.config, f) self.close() @@ -144,18 +144,18 @@ class SettingWindow(QMainWindow): def __update_ui__(self): self.ui.plainTextEdit_file_path_input_signal_OrgBCG.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_ORGBCG_ALIGNED / + Filename.PATH_ORGBCG_ALIGNED / Path(str(self.sampID)) / - Path(ConfigParams.ORGBCG_SYNC + + Path(Filename.ORGBCG_SYNC + str(self.ui.spinBox_input_freq_signal_OrgBCG.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) self.ui.plainTextEdit_file_path_input_signal_Tho.setPlainText( str((Path(self.root_path) / - ConfigParams.PUBLIC_PATH_PSG_ALIGNED / + Filename.PATH_PSG_ALIGNED / Path(str(self.sampID)) / - Path(ConfigParams.THO_SYNC + + Path(Filename.THO_SYNC + str(self.ui.spinBox_input_freq_signal_Tho.value()) + - ConfigParams.ENDSWITH_TXT)))) + Params.ENDSWITH_TXT)))) class MainWindow_resp_quality_label(QMainWindow): @@ -227,10 +227,10 @@ class MainWindow_resp_quality_label(QMainWindow): self.fig.subplots_adjust(top=0.98, bottom=0.05, right=0.98, left=0.1, hspace=0.1, 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.xaxis.set_major_formatter(Params.FORMATTER) self.ax1 = self.fig.add_subplot(self.gs[1]) self.ax1.grid(True) - self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax1.xaxis.set_major_formatter(Params.FORMATTER) # 初始化频谱画框 self.fig_spectrum = plt.figure(figsize=(12, 9), dpi=100) @@ -353,10 +353,10 @@ class MainWindow_resp_quality_label(QMainWindow): try: if Config["CurrentPartNum"] != Config["DataPartNum"]: begin_OrgBCG = Config["CurrentOrgBCGIndex"] - end_OrgBCG = (Config["CurrentOrgBCGIndex"] + ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + end_OrgBCG = (Config["CurrentOrgBCGIndex"] + Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC * int(Config["InputConfig"]["OrgBCGUseFreq"])) begin_Tho = Config["CurrentThoIndex"] - end_Tho = (Config["CurrentThoIndex"] + ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + end_Tho = (Config["CurrentThoIndex"] + Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC * int(Config["InputConfig"]["ThoUseFreq"])) else: begin_OrgBCG = Config["CurrentOrgBCGIndex"] @@ -428,7 +428,7 @@ class MainWindow_resp_quality_label(QMainWindow): try: if Config["CurrentPartNum"] != Config["DataPartNum"]: begin_Tho = Config["CurrentThoIndex"] - end_Tho = (Config["CurrentThoIndex"] + ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + end_Tho = (Config["CurrentThoIndex"] + Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC * int(Config["InputConfig"]["ThoUseFreq"])) elif Config["CurrentPartNum"] == Config["DataPartNum"]: begin_Tho = Config["CurrentThoIndex"] @@ -730,8 +730,8 @@ class MainWindow_resp_quality_label(QMainWindow): artifact_indices = [] for i in range(0, len(self.data.Artifact_a)): if i + 3 < len(self.data.Artifact_a): # 防止索引越界 - index0 = self.data.Artifact_a[i + 2] // (Config["InputConfig"]["OrgBCGUseFreq"] * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC) # 第三行(索引+2) - index1 = self.data.Artifact_a[i + 3] // (Config["InputConfig"]["OrgBCGUseFreq"] * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC) # 第四行(索引+3) + index0 = self.data.Artifact_a[i + 2] // (Config["InputConfig"]["OrgBCGUseFreq"] * Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC) # 第三行(索引+2) + index1 = self.data.Artifact_a[i + 3] // (Config["InputConfig"]["OrgBCGUseFreq"] * Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC) # 第四行(索引+3) if index0 == index1: artifact_indices.append(index0) else: @@ -742,10 +742,10 @@ class MainWindow_resp_quality_label(QMainWindow): # 数据切片预处理 BCG = pre_process( get_slice( - self.data.OrgBCG_Processed, seg_idx, ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC, Config["InputConfig"]["OrgBCGUseFreq"]), Config["InputConfig"]["OrgBCGUseFreq"], ConfigParams.RESP_QUALITY_LABEL_PREPROCESS_FC) + self.data.OrgBCG_Processed, seg_idx, Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC, Config["InputConfig"]["OrgBCGUseFreq"]), Config["InputConfig"]["OrgBCGUseFreq"], Params.RESP_QUALITY_LABEL_PREPROCESS_FC) THO = pre_process( get_slice( - self.data.Tho_Processed, seg_idx, ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC, Config["InputConfig"]["ThoUseFreq"]), Config["InputConfig"]["ThoUseFreq"], ConfigParams.RESP_QUALITY_LABEL_PREPROCESS_FC) + self.data.Tho_Processed, seg_idx, Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC, Config["InputConfig"]["ThoUseFreq"]), Config["InputConfig"]["ThoUseFreq"], Params.RESP_QUALITY_LABEL_PREPROCESS_FC) # 质量评估 # 有体动:1 无体动:0 @@ -805,10 +805,10 @@ class MainWindow_resp_quality_label(QMainWindow): PublicFunc.msgbox_output(self, Constants.RESP_QUALITY_LABEL_VIEWING_THE_FIRST_PART, Constants.MSGBOX_TYPE_INFO) return Config["CurrentPartNum"] = Config["CurrentPartNum"] - 1 - Config["CurrentOrgBCGIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + Config["CurrentOrgBCGIndex"] = ((Config["CurrentPartNum"] - 1) * Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC * int(Config["InputConfig"]["OrgBCGUseFreq"])) - Config["CurrentThoIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * - int(Config["InputConfig"]["ThoUseFreq"])) + Config["CurrentThoIndex"] = ((Config["CurrentPartNum"] - 1) * Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])) result = self.__plot__() if not result.status: PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_ERROR) @@ -836,10 +836,10 @@ class MainWindow_resp_quality_label(QMainWindow): PublicFunc.msgbox_output(self, Constants.RESP_QUALITY_LABEL_VIEWING_THE_LAST_PART, Constants.MSGBOX_TYPE_INFO) return Config["CurrentPartNum"] = Config["CurrentPartNum"] + 1 - Config["CurrentOrgBCGIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * - int(Config["InputConfig"]["OrgBCGUseFreq"])) - Config["CurrentThoIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * - int(Config["InputConfig"]["ThoUseFreq"])) + Config["CurrentOrgBCGIndex"] = ((Config["CurrentPartNum"] - 1) * Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["OrgBCGUseFreq"])) + Config["CurrentThoIndex"] = ((Config["CurrentPartNum"] - 1) * Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])) result = self.__plot__() if not result.status: PublicFunc.text_output(self.ui, result.info, Constants.TIPS_TYPE_ERROR) @@ -870,17 +870,17 @@ class MainWindow_resp_quality_label(QMainWindow): if sender == self.ui.tableWidget_labeled: Config["CurrentPartNum"] = int( self.ui.tableWidget_labeled.item(row, 0).text()) - Config["CurrentOrgBCGIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * - int(Config["InputConfig"]["OrgBCGUseFreq"])) - Config["CurrentThoIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * - int(Config["InputConfig"]["ThoUseFreq"])) + Config["CurrentOrgBCGIndex"] = ((Config["CurrentPartNum"] - 1) * Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["OrgBCGUseFreq"])) + Config["CurrentThoIndex"] = ((Config["CurrentPartNum"] - 1) * Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])) elif sender == self.ui.tableWidget_tobelabeled: Config["CurrentPartNum"] = int( self.ui.tableWidget_tobelabeled.item(row, 0).text()) - Config["CurrentOrgBCGIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * - int(Config["InputConfig"]["OrgBCGUseFreq"])) - Config["CurrentThoIndex"] = ((Config["CurrentPartNum"] - 1) * ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * - int(Config["InputConfig"]["ThoUseFreq"])) + Config["CurrentOrgBCGIndex"] = ((Config["CurrentPartNum"] - 1) * Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["OrgBCGUseFreq"])) + Config["CurrentThoIndex"] = ((Config["CurrentPartNum"] - 1) * Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])) else: raise ValueError("发射信号不存在") result = self.__plot__() @@ -956,11 +956,11 @@ class MainWindow_resp_quality_label(QMainWindow): if self.ax0 is not None: self.ax0.clear() self.ax0.grid(True) - self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax0.xaxis.set_major_formatter(Params.FORMATTER) if self.ax1 is not None: self.ax1.clear() self.ax1.grid(True) - self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER) + self.ax1.xaxis.set_major_formatter(Params.FORMATTER) if self.ax0_spectrum is not None: self.ax0_spectrum.clear() self.ax0_spectrum.grid(True) @@ -1093,13 +1093,13 @@ class MainWindow_resp_quality_label(QMainWindow): self.is_left_button_pressed = False if rect_left < Config["CurrentThoIndex"]: rect_left = Config["CurrentThoIndex"] - elif rect_left >= (Config["CurrentThoIndex"] + ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * - int(Config["InputConfig"]["ThoUseFreq"])): + elif rect_left >= (Config["CurrentThoIndex"] + Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + int(Config["InputConfig"]["ThoUseFreq"])): rect_left = 0 rect_right = 0 - if (rect_right >= Config["CurrentThoIndex"] + ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + if (rect_right >= Config["CurrentThoIndex"] + Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC * int(Config["InputConfig"]["ThoUseFreq"])): - rect_right = (Config["CurrentThoIndex"] + ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + rect_right = (Config["CurrentThoIndex"] + Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC * int(Config["InputConfig"]["ThoUseFreq"]) - 1) elif rect_right < Config["CurrentThoIndex"]: rect_left = 0 @@ -1167,12 +1167,12 @@ class MainWindow_resp_quality_label(QMainWindow): 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.RESP_QUALITY_LABEL_LABEL_TRANSPARENCY, - color=Constants.PLOT_COLOR_PINK) + alpha=Params.RESP_QUALITY_LABEL_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.RESP_QUALITY_LABEL_LABEL_TRANSPARENCY, - color=Constants.PLOT_COLOR_RED) + alpha=Params.RESP_QUALITY_LABEL_LABEL_TRANSPARENCY, + color=Constants.PLOT_COLOR_RED) self.ax1.add_patch(self.figToolbar.rect_patch_ax1) # 更新矩形patch的位置和大小 @@ -1215,7 +1215,7 @@ class Data(): if Path(Config["Path"]["Save_Tho_peak"]).is_file(): Config["Path"]["Save_Tho_peak"] = str(Path(Config["Path"]["Save_Tho_peak"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], ConfigParams.THO_SYNC, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], Filename.THO_SYNC, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Tho"] = result.data["path"] Config["InputConfig"]["ThoFreq"] = result.data["freq"] @@ -1223,11 +1223,11 @@ class Data(): return result Config["Path"]["Save_Tho_peak"] = str( - Path(Config["Path"]["Save_Tho_peak"]) / Path(ConfigParams.THO_PEAK + str(Config["InputConfig"]["ThoUseFreq"]) + ConfigParams.ENDSWITH_TXT)) + Path(Config["Path"]["Save_Tho_peak"]) / Path(Filename.THO_PEAK + str(Config["InputConfig"]["ThoUseFreq"]) + Params.ENDSWITH_TXT)) try: self.Tho = read_csv(Config["Path"]["Input_Tho"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) except Exception as e: return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Open_Data_Exception"] + "\n" + format_exc()) @@ -1256,7 +1256,7 @@ class Data(): return Result().failure(info=Constants.PREPROCESS_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) try: - self.Tho_Processed = pre_process(self.Tho, Config["InputConfig"]["ThoUseFreq"], ConfigParams.RESP_QUALITY_LABEL_PREPROCESS_FC) + self.Tho_Processed = pre_process(self.Tho, Config["InputConfig"]["ThoUseFreq"], Params.RESP_QUALITY_LABEL_PREPROCESS_FC) except Exception as e: return Result().failure(info=Constants.PREPROCESS_FAILURE + Constants.FAILURE_REASON["Preprocess_Exception"] + "\n" + format_exc()) @@ -1284,15 +1284,15 @@ class Data(): if self.Tho_peak is None: - return Result().failure(info=ConfigParams.THO_PEAK + Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + return Result().failure(info=Filename.THO_PEAK + Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) try: DataFrame(self.Tho_peak).to_csv(Path(Config["Path"]["Save_Tho_peak"]), mode='w', index=False, header=False) except Exception as e: - return Result().failure(info=ConfigParams.THO_PEAK + Constants.SAVE_FAILURE + + return Result().failure(info=Filename.THO_PEAK + Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Save_Exception"] + "\n" + format_exc()) - return Result().success(info=ConfigParams.THO_PEAK + Constants.SAVE_FINISHED) + return Result().success(info=Filename.THO_PEAK + Constants.SAVE_FINISHED) def open_file_label(self): if Path(Config["Path"]["Input_OrgBCG"]).is_file(): @@ -1306,21 +1306,21 @@ class Data(): if Path(Config["Path"]["Save_Tho_peak"]).is_file(): Config["Path"]["Save_Tho_peak"] = str(Path(Config["Path"]["Save_Tho_peak"]).parent) - result = PublicFunc.examine_file(Config["Path"]["Input_OrgBCG"], ConfigParams.ORGBCG_SYNC, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_OrgBCG"], Filename.ORGBCG_SYNC, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_OrgBCG"] = result.data["path"] Config["InputConfig"]["OrgBCGFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], ConfigParams.THO_SYNC, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], Filename.THO_SYNC, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Tho"] = result.data["path"] Config["InputConfig"]["ThoFreq"] = result.data["freq"] else: return result - result = PublicFunc.examine_file(Config["Path"]["Input_Artifact"], ConfigParams.ARTIFACT_A, ConfigParams.ENDSWITH_TXT) + result = PublicFunc.examine_file(Config["Path"]["Input_Artifact"], Filename.ARTIFACT_A, Params.ENDSWITH_TXT) if result.status: Config["Path"]["Input_Artifact"] = result.data["path"] else: @@ -1328,27 +1328,27 @@ class Data(): Config["Path"]["Save_Resp_quality_label"] = str( Path(Config["Path"]["Save_Resp_quality_label"]) / Path( - ConfigParams.RESP_QUALITY_LABEL + ConfigParams.ENDSWITH_TXT)) + Filename.RESP_QUALITY_LABEL + Params.ENDSWITH_TXT)) Config["Path"]["Save_Tho_peak"] = str( Path(Config["Path"]["Save_Tho_peak"]) / Path( - ConfigParams.THO_PEAK + str(Config["InputConfig"]["ThoUseFreq"]) + ConfigParams.ENDSWITH_TXT)) + Filename.THO_PEAK + str(Config["InputConfig"]["ThoUseFreq"]) + Params.ENDSWITH_TXT)) try: self.OrgBCG = read_csv(Config["Path"]["Input_OrgBCG"], - encoding=ConfigParams.UTF8_ENCODING, - header=None).to_numpy().reshape(-1) + encoding=Params.UTF8_ENCODING, + header=None).to_numpy().reshape(-1) self.Tho = read_csv(Config["Path"]["Input_Tho"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) self.Artifact_a = read_csv(Config["Path"]["Input_Artifact"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) except Exception as e: return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Open_Data_Exception"] + "\n" + format_exc()) try: - Config["DataPartNum"] = len(self.OrgBCG) // (ConfigParams.RESP_QUALITY_LABEL_PARTS_TIME_SEC * - Config["InputConfig"]["OrgBCGFreq"]) + 1 + Config["DataPartNum"] = len(self.OrgBCG) // (Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC * + Config["InputConfig"]["OrgBCGFreq"]) + 1 if Config["DataPartNum"] == 0: return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Data_Length_Not_Correct"]) except Exception as e: @@ -1382,24 +1382,24 @@ class Data(): def get_archive_resp_quality(self): if not Path(Config["Path"]["Save_Resp_quality_label"]).exists(): self.resp_quality_label = full(Config["DataPartNum"], -1) - return Result().success(info=ConfigParams.RESP_QUALITY_LABEL + ":" + Constants.ARCHIVE_NOT_EXIST) + return Result().success(info=Filename.RESP_QUALITY_LABEL + ":" + Constants.ARCHIVE_NOT_EXIST) else: self.resp_quality_label = read_csv(Config["Path"]["Save_Resp_quality_label"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) - return Result().success(info=ConfigParams.RESP_QUALITY_LABEL + ":" + Constants.ARCHIVE_EXIST) + return Result().success(info=Filename.RESP_QUALITY_LABEL + ":" + Constants.ARCHIVE_EXIST) def get_archive_tho_peak(self): if not Path(Config["Path"]["Save_Tho_peak"]).exists(): self.Tho_peak = array([]).astype(int) self.Tho_peak_y = array([]).astype(int) - return Result().success(info=ConfigParams.RESP_QUALITY_LABEL + ":" + Constants.ARCHIVE_NOT_EXIST) + return Result().success(info=Filename.RESP_QUALITY_LABEL + ":" + Constants.ARCHIVE_NOT_EXIST) else: self.Tho_peak = read_csv(Config["Path"]["Save_Tho_peak"], - encoding=ConfigParams.UTF8_ENCODING, + encoding=Params.UTF8_ENCODING, header=None).to_numpy().reshape(-1) - return Result().success(info=ConfigParams.THO_PEAK + ":" + Constants.ARCHIVE_EXIST) + return Result().success(info=Filename.THO_PEAK + ":" + Constants.ARCHIVE_EXIST) def resample_tho_and_OrgBCG(self): if (self.OrgBCG is None) or (self.Tho is None): @@ -1431,7 +1431,7 @@ class Data(): try: self.OrgBCG_Processed = self.OrgBCG.copy() - self.Tho_Processed = pre_process(self.Tho, Config["InputConfig"]["ThoUseFreq"], ConfigParams.RESP_QUALITY_LABEL_PREPROCESS_FC) + self.Tho_Processed = pre_process(self.Tho, Config["InputConfig"]["ThoUseFreq"], Params.RESP_QUALITY_LABEL_PREPROCESS_FC) self.Tho_peak_y = [self.Tho_Processed[x] for x in (self.Tho_peak)] except Exception as e: return Result().failure(info=Constants.PREPROCESS_FAILURE + @@ -1441,7 +1441,7 @@ class Data(): def preprocess_getBDR(self, orgBcg_slice, THO_slice, mode): orgBcg = pre_process(orgBcg_slice, int(Config["InputConfig"]["OrgBCGUseFreq"]), - ConfigParams.RESP_QUALITY_LABEL_PREPROCESS_FC) + Params.RESP_QUALITY_LABEL_PREPROCESS_FC) if mode == "preset": BDR, band_low, band_high, bcg_spectrum, bcg_freq, tho_spectrum, tho_freq = ( get_bandpass_bcgsignal(orgBcg, THO_slice, int(Config["InputConfig"]["OrgBCGUseFreq"]), @@ -1463,15 +1463,15 @@ class Data(): if self.resp_quality_label is None: - return Result().failure(info=ConfigParams.RESP_QUALITY_LABEL + Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) + return Result().failure(info=Filename.RESP_QUALITY_LABEL + Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) try: DataFrame(self.resp_quality_label).to_csv(Path(Config["Path"]["Save_Resp_quality_label"]), mode='w', index=False, header=False) except Exception as e: - return Result().failure(info=ConfigParams.RESP_QUALITY_LABEL + Constants.SAVE_FAILURE + + return Result().failure(info=Filename.RESP_QUALITY_LABEL + Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Save_Exception"] + "\n" + format_exc()) - return Result().success(info=ConfigParams.RESP_QUALITY_LABEL + Constants.SAVE_FINISHED) + return Result().success(info=Filename.RESP_QUALITY_LABEL + Constants.SAVE_FINISHED) class CustomNavigationToolbar(NavigationToolbar2QT): @@ -1480,14 +1480,14 @@ class CustomNavigationToolbar(NavigationToolbar2QT): super().__init__(canvas, parent) # 初始化画框工具栏 self.action_Label_Multiple = QAction(Constants.RESP_QUALITY_LABEL_ACTION_LABEL_MULTIPLE_NAME, self) - self.action_Label_Multiple.setFont(QFont(ConfigParams.FONT, 14)) + self.action_Label_Multiple.setFont(QFont(Params.FONT, 14)) self.action_Label_Multiple.setCheckable(True) self.action_Label_Multiple.setShortcut(QCoreApplication.translate("MainWindow", - ConfigParams.RESP_QUALITY_LABEL_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY)) + Params.RESP_QUALITY_LABEL_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)) + self._actions['pan'].setShortcut(QCoreApplication.translate("MainWindow", Params.ACTION_PAN_SHORTCUT_KEY)) + self._actions['zoom'].setShortcut(QCoreApplication.translate("MainWindow", Params.ACTION_ZOOM_SHORTCUT_KEY)) # 用于存储事件连接ID self.cid_mouse_press = None diff --git a/func/utils/ConfigParams.py b/func/utils/ConfigParams.py index 5a9e150..c706f00 100644 --- a/func/utils/ConfigParams.py +++ b/func/utils/ConfigParams.py @@ -2,35 +2,20 @@ from PySide6.QtGui import QIntValidator, QDoubleValidator from matplotlib.ticker import FuncFormatter -class ConfigParams: - - # 公共 - PUBLIC_CONFIG_FILE_PATH: str = "./config/Config_public.yaml" - PUBLIC_PATH_ORGBCG_TEXT: str = "OrgBCG_Text" - PUBLIC_PATH_PSG_TEXT: str = "PSG_Text" - PUBLIC_PATH_ORGBCG_ALIGNED: str = "OrgBCG_Aligned" - PUBLIC_PATH_PSG_ALIGNED: str = "PSG_Aligned" - PUBLIC_PATH_LABEL: str = "Label" - PUBLIC_CONFIG_NEW_CONTENT = { - "Path": { - "Root": "" - } - } - UTF8_ENCODING: str = "utf-8" - # 目前用到这个编码的地方: - # 里的保存和读取csv文件的地方(注意的是,读取原始数据时依然使用UTF-8) - GBK_ENCODING: str = "gbk" - ENDSWITH_TXT: str = ".txt" - ENDSWITH_CSV: str = ".csv" - ENDSWITH_EDF: str = ".edf" - FORMATTER = FuncFormatter(lambda x, p: f"{x:.0f}") - ACTION_PAN_SHORTCUT_KEY: str = "X" - ACTION_ZOOM_SHORTCUT_KEY: str = "C" - FONT: str = "Microsoft YaHei UI" - VALIDATOR_INTEGER = QIntValidator(-2**31, 2**31 - 1) - VALIDATOR_DOUBLE = QDoubleValidator(-1e100, 1e100, 10) - +class Filename: # 文件命名 + PATH_ORGBCG_TEXT: str = "OrgBCG_Text" + PATH_PSG_TEXT: str = "PSG_Text" + PATH_ORGBCG_ALIGNED: str = "OrgBCG_Aligned" + PATH_PSG_ALIGNED: str = "PSG_Aligned" + PATH_ORGBCG_ORIGIN: str = "OrgBCG_Origin" + PATH_PSG_ORIGIN: str = "PSG_Origin" + PATH_LABEL: str = "Label" + PATH_REVEIVE_ORIGIN: str = "Receive_Origin" + PATH_REPORT: str = "Report" + PATH_SAMPID: str = "" + SUFFIX_FREQ: str = "采样率" + # Folder: OrgBCG_Text ORGBCG_RAW: str = "OrgBCG_Raw_" BCG_FILTER: str = "BCG_Filter_" @@ -82,6 +67,28 @@ class ConfigParams: SQ_LABEL_10S: str = "SQ_label_10s" SQ_LABEL_30S: str = "SQ_label_30s" + +class Params: + + # 公共 + PUBLIC_CONFIG_FILE_PATH: str = "./config/Config_public.yaml" + PUBLIC_CONFIG_NEW_CONTENT = { + "Path": { + "Root": "" + } + } + UTF8_ENCODING: str = "utf-8" + GBK_ENCODING: str = "gbk" + ENDSWITH_TXT: str = ".txt" + ENDSWITH_CSV: str = ".csv" + ENDSWITH_EDF: str = ".edf" + FORMATTER = FuncFormatter(lambda x, p: f"{x:.0f}") + ACTION_PAN_SHORTCUT_KEY: str = "X" + ACTION_ZOOM_SHORTCUT_KEY: str = "C" + FONT: str = "Microsoft YaHei UI" + VALIDATOR_INTEGER = QIntValidator(-2**31, 2**31 - 1) + VALIDATOR_DOUBLE = QDoubleValidator(-1e100, 1e100, 10) + # 数据粗同步 APPROXIMATELY_ALIGN_CONFIG_FILE_PATH: str = "./config/Config_approximately_align.yaml" APPROXIMATELY_ALIGN_CONFIG_NEW_CONTENT: dict = { @@ -207,29 +214,29 @@ class ConfigParams: CUT_PSG_CONFIG_NEW_CONTENT: dict = { "ECGFreq": 1000, "ChannelInput": { - "Effort Tho": THO_RAW, - "Effort Abd": ABD_RAW, - "Flow T": FLOWT_RAW, - "Flow P": FLOWP_RAW, - "Snore": SNORE_RAW, - "SpO2": SPO2_RAW, - "5_class": FIVE_CLASS_RAW + "Effort Tho": Filename.THO_RAW, + "Effort Abd": Filename.ABD_RAW, + "Flow T": Filename.FLOWT_RAW, + "Flow P": Filename.FLOWP_RAW, + "Snore": Filename.SNORE_RAW, + "SpO2": Filename.SPO2_RAW, + "5_class": Filename.FIVE_CLASS_RAW }, "LabelInput": { - "SA Label": SA_LABEL_RAW + "SA Label": Filename.SA_LABEL_RAW }, - "StartTime": STARTTIME_RAW, + "StartTime": Filename.STARTTIME_RAW, "ChannelSave": { - "Effort Tho": THO_SYNC, - "Effort Abd": ABD_SYNC, - "Flow T": FLOWT_SYNC, - "Flow P": FLOWP_SYNC, - "Snore": SNORE_SYNC, - "SpO2": SPO2_SYNC, - "5_class": FIVE_CLASS_SYNC + "Effort Tho": Filename.THO_SYNC, + "Effort Abd": Filename.ABD_SYNC, + "Flow T": Filename.FLOWT_SYNC, + "Flow P": Filename.FLOWP_SYNC, + "Snore": Filename.SNORE_SYNC, + "SpO2": Filename.SPO2_SYNC, + "5_class": Filename.FIVE_CLASS_SYNC }, "LabelSave": { - "SA Label": SA_LABEL_SYNC + "SA Label": Filename.SA_LABEL_SYNC }, "EndWith": { "Effort Tho": ENDSWITH_TXT, @@ -335,7 +342,6 @@ class ConfigParams: def __new__(cls): raise TypeError("Constants class cannot be instantiated") - # 禁止修改常量 @classmethod def __setattr__(cls, key, value): diff --git a/func/utils/Constants.py b/func/utils/Constants.py index 56df68d..ab85a69 100644 --- a/func/utils/Constants.py +++ b/func/utils/Constants.py @@ -1,4 +1,4 @@ -from func.utils.ConfigParams import ConfigParams +from func.utils.ConfigParams import Params class Constants: @@ -240,7 +240,7 @@ class Constants: 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})" + LABEL_CHECK_ACTION_LABEL_MULTIPLE_NAME: str = f"批量更改标签({Params.LABEL_CHECK_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY})" # 数据精同步 PRECISELY_ALIGN_PROCESSING_DATA: str = "正在处理数据" @@ -296,7 +296,7 @@ class Constants: PRECISELY_ALIGN_PLOT_LABEL_SELECTED_POINT: str = "Selected Point" PRECISELY_ALIGN_NO_POINT_IN_THE_INTERVAL: str = "所选区间内无有效点" PRECISELY_ALIGN_RECOVER_SCALE: str = "尺度恢复" - PRECISELY_ALIGN_ACTION_GET_RANGE_NAME: str = f"设置范围({ConfigParams.PRECISELY_ALIGN_ACTION_GET_RANGE_SHORTCUT_KEY})" + PRECISELY_ALIGN_ACTION_GET_RANGE_NAME: str = f"设置范围({Params.PRECISELY_ALIGN_ACTION_GET_RANGE_SHORTCUT_KEY})" # 冗余数据切割和标签映射 CUT_PSG_GETTING_FILE_AND_FREQ: str = "正在获取文件及其采样率" @@ -328,7 +328,7 @@ class Constants: ARTIFACT_LABEL_MERGE: str = "当前所打标的片段距离附近片段不到2秒,片段序号:" ARTIFACT_LABEL_DELETE_ARTIFACT_SUCCESSFULLY: str = "体动被删除" ARTIFACT_LABEL_DELETE_ARTIFACT_FAILURE: str = "需要被删除的体动不存在" - ARTIFACT_LABEL_ACTION_LABEL: str = f"标注体动({ConfigParams.ARTIFACT_LABEL_ACTION_LABEL_ARTIFACT_SHORTCUT_KEY})" + ARTIFACT_LABEL_ACTION_LABEL: str = f"标注体动({Params.ARTIFACT_LABEL_ACTION_LABEL_ARTIFACT_SHORTCUT_KEY})" ARTIFACT_LABEL_LABELBTN_STYLE_1: str = """ QPushButton { @@ -444,7 +444,7 @@ class Constants: RESP_QUALITY_LABEL_CUSTOM_FILTER_ARGS_ERROR: str = "OrgBCG带通滤波频率设置范围应为数字,范围是0~1" RESP_QUALITY_LABEL_AUTOLABEL_ARGS_ERROR: str = "人工标注阈值设置范围应为数字,范围是0~1" RESP_QUALITY_LABEL_CHECK_ARGS_QUESTION_CONTENT: str = "你确定要执行此操作吗,请确保参数输入正确" - RESP_QUALITY_LABEL_ACTION_LABEL_MULTIPLE_NAME: str = f"批量更改标签({ConfigParams.RESP_QUALITY_LABEL_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY})" + RESP_QUALITY_LABEL_ACTION_LABEL_MULTIPLE_NAME: str = f"批量更改标签({Params.RESP_QUALITY_LABEL_ACTION_LABEL_MULTIPLE_SHORTCUT_KEY})" RESP_QUALITY_LABEL_A_QUALITY: int = 1 RESP_QUALITY_LABEL_B_QUALITY: int = 0 RESP_QUALITY_LABEL_C_QUALITY: int = -1 diff --git a/数据结构化输入和输出命名规范.html b/数据结构化输入和输出命名规范.html new file mode 100644 index 0000000..ac2ba9c --- /dev/null +++ b/数据结构化输入和输出命名规范.html @@ -0,0 +1,168 @@ +

文件命名规范

+

当一份数据被完整走完标注流程后,数据文件夹目录结构将会是:

+
.../Label/<sampID>
+    |-Artifact_a_采样率.txt
+    |-Artifact_b_采样率.txt
+    |-Artifact_c_采样率.csv
+    |-SQ_label_10s.csv
+    |-SQ_label_30s.csv
+    |-Resp_quality_label.txt
+    |-Tho_peak_采样率.txt
+    |-SA Label_corrected.csv
+    |-SA Label_add.csv
+    |-Precisely_Align_Info.txt
+    |-Approximately_Align_Info.csv
+.../OrgBCG_Aligned/<sampID>
+    |-BCG_Sync_采样率.txt
+    |-OrgBCG_Sync_采样率.txt
+    |-Jpeak_Sync_采样率.txt
+.../OrgBCG_Text/<sampID>
+    |-OrgBCG_Raw_采样率.txt
+    |-BCG_Filter_采样率.txt
+    |-Jpeak_revise_采样率.txt
+    |-Jpeak_revise_corrected_采样率.txt
+.../OrgBCG_Origin/<sampID>
+    |-...
+.../PSG_Aligned/<sampID>
+    |-ECG_Sync_采样率.txt
+    |-Rpeak_Sync_采样率.txt
+    |-5_class_Sync_采样率.txt
+    |-SA Label_Sync.csv
+    |-Effort Abd_Sync_采样率.txt
+    |-Effort Tho_Sync_采样率.txt
+    |-Flow T_Sync_采样率.txt
+    |-Flow P_Sync_采样率.txt
+    |-Snore_Sync_采样率.txt
+    |-SpO2_Sync_采样率.txt
+.../PSG_Text/<sampID>
+    |-ECG II_Raw_采样率.txt
+    |-ECG_Filter_采样率.txt
+    |-Rpeak_final_采样率.txt
+    |-Rpeak_final_corrected_采样率.txt
+    |-5_class_Raw_采样率.txt
+    |-SA Label_Raw.csv
+    |-Effort Abd_Raw_采样率.txt
+    |-Effort Tho_Raw_采样率.txt
+    |-Flow T_Raw_采样率.txt
+    |-Flow P_Raw_采样率.txt
+    |-Snore_Raw_采样率.txt
+    |-SpO2_Raw_采样率.txt
+    |-StartTime_Raw.txt
+.../PSG_Origin/<sampID>
+    |-...
+.../Receive_Origin
+    |-...
+.../Report
+    |-...
+
+

1 数据粗同步

+

输入:

+

原始OrgBCG信号:./OrgBCG_Text/<sampID>/OrgBCG_Raw_采样率.txt

+

原始Tho信号:./PSG_Text/<sampID>/Effort Tho_Raw_采样率.txt

+

原始Abd信号:./PSG_Text/<sampID>/Effort Abd_Raw_采样率.txt

+

输出:

+

粗同步后的位置索引:./Label/<sampID>/Approximately_Align_Info.csv

+

2 预处理

+

输入:

+

原始OrgBCG信号:./OrgBCG_Text/<sampID>/OrgBCG_Raw_采样率.txt

+

原始ECG信号:./PSG_Text/<sampID>/ECG II_Raw_采样率.txt

+

输出:

+

滤波后的BCG信号:./OrgBCG_Text/<sampID>/BCG_Filter_采样率.txt

+

滤波后的ECG信号:./PSG_Text/<sampID>/ECG_Filter_采样率.txt

+

3 数据精同步

+

3.1 算法定位

+

3.1.1 R峰算法定位

+

输入:

+

滤波后的ECG信号:./PSG_Text/<sampID>/ECG_Filter_采样率.txt

+

输出:

+

算法定位的R峰坐标:./PSG_Text/<sampID>/Rpeak_final_采样率.txt

+

3.1.2 J峰算法定位

+

输入:

+

滤波后的BCG信号:./OrgBCG_Text/<sampID>/BCG_Filter_采样率.txt

+

输出:

+

算法定位的J峰坐标:./OrgBCG_Text/<sampID>/Jpeak_revise_采样率.txt

+

3.2 人工纠正

+

3.2.1 R峰人工纠正

+

输入:

+

滤波后的ECG信号:./PSG_Text/<sampID>/ECG_Filter_采样率.txt

+

算法定位的R峰坐标:./PSG_Text/<sampID>/Rpeak_final_采样率.txt

+

粗同步后的位置索引:./Label/<sampID>/Approximately_Align_Info.csv

+

输出:

+

人工纠正后的R峰坐标:./PSG_Text/<sampID>/Rpeak_final_corrected_采样率.txt

+

3.2.2 J峰人工纠正*

+

输入:

+

滤波后的BCG信号:./OrgBCG_Text/<sampID>/BCG_Filter_采样率.txt

+

算法定位的J峰坐标:./OrgBCG_Text/<sampID>/Jpeak_revise_采样率.txt

+

粗同步后的位置索引:./Label/<sampID>/Approximately_Align_Info.csv

+

输出:

+

人工纠正后的J峰坐标:./OrgBCG_Text/<sampID>/Jpeak_revise_corrected_采样率.txt

+

3.3 数据片段起止对齐、数据采样率同步

+

输入:

+

滤波后的ECG信号:./PSG_Text/<sampID>/ECG_Filter_采样率.txt

+

人工纠正后的R峰坐标:./PSG_Text/<sampID>/Rpeak_final_corrected_采样率.txt

+

滤波后的BCG信号:./OrgBCG_Text/<sampID>/BCG_Filter_采样率.txt

+

人工纠正后的J峰坐标:./OrgBCG_Text/<sampID>/Jpeak_revise_corrected_采样率.txt

+

原始OrgBCG信号:./OrgBCG_Text/<sampID>/OrgBCG_Raw_采样率.txt

+

粗同步后的位置索引:./Label/<sampID>/Approximately_Align_Info.csv

+

输出:

+

精同步对齐信息:./Label/<sampID>/Precisely_Align_Info.txt

+

同步后的ECG信号:./PSG_Aligned/<sampID>/ECG_Sync_采样率.txt

+

同步后的R峰坐标:./PSG_Aligned/<sampID>/Rpeak_Sync_采样率.txt

+

同步后的BCG信号:./OrgBCG_Aligned/<sampID>/BCG_Sync_采样率.txt

+

同步后的OrgBCG信号:./OrgBCG_Aligned/<sampID>/OrgBCG_Sync_采样率.txt

+

同步后的J峰坐标:./OrgBCG_Aligned/<sampID>/Jpeak_Sync_采样率.txt

+

3.4、冗余数据切割、标签映射

+

输入:

+

精同步对齐信息:./Label/<sampID>/Precisely_Align_Info.txt

+

原始的Flow T信号:./PSG_Text/<sampID>/Flow T_Sync_采样率.txt

+

原始的Flow P信号:./PSG_Text/<sampID>/Flow P_Sync_采样率.txt

+

原始的Tho信号:./PSG_Text/<sampID>/Effort Tho_Sync_采样率.txt

+

原始的Abd信号:./PSG_Text/<sampID>/Effort Abd_Sync_采样率.txt

+

原始的SpO2信号:./PSG_Text/<sampID>/SpO2_Sync_采样率.txt

+

原始的Snore信号:./PSG_Text/<sampID>/Snore_Sync_采样率.txt

+

原始的睡眠分期标签:./PSG_Text/<sampID>/5_class_Raw_采样率.txt

+

原始的睡眠呼吸暂停事件标签:./PSG_Text/<sampID>/SA Label_Raw.csv

+

输出:

+

同步后的Flow T信号:./PSG_Aligned/<sampID>/Flow T_Sync_采样率.txt

+

同步后的Flow P信号:./PSG_Aligned/<sampID>/Flow P_Sync_采样率.txt

+

同步后的Tho信号:./PSG_Aligned/<sampID>/Effort Tho_Sync_采样率.txt

+

同步后的Abd信号:./PSG_Aligned/<sampID>/Effort Abd_Sync_采样率.txt

+

同步后的SpO2信号:./PSG_Aligned/<sampID>/SpO2_Sync_采样率.txt

+

同步后的Snore信号:./PSG_Aligned/<sampID>/Snore_Sync_采样率.txt

+

同步后的睡眠分期标签:./PSG_Aligned/<sampID>/5_class_Sync_采样率.txt

+

同步后的睡眠呼吸暂停事件标签:./PSG_Aligned/<sampID>/SA Label_Sync.csv

+

4 体动标记

+

输入:

+

同步后的BCG信号:./OrgBCG_Aligned/<sampID>/BCG_Sync_采样率.txt

+

同步后的OrgBCG信号:./OrgBCG_Aligned/<sampID>/OrgBCG_Sync_采样率.txt

+

输出:

+

txt格式的体动标签:./Label/<sampID>/Artifact_a_采样率.txt

+

体动标签类型数量统计:./Label/<sampID>/Artifact_b_采样率.txt

+

csv格式的体动标签:./Label/<sampID>/Artifact_c_采样率.csv

+

5 质量评估

+

输入:

+

同步后的BCG信号:./OrgBCG_Aligned/<sampID>/BCG_Sync_采样率.txt

+

txt格式的体动标签:./Label/<sampID>/Artifact_a_采样率.txt

+

输出:

+

质量标签:./Label/<sampID>/SQ_label_10s.csv./Label/<sampID>/SQ_label_30s.csv

+

6 呼吸提取

+

输入:

+

同步后的OrgBCG信号:./OrgBCG_Aligned/<sampID>/OrgBCG_Sync_采样率.txt

+

同步后的Tho信号:./PSG_Aligned/<sampID>/Effort Tho_Sync_采样率.txt

+

txt格式的体动标签:./Label/<sampID>/Artifact_a_采样率.txt

+

输出:

+

呼吸可用性标签:./Label/<sampID>/Resp_quality_label.txt

+

Tho信号呼吸间期标签:./Label/<sampID>/Tho_peak_采样率.txt

+

8 呼吸暂停事件标注

+

输入:

+

同步后的OrgBCG信号:./OrgBCG_Aligned/<sampID>/OrgBCG_Sync_采样率.txt

+

txt格式的体动标签:./Label/<sampID>/Artifact_a_采样率.txt

+

同步后的Flow T信号:./PSG_Aligned/<sampID>/Flow T_Sync_采样率.txt

+

同步后的Flow P信号:./PSG_Aligned/<sampID>/Flow P_Sync_采样率.txt

+

同步后的Tho信号:./PSG_Aligned/<sampID>/Effort Tho_Sync_采样率.txt

+

同步后的Abd信号:./PSG_Aligned/<sampID>/Effort Abd_Sync_采样率.txt

+

同步后的SpO2信号:./PSG_Aligned/<sampID>/SpO2_Sync_采样率.txt

+

同步后的睡眠呼吸暂停事件标签:./PSG_Aligned/<sampID>/SA Label_Sync.csv

+

输出:

+

修正后的呼吸暂停标签:./Label/<sampID>/SA Label_corrected.csv

+

新增的呼吸暂停标签:./Label/<sampID>/SA Label_add.csv

\ No newline at end of file diff --git a/数据结构化输入和输出命名规范.md b/数据结构化输入和输出命名规范.md deleted file mode 100644 index e7b4a5f..0000000 --- a/数据结构化输入和输出命名规范.md +++ /dev/null @@ -1,300 +0,0 @@ -# 文件命名规范 - - -### 当一份数据被完整走完标注流程后,数据文件夹目录结构将会是: - - -``` -.../Label/ - |-Artifact_a_采样率.txt - |-Artifact_b_采样率.txt - |-Artifact_c_采样率.csv - |-SQ_label_10s.csv - |-SQ_label_30s.csv - |-Resp_quality_label.txt - |-Tho_peak_采样率.txt - |-SA Label_corrected.csv - |-SA Label_add.csv - |-Precisely_Align_info.txt - |-Approximately_Align_Info.csv -.../OrgBCG_Aligned/ - |-BCG_Sync_采样率.txt - |-OrgBCG_Sync_采样率.txt - |-Jpeak_Sync_采样率.txt -.../OrgBCG_Text/ - |-OrgBCG_Raw_采样率.txt - |-BCG_Filter_采样率.txt - |-Jpeak_revise_采样率.txt - |-Jpeak_revise_corrected_采样率.txt -.../OrgBCG_Origin/ - |-... -.../PSG_Aligned/ - |-ECG_Sync_采样率.txt - |-Rpeak_Sync_采样率.txt - |-5_class_Sync_采样率.txt - |-SA Label_Sync.csv - |-Effort Abd_Sync_采样率.txt - |-Effort Tho_Sync_采样率.txt - |-Flow T_Sync_采样率.txt - |-Flow P_Sync_采样率.txt - |-Snore_Sync_采样率.txt - |-SpO2_Sync_采样率.txt -.../PSG_Text/ - |-ECG II_Raw_采样率.txt - |-ECG_Filter_采样率.txt - |-Rpeak_final_采样率.txt - |-Rpeak_final_corrected_采样率.txt - |-5_class_Raw_采样率.txt - |-SA Label_Raw.csv - |-Effort Abd_Raw_采样率.txt - |-Effort Tho_Raw_采样率.txt - |-Flow T_Raw_采样率.txt - |-Flow P_Raw_采样率.txt - |-Snore_Raw_采样率.txt - |-SpO2_Raw_采样率.txt - |-StartTime_Raw.txt -.../PSG_Origin/ - |-... -.../Receive_Origin - |-... -.../Report - |-... -``` - - -### 1 数据粗同步 - - -输入: - -原始orgBcg信号:`./OrgBCG_Text//OrgBCG_Raw_采样率.txt` - -原始PSG信号:`./PSG_Text//Axxxxxxx.edf` - -输出: - -粗同步后的位置索引:`./Label//Approximately_Align_Info.csv` - - -### 2 预处理 - - -输入: - -原始orgBcg信号:`./OrgBCG_Text//OrgBCG_Raw_采样率.txt` - -原始ECG信号:`./PSG_Text//ECG II_Raw_采样率.txt` - -输出: - -带通滤波BCG信号:`./OrgBCG_Text//BCG_Filter_采样率.txt` - -滤波后的ECG信号:`./PSG_Text//ECG_Filter_采样率.txt` - - -### 3 数据精同步 - - -#### 3.1 算法定位 - - -#### 3.1.1 R峰算法定位 - -输入: - -滤波后的ECG信号:`./PSG_Text//ECG_Filter_采样率.txt` - -输出: - -算法定位的R峰坐标:`./PSG_Text//Rpeak_final_采样率.txt` - - -#### 3.1.2 J峰算法定位 - - -输入: - -带通滤波BCG信号:`./OrgBCG_Text//BCG_Filter_采样率.txt` - -输出: - -算法定位的J峰坐标:`./OrgBCG_Text//Jpeak_revise_采样率.txt` - - -#### 3.2 人工纠正 - - -#### 3.2.1 R峰人工纠正 - - -输入: - -滤波后的ECG信号:`./PSG_Text//ECG_Filter_采样率.txt` - -算法定位的R峰坐标:`./PSG_Text//Rpeak_final_采样率.txt` - -粗同步后的位置索引:`./Label//Approximately_Align_Info.csv` - -输出: - -人工纠正后的R峰坐标:`./PSG_Text//Rpeak_final_corrected_采样率.txt` - - -#### 3.2.2 J峰人工纠正* - - -输入: - -带通滤波BCG信号:`./OrgBCG_Text//BCG_Filter_采样率.txt` - -算法定位的J峰坐标:`./OrgBCG_Text//Jpeak_revise_采样率.txt` - -粗同步后的位置索引:`./Label//Approximately_Align_Info.csv` - -输出: - -人工纠正后的J峰坐标:`./OrgBCG_Text//Jpeak_revise_corrected_采样率.txt` - - -#### 3.3 数据片段起止对齐、数据采样率同步 - - -输入: - -滤波后的ECG信号:`./PSG_Text//ECG_Filter_采样率.txt` - -人工纠正后的R峰坐标:`./PSG_Text//Rpeak_final_corrected_采样率.txt` - -带通滤波BCG信号:`./OrgBCG_Text//BCG_Filter_采样率.txt` - -人工纠正后的J峰坐标:`./OrgBCG_Text//Jpeak_revise_corrected_采样率.txt` - -原始orgBcg信号:`./OrgBCG_Text//OrgBCG_Raw_采样率.txt` - -粗同步后的位置索引:`./Label//Approximately_Align_Info.csv` - -输出: - -精同步对齐信息:`./Label//Precisely_Align_info.txt` - -同步后的ECG信号:`./PSG_Aligned//ECG_Sync_采样率.txt` - -同步后的R峰坐标:`./PSG_Aligned//Rpeak_Sync_采样率.txt` - -同步后的BCG信号:`./OrgBCG_Aligned//BCG_Sync_采样率.txt` - -同步后的orgBcg信号:`./OrgBCG_Aligned//OrgBCG_Sync_采样率.txt` - -同步后的J峰坐标:`./OrgBCG_Aligned//Jpeak_Sync_采样率.txt` - - -#### 3.4、冗余数据切割、标签映射 - - -输入: - -精同步对齐信息:`./Label//Precisely_Align_info.txt` - -原始的其他PSG通道信号:`./PSG_Text//通道名_Raw_采样率.txt`(通道名包括:Effort Abd, Effort Tho, Flow T, Flow P, Snore, SpO2) - -原始的睡眠分期标签:`./PSG_Text//5_class_Raw_采样率.txt` - -原始的睡眠呼吸暂停事件标签:`./PSG_Text//SA Label_Raw.csv` - -输出: - -同步后的其他PSG通道信号:`./PSG_Aligned//通道名_Sync_采样率.txt`(通道名包括:Effort Abd, Effort Tho, Flow T, Flow P, Snore, SpO2) - -同步后的睡眠分期标签:`./PSG_Aligned//5_class_Sync_采样率.txt` - -同步后的睡眠呼吸暂停事件标签:`./PSG_Aligned//SA Label_Sync.csv` - - -### 4 体动标记 - - -输入: - -同步后的BCG信号:`./OrgBCG_Aligned//BCG_Sync_采样率.txt` - -同步后的orgBcg信号:`./OrgBCG_Aligned//OrgBCG_Sync_采样率.txt` - -输出: - -txt格式的体动标签:`./Label//Artifact_a_采样率.txt` - -体动标签类型数量统计:`./Label//Artifact_b_采样率.txt` - -csv格式的体动标签:`./Label//Artifact_c_采样率.csv` - - -### 5 质量评估 - - -输入: - -同步后的BCG信号:`./OrgBCG_Aligned//BCG_Sync_采样率.txt` - -txt格式的体动标签:`./Label//Artifact_a_采样率.txt` - -输出: - -质量标签:`./Label//SQ_label_10s.csv`或`./Label//SQ_label_30s.csv` - - -### 6 心搏定位数据标注 - - -输入: - -? - -输出: - -? - - -### 7 呼吸提取 - - -输入: - -同步后的orgBcg信号:`./OrgBCG_Aligned//orgBcg_Sync_采样率.txt` - -同步后的THO信号:`./PSG_Aligned//Effort Tho_Sync_采样率.txt` - -txt格式的体动标签:`./Label//Artifact_a_采样率.txt` - -输出: - -呼吸可用性标签:`./Label//Resp_quality_label.txt` - -THO信号呼吸间期标签:`./Label//Tho_peak_采样率.txt` - - -### 8 呼吸暂停事件标注 - - -输入: - -同步后的orgBcg信号:`./OrgBCG_Aligned//OrgBCG_Sync_采样率.txt` - -txt格式的体动标签:`./Label//Artifact_a_采样率.txt` - -同步后的Flow T信号:`./PSG_Aligned//Flow T_Sync_采样率.txt` - -同步后的Flow P信号:`./PSG_Aligned//Flow P_Sync_采样率.txt` - -同步后的THO信号:`./PSG_Aligned//Effort Tho_Sync_采样率.txt` - -同步后的ABD信号:`./PSG_Aligned//Effort Abd_Sync_采样率.txt` - -同步后的SpO2信号:`./PSG_Aligned//SpO2_Sync_采样率.txt` - -同步后的呼吸暂停标签:`./PSG_Aligned//SA Label_Sync.csv` - -输出: - -修正后的呼吸暂停标签:`./Label//SA Label_corrected.csv` - -新增的呼吸暂停标签:`./Label//SA Label_add.csv` \ No newline at end of file From 5b7516985ffa9d651f917ac4fb321832fc792876 Mon Sep 17 00:00:00 2001 From: Yorusora Date: Wed, 28 May 2025 22:07:02 +0800 Subject: [PATCH 18/26] =?UTF-8?q?=E6=9B=B4=E6=96=B0README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b688d9..ec99799 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ 4、在J峰算法定位的时候滤波导致的信号偏移,导致之后的峰值坐标点与实际峰值出现偏移 -5、写一个脚本,用于直接从ConfigParams.py中读取文件命名规则,并直接自动化写入到一个markdown文件中。目的是方便文件命名的修改。 +~~5、写一个脚本,用于直接从ConfigParams.py中读取文件命名规则,并直接自动化写入到一个markdown文件中。目的是方便文件命名的修改。~~ ## 1、主菜单 From 6b7ba17c6a1231147f0bd721d6bd3d65eeb62466 Mon Sep 17 00:00:00 2001 From: Yorusora Date: Thu, 29 May 2025 13:49:44 +0800 Subject: [PATCH 19/26] =?UTF-8?q?=E5=AE=8C=E5=96=84=E4=BA=86<=E4=BD=93?= =?UTF-8?q?=E5=8A=A8=E6=A0=87=E6=B3=A8>=E4=B8=AD=E4=BD=93=E5=8A=A8?= =?UTF-8?q?=E9=80=89=E5=8F=96=E5=8C=BA=E5=9F=9F=E7=9A=84=E5=88=A4=E5=88=AB?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +- func/Module_approximately_align.py | 1 - func/Module_artifact_label.py | 181 ++++++++++++++++++++++------- func/utils/Constants.py | 10 +- 4 files changed, 151 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index ec99799..b38f597 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,17 @@ ## TODO LIST: 1、根据选定区域获取峰值时,将绘制的区域设置为有上限和下限的矩形,根据矩形获取到的横纵区域来计算峰值 -2、体动选取区域的判别尚未做的很完整,选中多个已有的体动的区域时可能会出现问题 +~~2、体动选取区域的判别尚未做的很完整,选中多个已有的体动的区域时可能会出现问题~~ 3、部分模块在导入失败后重新导入时会出现问题,已知模块有<人工纠正>、<体动标注>、<呼吸可用性及间期标注>、<睡眠呼吸暂停事件标注>,主要是涉及到按钮状态的设置,有待后续优化。当前将这些有涉及到的功能,禁止了导入数据后在不关闭界面的情况下直接重新导入 4、在J峰算法定位的时候滤波导致的信号偏移,导致之后的峰值坐标点与实际峰值出现偏移 -~~5、写一个脚本,用于直接从ConfigParams.py中读取文件命名规则,并直接自动化写入到一个markdown文件中。目的是方便文件命名的修改。~~ +~~5、写一个脚本,用于直接从ConfigParams.py中读取文件命名规则,并直接自动化写入到一个markdown文件中。目的是方便文件命名的修改~~ + +6、<呼吸可用性及间期标注>的体动显示做一个和一样的可以根据勾选来显示需要显示的体动 + +7、各个模块中的检测父级文件夹是否存在的功能仍存在问题,无法正确创建文件夹 ## 1、主菜单 diff --git a/func/Module_approximately_align.py b/func/Module_approximately_align.py index 3b64623..b0b8a8f 100644 --- a/func/Module_approximately_align.py +++ b/func/Module_approximately_align.py @@ -1041,7 +1041,6 @@ class Data: # 预重采样 try: if Config["InputConfig"]["ThoFreq"] != Config["TempFrequency"]: - print(int(Config["InputConfig"]["ThoFreq"]), int(Config["TempFrequency"])) self.processed_Tho = resample(self.processed_Tho, int(Config["PSG_seconds"] * Config["TempFrequency"])) diff --git a/func/Module_artifact_label.py b/func/Module_artifact_label.py index ccd4348..f092361 100644 --- a/func/Module_artifact_label.py +++ b/func/Module_artifact_label.py @@ -9,7 +9,7 @@ from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication, QTableWidg from matplotlib import gridspec, patches from matplotlib.backends.backend_qt import NavigationToolbar2QT from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg -from numpy import array +from numpy import array, append, sum as np_sum, nonzero from numpy.fft import fft, fftfreq from overrides import overrides from pandas import read_csv, DataFrame, concat @@ -655,7 +655,12 @@ class MainWindow_artifact_label(QMainWindow): def __slot_btn_label__(self): sender = self.sender() flag = False - select_row = array([]).astype(dict) + select_row = [] + select_type = array([0, 0, 0, 0, 0]) + flagf = False + flagb = False + start_time = 0 + end_time = 0 if sender == self.ui.pushButton_type_1: type = 1 @@ -678,61 +683,149 @@ class MainWindow_artifact_label(QMainWindow): for index, row in self.data.df_Artifact_a.iterrows(): value_startTime = row['startTime'] value_endTime = row['endTime'] + value_type = row['type'] - # if ((value_endTime >= int(self.ui.lineEdit_start_time.text()) and value_startTime <= int(self.ui.lineEdit_start_time.text())) or - # (value_endTime >= int(self.ui.lineEdit_end_time.text()) and value_startTime <= int(self.ui.lineEdit_end_time.text())) or - # (value_startTime >= int(self.ui.lineEdit_start_time.text()) and value_endTime <= int(self.ui.lineEdit_end_time.text())) or - # (value_startTime <= int(self.ui.lineEdit_start_time.text()) and value_endTime >= int(self.ui.lineEdit_end_time.text()))): - # select_row = append(select_row, row) + if ((value_startTime <= int(self.ui.lineEdit_end_time.text()) <= value_endTime) or + (value_startTime <= int(self.ui.lineEdit_start_time.text()) <= value_endTime) or + (value_startTime >= int(self.ui.lineEdit_start_time.text()) and value_endTime <= int(self.ui.lineEdit_end_time.text())) or + (0 < (int(self.ui.lineEdit_start_time.text()) - value_endTime) <= (2 * Config["InputConfig"]["UseFreq"])) or + (0 < (value_startTime - int(self.ui.lineEdit_end_time.text())) <= (2 * Config["InputConfig"]["UseFreq"]))): + select_row.append(row.to_dict()) + if row['type'] == 1: + select_type[0] = select_type[0] + 1 + elif row['type'] == 2: + select_type[1] = select_type[1] + 1 + elif row['type'] == 3: + select_type[2] = select_type[2] + 1 + elif row['type'] == 4: + select_type[3] = select_type[3] + 1 + elif row['type'] == 5: + select_type[4] = select_type[4] + 1 + if (0 < (int(self.ui.lineEdit_start_time.text()) - value_endTime) <= (2 * Config["InputConfig"]["UseFreq"])) and (value_type == type): + flagf = True + if (0 < (value_startTime - int(self.ui.lineEdit_end_time.text())) <= (2 * Config["InputConfig"]["UseFreq"])) and (value_type == type): + flagb = True - # TODO:体动选取区域的判别尚未做的很完整,选中多个已有的体动的区域时可能会出现问题 - if (type == 1 and row['type'] == 1) or (type == 2 and row['type'] == 2) or (type == 3 and row['type'] == 3): - if ((value_startTime > int(self.ui.lineEdit_start_time.text()) and (value_startTime - int(self.ui.lineEdit_end_time.text()) <= 2 * Config["InputConfig"]["UseFreq"])) or - (value_endTime < int(self.ui.lineEdit_end_time.text()) and (int(self.ui.lineEdit_end_time.text()) - value_endTime <= 2 * Config["InputConfig"]["UseFreq"]))): - reply = QMessageBox.question(self, '确认', '{}{},是否确认合并?'.format(Constants.ARTIFACT_LABEL_MERGE, row['number']), QMessageBox.Yes | QMessageBox.No, - QMessageBox.No) - if reply == QMessageBox.Yes: - self.data.df_Artifact_a.loc[self.data.df_Artifact_a['number'] == row['number'], - ['number', 'type', 'startTime', 'endTime']] = [ - int(row['number']), - int(type), - int(self.ui.lineEdit_start_time.text()) if int(self.ui.lineEdit_start_time.text()) < int(row['startTime']) else int(row['startTime']), - int(self.ui.lineEdit_end_time.text()) if int(self.ui.lineEdit_end_time.text()) > int(row['endTime']) else int(row['endTime']) - ] - new_row = {'number': int(row['number']), - 'type': int(type), - 'startTime': int(self.ui.lineEdit_start_time.text()), - 'endTime': int(self.ui.lineEdit_end_time.text())} - flag = True - break - else: - return - 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 + count = np_sum(select_type >= 1) + if count >= 2 or (count == 1 and nonzero(select_type)[0][0] + 1 == type): + if count >= 2: + reply = QMessageBox.question(self, '确认', + '{}{}'.format(Constants.ARTIFACT_LABEL_MULTIPLE_ARTIFACT_COVER_OR_DELETE, [d["number"] for d in select_row]), + QMessageBox.Yes | QMessageBox.No, + QMessageBox.No) + if reply == QMessageBox.No: + return - if not flag: - 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( + if flagf == True and flagb == False: + if type == 1 or type == 2 or type == 3: + PublicFunc.msgbox_output(self, Constants.ARTIFACT_LABEL_FRONT_TWO_SECONDS_MERGE, + Constants.MSGBOX_TYPE_INFO) + start_time = select_row[0]['startTime'] + end_time = int(self.ui.lineEdit_end_time.text()) + elif type == 4 or type == 5: + PublicFunc.msgbox_output(self, Constants.ARTIFACT_LABEL_FRONT_TWO_SECONDS_WARNING, + Constants.MSGBOX_TYPE_INFO) + select_row = select_row[1:] + start_time = int(self.ui.lineEdit_start_time.text()) + end_time = int(self.ui.lineEdit_end_time.text()) + if flagf == False and flagb == True: + if type == 1 or type == 2 or type == 3: + PublicFunc.msgbox_output(self, Constants.ARTIFACT_LABEL_BACK_TWO_SECONDS_MERGE, + Constants.MSGBOX_TYPE_INFO) + start_time = int(self.ui.lineEdit_start_time.text()) + end_time = select_row[-1]['endTime'] + elif type == 4 or type == 5: + PublicFunc.msgbox_output(self, Constants.ARTIFACT_LABEL_BACK_TWO_SECONDS_WARNING, + Constants.MSGBOX_TYPE_INFO) + select_row = select_row[:-1] + start_time = int(self.ui.lineEdit_start_time.text()) + end_time = int(self.ui.lineEdit_end_time.text()) + if flagf == True and flagb == True: + if type == 1 or type == 2 or type == 3: + PublicFunc.msgbox_output(self, Constants.ARTIFACT_LABEL_FRONT_AND_BACK_TWO_SECONDS_MERGE, + Constants.MSGBOX_TYPE_INFO) + start_time = select_row[0]['startTime'] + end_time = select_row[-1]['endTime'] + elif type == 4 or type == 5: + PublicFunc.msgbox_output(self, Constants.ARTIFACT_LABEL_FRONT_AND_BACK_TWO_SECONDS_WARNING, + Constants.MSGBOX_TYPE_INFO) + select_row = select_row[1:-1] + start_time = int(self.ui.lineEdit_start_time.text()) + end_time = int(self.ui.lineEdit_end_time.text()) + if flagf == False and flagb == False: + start_time = int(self.ui.lineEdit_start_time.text()) + end_time = int(self.ui.lineEdit_end_time.text()) + + for select_each_row in select_row: + self.data.df_Artifact_a = self.data.df_Artifact_a[self.data.df_Artifact_a['number'] != select_each_row["number"]] + else: + select_row = [] + select_type = array([0, 0, 0, 0, 0]) + for index, row in self.data.df_Artifact_a.iterrows(): + value_startTime = row['startTime'] + value_endTime = row['endTime'] + value_type = row['type'] + if ((value_startTime <= int(self.ui.lineEdit_end_time.text()) <= value_endTime) or + (value_startTime <= int(self.ui.lineEdit_start_time.text()) <= value_endTime) or + (value_startTime >= int(self.ui.lineEdit_start_time.text()) and value_endTime <= int( + self.ui.lineEdit_end_time.text()))): + select_row.append(row.to_dict()) + if row['type'] == 1: + select_type[0] = select_type[0] + 1 + elif row['type'] == 2: + select_type[1] = select_type[1] + 1 + elif row['type'] == 3: + select_type[2] = select_type[2] + 1 + elif row['type'] == 4: + select_type[3] = select_type[3] + 1 + elif row['type'] == 5: + select_type[4] = select_type[4] + 1 + + count = np_sum(select_type >= 1) + + if (count == 1 and nonzero(select_type)[0][0] + 1 != type): + reply = QMessageBox.question(self, '确认', + '{}{}'.format(Constants.ARTIFACT_LABEL_SINGLE_TYPE_NOT_EQUAL, + [d["number"] for d in select_row]), + QMessageBox.Yes | QMessageBox.No, + QMessageBox.No) + if reply == QMessageBox.No: + return + + start_time = int(self.ui.lineEdit_start_time.text()) + end_time = int(self.ui.lineEdit_end_time.text()) + + for select_each_row in select_row: + self.data.df_Artifact_a = self.data.df_Artifact_a[self.data.df_Artifact_a['number'] != select_each_row["number"]] + elif count == 0: + start_time = int(self.ui.lineEdit_start_time.text()) + end_time = int(self.ui.lineEdit_end_time.text()) + else: + raise ValueError("count值不存在") + + new_row = { + 'number': 1, + 'type': int(type), + 'startTime': start_time, + 'endTime': end_time + } + + self.data.df_Artifact_a = concat([self.data.df_Artifact_a, DataFrame([new_row])], ignore_index=True) + self.data.df_Artifact_a[['type', 'startTime', 'endTime']] = 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'] = range(1, len(self.data.df_Artifact_a) + 1) + 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)] + target_row = self.data.df_Artifact_a[self.data.df_Artifact_a.eq(start_time).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) + PublicFunc.text_output(self.ui, f"新增体动标签{first_column_value}, 类型{new_row['type']},从{int(start_time)}ms到{int(end_time)}ms", Constants.TIPS_TYPE_INFO) self.save() diff --git a/func/utils/Constants.py b/func/utils/Constants.py index ab85a69..7cbdab4 100644 --- a/func/utils/Constants.py +++ b/func/utils/Constants.py @@ -324,8 +324,14 @@ class Constants: ARTIFACT_LABEL_JUMP_ARTIFACT: str = "跳转到体动" ARTIFACT_LABEL_RECOVER_SCALE: str = "尺度恢复" ARTIFACT_LABEL_MISS_ARGS: str = "打标参数未填写" - ARTIFACT_LABEL_OVERLAPPING: str = "当前所打标的片段存在重合,重合片段序号:" - ARTIFACT_LABEL_MERGE: str = "当前所打标的片段距离附近片段不到2秒,片段序号:" + ARTIFACT_LABEL_MULTIPLE_ARTIFACT_COVER_OR_DELETE: str = "所选区域包含多种类型的体动,是否需要删除它们并使用新标注进行覆盖?所选区域中含有的体动序号:" + ARTIFACT_LABEL_FRONT_TWO_SECONDS_MERGE: str = "所选区域前2秒内有与当前标注相同类型的体动,将执行合并" + ARTIFACT_LABEL_BACK_TWO_SECONDS_MERGE: str = "所选区域后2秒内有与当前标注相同类型的体动,将执行合并" + ARTIFACT_LABEL_FRONT_AND_BACK_TWO_SECONDS_MERGE: str = "所选区域前后2秒内都有与当前标注相同类型的体动,将执行合并" + ARTIFACT_LABEL_FRONT_TWO_SECONDS_WARNING: str = "所选区域前2秒内有与当前标注相同类型的体动,仅进行提示" + ARTIFACT_LABEL_BACK_TWO_SECONDS_WARNING: str = "所选区域后2秒内有与当前标注相同类型的体动,仅进行提示" + ARTIFACT_LABEL_FRONT_AND_BACK_TWO_SECONDS_WARNING: str = "所选区域前后2秒内都有与当前标注相同类型的体动,仅进行提示" + ARTIFACT_LABEL_SINGLE_TYPE_NOT_EQUAL: str = "所选区域仅包含一种类型的体动,但其类型与当前标注的类型不匹配,是否需要删除它们并使用新标注覆盖?所选区域中含有的体动序号:" ARTIFACT_LABEL_DELETE_ARTIFACT_SUCCESSFULLY: str = "体动被删除" ARTIFACT_LABEL_DELETE_ARTIFACT_FAILURE: str = "需要被删除的体动不存在" ARTIFACT_LABEL_ACTION_LABEL: str = f"标注体动({Params.ARTIFACT_LABEL_ACTION_LABEL_ARTIFACT_SHORTCUT_KEY})" From b01e2f1161ce1a56deb40732e8ffe0661d42d6f3 Mon Sep 17 00:00:00 2001 From: Yorusora Date: Thu, 29 May 2025 14:05:52 +0800 Subject: [PATCH 20/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E4=B8=8D=E5=AD=98=E5=9C=A8=E6=97=B6=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E6=AD=A3=E7=A1=AE=E5=88=9B=E5=BB=BA=E6=96=87=E4=BB=B6=E5=A4=B9?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- func/Module_SA_label.py | 3 --- func/Module_approximately_align.py | 2 -- func/Module_artifact_label.py | 7 ------- func/Module_bcg_quality_label.py | 3 --- func/Module_cut_PSG.py | 3 --- func/Module_detect_Jpeak.py | 3 --- func/Module_detect_Rpeak.py | 3 --- func/Module_label_check.py | 3 --- func/Module_mainwindow.py | 25 ++++++++++++++++++++++++- func/Module_precisely_align.py | 3 --- func/Module_preprocess.py | 3 --- func/Module_resp_quality_label.py | 3 --- 13 files changed, 25 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index b38f597..15e2934 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ 6、<呼吸可用性及间期标注>的体动显示做一个和一样的可以根据勾选来显示需要显示的体动 -7、各个模块中的检测父级文件夹是否存在的功能仍存在问题,无法正确创建文件夹 +~~7、各个模块中的检测父级文件夹是否存在的功能仍存在问题,无法正确创建文件夹~~ ## 1、主菜单 diff --git a/func/Module_SA_label.py b/func/Module_SA_label.py index a92237f..acc017f 100644 --- a/func/Module_SA_label.py +++ b/func/Module_SA_label.py @@ -1590,9 +1590,6 @@ class Data: return Result().success(info=Constants.RESAMPLE_FINISHED) def save(self): - if (not Path(Config["Path"]["Save"]).parent.exists()) or (not Path(Config["Path"]["Save"]).parent.is_dir()): - Path(Config["Path"]["Save"]).parent.mkdir(parents=True, exist_ok=True) - if self.df_corrected is None: return Result().failure(info=Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) diff --git a/func/Module_approximately_align.py b/func/Module_approximately_align.py index b0b8a8f..8d4b482 100644 --- a/func/Module_approximately_align.py +++ b/func/Module_approximately_align.py @@ -964,8 +964,6 @@ class Data: return Result().success(info=Constants.INPUT_FINISHED) def save(self, epoch): - if (not Path(Config["Path"]["Save"]).parent.exists()) or (not Path(Config["Path"]["Save"]).parent.is_dir()): - Path(Config["Path"]["Save"]).parent.mkdir(parents=True, exist_ok=True) try: pos = Config["pos"] ApplyFrequency = Config["ApplyFrequency"] diff --git a/func/Module_artifact_label.py b/func/Module_artifact_label.py index f092361..4c946ae 100644 --- a/func/Module_artifact_label.py +++ b/func/Module_artifact_label.py @@ -1378,13 +1378,6 @@ class Data: return Result().success(info=Constants.ARCHIVE_EXIST) def save(self, amount, duration): - if (not Path(Config["Path"]["Save_a"]).parent.exists()) or (not Path(Config["Path"]["Save_a"]).parent.is_dir()): - Path(Config["Path"]["Save_a"]).parent.mkdir(parents=True, exist_ok=True) - if (not Path(Config["Path"]["Save_b"]).parent.exists()) or (not Path(Config["Path"]["Save_b"]).parent.is_dir()): - Path(Config["Path"]["Save_b"]).parent.mkdir(parents=True, exist_ok=True) - if (not Path(Config["Path"]["Save_c"]).parent.exists()) or (not Path(Config["Path"]["Save_c"]).parent.is_dir()): - Path(Config["Path"]["Save_c"]).parent.mkdir(parents=True, exist_ok=True) - try: # Artifact_a.txt和Artifact_c.csv的内容遍历 output_lines = [] diff --git a/func/Module_bcg_quality_label.py b/func/Module_bcg_quality_label.py index e6f5217..e7deb72 100644 --- a/func/Module_bcg_quality_label.py +++ b/func/Module_bcg_quality_label.py @@ -1085,9 +1085,6 @@ class Data(): return Result().success(info=Constants.PREPROCESS_FINISHED) def save(self, label): - if (not Path(Config["Path"]["Save"]).parent.exists()) or (not Path(Config["Path"]["Save"]).parent.is_dir()): - Path(Config["Path"]["Save"]).parent.mkdir(parents=True, exist_ok=True) - if self.df_label is None: return Result().failure(info=Filename.RESP_QUALITY_LABEL + Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) diff --git a/func/Module_cut_PSG.py b/func/Module_cut_PSG.py index cedb1d6..1d43c64 100644 --- a/func/Module_cut_PSG.py +++ b/func/Module_cut_PSG.py @@ -323,9 +323,6 @@ class Data: return Result().success(info=Constants.CUT_PSG_ALIGN_LABEL_FINISHED) def save(self): - if (not Path(Config["Path"]["SaveFolder"]).exists()) or (not Path(Config["Path"]["SaveFolder"]).is_dir()): - Path(Config["Path"]["SaveFolder"]).mkdir(parents=True, exist_ok=True) - for raw in self.raw.values(): if len(raw) == 0: return Result().failure(info=Constants.SAVE_FAILURE + diff --git a/func/Module_detect_Jpeak.py b/func/Module_detect_Jpeak.py index de66a0d..11f36ff 100644 --- a/func/Module_detect_Jpeak.py +++ b/func/Module_detect_Jpeak.py @@ -460,9 +460,6 @@ class Data: return Result().success(info=Constants.DETECT_JPEAK_PREDICT_FINISHED) def save(self, chunk): - if (not Path(Config["Path"]["Save"]).parent.exists()) or (not Path(Config["Path"]["Save"]).parent.is_dir()): - Path(Config["Path"]["Save"]).parent.mkdir(parents=True, exist_ok=True) - if self.peak is None: return Result().failure(info=Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) diff --git a/func/Module_detect_Rpeak.py b/func/Module_detect_Rpeak.py index 76d700e..f884eb4 100644 --- a/func/Module_detect_Rpeak.py +++ b/func/Module_detect_Rpeak.py @@ -452,9 +452,6 @@ class Data: return Result().success(info=Constants.DETECT_RPEAK_PREDICT_FINISHED) def save(self, chunk): - if (not Path(Config["Path"]["Save"]).parent.exists()) or (not Path(Config["Path"]["Save"]).parent.is_dir()): - Path(Config["Path"]["Save"]).parent.mkdir(parents=True, exist_ok=True) - if self.peak is None: return Result().failure(info=Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) diff --git a/func/Module_label_check.py b/func/Module_label_check.py index 14d5517..55b1a43 100644 --- a/func/Module_label_check.py +++ b/func/Module_label_check.py @@ -960,9 +960,6 @@ class Data: return Result().success(info=Constants.INPUT_FINISHED) def get_archive(self): - if (not Path(Config["Path"]["Save"]).parent.exists()) or (not Path(Config["Path"]["Save"]).parent.is_dir()): - Path(Config["Path"]["Save"]).parent.mkdir(parents=True, exist_ok=True) - if not Path(Config["Path"]["Save"]).exists(): self.corrected_peak = self.original_peak return Result().success(info=Constants.ARCHIVE_NOT_EXIST) diff --git a/func/Module_mainwindow.py b/func/Module_mainwindow.py index 3f62ec0..056972e 100644 --- a/func/Module_mainwindow.py +++ b/func/Module_mainwindow.py @@ -126,6 +126,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.approximately_align.show(root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.approximately_align.showMaximized() + self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_preprocess__(self): self.preprocess = MainWindow_preprocess() @@ -146,6 +147,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.preprocess.show(mode, root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.preprocess.showMaximized() + self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_detect_Jpeak__(self): self.detect_Jpeak = MainWindow_detect_Jpeak() @@ -158,6 +160,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.detect_Jpeak.show(root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.detect_Jpeak.showMaximized() + self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_detect_Rpeak__(self): self.detect_Rpeak = MainWindow_detect_Rpeak() @@ -170,6 +173,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.detect_Rpeak.show(root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.detect_Rpeak.showMaximized() + self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_label_check__(self): self.label_check = MainWindow_label_check() @@ -192,6 +196,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.label_check.show(mode, root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.label_check.showMaximized() + self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_precisely_align__(self): self.precisely_align = MainWindow_precisely_align() @@ -204,6 +209,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.precisely_align.show(root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.precisely_align.showMaximized() + self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_cut_PSG__(self): self.cut_PSG = MainWindow_cut_PSG() @@ -214,6 +220,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): if not self.check_sampID(): return self.cut_PSG.show(root_path, int(sampID)) + self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_artifact_label__(self): self.artifact_label = MainWindow_artifact_label() @@ -226,6 +233,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.artifact_label.show(root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.artifact_label.showMaximized() + self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_bcg_quality_label__(self): self.bcg_quality_label = MainWindow_bcg_quality_label() @@ -238,6 +246,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.bcg_quality_label.show(root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.bcg_quality_label.showMaximized() + self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_resp_quality_label__(self): self.resp_quality_label = MainWindow_resp_quality_label() @@ -250,6 +259,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.resp_quality_label.show(root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.resp_quality_label.showMaximized() + self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_SA_label__(self): self.SA_label = MainWindow_SA_label() @@ -262,6 +272,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label): self.SA_label.show(root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.SA_label.showMaximized() + self.check_save_path_and_mkdir(root_path, sampID) def seek_sampID(self, path): if not Path(path).exists(): @@ -271,7 +282,6 @@ class MainWindow(QMainWindow, Ui_Signal_Label): sub_folders = [item.name for item in Path(path).iterdir() if item.is_dir()] self.ui.comboBox_sampID.addItems(sub_folders) - def check_root_path(self): if self.ui.plainTextEdit_root_path.toPlainText() == Constants.STRING_IS_EMPTY: PublicFunc.msgbox_output(self, Constants.MAINWINDOW_ROOT_PATH_NOT_EXIST, Constants.MSGBOX_TYPE_ERROR) @@ -283,3 +293,16 @@ class MainWindow(QMainWindow, Ui_Signal_Label): PublicFunc.msgbox_output(self, Constants.MAINWINDOW_SAMPID_EMPTY, Constants.MSGBOX_TYPE_ERROR) return False return True + + def check_save_path_and_mkdir(self, root_path, sampID): + path_Label = Path(root_path) / Path(Filename.PATH_LABEL) / Path(str(sampID)) + path_OrgBCG_Aligned = Path(root_path) / Path(Filename.PATH_ORGBCG_ALIGNED) / Path(str(sampID)) + path_PSG_Aligned = Path(root_path) / Path(Filename.PATH_PSG_ALIGNED) / Path(str(sampID)) + path_OrgBCG_Text = Path(root_path) / Path(Filename.PATH_ORGBCG_TEXT) / Path(str(sampID)) + path_PSG_Text = Path(root_path) / Path(Filename.PATH_PSG_TEXT) / Path(str(sampID)) + + path_list = [path_Label, path_OrgBCG_Aligned, path_PSG_Aligned, path_OrgBCG_Text, path_PSG_Text] + + for path in path_list: + if not path.exists(): + path.mkdir(parents=True, exist_ok=True) \ No newline at end of file diff --git a/func/Module_precisely_align.py b/func/Module_precisely_align.py index 4093469..98934a6 100644 --- a/func/Module_precisely_align.py +++ b/func/Module_precisely_align.py @@ -1871,9 +1871,6 @@ class Data: return Result().success(info=info) def save_alignInfo(self): - if (not Path(Config["Path"]["Save_AlignInfo"]).parent.exists()) or (not Path(Config["Path"]["Save_AlignInfo"]).parent.is_dir()): - Path(Config["Path"]["Save_AlignInfo"]).parent.mkdir(parents=True, exist_ok=True) - try: save_data = { "front": { diff --git a/func/Module_preprocess.py b/func/Module_preprocess.py index f751ef5..f016e26 100644 --- a/func/Module_preprocess.py +++ b/func/Module_preprocess.py @@ -474,9 +474,6 @@ class Data: return Result().success(info=Constants.PREPROCESS_FINISHED) def save(self, chunk): - if (not Path(Config["Path"]["Save"]).parent.exists()) or (not Path(Config["Path"]["Save"]).parent.is_dir()): - Path(Config["Path"]["Save"]).parent.mkdir(parents=True, exist_ok=True) - if self.processed_data is None: return Result().failure(info=Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) diff --git a/func/Module_resp_quality_label.py b/func/Module_resp_quality_label.py index e6ab281..7699227 100644 --- a/func/Module_resp_quality_label.py +++ b/func/Module_resp_quality_label.py @@ -1458,9 +1458,6 @@ class Data(): return BDR, band_low, band_high, bcg_spectrum, bcg_freq, tho_spectrum, tho_freq def save_resp_quality_label(self): - if (not Path(Config["Path"]["Save_Resp_quality_label"]).parent.exists()) or (not Path(Config["Path"]["Save_Resp_quality_label"]).parent.is_dir()): - Path(Config["Path"]["Save_Resp_quality_label"]).parent.mkdir(parents=True, exist_ok=True) - if self.resp_quality_label is None: return Result().failure(info=Filename.RESP_QUALITY_LABEL + Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"]) From e379aa6a4abc5147451791ef9e2b22a7ab6515ee Mon Sep 17 00:00:00 2001 From: Yorusora Date: Thu, 29 May 2025 21:13:44 +0800 Subject: [PATCH 21/26] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BA=86=E5=92=8C<=E5=91=BC?= =?UTF-8?q?=E5=90=B8=E5=8F=AF=E7=94=A8=E6=80=A7=E5=8F=8A=E9=97=B4=E6=9C=9F?= =?UTF-8?q?=E6=A0=87=E6=B3=A8>=E7=9A=84=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_bcg_quality_label.py | 26 +- ui/MainWindow/MainWindow_bcg_quality_label.py | 26 +- ui/MainWindow/MainWindow_bcg_quality_label.ui | 24 +- .../MainWindow_resp_quality_label.py | 83 +++++- .../MainWindow_resp_quality_label.ui | 244 +++++++++++++----- 5 files changed, 291 insertions(+), 112 deletions(-) diff --git a/func/Module_bcg_quality_label.py b/func/Module_bcg_quality_label.py index e7deb72..b524db7 100644 --- a/func/Module_bcg_quality_label.py +++ b/func/Module_bcg_quality_label.py @@ -293,14 +293,20 @@ class MainWindow_bcg_quality_label(QMainWindow): if (sender == self.ui.pushButton_input or sender == self.ui.pushButton_prev or sender == self.ui.pushButton_next or - self.ui.tableWidget_a1 or - self.ui.tableWidget_a2 or - self.ui.tableWidget_b1 or - self.ui.tableWidget_b2 or - self.ui.tableWidget_c or - self.ui.tableWidget_f or - self.ui.checkBox_highlight_longest_continuous or - self.ui.checkBox_display_afterfilter): + sender == self.ui.tableWidget_a1 or + sender == self.ui.tableWidget_a2 or + sender == self.ui.tableWidget_b1 or + sender == self.ui.tableWidget_b2 or + sender == self.ui.tableWidget_c or + sender == self.ui.tableWidget_f or + sender == self.ui.checkBox_highlight_longest_continuous or + sender == self.ui.checkBox_display_afterfilter or + sender == self.ui.checkBox_allin or + sender == self.ui.checkBox_type1 or + sender == self.ui.checkBox_type2 or + sender == self.ui.checkBox_type3 or + sender == self.ui.checkBox_type4 or + sender == self.ui.checkBox_type5): try: artifact_type_seq = array([]) artifact_type_seq = artifact_type_seq.astype(int64) @@ -336,8 +342,8 @@ class MainWindow_bcg_quality_label(QMainWindow): display_data[Config["CurrentDataIdx"]: Config["CurrentDataIdx"] + length], label=Constants.BCG_QUALITY_LABEL_PLOT_LABEL_SIGNAL, color=Constants.PLOT_COLOR_BLUE) for i in artifact_type_seq: - mask[i] = self.data.artifact_mask[Config["CurrentDataIdx"]: Config["CurrentDataIdx"] + length] == i - mask[i] = (display_data[Config["CurrentDataIdx"]: Config["CurrentDataIdx"] + length] * + mask[i] = self.data.artifact_mask[Config["CurrentDataIdx"]:Config["CurrentDataIdx"] + length] == i + mask[i] = (display_data[Config["CurrentDataIdx"]:Config["CurrentDataIdx"] + length] * mask[i]).astype(float64) place(mask[i], mask[i] == 0, nan) self.ax0.plot(arange(Config["CurrentDataIdx"], Config["CurrentDataIdx"] + length), mask[i], diff --git a/ui/MainWindow/MainWindow_bcg_quality_label.py b/ui/MainWindow/MainWindow_bcg_quality_label.py index dec5d33..2d2c363 100644 --- a/ui/MainWindow/MainWindow_bcg_quality_label.py +++ b/ui/MainWindow/MainWindow_bcg_quality_label.py @@ -158,8 +158,8 @@ class Ui_MainWindow_bcg_quality_label(object): self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") self.groupBox_artifact_type = QGroupBox(self.groupBox_left) self.groupBox_artifact_type.setObjectName(u"groupBox_artifact_type") - self.gridLayout_6 = QGridLayout(self.groupBox_artifact_type) - self.gridLayout_6.setObjectName(u"gridLayout_6") + self.verticalLayout_3 = QVBoxLayout(self.groupBox_artifact_type) + self.verticalLayout_3.setObjectName(u"verticalLayout_3") self.checkBox_allin = QCheckBox(self.groupBox_artifact_type) self.checkBox_allin.setObjectName(u"checkBox_allin") font2 = QFont() @@ -167,42 +167,42 @@ class Ui_MainWindow_bcg_quality_label(object): self.checkBox_allin.setFont(font2) self.checkBox_allin.setChecked(True) - self.gridLayout_6.addWidget(self.checkBox_allin, 0, 1, 1, 1) + self.verticalLayout_3.addWidget(self.checkBox_allin) self.checkBox_type1 = QCheckBox(self.groupBox_artifact_type) self.checkBox_type1.setObjectName(u"checkBox_type1") self.checkBox_type1.setFont(font1) self.checkBox_type1.setChecked(True) - self.gridLayout_6.addWidget(self.checkBox_type1, 0, 2, 1, 1) + self.verticalLayout_3.addWidget(self.checkBox_type1) self.checkBox_type2 = QCheckBox(self.groupBox_artifact_type) self.checkBox_type2.setObjectName(u"checkBox_type2") self.checkBox_type2.setFont(font1) self.checkBox_type2.setChecked(True) - self.gridLayout_6.addWidget(self.checkBox_type2, 1, 1, 1, 1) + self.verticalLayout_3.addWidget(self.checkBox_type2) self.checkBox_type3 = QCheckBox(self.groupBox_artifact_type) self.checkBox_type3.setObjectName(u"checkBox_type3") self.checkBox_type3.setFont(font1) self.checkBox_type3.setChecked(True) - self.gridLayout_6.addWidget(self.checkBox_type3, 1, 2, 1, 1) + self.verticalLayout_3.addWidget(self.checkBox_type3) self.checkBox_type4 = QCheckBox(self.groupBox_artifact_type) self.checkBox_type4.setObjectName(u"checkBox_type4") self.checkBox_type4.setFont(font1) self.checkBox_type4.setChecked(True) - self.gridLayout_6.addWidget(self.checkBox_type4, 2, 1, 1, 1) + self.verticalLayout_3.addWidget(self.checkBox_type4) self.checkBox_type5 = QCheckBox(self.groupBox_artifact_type) self.checkBox_type5.setObjectName(u"checkBox_type5") self.checkBox_type5.setFont(font1) self.checkBox_type5.setChecked(True) - self.gridLayout_6.addWidget(self.checkBox_type5, 2, 2, 1, 1) + self.verticalLayout_3.addWidget(self.checkBox_type5) self.horizontalLayout_2.addWidget(self.groupBox_artifact_type) @@ -510,11 +510,11 @@ class Ui_MainWindow_bcg_quality_label(object): self.label_13.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u4f53\u52a8\u65f6\u95f4\u5360\u6bd4", None)) self.groupBox_artifact_type.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u4f53\u52a8\u7c7b\u578b", None)) self.checkBox_allin.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u5168\u9009", None)) - self.checkBox_type1.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u7c7b\u578b1", None)) - self.checkBox_type2.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u7c7b\u578b2", None)) - self.checkBox_type3.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u7c7b\u578b3", None)) - self.checkBox_type4.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u7c7b\u578b4", None)) - self.checkBox_type5.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u7c7b\u578b5", None)) + self.checkBox_type1.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u7c7b\u578b1-\u5267\u70c8\u4f53\u52a8", None)) + self.checkBox_type2.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u7c7b\u578b2-\u8109\u51b2\u4f53\u52a8", None)) + self.checkBox_type3.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u7c7b\u578b3-\u5e38\u89c4\u4f53\u52a8", None)) + self.checkBox_type4.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u7c7b\u578b4-\u7591\u4f3c\u9f3e\u58f0", None)) + self.checkBox_type5.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u7c7b\u578b5-\u79bb\u5e8a", None)) self.groupBox_function.setTitle(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u529f\u80fd", None)) self.pushButton_invalid_signal_label.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"\u65e0\u6548\u4fe1\u53f7\u6807\u6ce8", None)) self.pushButton_Ctype_signal_label.setText(QCoreApplication.translate("MainWindow_bcg_quality_label", u"C\u7c7b\u4fe1\u53f7\u6807\u6ce8", None)) diff --git a/ui/MainWindow/MainWindow_bcg_quality_label.ui b/ui/MainWindow/MainWindow_bcg_quality_label.ui index 5be4fb4..7fdaef1 100644 --- a/ui/MainWindow/MainWindow_bcg_quality_label.ui +++ b/ui/MainWindow/MainWindow_bcg_quality_label.ui @@ -245,8 +245,8 @@ 体动类型 - - + + @@ -261,7 +261,7 @@ - + @@ -269,14 +269,14 @@ - 类型1 + 类型1-剧烈体动 true - + @@ -284,14 +284,14 @@ - 类型2 + 类型2-脉冲体动 true - + @@ -299,14 +299,14 @@ - 类型3 + 类型3-常规体动 true - + @@ -314,14 +314,14 @@ - 类型4 + 类型4-疑似鼾声 true - + @@ -329,7 +329,7 @@ - 类型5 + 类型5-离床 true diff --git a/ui/MainWindow/MainWindow_resp_quality_label.py b/ui/MainWindow/MainWindow_resp_quality_label.py index 24339c4..7a5e9a5 100644 --- a/ui/MainWindow/MainWindow_resp_quality_label.py +++ b/ui/MainWindow/MainWindow_resp_quality_label.py @@ -15,11 +15,11 @@ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, QFont, QFontDatabase, QGradient, QIcon, QImage, QKeySequence, QLinearGradient, QPainter, QPalette, QPixmap, QRadialGradient, QTransform) -from PySide6.QtWidgets import (QApplication, QDoubleSpinBox, QGridLayout, QGroupBox, - QHBoxLayout, QHeaderView, QLabel, QLineEdit, - QMainWindow, QPushButton, QRadioButton, QSizePolicy, - QSpacerItem, QStatusBar, QTableWidget, QTableWidgetItem, - QTextBrowser, QVBoxLayout, QWidget) +from PySide6.QtWidgets import (QApplication, QCheckBox, QDoubleSpinBox, QGridLayout, + QGroupBox, QHBoxLayout, QHeaderView, QLabel, + QLineEdit, QMainWindow, QPushButton, QRadioButton, + QSizePolicy, QSpacerItem, QStatusBar, QTableWidget, + QTableWidgetItem, QTextBrowser, QVBoxLayout, QWidget) class Ui_MainWindow_resp_quality_label(object): def setupUi(self, MainWindow_resp_quality_label): @@ -159,6 +159,59 @@ class Ui_MainWindow_resp_quality_label(object): self.verticalLayout_2.addWidget(self.groupBox_autoqualitylabel_options) + self.horizontalLayout_2 = QHBoxLayout() + self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") + self.groupBox_artifact_type = QGroupBox(self.groupBox_left) + self.groupBox_artifact_type.setObjectName(u"groupBox_artifact_type") + self.verticalLayout_3 = QVBoxLayout(self.groupBox_artifact_type) + self.verticalLayout_3.setObjectName(u"verticalLayout_3") + self.checkBox_allin = QCheckBox(self.groupBox_artifact_type) + self.checkBox_allin.setObjectName(u"checkBox_allin") + font2 = QFont() + font2.setPointSize(20) + self.checkBox_allin.setFont(font2) + self.checkBox_allin.setChecked(True) + + self.verticalLayout_3.addWidget(self.checkBox_allin) + + self.checkBox_type1 = QCheckBox(self.groupBox_artifact_type) + self.checkBox_type1.setObjectName(u"checkBox_type1") + self.checkBox_type1.setFont(font1) + self.checkBox_type1.setChecked(True) + + self.verticalLayout_3.addWidget(self.checkBox_type1) + + self.checkBox_type2 = QCheckBox(self.groupBox_artifact_type) + self.checkBox_type2.setObjectName(u"checkBox_type2") + self.checkBox_type2.setFont(font1) + self.checkBox_type2.setChecked(True) + + self.verticalLayout_3.addWidget(self.checkBox_type2) + + self.checkBox_type3 = QCheckBox(self.groupBox_artifact_type) + self.checkBox_type3.setObjectName(u"checkBox_type3") + self.checkBox_type3.setFont(font1) + self.checkBox_type3.setChecked(True) + + self.verticalLayout_3.addWidget(self.checkBox_type3) + + self.checkBox_type4 = QCheckBox(self.groupBox_artifact_type) + self.checkBox_type4.setObjectName(u"checkBox_type4") + self.checkBox_type4.setFont(font1) + self.checkBox_type4.setChecked(True) + + self.verticalLayout_3.addWidget(self.checkBox_type4) + + self.checkBox_type5 = QCheckBox(self.groupBox_artifact_type) + self.checkBox_type5.setObjectName(u"checkBox_type5") + self.checkBox_type5.setFont(font1) + self.checkBox_type5.setChecked(True) + + self.verticalLayout_3.addWidget(self.checkBox_type5) + + + self.horizontalLayout_2.addWidget(self.groupBox_artifact_type) + self.groupBox_findpeaks_options = QGroupBox(self.groupBox_left) self.groupBox_findpeaks_options.setObjectName(u"groupBox_findpeaks_options") self.gridLayout_2 = QGridLayout(self.groupBox_findpeaks_options) @@ -194,7 +247,11 @@ class Ui_MainWindow_resp_quality_label(object): self.gridLayout_2.addWidget(self.doubleSpinBox_findpeaks_min_height, 1, 1, 1, 1) - self.verticalLayout_2.addWidget(self.groupBox_findpeaks_options) + self.horizontalLayout_2.addWidget(self.groupBox_findpeaks_options) + + self.horizontalLayout_2.setStretch(0, 2) + + self.verticalLayout_2.addLayout(self.horizontalLayout_2) self.groupBox_threshold_setting = QGroupBox(self.groupBox_left) self.groupBox_threshold_setting.setObjectName(u"groupBox_threshold_setting") @@ -246,6 +303,7 @@ class Ui_MainWindow_resp_quality_label(object): self.label_7 = QLabel(self.groupBox_threshold_setting) self.label_7.setObjectName(u"label_7") self.label_7.setFont(font1) + self.label_7.setAlignment(Qt.AlignmentFlag.AlignCenter) self.gridLayout_6.addWidget(self.label_7, 3, 2, 1, 1) @@ -257,6 +315,10 @@ class Ui_MainWindow_resp_quality_label(object): self.gridLayout_6.addWidget(self.pushButton_refilter_orgBcg, 0, 2, 1, 2) + self.gridLayout_6.setColumnStretch(0, 2) + self.gridLayout_6.setColumnStretch(1, 2) + self.gridLayout_6.setColumnStretch(2, 1) + self.gridLayout_6.setColumnStretch(3, 2) self.verticalLayout_2.addWidget(self.groupBox_threshold_setting) @@ -364,8 +426,6 @@ class Ui_MainWindow_resp_quality_label(object): self.verticalLayout_2.setStretch(1, 3) self.verticalLayout_2.setStretch(2, 1) self.verticalLayout_2.setStretch(3, 3) - self.verticalLayout_2.setStretch(4, 3) - self.verticalLayout_2.setStretch(5, 3) self.verticalLayout_2.setStretch(6, 1) self.verticalLayout_2.setStretch(7, 6) self.verticalLayout_2.setStretch(8, 5) @@ -467,6 +527,13 @@ class Ui_MainWindow_resp_quality_label(object): self.label_6.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"threshold[1]", None)) self.label_5.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"threshold[0]", None)) self.pushButton_autoqualitylabel_recalculate.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u5e94\u7528\u5e76\u8ba1\u7b97", None)) + self.groupBox_artifact_type.setTitle(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u4f53\u52a8\u7c7b\u578b", None)) + self.checkBox_allin.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u5168\u9009", None)) + self.checkBox_type1.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u7c7b\u578b1-\u5267\u70c8\u4f53\u52a8", None)) + self.checkBox_type2.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u7c7b\u578b2-\u8109\u51b2\u4f53\u52a8", None)) + self.checkBox_type3.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u7c7b\u578b3-\u5e38\u89c4\u4f53\u52a8", None)) + self.checkBox_type4.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u7c7b\u578b4-\u7591\u4f3c\u9f3e\u58f0", None)) + self.checkBox_type5.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u7c7b\u578b5-\u79bb\u5e8a", None)) self.groupBox_findpeaks_options.setTitle(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u5bfb\u5cf0\u53c2\u6570\u8bbe\u7f6e", None)) self.label_4.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u6700\u5c0f\u95f4\u9694", None)) self.label_3.setText(QCoreApplication.translate("MainWindow_resp_quality_label", u"\u6700\u5c0f\u9ad8\u5ea6", None)) diff --git a/ui/MainWindow/MainWindow_resp_quality_label.ui b/ui/MainWindow/MainWindow_resp_quality_label.ui index 14af760..d522177 100644 --- a/ui/MainWindow/MainWindow_resp_quality_label.ui +++ b/ui/MainWindow/MainWindow_resp_quality_label.ui @@ -42,7 +42,7 @@ 呼吸可用性及间期标注 - + @@ -248,80 +248,183 @@ - - - 寻峰参数设置 - - - - - - - 0 - 0 - - - - - 12 - - - - 最小间隔 - - - - - - - - 12 - - - - 10000.000000000000000 - - - - - - - - 0 - 0 - - - - - 12 - - - - 最小高度 - - - - - - - - 12 - - - - 10000.000000000000000 - - - - - + + + + + 体动类型 + + + + + + + 20 + + + + 全选 + + + true + + + + + + + + 12 + + + + 类型1-剧烈体动 + + + true + + + + + + + + 12 + + + + 类型2-脉冲体动 + + + true + + + + + + + + 12 + + + + 类型3-常规体动 + + + true + + + + + + + + 12 + + + + 类型4-疑似鼾声 + + + true + + + + + + + + 12 + + + + 类型5-离床 + + + true + + + + + + + + + + 寻峰参数设置 + + + + + + + 0 + 0 + + + + + 12 + + + + 最小间隔 + + + + + + + + 12 + + + + 10000.000000000000000 + + + + + + + + 0 + 0 + + + + + 12 + + + + 最小高度 + + + + + + + + 12 + + + + 10000.000000000000000 + + + + + + + OrgBCG带通滤波频率设置 - + @@ -419,6 +522,9 @@ ~ + + Qt::AlignmentFlag::AlignCenter + From afc93cf498fdff4cd8529bf54757367fbec1811e Mon Sep 17 00:00:00 2001 From: Yorusora Date: Thu, 29 May 2025 21:21:02 +0800 Subject: [PATCH 22/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E4=B8=AD=E4=BD=93?= =?UTF-8?q?=E5=8A=A8=E6=98=BE=E7=A4=BA=E5=BC=82=E5=B8=B8=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_bcg_quality_label.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/func/Module_bcg_quality_label.py b/func/Module_bcg_quality_label.py index b524db7..d903e9f 100644 --- a/func/Module_bcg_quality_label.py +++ b/func/Module_bcg_quality_label.py @@ -1030,7 +1030,16 @@ class Data(): artifact_end = append(artifact_end, self.Artifact_a[i]) self.artifact_mask = zeros(len(self.BCG)) for i in range(0, len(self.artifact_number)): - self.artifact_mask[artifact_start[i]: artifact_end[i] + 1] = 1 + if self.artifact_type[i] == 1: + self.artifact_mask[artifact_start[i]: artifact_end[i] + 1] = 1 + elif self.artifact_type[i] == 2: + self.artifact_mask[artifact_start[i]: artifact_end[i] + 1] = 2 + elif self.artifact_type[i] == 3: + self.artifact_mask[artifact_start[i]: artifact_end[i] + 1] = 3 + elif self.artifact_type[i] == 4: + self.artifact_mask[artifact_start[i]: artifact_end[i] + 1] = 4 + elif self.artifact_type[i] == 5: + self.artifact_mask[artifact_start[i]: artifact_end[i] + 1] = 5 except Exception as e: return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Get_Artifact_Format_Exception"] + "\n" + format_exc()) From 6494dc84788fa5ab81dbf09b887bd8b396ed1d79 Mon Sep 17 00:00:00 2001 From: Yorusora Date: Thu, 29 May 2025 21:30:25 +0800 Subject: [PATCH 23/26] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BA=86<=E5=91=BC?= =?UTF-8?q?=E5=90=B8=E5=8F=AF=E7=94=A8=E6=80=A7=E5=8F=8A=E9=97=B4=E6=9C=9F?= =?UTF-8?q?=E6=A0=87=E6=B3=A8>=E7=9A=84=E4=BD=93=E5=8A=A8=E5=88=86?= =?UTF-8?q?=E7=B1=BB=E6=98=BE=E7=A4=BA=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_resp_quality_label.py | 92 ++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 9 deletions(-) diff --git a/func/Module_resp_quality_label.py b/func/Module_resp_quality_label.py index 7699227..54c9577 100644 --- a/func/Module_resp_quality_label.py +++ b/func/Module_resp_quality_label.py @@ -285,6 +285,12 @@ class MainWindow_resp_quality_label(QMainWindow): self.ui.pushButton_reset.clicked.connect(self.__slot_btn_label__) self.ui.lineEdit_filter_labeled.textChanged.connect(self.__slot_lineEdit_filter__) self.ui.lineEdit_filter_tobelabeled.textChanged.connect(self.__slot_lineEdit_filter__) + self.ui.checkBox_allin.clicked.connect(self.__slot_checkBox__) + self.ui.checkBox_type1.clicked.connect(self.__slot_checkBox__) + self.ui.checkBox_type2.clicked.connect(self.__slot_checkBox__) + self.ui.checkBox_type3.clicked.connect(self.__slot_checkBox__) + self.ui.checkBox_type4.clicked.connect(self.__slot_checkBox__) + self.ui.checkBox_type5.clicked.connect(self.__slot_checkBox__) self.ui.doubleSpinBox_quality_threshold1.valueChanged.connect(self.update_config) self.ui.doubleSpinBox_quality_threshold2.valueChanged.connect(self.update_config) self.ui.doubleSpinBox_findpeaks_min_interval.valueChanged.connect(self.update_config) @@ -349,7 +355,13 @@ class MainWindow_resp_quality_label(QMainWindow): sender == self.ui.pushButton_prev or sender == self.ui.pushButton_next or sender == self.ui.tableWidget_labeled or - sender == self.ui.tableWidget_tobelabeled): + sender == self.ui.tableWidget_tobelabeled or + sender == self.ui.checkBox_allin or + sender == self.ui.checkBox_type1 or + sender == self.ui.checkBox_type2 or + sender == self.ui.checkBox_type3 or + sender == self.ui.checkBox_type4 or + sender == self.ui.checkBox_type5): try: if Config["CurrentPartNum"] != Config["DataPartNum"]: begin_OrgBCG = Config["CurrentOrgBCGIndex"] @@ -385,15 +397,34 @@ class MainWindow_resp_quality_label(QMainWindow): [self.data.Tho_peak_y[x] for x in [index for index, value in enumerate(self.data.Tho_peak) if begin_Tho <= value <= end_Tho]], 'ro', label=Constants.RESP_QUALITY_LABEL_PLOT_LABEL_THO_PEAKS) + + # 绘制体动 + artifact_type_seq = array([]) + artifact_type_seq = artifact_type_seq.astype(int64) + if self.ui.checkBox_type1.isChecked(): + artifact_type_seq = append(artifact_type_seq, 1) + if self.ui.checkBox_type2.isChecked(): + artifact_type_seq = append(artifact_type_seq, 2) + if self.ui.checkBox_type3.isChecked(): + artifact_type_seq = append(artifact_type_seq, 3) + if self.ui.checkBox_type4.isChecked(): + artifact_type_seq = append(artifact_type_seq, 4) + if self.ui.checkBox_type5.isChecked(): + artifact_type_seq = append(artifact_type_seq, 5) + length = Config["InputConfig"]["OrgBCGUseFreq"] * Params.RESP_QUALITY_LABEL_PARTS_TIME_SEC + mask = array([arange(length), arange(length), arange(length), arange(length), arange(length), arange(length)]) + mask = mask.astype(float64) + for i in artifact_type_seq: + mask[i] = self.data.artifact_mask[begin_OrgBCG:end_OrgBCG] == i + mask[i] = (BDR[begin_OrgBCG:end_OrgBCG] * mask[i]).astype(float64) + place(mask[i], mask[i] == 0, nan) + self.ax0.plot(arange(begin_OrgBCG, end_OrgBCG), mask[i], + label=f"{Constants.RESP_QUALITY_LABEL_PLOT_LABEL_ARTIFACT}{i}", color=Constants.PLOT_COLOR_RED, + linestyle="-") + self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT) self.ax1.legend(loc=Constants.PLOT_UPPER_RIGHT) - # 绘制体动 - mask = self.data.artifact_mask[begin_OrgBCG: end_OrgBCG] == 1 - mask = (BDR * mask).astype(float64) - place(mask, mask == 0, nan) - self.ax0.plot(arange(begin_OrgBCG, end_OrgBCG), mask, - label=f"{Constants.RESP_QUALITY_LABEL_PLOT_LABEL_ARTIFACT}", - color=Constants.PLOT_COLOR_PINK, linestyle="-") + # 绘制频谱 self.ax0_spectrum.plot(bcg_freq, bcg_spectrum, label=Constants.RESP_QUALITY_LABEL_SPECTRUM_ORGBCG_LABEL, @@ -952,6 +983,40 @@ class MainWindow_resp_quality_label(QMainWindow): else: raise ValueError("发生信号不存在") + def __slot_checkBox__(self): + sender = self.sender() + + if sender == self.ui.checkBox_allin: + if self.ui.checkBox_allin.isChecked(): + self.ui.checkBox_type1.setChecked(True) + self.ui.checkBox_type2.setChecked(True) + self.ui.checkBox_type3.setChecked(True) + self.ui.checkBox_type4.setChecked(True) + self.ui.checkBox_type5.setChecked(True) + else: + self.ui.checkBox_type1.setChecked(False) + self.ui.checkBox_type2.setChecked(False) + self.ui.checkBox_type3.setChecked(False) + self.ui.checkBox_type4.setChecked(False) + self.ui.checkBox_type5.setChecked(False) + elif (sender == self.ui.checkBox_type1 or + sender == self.ui.checkBox_type2 or + sender == self.ui.checkBox_type3 or + sender == self.ui.checkBox_type4 or + sender == self.ui.checkBox_type5): + if (self.ui.checkBox_type1.isChecked() and + self.ui.checkBox_type2.isChecked() and + self.ui.checkBox_type3.isChecked() and + self.ui.checkBox_type4.isChecked() and + self.ui.checkBox_type5.isChecked()): + self.ui.checkBox_allin.setChecked(True) + else: + self.ui.checkBox_allin.setChecked(False) + else: + raise ValueError("发射信号不存在") + + self.__plot__() + def reset_axes(self): if self.ax0 is not None: self.ax0.clear() @@ -1372,7 +1437,16 @@ class Data(): artifact_end = append(artifact_end, self.Artifact_a[i]) self.artifact_mask = zeros(len(self.OrgBCG)) for i in range(0, len(self.artifact_number)): - self.artifact_mask[artifact_start[i]: artifact_end[i] + 1] = 1 + if self.artifact_type[i] == 1: + self.artifact_mask[artifact_start[i]: artifact_end[i] + 1] = 1 + elif self.artifact_type[i] == 2: + self.artifact_mask[artifact_start[i]: artifact_end[i] + 1] = 2 + elif self.artifact_type[i] == 3: + self.artifact_mask[artifact_start[i]: artifact_end[i] + 1] = 3 + elif self.artifact_type[i] == 4: + self.artifact_mask[artifact_start[i]: artifact_end[i] + 1] = 4 + elif self.artifact_type[i] == 5: + self.artifact_mask[artifact_start[i]: artifact_end[i] + 1] = 5 except Exception as e: return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON["Get_Artifact_Format_Exception"] + "\n" + format_exc()) From 80ffbbcc6980aa7d0834c945ef59adef16a9dab4 Mon Sep 17 00:00:00 2001 From: Yorusora Date: Thu, 29 May 2025 21:40:00 +0800 Subject: [PATCH 24/26] =?UTF-8?q?=E6=9B=B4=E6=96=B0README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 15e2934..7357f8d 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ ~~5、写一个脚本,用于直接从ConfigParams.py中读取文件命名规则,并直接自动化写入到一个markdown文件中。目的是方便文件命名的修改~~ -6、<呼吸可用性及间期标注>的体动显示做一个和一样的可以根据勾选来显示需要显示的体动 +~~6、<呼吸可用性及间期标注>的体动显示做一个和一样的可以根据勾选来显示需要显示的体动~~ ~~7、各个模块中的检测父级文件夹是否存在的功能仍存在问题,无法正确创建文件夹~~ From e23f3e8ee054766855425843717150083c0a2c1a Mon Sep 17 00:00:00 2001 From: Yorusora Date: Thu, 29 May 2025 22:07:37 +0800 Subject: [PATCH 25/26] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BA=86=E7=AC=AC?= =?UTF-8?q?=E4=B8=80=E6=AC=A1=E6=89=93=E5=BC=80<=E4=BA=BA=E5=B7=A5?= =?UTF-8?q?=E7=BA=A0=E6=AD=A3>=E6=97=B6=E5=B0=B1=E4=BF=9D=E5=AD=98?= =?UTF-8?q?=E7=BA=A0=E6=AD=A3=E5=90=8E=E7=9A=84=E6=96=87=E4=BB=B6=E7=9A=84?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_label_check.py | 47 +++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/func/Module_label_check.py b/func/Module_label_check.py index 55b1a43..e28b0b1 100644 --- a/func/Module_label_check.py +++ b/func/Module_label_check.py @@ -464,70 +464,81 @@ class MainWindow_label_check(QMainWindow): self.data = Data() # 导入数据 - PublicFunc.progressbar_update(self, 1, 6, Constants.INPUTTING_DATA, 0) + PublicFunc.progressbar_update(self, 1, 7, Constants.INPUTTING_DATA, 0) result = self.data.open_file() if not result.status: - PublicFunc.text_output(self.ui, "(1/6)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.text_output(self.ui, "(1/7)" + 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/6)" + result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(1/7)" + result.info, Constants.TIPS_TYPE_INFO) # 获取存档 - PublicFunc.progressbar_update(self, 2, 6, Constants.LOADING_ARCHIVE, 20) + PublicFunc.progressbar_update(self, 2, 7, Constants.LOADING_ARCHIVE, 20) result = self.data.get_archive() if not result.status: - PublicFunc.text_output(self.ui, "(2/6)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.text_output(self.ui, "(2/7)" + 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/6)" + result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(2/7)" + result.info, Constants.TIPS_TYPE_INFO) + + # 保存 + PublicFunc.progressbar_update(self, 3, 7, Constants.SAVING_DATA, 25) + result = self.data.save() + if not result.status: + PublicFunc.text_output(self.ui, "(3/7)" + 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/7)" + result.info, Constants.TIPS_TYPE_INFO) # 数据预处理 - PublicFunc.progressbar_update(self, 3, 6, Constants.PREPROCESSING_DATA, 30) + PublicFunc.progressbar_update(self, 4, 7, Constants.PREPROCESSING_DATA, 30) result = self.data.preprocess() if not result.status: - PublicFunc.text_output(self.ui, "(3/6)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.text_output(self.ui, "(4/7)" + 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/6)" + result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(4/7)" + result.info, Constants.TIPS_TYPE_INFO) # 更新表格 - PublicFunc.progressbar_update(self, 4, 6, Constants.UPDATING_TABLEWIDGET_AND_INFO, 50) + PublicFunc.progressbar_update(self, 5, 7, Constants.UPDATING_TABLEWIDGET_AND_INFO, 50) result = self.__update_tableWidget_and_info__() if not result.status: - PublicFunc.text_output(self.ui, "(4/6)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.text_output(self.ui, "(5/7)" + 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/6)" + result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(5/7)" + result.info, Constants.TIPS_TYPE_INFO) # 绘图 - PublicFunc.progressbar_update(self, 5, 6, Constants.DRAWING_DATA, 60) + PublicFunc.progressbar_update(self, 6, 7, Constants.DRAWING_DATA, 60) result = self.__plot__() if not result.status: - PublicFunc.text_output(self.ui, "(5/6)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.text_output(self.ui, "(6/7)" + 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/6)" + result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(6/7)" + result.info, Constants.TIPS_TYPE_INFO) # 绘点 - PublicFunc.progressbar_update(self, 6, 6, Constants.DRAWING_DATA, 80) + PublicFunc.progressbar_update(self, 7, 7, Constants.DRAWING_DATA, 80) result = self.__plot_peaks__() if not result.status: - PublicFunc.text_output(self.ui, "(6/6)" + result.info, Constants.TIPS_TYPE_ERROR) + PublicFunc.text_output(self.ui, "(7/7)" + 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, "(6/6)" + result.info, Constants.TIPS_TYPE_INFO) + PublicFunc.text_output(self.ui, "(7/7)" + result.info, Constants.TIPS_TYPE_INFO) self.__reset__() self.canvas.mpl_connect("motion_notify_event", self.on_motion) From 31a6160c972ab41aef3b854b8043e2fc25e132f1 Mon Sep 17 00:00:00 2001 From: Yorusora Date: Fri, 30 May 2025 20:46:15 +0800 Subject: [PATCH 26/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86<=E5=91=BC?= =?UTF-8?q?=E5=90=B8=E5=8F=AF=E7=94=A8=E6=80=A7=E5=8F=8A=E9=97=B4=E6=9C=9F?= =?UTF-8?q?=E6=A0=87=E6=B3=A8>=E4=B8=AD=E7=BB=98=E5=9B=BE=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func/Module_resp_quality_label.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/func/Module_resp_quality_label.py b/func/Module_resp_quality_label.py index 54c9577..5da029e 100644 --- a/func/Module_resp_quality_label.py +++ b/func/Module_resp_quality_label.py @@ -416,7 +416,7 @@ class MainWindow_resp_quality_label(QMainWindow): mask = mask.astype(float64) for i in artifact_type_seq: mask[i] = self.data.artifact_mask[begin_OrgBCG:end_OrgBCG] == i - mask[i] = (BDR[begin_OrgBCG:end_OrgBCG] * mask[i]).astype(float64) + mask[i] = (BDR * mask[i]).astype(float64) place(mask[i], mask[i] == 0, nan) self.ax0.plot(arange(begin_OrgBCG, end_OrgBCG), mask[i], label=f"{Constants.RESP_QUALITY_LABEL_PLOT_LABEL_ARTIFACT}{i}", color=Constants.PLOT_COLOR_RED,