diff --git a/func/Module_SA_label_v2.py b/func/Module_SA_label_v2.py
new file mode 100644
index 0000000..f41f60e
--- /dev/null
+++ b/func/Module_SA_label_v2.py
@@ -0,0 +1,1919 @@
+from gc import collect
+from pathlib import Path
+from traceback import format_exc
+
+import matplotlib.pyplot as plt
+import pandas as pd
+from PySide6.QtCore import QCoreApplication, QAbstractTableModel, QModelIndex, Qt, QTimer
+from PySide6.QtGui import QAction, QFont, QColor, QCursor, QIntValidator
+from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication, QButtonGroup, QTableWidget, QTableWidgetItem, \
+ QHeaderView, QPlainTextEdit
+from matplotlib import gridspec
+from matplotlib.backends.backend_qt import NavigationToolbar2QT
+from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg
+
+from numpy import array, zeros, append, linspace, place, nan
+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
+from func.utils.Result import Result
+
+from ui.MainWindow.MainWindow_SA_label_v2 import Ui_MainWindow_SA_label
+from ui.setting.SA_label_input_setting_v2 import Ui_MainWindow_SA_label_input_setting
+
+ButtonState = {
+ "Default": {
+ "pushButton_input_setting": True,
+ "pushButton_input": True,
+ "pushButton_quick_remark_input_waitingForTalk": False,
+ "pushButton_quick_remark_input_maybeDesaturation": False,
+ "pushButton_quick_remark_input_maybeWrongLabeled": False,
+ "pushButton_quick_remark_input_durationNoEnough": False,
+ "pushButton_quick_remark_input_littleChange": False,
+ "pushButton_quick_remark_input_noNormalRespBetweenArtifact": False,
+ "pushButton_quick_remark_input_lowSignalNoiseRatio": False,
+ "pushButton_quick_remark_input_changeOnMiddle": False,
+ "pushButton_save": False,
+ "pushButton_prev": False,
+ "pushButton_next": False,
+ "pushButton_confirmLabel": False,
+ "pushButton_jump_to": False,
+ "pushButton_previous10s": False,
+ "pushButton_previous30s": False,
+ "pushButton_previous_half": False,
+ "pushButton_next10s": False,
+ "pushButton_next30s": False,
+ "pushButton_next_half": False
+ },
+ "Current": {
+ "pushButton_input_setting": True,
+ "pushButton_input": True,
+ "pushButton_quick_remark_input_waitingForTalk": False,
+ "pushButton_quick_remark_input_maybeDesaturation": False,
+ "pushButton_quick_remark_input_maybeWrongLabeled": False,
+ "pushButton_quick_remark_input_durationNoEnough": False,
+ "pushButton_quick_remark_input_littleChange": False,
+ "pushButton_quick_remark_input_noNormalRespBetweenArtifact": False,
+ "pushButton_quick_remark_input_lowSignalNoiseRatio": False,
+ "pushButton_quick_remark_input_changeOnMiddle": False,
+ "pushButton_save": False,
+ "pushButton_prev": False,
+ "pushButton_next": False,
+ "pushButton_confirmLabel": False,
+ "pushButton_jump_to": False,
+ "pushButton_previous10s": False,
+ "pushButton_previous30s": False,
+ "pushButton_previous_half": False,
+ "pushButton_next10s": False,
+ "pushButton_next30s": False,
+ "pushButton_next_half": False
+ }
+}
+
+
+class SettingWindow(QMainWindow):
+ def __init__(self, root_path, sampID):
+ super(SettingWindow, self).__init__()
+ self.ui = Ui_MainWindow_SA_label_input_setting()
+ self.ui.setupUi(self)
+
+ self.root_path = root_path
+ self.sampID = sampID
+
+ self.msgBox = QMessageBox()
+ self.msgBox.setWindowTitle(Constants.MAINWINDOW_MSGBOX_TITLE)
+
+ self.params = {}
+ self.connect_signals()
+ self.__read_config__()
+ # self.__examine_freq__()
+
+ def connect_signals(self):
+ self.ui.plainTextEdit_file_path_input_signal_Abd.textChanged.connect(self.__set_plaintext_font_color_by_path__)
+ self.ui.plainTextEdit_file_path_input_signal_FlowP.textChanged.connect(
+ self.__set_plaintext_font_color_by_path__)
+ self.ui.plainTextEdit_file_path_input_signal_FlowT.textChanged.connect(
+ self.__set_plaintext_font_color_by_path__)
+ self.ui.plainTextEdit_file_path_input_signal_OrgBCG.textChanged.connect(
+ self.__set_plaintext_font_color_by_path__)
+ self.ui.plainTextEdit_file_path_input_signal_SpO2.textChanged.connect(
+ self.__set_plaintext_font_color_by_path__)
+ self.ui.plainTextEdit_file_path_input_signal_Tho.textChanged.connect(self.__set_plaintext_font_color_by_path__)
+
+ 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(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(Params.SA_LABEL_CONFIG_FILE_PATH, "r") as f:
+ file_config = load(f.read(), Loader=FullLoader)
+ self.params.update({"Config": file_config})
+
+ sync_bcg_path = Path(self.root_path) / Filename.PATH_ORGBCG_ALIGNED / str(self.sampID)
+ sync_psg_path = Path(self.root_path) / Filename.PATH_PSG_ALIGNED / str(self.sampID)
+ label_path = Path(self.root_path) / Filename.PATH_LABEL / str(self.sampID)
+
+ self.params.update({
+ "Path": {
+ "Input_OrgBCG": sync_bcg_path,
+ "Input_Tho": sync_psg_path,
+ "Input_Abd": sync_psg_path,
+ "Input_FlowT": sync_psg_path,
+ "Input_FlowP": sync_psg_path,
+ "Input_SpO2": sync_psg_path,
+
+ "Input_SA_Label": sync_psg_path / f"{Filename.SA_LABEL_SYNC}{Params.ENDSWITH_CSV}",
+ "Input_Artifact_A": label_path / f"{Filename.ARTIFACT_A}{Params.ENDSWITH_CSV}",
+
+ "SA_Label_Revised": label_path / f"{Filename.SA_LABEL_CORRECTED}{Params.ENDSWITH_CSV}",
+ # "Save_2": label_path / f"{Filename.SA_LABEL_ADD}{Params.ENDSWITH_CSV}"
+ }
+ })
+ self.__auto_find_file__()
+ self.__update_ui_info__()
+
+ def __write_config__(self):
+ # 从界面写入配置
+ self.params["Path"]["Input_OrgBCG"] = self.ui.plainTextEdit_file_path_input_signal_OrgBCG.toPlainText()
+ self.params["Path"]["Input_Tho"] = self.ui.plainTextEdit_file_path_input_signal_Tho.toPlainText()
+ self.params["Path"]["Input_Abd"] = self.ui.plainTextEdit_file_path_input_signal_Abd.toPlainText()
+ self.params["Path"]["Input_FlowT"] = self.ui.plainTextEdit_file_path_input_signal_FlowT.toPlainText()
+ self.params["Path"]["Input_FlowP"] = self.ui.plainTextEdit_file_path_input_signal_FlowP.toPlainText()
+ self.params["Path"]["Input_SpO2"] = self.ui.plainTextEdit_file_path_input_signal_SpO2.toPlainText()
+ self.params["Path"]["Input_Artifact_A"] = self.ui.plainTextEdit_file_path_input_artifact.toPlainText()
+ self.params["Path"]["Input_SA_Label"] = self.ui.plainTextEdit_file_path_input_label.toPlainText()
+ self.params["Path"]["SA_Label_Revised"] = self.ui.plainTextEdit_file_path_save.toPlainText()
+ # self.params["Path"]["Save_2"] = self.ui.plainTextEdit_file_path_save_2.toPlainText()
+
+ self.params["Config"]["InputConfig"]["OrgBCGFreq"] = self.ui.spinBox_input_freq_signal_OrgBCG.value()
+ self.params["Config"]["InputConfig"]["ThoFreq"] = self.ui.spinBox_input_freq_signal_Tho.value()
+ self.params["Config"]["InputConfig"]["AbdFreq"] = self.ui.spinBox_input_freq_signal_Abd.value()
+ self.params["Config"]["InputConfig"]["FlowTFreq"] = self.ui.spinBox_input_freq_signal_FlowT.value()
+ self.params["Config"]["InputConfig"]["FlowPFreq"] = self.ui.spinBox_input_freq_signal_FlowP.value()
+ self.params["Config"]["InputConfig"]["SpO2Freq"] = self.ui.spinBox_input_freq_signal_SpO2.value()
+
+ # 保存配置到文件
+ with open(Params.SA_LABEL_CONFIG_FILE_PATH, "w") as f:
+ dump(self.params["Config"], f)
+
+ self.close()
+
+ def __update_ui_info__(self):
+ self.ui.spinBox_input_freq_signal_OrgBCG.setValue(self.params["Config"]["InputConfig"]["OrgBCGFreq"])
+ self.ui.spinBox_input_freq_signal_Tho.setValue(self.params["Config"]["InputConfig"]["ThoFreq"])
+ self.ui.spinBox_input_freq_signal_Abd.setValue(self.params["Config"]["InputConfig"]["AbdFreq"])
+ self.ui.spinBox_input_freq_signal_FlowT.setValue(self.params["Config"]["InputConfig"]["FlowTFreq"])
+ self.ui.spinBox_input_freq_signal_FlowP.setValue(self.params["Config"]["InputConfig"]["FlowPFreq"])
+ self.ui.spinBox_input_freq_signal_SpO2.setValue(self.params["Config"]["InputConfig"]["SpO2Freq"])
+
+ self.ui.plainTextEdit_file_path_input_signal_OrgBCG.setPlainText(str(self.params["Path"]["Input_OrgBCG"]))
+ self.ui.plainTextEdit_file_path_input_signal_Tho.setPlainText(str(self.params["Path"]["Input_Tho"]))
+ self.ui.plainTextEdit_file_path_input_signal_Abd.setPlainText(str(self.params["Path"]["Input_Abd"]))
+ self.ui.plainTextEdit_file_path_input_signal_FlowT.setPlainText(str(self.params["Path"]["Input_FlowT"]))
+ self.ui.plainTextEdit_file_path_input_signal_FlowP.setPlainText(str(self.params["Path"]["Input_FlowP"]))
+ self.ui.plainTextEdit_file_path_input_signal_SpO2.setPlainText(str(self.params["Path"]["Input_SpO2"]))
+ self.ui.plainTextEdit_file_path_input_artifact.setPlainText(str(self.params["Path"]["Input_Artifact_A"]))
+ self.ui.plainTextEdit_file_path_input_label.setPlainText(str(self.params["Path"]["Input_SA_Label"]))
+ self.ui.plainTextEdit_file_path_save.setPlainText(str(self.params["Path"]["SA_Label_Revised"]))
+ # self.ui.plainTextEdit_file_path_save_2.setPlainText(str(self.params["Path"]["Save_2"]))
+
+ def __auto_find_file__(self):
+ check_signal_type_list = ["Input_OrgBCG", "Input_Tho", "Input_Abd", "Input_FlowT", "Input_FlowP", "Input_SpO2"]
+
+ def find_file(file_path: Path, _type, endswith):
+ if file_path.is_file():
+ file_path = file_path.parent
+
+ filename_start = getattr(Filename, f"{_type.upper()}_SYNC")
+
+ result = PublicFunc.examine_file(file_path, filename_start, endswith)
+ if result.status:
+ self.params["Path"][f"Input_{_type}"] = result.data["path"]
+
+ self.params["Config"]["InputConfig"][f"{_type}Freq"] = result.data["freq"]
+ else:
+ self.params["Path"][f"Input_{_type}"] = file_path
+ self.params["Config"]["InputConfig"][f"{_type}Freq"] = -1
+
+ for signal_type in check_signal_type_list:
+ signal_file_path = Path(self.params["Path"][signal_type])
+
+ find_file(signal_file_path, signal_type.split("_")[-1], endswith=Params.ENDSWITH_TXT)
+
+ self.__update_ui_info__()
+
+ def __rollback_config__(self):
+ self.__read_config__()
+
+ def __set_plaintext_font_color_by_path__(self):
+ if isinstance(self.sender(), QPlainTextEdit):
+ input_path = Path(self.sender().toPlainText())
+ else:
+ raise TypeError("Sender is not a QPlainTextEdit instance.")
+
+ if input_path.exists() and input_path.is_file():
+ self.sender().setStyleSheet("QPlainTextEdit { color: green; }")
+ else:
+ self.sender().setStyleSheet("QPlainTextEdit { color: red; }")
+
+
+class Data:
+ def __init__(self, config):
+ self.config = config
+ self.OrgBCG = None
+ self.Tho = None
+ self.Abd = None
+ self.FlowT = None
+ self.FlowP = None
+ self.SpO2 = None
+ self.lowPass20Hz = None
+ self.lowPassResp = None
+ self.OrgBCG_Resampled = None
+ self.Tho_Resampled = None
+ self.Abd_Resampled = None
+ self.FlowT_Resampled = None
+ self.FlowP_Resampled = None
+ self.SpO2_Resampled = None
+ self.lowPass20Hz_Resampled = None
+ self.lowPassResp_Resampled = None
+ self.channel = {
+ "orgdata": None,
+ "0.7lowpass_resp": None,
+ "Effort Tho": None,
+ "Effort Abd": None,
+ "Flow T": None,
+ "Flow P": None,
+ "SpO2": None
+ }
+
+ self.event_type_to_value = {
+ "Hypopnea": 1,
+ "Central apnea": 2,
+ "Obstructive apnea": 3,
+ "Mixed apnea": 4,
+ }
+
+ self.event_label_origin = None
+ self.event_label_revised = None
+ self.event_index_origin = None
+ self.event_index_revised = None
+ self.artifact_label = None
+
+ self.Artifact = None
+ self.df_origin = None
+ self.df_revised = None
+
+ def open_file(self):
+ # 仅判断文件是否存在
+ check_file_list = ["Input_OrgBCG", "Input_Tho", "Input_Abd", "Input_FlowT", "Input_FlowP", "Input_SpO2",
+ "Input_SA_Label"]
+
+ for file_key in check_file_list:
+ if (not self.config["Path"][file_key].is_file()) or (not self.config["Path"][file_key].exists()):
+ return Result().failure(info=Constants.INPUT_FAILURE + "\n" +
+ self.config["Path"][file_key] +
+ Constants.FAILURE_REASON["Path_Not_Exist"])
+
+ try:
+ self.OrgBCG = read_csv(self.config["Path"]["Input_OrgBCG"], encoding=Params.UTF8_ENCODING,
+ header=None).to_numpy().reshape(-1)
+ self.Tho = read_csv(self.config["Path"]["Input_Tho"], encoding=Params.UTF8_ENCODING,
+ header=None).to_numpy().reshape(-1)
+ self.Abd = read_csv(self.config["Path"]["Input_Abd"], encoding=Params.UTF8_ENCODING,
+ header=None).to_numpy().reshape(-1)
+ self.FlowT = read_csv(self.config["Path"]["Input_FlowT"], encoding=Params.UTF8_ENCODING,
+ header=None).to_numpy().reshape(-1)
+ self.FlowP = read_csv(self.config["Path"]["Input_FlowP"], encoding=Params.UTF8_ENCODING,
+ header=None).to_numpy().reshape(-1)
+ self.SpO2 = read_csv(self.config["Path"]["Input_SpO2"], encoding=Params.UTF8_ENCODING,
+ header=None).to_numpy().reshape(-1)
+
+ if self.config["Path"]["Input_Artifact_A"].exists() and self.config["Path"]["Input_Artifact_A"].is_file():
+ self.Artifact = read_csv(self.config["Path"]["Input_Artifact_A"],
+ encoding=Params.UTF8_ENCODING,
+ header=None).to_numpy().reshape(-1)
+ else:
+ self.Artifact = array([])
+
+
+ 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)
+ self.Artifact = self.Artifact.reshape(-1, 4)
+ except Exception as e:
+ return Result().failure(info=Constants.INPUT_FAILURE +
+ Constants.FAILURE_REASON[
+ "Get_Artifact_Format_Exception"] + "\n" + format_exc())
+
+ self.config.update({
+ "SignalSecond": int(len(self.OrgBCG) // self.config["Config"]["InputConfig"]["OrgBCGFreq"])
+ })
+
+ # 根据秒数对信号截断
+ self.OrgBCG = self.OrgBCG[:self.config["SignalSecond"] * self.config["Config"]["InputConfig"]["OrgBCGFreq"]]
+ self.Tho = self.Tho[:self.config["SignalSecond"] * self.config["Config"]["InputConfig"]["ThoFreq"]]
+ self.Abd = self.Abd[:self.config["SignalSecond"] * self.config["Config"]["InputConfig"]["AbdFreq"]]
+ self.FlowT = self.FlowT[:self.config["SignalSecond"] * self.config["Config"]["InputConfig"]["FlowTFreq"]]
+ self.FlowP = self.FlowP[:self.config["SignalSecond"] * self.config["Config"]["InputConfig"]["FlowPFreq"]]
+ self.SpO2 = self.SpO2[:self.config["SignalSecond"] * self.config["Config"]["InputConfig"]["SpO2Freq"]]
+ self.event_label_origin = zeros(len(self.OrgBCG))
+ self.event_label_revised = zeros(len(self.OrgBCG))
+ self.event_index_origin = zeros(len(self.OrgBCG))
+ self.event_index_revised = zeros(len(self.OrgBCG))
+
+ return Result().success(info=Constants.INPUT_FINISHED)
+
+ def get_archive(self):
+ # if (not Path(self.config["Path"]["Save"]).exists()) or (not Path(self.config["Path"]["Save_2"]).exists()):
+ plot_freq = self.config["Config"]["InputConfig"]["PlotFreq"]
+ self.df_origin = read_csv(self.config["Path"]["Input_SA_Label"], encoding="gbk")
+ self.df_origin["Start"] = self.df_origin["Start"].astype(int)
+ self.df_origin["End"] = self.df_origin["End"].astype(int)
+ self.df_origin["Index"] = self.df_origin["Index"].astype(int)
+
+ self.df_origin = self.df_origin.sort_values(by="Start", ascending=True)
+ for one_data in self.df_origin.index:
+ one_data = self.df_origin.loc[one_data]
+ start = one_data["Start"]
+ end = one_data["End"]
+
+ self.event_label_origin[start * plot_freq:end * plot_freq] = self.event_type_to_value[
+ one_data["Event type"]]
+ self.event_index_origin[start:end] = one_data["Index"]
+
+ if not Path(self.config["Path"]["SA_Label_Revised"]).exists():
+ self.df_revised = self.df_origin.copy()
+
+ self.df_revised["score"] = -1
+ self.df_revised["remark"] = ""
+ self.df_revised["correct_Start"] = -1
+ self.df_revised["correct_End"] = -1
+ self.df_revised["correct_EventsType"] = ""
+ self.df_revised["isLabeled"] = -1
+
+ self.event_label_revised = self.event_label_origin.copy()
+ self.event_index_revised = self.event_index_origin.copy()
+
+ return Result().success(info=Constants.ARCHIVE_NOT_EXIST)
+ else:
+ try:
+ self.df_revised = read_csv(self.config["Path"]["SA_Label_Revised"], encoding="gbk")
+ csv_headers = self.df_revised.columns.tolist()
+ revised_columns = ["Index", "isLabeled", "correct_EventsType", "score", "correct_Start", "correct_End",
+ "remark"]
+ if not all(col in csv_headers for col in revised_columns):
+ return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON[
+ "Label_Format_Exception"] + "\n" + f"缺少列: {', '.join(set(revised_columns) - set(csv_headers))}")
+
+ # 类型转换
+ self.df_revised["correct_Start"] = self.df_revised["correct_Start"].astype(int)
+ self.df_revised["correct_End"] = self.df_revised["correct_End"].astype(int)
+ self.df_revised["isLabeled"] = self.df_revised["isLabeled"].astype(int)
+ self.df_revised["score"] = self.df_revised["score"].astype(int)
+ self.df_revised["Index"] = self.df_revised["Index"].astype(int)
+ self.df_revised["remark"] = self.df_revised["remark"].astype(str)
+ self.df_revised["correct_EventsType"] = self.df_revised["correct_EventsType"].astype(str)
+
+ for index in self.df_revised.index:
+ one_data = self.df_revised.iloc[index]
+ if one_data["score"] == 3:
+ continue
+
+ start = one_data["correct_Start"] if one_data["isLabeled"] == 1 else one_data["Start"]
+ end = one_data["correct_End"] if one_data["isLabeled"] == 1 else one_data["End"]
+
+ self.event_label_revised[start * plot_freq:end * plot_freq] = self.event_type_to_value[
+ one_data["Event type"]]
+ self.event_index_revised[start:end] = one_data["Index"]
+
+ except Exception as e:
+ return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON[
+ "Label_Format_Exception"] + "\n" + format_exc())
+
+ return Result().success(info=Constants.ARCHIVE_EXIST)
+
+ def preprocess(self):
+ if self.OrgBCG is None:
+ return Result().failure(info=Constants.PREPROCESS_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"])
+
+ try:
+ plot_freq = self.config["Config"]["InputConfig"]["PlotFreq"]
+ orgbcg_freq = self.config["Config"]["InputConfig"]["OrgBCGFreq"]
+
+ self.lowPass20Hz = Butterworth_for_ECG_PreProcess(self.OrgBCG,
+ orgbcg_freq,
+ 'lowpass', low_cut=20, order=3)
+ self.lowPassResp = Butterworth_for_ECG_PreProcess(self.OrgBCG,
+ orgbcg_freq,
+ 'lowpass', low_cut=0.7, order=3)
+ self.artifact_label = zeros(len(self.event_label_origin))
+
+ for i, artifact_type, start, end in self.Artifact:
+ start = int(start) // (orgbcg_freq // plot_freq)
+ end = int(end) // (orgbcg_freq // plot_freq)
+ artifact_type = int(artifact_type) + 5
+ start = 0 if start < 0 else start
+ if end < 0:
+ continue
+ if start > len(self.event_label_origin):
+ continue
+ self.artifact_label[start:end] = artifact_type
+
+ 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 resample(self):
+ if self.Tho is None or self.Abd is None or self.FlowT is None or self.FlowP is None or self.SpO2 is None or self.lowPass20Hz is None or self.lowPassResp is None:
+ return Result().failure(info=Constants.RESAMPLE_FAILURE +
+ Constants.FAILURE_REASON["Data_Not_Exist"])
+
+ try:
+ def _resample_signal(signal, orig_freq, target_freq):
+ if orig_freq < target_freq:
+ return signal.repeat(int(target_freq / orig_freq))
+ elif orig_freq > target_freq:
+ return signal[::int(orig_freq / target_freq)]
+ else:
+ return signal
+
+ plot_freq = self.config["Config"]["InputConfig"]["PlotFreq"]
+ orgbcg_freq = self.config["Config"]["InputConfig"]["OrgBCGFreq"]
+
+ self.lowPass20Hz_Resampled = _resample_signal(self.lowPass20Hz, orgbcg_freq, plot_freq)
+ self.lowPassResp_Resampled = _resample_signal(self.lowPassResp, orgbcg_freq, plot_freq)
+ self.Tho_Resampled = _resample_signal(self.Tho, self.config["Config"]["InputConfig"]["ThoFreq"], plot_freq)
+ self.Abd_Resampled = _resample_signal(self.Abd, self.config["Config"]["InputConfig"]["AbdFreq"], plot_freq)
+ self.FlowT_Resampled = _resample_signal(self.FlowT, self.config["Config"]["InputConfig"]["FlowTFreq"],
+ plot_freq)
+ self.FlowP_Resampled = _resample_signal(self.FlowP, self.config["Config"]["InputConfig"]["FlowPFreq"],
+ plot_freq)
+ self.SpO2_Resampled = _resample_signal(self.SpO2, self.config["Config"]["InputConfig"]["SpO2Freq"],
+ plot_freq)
+
+ self.channel["orgdata"] = self.lowPass20Hz_Resampled
+ self.channel["0.7lowpass_resp"] = self.lowPassResp_Resampled
+ self.channel["Effort Tho"] = self.Tho_Resampled
+ self.channel["Effort Abd"] = self.Abd_Resampled
+ self.channel["Flow T"] = self.FlowT_Resampled
+ self.channel["Flow P"] = self.FlowP_Resampled
+ self.channel["SpO2"] = self.SpO2_Resampled
+ except Exception as e:
+ return Result().failure(info=Constants.RESAMPLE_FAILURE +
+ Constants.FAILURE_REASON["Resample_Exception"] + "\n" + format_exc())
+
+ return Result().success(info=Constants.RESAMPLE_FINISHED)
+
+ def save(self):
+ if self.df_revised is None:
+ return Result().failure(info=Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Data_Not_Exist"])
+
+ try:
+ self.df_revised.to_csv(self.config["Path"]["SA_Label_Revised"], mode='w', index=None, encoding="gbk")
+ except PermissionError as e:
+ return Result().failure(info=Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Save_Permission_Denied"])
+ except FileNotFoundError as e:
+ return Result().failure(info=Constants.SAVE_FAILURE + Constants.FAILURE_REASON["Save_File_Not_Found"])
+ except Exception as e:
+ return Result().failure(info=Constants.SAVE_FAILURE +
+ Constants.FAILURE_REASON["Save_Exception"] + "\n" + format_exc())
+
+ return Result().success(Constants.SAVE_FINISHED)
+
+
+class DataFrameModel(QAbstractTableModel):
+ def __init__(self, dataframe, display_columns, header_mapping):
+ super().__init__()
+ self._dataframe = dataframe
+ self._display_columns = display_columns
+ self._showdata = dataframe[display_columns].copy() # Copy the DataFrame to avoid modifying the original
+ self.filter_txt = "" # Initialize filter text
+ self._header_mapping = header_mapping # Dictionary for custom header names
+
+ def rowCount(self, parent=QModelIndex()):
+ return len(self._showdata)
+
+ def columnCount(self, parent=QModelIndex()):
+ return len(self._display_columns)
+
+ def data(self, index, role=Qt.DisplayRole):
+ if not index.isValid():
+ return None
+ row = index.row()
+ col = index.column()
+ column_name = self._display_columns[col]
+ value = self._showdata.iloc[row][column_name]
+
+ if role == Qt.DisplayRole:
+ # 返回显示的文本
+ return str(value)
+
+ # 当isLabeled列为1时,整行前景变色
+ if role == Qt.ForegroundRole:
+ if "isLabeled" in self._dataframe.columns:
+ try:
+ is_labeled_value = pd.to_numeric(self._showdata.iloc[row]["isLabeled"], errors='coerce')
+ if is_labeled_value == 1:
+ return QColor(0, 255, 0)
+ else:
+ return QColor(255, 165, 0)
+ except Exception as e:
+ return None
+
+ return None
+
+ def headerData(self, section, orientation, role=Qt.DisplayRole):
+ if role != Qt.DisplayRole:
+ return None
+ if orientation == Qt.Horizontal:
+ # Return custom header name if available, otherwise use column name
+ return self._header_mapping.get(self._display_columns[section], self._display_columns[section])
+ return str(section + 1)
+
+ def get_data(self, index):
+ if not index.isValid():
+ return None
+ row = index.row()
+ col = "Index"
+ if 0 <= row < len(self._showdata):
+ return self._showdata.iloc[row][col]
+ return None
+
+ def flags(self, index):
+ # Make table non-editable
+ return Qt.ItemIsSelectable | Qt.ItemIsEnabled
+
+ def filter_data(self, filter_text):
+ self.filter_txt = filter_text
+ if filter_text == "":
+ self._showdata = self._dataframe[self._display_columns].copy()
+ else:
+ # Filter the DataFrame based on the filter text
+ filtered_df = self._dataframe[
+ self._dataframe.apply(lambda row: row.astype(str).str.contains(filter_text, case=False).any(), axis=1)]
+ self._showdata = filtered_df[self._display_columns].copy()
+
+ self.layoutChanged.emit() # Notify the view that the data has changed
+
+ def update_all(self, _dataframe):
+ # 整张表更新或增删一行
+ self._dataframe = _dataframe
+ self._showdata = _dataframe[self._display_columns].copy() # Update the displayed data
+ self.filter_data(self.filter_txt)
+ self.layoutChanged.emit()
+
+
+class MainWindow_SA_label(QMainWindow):
+ def __init__(self):
+ super(MainWindow_SA_label, self).__init__()
+ self.ui = Ui_MainWindow_SA_label()
+ self.ui.setupUi(self)
+
+ self.root_path = None
+ self.sampID = None
+
+ self.data = None
+
+ self.setting = None
+ self.config = None
+
+ self.buttonGroup_event = None
+ self.buttonGroup_class = None
+
+ # 初始化进度条
+ self.progressbar = None
+ PublicFunc.add_progressbar(self)
+
+ # 初始化画框
+ self.fig = None
+ self.canvas = None
+ self.figToolbar = None
+ self.gs = None
+
+ self.ui.textBrowser_info.setStyleSheet("QTextBrowser { background-color: rgb(255, 255, 200); }")
+ PublicFunc.__styleAllButton__(self, ButtonState)
+
+ # 设定事件和其对应颜色
+ # event_code color event
+ # 0 黑色 背景
+ # 1 粉色 低通气
+ # 2 蓝色 中枢性
+ # 3 红色 阻塞型
+ # 4 灰色 混合型
+ # 5 绿色 血氧饱和度下降
+ # 6 橙色 大体动
+ # 7 橙色 小体动
+ # 8 橙色 深呼吸
+ # 9 橙色 脉冲体动
+ # 10 橙色 无效片段
+ self.color_cycle = ["black", "pink", "blue", "red", "silver", "green", "orange", "orange", "orange", "orange",
+ "orange"]
+
+ self.display_columns_origin = ["Index", "Event type", "Start", "End"]
+ self.display_columns_name_origin = ["事件编号", "事件类型", "起始时间(s)", "终止时间(s)"]
+ self.header_mapping_origin = dict(zip(self.display_columns_origin, self.display_columns_name_origin))
+
+ self.display_columns_revised = ["Index", "isLabeled", "correct_EventsType", "score", "correct_Start",
+ "correct_End"]
+ self.display_columns_name_revised = ["事件编号", "已标注", "修正事件类型", "标签类型", "起始时间(s)",
+ "终止时间(s)"]
+ self.header_mapping_revised = dict(zip(self.display_columns_revised, self.display_columns_name_revised))
+
+ self.event_type_to_radio = {
+ "Obstructive apnea": self.ui.radioButton_OSA,
+ "Central apnea": self.ui.radioButton_CSA,
+ "Mixed apnea": self.ui.radioButton_MSA,
+ "Hypopnea": self.ui.radioButton_HPY
+ }
+
+ self.score_to_radio = {
+ "1": self.ui.radioButton_1_class,
+ "2": self.ui.radioButton_2_class,
+ "3": self.ui.radioButton_3_class
+ }
+
+ self.msgBox = QMessageBox()
+ self.msgBox.setWindowTitle(Constants.MAINWINDOW_MSGBOX_TITLE)
+
+ self.event_ploy_collection = {}
+ self.selected_event_info = None
+ self.selected_event_rect = None
+ self.press = None
+
+ @overrides
+ def show(self, root_path, sampID):
+ super().show()
+ self.root_path = root_path
+ self.sampID = sampID
+
+ self.setting = SettingWindow(root_path, sampID)
+ self.config = self.setting.params
+ self.config.update(
+ {
+ "WindowStartSecond": 0,
+ "WindowSignalSecond": int(self.ui.comboBox_window_signal_length.currentText()),
+ }
+ )
+
+ # 初始化画框
+ self.fig = plt.figure(figsize=(12, 9), dpi=100)
+ self.canvas = FigureCanvasQTAgg(self.fig)
+ self.figToolbar = CustomNavigationToolbar(self.canvas, self)
+
+ self.figToolbar.cid_mouse_press = self.canvas.mpl_connect('button_press_event', self.on_press)
+ self.figToolbar.cid_mouse_release = self.canvas.mpl_connect('button_release_event', self.on_release)
+ self.figToolbar.cid_mouse_move = self.canvas.mpl_connect('motion_notify_event', self.on_motion)
+
+ self.ui.verticalLayout_canvas.addWidget(self.canvas)
+ self.ui.verticalLayout_canvas.addWidget(self.figToolbar)
+
+ self.gs = gridspec.GridSpec(7, 1, height_ratios=[1, 1, 1, 1, 1, 3, 2])
+ 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(Params.FORMATTER)
+ self.ax0.set_ylim((85, 100))
+ 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(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(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(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(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(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(Params.FORMATTER)
+
+ self.channel_to_ax = {
+ "SpO2": self.ax0,
+ "Flow T": self.ax1,
+ "Flow P": self.ax2,
+ "Effort Tho": self.ax3,
+ "Effort Abd": self.ax4,
+ "0.7lowpass_resp": self.ax5,
+ "orgdata": self.ax6,
+ }
+
+ PublicFunc.__resetAllButton__(self, ButtonState)
+
+ self.ui.comboBox_window_signal_length.lineEdit().setValidator(QIntValidator(10, 1200))
+
+ self.ui.tableView_label_revised.doubleClicked.connect(self.show_selected_event)
+ self.ui.tableView_label.doubleClicked.connect(self.show_selected_event)
+
+ self.buttonGroup_event = QButtonGroup(self)
+ self.buttonGroup_class = QButtonGroup(self)
+
+ self.buttonGroup_event.addButton(self.ui.radioButton_OSA)
+ self.buttonGroup_event.addButton(self.ui.radioButton_CSA)
+ self.buttonGroup_event.addButton(self.ui.radioButton_MSA)
+ self.buttonGroup_event.addButton(self.ui.radioButton_HPY)
+ self.buttonGroup_class.addButton(self.ui.radioButton_1_class)
+ self.buttonGroup_class.addButton(self.ui.radioButton_2_class)
+ self.buttonGroup_class.addButton(self.ui.radioButton_3_class)
+ self.ui.radioButton_OSA.setChecked(True)
+ self.ui.radioButton_2_class.setChecked(True)
+
+ self.ui.pushButton_input.clicked.connect(self.__slot_btn_input__)
+ self.ui.pushButton_input_setting.clicked.connect(self.setting.show)
+
+ self.ui.comboBox_window_signal_length.currentTextChanged.connect(self.__update_window_signal_length__)
+ self.ui.pushButton_best_fit.clicked.connect(self.best_fit)
+
+ # self.ui.pushButton_prev.clicked.connect(self.__slot_btn_move__)
+ # self.ui.pushButton_next.clicked.connect(self.__slot_btn_move__)
+ self.ui.pushButton_save.clicked.connect(self.__save_revise_df__)
+ self.ui.pushButton_quick_remark_input_waitingForTalk.clicked.connect(self.__slot_btn_quick_remark__)
+ self.ui.pushButton_quick_remark_input_maybeDesaturation.clicked.connect(self.__slot_btn_quick_remark__)
+ self.ui.pushButton_quick_remark_input_maybeWrongLabeled.clicked.connect(self.__slot_btn_quick_remark__)
+ self.ui.pushButton_quick_remark_input_durationNoEnough.clicked.connect(self.__slot_btn_quick_remark__)
+ self.ui.pushButton_quick_remark_input_littleChange.clicked.connect(self.__slot_btn_quick_remark__)
+ self.ui.pushButton_quick_remark_input_noNormalRespBetweenArtifact.clicked.connect(
+ self.__slot_btn_quick_remark__)
+ self.ui.pushButton_quick_remark_input_lowSignalNoiseRatio.clicked.connect(self.__slot_btn_quick_remark__)
+ self.ui.pushButton_quick_remark_input_changeOnMiddle.clicked.connect(self.__slot_btn_quick_remark__)
+ self.ui.pushButton_previous10s.clicked.connect(self.__slot_btn_move__)
+ self.ui.pushButton_previous30s.clicked.connect(self.__slot_btn_move__)
+ self.ui.pushButton_previous_half.clicked.connect(self.__slot_btn_move__)
+ self.ui.pushButton_next10s.clicked.connect(self.__slot_btn_move__)
+ self.ui.pushButton_next30s.clicked.connect(self.__slot_btn_move__)
+ self.ui.pushButton_next_half.clicked.connect(self.__slot_btn_move__)
+ self.ui.pushButton_jump_to.clicked.connect(self.__slot_btn_move__)
+ self.ui.pushButton_confirmLabel.clicked.connect(self.__slot_btn_confirmLabel__)
+
+ # 输入防抖
+ self.debounce_timer1 = QTimer()
+ self.debounce_timer1.setSingleShot(True)
+ self.debounce_timer1.setInterval(500)
+ self.debounce_timer1.timeout.connect(self.apply_text_filter)
+ self.ui.lineEdit_filter_label_origin.textChanged.connect(self.debounce_timer1.start)
+
+ self.debounce_timer2 = QTimer()
+ self.debounce_timer2.setSingleShot(True)
+ self.debounce_timer2.setInterval(500)
+ self.debounce_timer2.timeout.connect(self.apply_text_filter)
+ self.ui.lineEdit_filter_label_revised.textChanged.connect(self.debounce_timer2.start)
+
+ # 快捷键
+ self.ui.pushButton_confirmLabel.setShortcut(
+ QCoreApplication.translate("MainWindow", Params.SA_LABEL_BTN_CONFIRMLABEL_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))
+ self.ui.pushButton_previous10s.setShortcut(QCoreApplication.translate("MainWindow", Params.
+ SA_LABEL_BTN_PREV_10s_SHORTCUT_KEY))
+ self.ui.pushButton_previous30s.setShortcut(QCoreApplication.translate("MainWindow", Params.
+ SA_LABEL_BTN_PREV_30s_SHORTCUT_KEY))
+ self.ui.pushButton_previous_half.setShortcut(QCoreApplication.translate("MainWindow", Params.
+ SA_LABEL_BTN_PREV_HALF_SHORTCUT_KEY))
+ self.ui.pushButton_next10s.setShortcut(QCoreApplication.translate("MainWindow", Params.
+ SA_LABEL_BTN_NEXT_10s_SHORTCUT_KEY))
+ self.ui.pushButton_next30s.setShortcut(QCoreApplication.translate("MainWindow", Params.
+ SA_LABEL_BTN_NEXT_30s_SHORTCUT_KEY))
+ self.ui.pushButton_next_half.setShortcut(
+ QCoreApplication.translate("MainWindow", Params.SA_LABEL_BTN_NEXT_HALF_SHORTCUT_KEY))
+ self.ui.pushButton_best_fit.setShortcut(
+ QCoreApplication.translate("MainWindow", Params.SA_LABEL_BTN_BEST_FIT_SHORTCUT_KEY))
+
+ def load_data_to_table(self):
+ try:
+ self.data_model_origin = DataFrameModel(self.data.df_origin, self.display_columns_origin,
+ self.header_mapping_origin)
+ self.ui.tableView_label.setModel(self.data_model_origin)
+
+ self.data_model_revised = DataFrameModel(self.data.df_revised, self.display_columns_revised,
+ self.header_mapping_revised)
+ self.ui.tableView_label_revised.setModel(self.data_model_revised)
+
+ except Exception as e:
+ return Result().failure(info=Constants.UPDATE_FAILURE +
+ Constants.FAILURE_REASON["Update_tableWidget_Exception"] + "\n" + format_exc())
+
+ return Result().success(info=Constants.UPDATE_FINISHED)
+
+ def best_fit(self):
+ plot_freq = self.config["Config"]["InputConfig"]["PlotFreq"]
+ start_point = self.config["WindowStartSecond"] * plot_freq
+ end_point = start_point + self.config["WindowSignalSecond"] * plot_freq
+ for channel, ax in self.channel_to_ax.items():
+ signal_max = self.data.channel[channel][start_point: end_point].max()
+ signal_min = self.data.channel[channel][start_point: end_point].min()
+ if channel == "SpO2":
+ signal_max = 100
+ signal_min = min(signal_min, 90)
+ else:
+ # 上限上移2%,下限下移2%
+ delta = abs(signal_max - signal_min) * 0.02
+ signal_max = signal_max + delta
+ signal_min = signal_min - delta
+
+ ax.set_ylim(int(signal_min), int(signal_max))
+ self.canvas.draw()
+
+ def apply_text_filter(self):
+ # 应用文本过滤器
+ if self.sender() == self.debounce_timer1:
+ self.data_model_origin.filter_data(self.ui.lineEdit_filter_label_origin.text())
+
+ elif self.sender() == self.debounce_timer2:
+ self.data_model_revised.filter_data(self.ui.lineEdit_filter_label_revised.text())
+
+ def show_selected_event(self, index):
+ # 通过点击选中
+ if isinstance(index, int):
+ table_index = index
+ keep_xlim = True
+ # 从左侧列表中直接获取当前表中选中行的事件编号列的内容
+ elif hasattr(index, "model"):
+ if index.model() == self.data_model_origin:
+ table_index = self.data_model_origin.get_data(index)
+ elif index.model() == self.data_model_revised:
+ table_index = self.data_model_revised.get_data(index)
+ else:
+ return
+ keep_xlim = False
+ else:
+ return
+ self.show_event_info(table_index)
+ self.__jump_to__event__(table_index, keep_xlim=keep_xlim)
+
+ def on_press(self, event):
+ # 只在编辑模式下响应左键按下事件
+ if not (self.figToolbar.edit_active and event.inaxes == self.ax5 and event.button == 1):
+ return
+ # x轴坐标,因为使用linespace设置,故实际对应秒数
+ x_press = event.xdata
+ # 边界容差
+ side_tol = 0.2
+ # print("press", x_press)
+
+ if self.selected_event_info is None:
+ # 未选中事件之前,按下不响应,释放时处理
+ # print(self.data.event_index_revised[int(x_press)],
+ # self.data.event_index_revised[int(x_press) - 2],
+ # self.data.event_index_revised[int(x_press) + 2])
+ left_wo_sa = self.data.event_index_revised[max(0, int(x_press) - 1)] == 0
+ right_wo_sa = self.data.event_index_revised[min(self.config["SignalSecond"], int(x_press) + 1)] == 0
+ if left_wo_sa and right_wo_sa:
+ self.press = x_press, 'empty', -1, -1
+ else:
+ self.press = None
+ # print("press", "1", self.press)
+ else:
+ x_rect = self.selected_event_rect.get_x()
+ width = self.selected_event_rect.get_width()
+ event_left = x_rect
+ event_right = x_rect + width
+
+ # 检查是否按在边界上
+ if abs(x_press - event_left) < side_tol:
+ self.press = x_press, 'left', x_rect, width
+ elif abs(x_press - event_right) < side_tol:
+ self.press = x_press, 'right', x_rect, width
+ elif event_left < x_press < event_right:
+ self.press = x_press, 'middle', x_rect, width
+ else:
+ # 按下了其他事件上
+ self.press = None
+ # print("press", "2", self.press)
+
+ self.canvas.draw_idle()
+
+ def on_motion(self, event):
+ if not (self.figToolbar.edit_active and event.inaxes == self.ax5):
+ return
+
+ x_motion = event.xdata
+ # 边界容差
+ side_tol = 0.2
+ if event.button == 1:
+ # 已经选中事件的情况下
+ if self.selected_event_info is not None:
+ if self.press is not None:
+
+ x_press, side, x_rect, width = self.press
+ dx = x_motion - x_press
+
+ if side == 'left':
+ self.canvas.setCursor(QCursor(Qt.CursorShape.SizeHorCursor))
+ # 吸附到最近的一秒
+ new_start = round(x_press + dx)
+ new_width = width - (new_start - x_rect)
+ elif side == 'right':
+ self.canvas.setCursor(QCursor(Qt.CursorShape.SizeHorCursor))
+ new_end = round(x_rect + width + dx)
+ new_width = new_end - x_rect
+ new_start = x_rect
+ elif side == 'middle':
+ self.canvas.setCursor(QCursor(Qt.CursorShape.ClosedHandCursor))
+ new_start = round(x_rect + dx)
+ new_width = width
+ else:
+ raise ValueError(
+ f'event({self.selected_event_info}) was selected, side:({side}) must be left/right/middle')
+
+ new_width = max(new_width, 1) # 最小宽度为1秒
+
+ self.selected_event_rect.set_x(new_start)
+ self.selected_event_rect.set_width(new_width)
+
+ else:
+ if self.press is not None and self.press[1] == 'empty':
+ x_press, side, x_rect, width = self.press
+ dx = x_motion - x_press
+ if dx > 1:
+ self.canvas.setCursor(QCursor(Qt.CursorShape.SizeHorCursor))
+ # 是否绑定了rect
+ if self.selected_event_rect is None:
+ # 起始位置向下取整
+ self.selected_event_rect = event.inaxes.axvspan(int(x_press), int(x_press) + 1,
+ color="orange",
+ alpha=0.4)
+ else:
+ x_rect = self.selected_event_rect.get_x()
+ new_right = round(int(x_press) + dx)
+ new_width = new_right - x_rect
+ self.selected_event_rect.set_width(new_width)
+ else:
+ self.canvas.setCursor(QCursor(Qt.CursorShape.ArrowCursor))
+ # 删除创建的矩形框
+ if self.selected_event_rect is not None:
+ self.selected_event_rect.remove()
+ self.selected_event_rect = None
+
+ else:
+ # 如果没有选中事件,则恢复默认光标样式
+ self.canvas.setCursor(QCursor(Qt.CursorShape.ArrowCursor))
+ # 非按下时,靠近边界时,修改光标样式
+ elif event.button is None:
+ if self.selected_event_info is not None and self.selected_event_rect is not None:
+ # 非按下时,靠近边界时,修改光标样式
+ x_rect = self.selected_event_rect.get_x()
+ width = self.selected_event_rect.get_width()
+ event_left = x_rect
+ event_right = x_rect + width
+
+ # 检查是否靠近边界
+ if abs(x_motion - event_left) < side_tol:
+ self.canvas.setCursor(QCursor(Qt.CursorShape.SizeHorCursor))
+ elif abs(x_motion - event_right) < side_tol:
+ self.canvas.setCursor(QCursor(Qt.CursorShape.SizeHorCursor))
+ elif event_left < x_motion < event_right:
+ self.canvas.setCursor(QCursor(Qt.CursorShape.OpenHandCursor))
+ else:
+ self.canvas.setCursor(QCursor(Qt.CursorShape.ArrowCursor))
+ self.canvas.draw_idle()
+
+ def on_release(self, event):
+ if not (self.figToolbar.edit_active and event.inaxes == self.ax5 and event.button == 1):
+ return
+ # print("release", self.selected_event_info, self.press)
+ x_release = event.xdata
+
+ # 检查是否位于SA事件上 用于选中事件
+ if self.data.event_index_revised[int(x_release)] != 0:
+ event_indices = self.data.event_index_revised[int(x_release)]
+ event_row = self.data.df_revised[self.data.df_revised["Index"] == event_indices].iloc[0]
+ else:
+ event_row = None
+
+ # 未选中SA事件下
+ if self.selected_event_info is None:
+ # 非拖动的情况下 停在了某个SA事件上 则显示事件信息
+ if self.press is None and event_row is not None:
+ self.selected_event_info = event_row.copy()
+ self.selected_event_rect = self.event_ploy_collection[self.selected_event_info["Index"]]
+ self.show_selected_event(int(event_row["Index"]))
+ # 高亮 透明度设置为0.4
+ self.selected_event_rect.set_alpha(0.4)
+ self.ui.spinBox_correctStart.setValue(self.selected_event_rect.get_x())
+ self.ui.spinBox_correctEnd.setValue(
+ self.selected_event_rect.get_x() + self.selected_event_rect.get_width())
+
+ elif self.press is None and event_row is None:
+ pass
+
+ # 拖动创建事件的情况下,即正在创建SA事件
+ elif self.press is not None and self.press[1] == 'empty':
+ x_press = self.press[0]
+ dx = x_release - x_press
+ if dx > 1 and self.selected_event_rect is not None:
+ new_start = int(x_press)
+ new_end = round(int(x_press) + dx)
+ if sum(self.data.event_index_revised[
+ max(0, new_start - 1):min(new_end + 1, self.config["SignalSecond"])]) != 0:
+ # 与已有事件重叠,删除创建的矩形框
+ self.selected_event_rect.remove()
+ self.selected_event_rect = None
+ self.selected_event_info = None
+ QMessageBox.warning(self, "警告", "新建事件与已有事件重叠,请重新创建!")
+ elif new_end - new_start < 10:
+ # 事件过短,删除创建的矩形框
+ QMessageBox.warning(self, "警告", "新建事件持续时间短于十秒!")
+
+ # 生成临时event_info
+ event_info_temp = {
+ "Index": -1,
+ "isLabeled": 0,
+ "correct_EventsType": "Obstructive apnea",
+ "score": "2",
+ "correct_Start": new_start,
+ "correct_End": new_end,
+ "remark": ""
+ }
+ self.selected_event_info = event_info_temp
+ self.ui.spinBox_correctStart.setValue(new_start)
+ self.ui.spinBox_correctEnd.setValue(new_end)
+
+ else:
+ # 删除创建的矩形框
+ if self.selected_event_rect is not None:
+ self.selected_event_rect.remove()
+ self.selected_event_rect = None
+ self.selected_event_info = None
+
+ # 选中SA事件的情况下
+ else:
+ # 非拖动的情况下
+ if self.press is None:
+ # 点击了新建SA事件区域
+ if event_row is None and self.selected_event_info["Index"] == -1:
+ x_rect = self.selected_event_rect.get_x()
+ width = self.selected_event_rect.get_width()
+ event_left = x_rect
+ event_right = x_rect + width
+
+ if event_left <= x_release <= event_right:
+ # 点击选中事件的矩形框内,无需响应
+ pass
+ else:
+ # 点击选中事件的矩形框外,取消选中
+ self.selected_event_rect.remove()
+ self.selected_event_rect = None
+ self.selected_event_info = None
+ self.__clear_event_info__()
+
+ # 点击了空白区域
+ elif event_row is None:
+ self.selected_event_rect.set_alpha(0.2)
+ self.selected_event_info = None
+ self.selected_event_rect = None
+ self.__clear_event_info__()
+
+ elif self.selected_event_info["Index"] != event_row["Index"]:
+ # TODO 弹窗提醒是否切换
+ self.selected_event_rect.set_alpha(0.2)
+ self.selected_event_info = event_row.copy()
+ self.selected_event_rect = self.event_ploy_collection[self.selected_event_info["Index"]]
+ self.selected_event_rect.set_alpha(0.4)
+ self.show_selected_event(int(event_row["Index"]))
+ else:
+ # 点击同一个SA事件,无需响应
+ pass
+
+ else:
+ # 松开时,更新数据
+ if self.press is not None:
+ x_press, side, x_rect, width = self.press
+ dx = x_release - x_press
+
+ event_left = x_rect
+ event_right = x_rect + width
+
+ if side == 'left':
+ new_start = round(x_press + dx)
+ new_end = event_right
+ elif side == 'right':
+ new_start = event_left
+ new_end = round(x_rect + width + dx)
+ elif side == 'middle':
+ new_start = round(x_rect + dx)
+ new_end = new_start + width
+ else:
+ raise ValueError(
+ f'event({self.selected_event_info}) was selected, side:({side}) must be left/right/middle')
+
+ new_start = max(new_start, 0)
+ new_end = max(new_end, new_start + 1)
+ if new_end - new_start < 10:
+ QMessageBox.warning(self, "警告", "事件持续时间短于十秒!")
+
+ # 更新到spinbox
+ self.ui.spinBox_correctStart.setValue(new_start)
+ self.ui.spinBox_correctEnd.setValue(new_end)
+
+ self.press = None
+ self.canvas.setCursor(QCursor(Qt.CursorShape.ArrowCursor))
+ self.canvas.draw_idle()
+
+ @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()
+ if self.ax1 is not None:
+ self.ax1.clear()
+ if self.ax2 is not None:
+ self.ax2.clear()
+ if self.ax3 is not None:
+ self.ax3.clear()
+ if self.ax4 is not None:
+ self.ax4.clear()
+ if self.ax5 is not None:
+ self.ax5.clear()
+ if self.ax6 is not None:
+ self.ax6.clear()
+
+ # 释放资源
+ self.setting.close()
+ del self.data
+ self.fig.clf()
+ plt.close(self.fig)
+ self.deleteLater()
+ collect()
+ self.canvas = None
+ event.accept()
+ else:
+ event.ignore()
+
+
+ def __save_revise_df__(self):
+ try:
+ # 过滤掉Index大于origin的行中score为3的行
+ origin_max_index = self.data.df_origin["Index"].max()
+ mask = (self.data.df_revised["Index"] > origin_max_index) & (self.data.df_revised["score"] == 3)
+
+ self.data.df_revised = self.data.df_revised[~mask].reset_index(drop=True)
+ self.data.df_revised.to_csv(self.config["Path"]["SA_Label_Revised"], index=False)
+ except Exception as e:
+ return Result().failure(info=Constants.SAVE_FAILURE +
+ Constants.FAILURE_REASON["Save_revised_csv_Exception"] + "\n" + format_exc())
+ return Result().success(info=Constants.SAVE_FINISHED)
+
+ def __clear_event_info__(self):
+ self.ui.label_BCG_Index.setText("0/0")
+ self.ui.label_BCG_Info.setText("Epoch:0 Duration:0s New Duration:0s")
+ self.ui.lineEdit_remark.setText("")
+ self.ui.radioButton_OSA.setChecked(False)
+ self.ui.radioButton_CSA.setChecked(False)
+ self.ui.radioButton_MSA.setChecked(False)
+ self.ui.radioButton_HPY.setChecked(False)
+ self.ui.radioButton_1_class.setChecked(False)
+ self.ui.radioButton_2_class.setChecked(False)
+ self.ui.radioButton_3_class.setChecked(False)
+ self.ui.spinBox_correctStart.setValue(0)
+ self.ui.spinBox_correctEnd.setValue(0)
+
+ def __reset__(self):
+ ButtonState["Current"].update(ButtonState["Default"].copy())
+
+ def __update_window_signal_length__(self):
+ self.config["WindowSignalSecond"] = int(self.ui.comboBox_window_signal_length.currentText())
+ self.ui.pushButton_next_half.setProperty("offset", self.config["WindowSignalSecond"] // 2)
+ self.ui.pushButton_previous_half.setProperty("offset", -self.config["WindowSignalSecond"] // 2)
+ self.__jump_to__by_time__(self.config["WindowStartSecond"])
+
+ def __jump_to__event__(self, index, keep_xlim=True):
+ event_info = self.data.df_revised[self.data.df_revised["Index"] == index].iloc[0].copy()
+ start_time = event_info["correct_Start"] if event_info["isLabeled"] != -1 else event_info["Start"]
+ end_time = event_info["correct_End"] if event_info["isLabeled"] != -1 else event_info["End"]
+ if keep_xlim:
+ middle_time = self.config["WindowStartSecond"]
+ else:
+ if end_time - start_time > self.config["WindowSignalSecond"]:
+ middle_time = start_time - self.config["WindowSignalSecond"] // 2
+ else:
+ middle_time = (start_time + end_time - self.config["WindowSignalSecond"]) // 2
+
+ self.__jump_to__by_time__(middle_time)
+
+ def __jump_to__by_time__(self, start_time, offset=0):
+ """
+ Jump to a specific time in the signal.
+ :param start_time: The start time in seconds to jump to.
+ :param offset: The offset in seconds to move from the start_time.
+ :return:
+ """
+
+ # if start_time < 0 or start_time > self.config["SignalSecond"]:
+ # raise ValueError("Time must be within the signal length.")
+
+ # Update the start start_time for the plot
+ start_time, end_time = self.check_start_end(start_time, offset)
+ self.config["WindowStartSecond"] = start_time
+ self.ax0.set_xlim((start_time, end_time))
+ self.canvas.draw()
+
+ def show_event_info(self, index):
+ event_info = self.data.df_revised[self.data.df_revised["Index"] == index].iloc[0].copy()
+ if self.selected_event_info is not None:
+ if self.selected_event_info["Index"] != event_info["Index"]:
+ if self.selected_event_rect is not None:
+ self.selected_event_rect.set_alpha(0.2)
+
+ self.selected_event_info = event_info
+ self.selected_event_rect = self.event_ploy_collection[event_info["Index"]]
+ if self.selected_event_rect is not None:
+ self.selected_event_rect.set_alpha(0.4)
+ # show event index info
+ bcg_duration = int(event_info["End"]) - int(event_info["Start"])
+ bcg_new_duration = int(event_info["correct_End"]) - int(event_info["correct_Start"])
+ self.ui.label_BCG_Index.setText(f"{index}/{len(self.data.df_revised)}")
+ self.ui.label_BCG_Info.setText(
+ f"Epoch:{event_info['Epoch']} Duration:{bcg_duration}s New Duration:{bcg_new_duration}")
+
+ # show remark
+ remark = event_info.get("remark", "")
+ if pd.isna(remark):
+ self.ui.lineEdit_remark.setText("")
+ else:
+ self.ui.lineEdit_remark.setText(str(remark))
+
+ # show event type
+ if event_info["isLabeled"] == -1:
+ # If not labeled, show original event type
+ event_type = event_info["Event type"]
+ else:
+ # If labeled, show corrected event type
+ event_type = event_info["correct_EventsType"]
+
+ if event_type in self.event_type_to_radio:
+ self.event_type_to_radio[event_type].setChecked(True)
+ else:
+ raise ValueError(f"Unknown event type: {event_type} event_info={event_info}")
+
+ # show score
+
+ # Default to 2 if (not found or -1)
+ score = str(event_info.get("score", -1))
+ score = "2" if score == "-1" else score
+
+ if score in self.score_to_radio:
+ self.score_to_radio[score].setChecked(True)
+ else:
+ raise ValueError(f"Unknown score: {score} event_info={event_info}")
+
+ # show start and end time to spinbox
+ if event_info["isLabeled"] == -1:
+ self.ui.spinBox_correctStart.setValue(event_info["Start"])
+ self.ui.spinBox_correctEnd.setValue(event_info["End"])
+ else:
+ self.ui.spinBox_correctStart.setValue(event_info["correct_Start"])
+ self.ui.spinBox_correctEnd.setValue(event_info["correct_End"])
+
+ def __slot_btn_confirmLabel__(self):
+ if self.selected_event_info is None:
+ PublicFunc.msgbox_output(self, "未选中任何事件,无法保存!", Constants.MSGBOX_TYPE_WARNING)
+ PublicFunc.text_output(self.ui, "未选中任何事件,无法保存!", Constants.TIPS_TYPE_ERROR)
+ return
+
+ if self.data is None or self.data.df_revised is None:
+ PublicFunc.msgbox_output(self, "请先载入数据", Constants.MSGBOX_TYPE_WARNING)
+ PublicFunc.text_output(self.ui, "请先载入数据", Constants.TIPS_TYPE_ERROR)
+ return
+
+ index = int(self.selected_event_info["Index"])
+
+ if self.ui.radioButton_3_class.isChecked():
+ if index != -1:
+ self.delete_event(index)
+ else:
+ if index == -1:
+ self.add_event()
+ elif index < 1 or index > len(self.data.df_revised):
+ PublicFunc.msgbox_output(self.ui, f"不合理的事件编号:{index}", Constants.MSGBOX_TYPE_WARNING)
+ PublicFunc.text_output(self.ui, f"不合理的事件编号:{index}", Constants.TIPS_TYPE_ERROR)
+ else:
+ self.edit_event(index)
+
+ def __update_label_from_ui__(self, event_info, is_new=False):
+ # Update the event type
+ if self.ui.radioButton_OSA.isChecked():
+ event_info["correct_EventsType"] = "Obstructive apnea"
+ elif self.ui.radioButton_CSA.isChecked():
+ event_info["correct_EventsType"] = "Central apnea"
+ elif self.ui.radioButton_MSA.isChecked():
+ event_info["correct_EventsType"] = "Mixed apnea"
+ elif self.ui.radioButton_HPY.isChecked():
+ event_info["correct_EventsType"] = "Hypopnea"
+ else:
+ raise ValueError("No event type selected.")
+
+ # Update the start and end time
+ # 边界检查
+ if self.ui.spinBox_correctStart.value() >= self.ui.spinBox_correctEnd.value():
+ raise ValueError("Start time must be less than end time.")
+ if self.ui.spinBox_correctStart.value() < 0 or self.ui.spinBox_correctEnd.value() < 0:
+ raise ValueError("Start and end times must be non-negative.")
+ signal_length = self.config["SignalSecond"]
+ if self.ui.spinBox_correctStart.value() > signal_length or self.ui.spinBox_correctEnd.value() > signal_length:
+ raise ValueError("Start and end times must be within the signal length.")
+
+ if is_new:
+ event_info["Start"] = self.ui.spinBox_correctStart.value()
+ event_info["End"] = self.ui.spinBox_correctEnd.value()
+ event_info["EventType"] = event_info["correct_EventsType"]
+
+ event_info["correct_Start"] = self.ui.spinBox_correctStart.value()
+ event_info["correct_End"] = self.ui.spinBox_correctEnd.value()
+
+ # Update the remark
+ remark_text = str(self.ui.lineEdit_remark.text()).strip()
+ if remark_text:
+ event_info["remark"] = remark_text
+ else:
+ event_info["remark"] = None
+
+ # Update the score
+ if self.ui.radioButton_1_class.isChecked():
+ event_info["score"] = 1
+ elif self.ui.radioButton_2_class.isChecked():
+ event_info["score"] = 2
+ elif self.ui.radioButton_3_class.isChecked():
+ event_info["score"] = 3
+ else:
+ raise ValueError("No score selected.")
+
+ return event_info
+
+ def delete_event(self, index):
+ """
+ 删除一个事件
+ :param index: The index of the event in the DataFrame.
+ """
+ if self.data is None or self.data.df_revised is None:
+ raise ValueError("Data or df_revised is not initialized.")
+
+ if index < 1 or index > len(self.data.df_revised):
+ raise IndexError("Index out of bounds for df_revised.")
+
+ event_info = self.data.df_revised[self.data.df_revised["Index"] == index].iloc[0].copy()
+ event_info = self.__update_label_from_ui__(event_info)
+ event_info["isLabeled"] = 1 # Mark as not labeled
+
+ self.data.df_revised[self.data.df_revised["Index"] == index] = event_info
+
+ # 更新表格模型
+ self.data_model_revised.update_all(self.data.df_revised)
+
+ # 去除事件索引映射
+ self.data.event_index_revised[self.data.event_index_revised == event_info["Index"]] = 0
+
+ # 从poly_collection中移除
+ if index in self.event_ploy_collection and self.event_ploy_collection[index] is not None:
+ poly = self.event_ploy_collection.pop(index)
+ poly.remove()
+ self.event_ploy_collection.update({index: None})
+ self.canvas.draw_idle()
+
+ self.selected_event_rect = None
+ # 清空选中状态
+ self.selected_event_info = None
+ self.__clear_event_info__()
+
+ def edit_event(self, index):
+ """
+ Save the revised event information to the DataFrame.
+ :param index: The index of the event in the DataFrame.
+ """
+
+ # Get the current event info
+ event_info = self.data.df_revised[self.data.df_revised["Index"] == index].iloc[0].copy()
+ event_info = self.__update_label_from_ui__(event_info)
+
+ # 检查是否已有事件重叠
+ overlapping_indices = set(self.data.event_index_revised[
+ max(0, event_info["correct_Start"] - 1):min(event_info["correct_End"] + 1,
+ self.config["SignalSecond"])])
+ overlapping_indices.discard(event_info["Index"]) # 去除自身
+ overlapping_indices.discard(0) # 去除空白区域标记
+ if len(overlapping_indices) > 0:
+ PublicFunc.msgbox_output(self, "修改后的事件与已有事件重叠,无法保存!", Constants.MSGBOX_TYPE_WARNING)
+ PublicFunc.text_output(self.ui, "修改后的事件与已有事件重叠,无法保存!", Constants.TIPS_TYPE_ERROR)
+ return
+
+ # 去除原始事件索引映射
+ # 从event_index_revised获取index所在区间
+ self.data.event_index_revised[self.data.event_index_revised == event_info["Index"]] = 0
+
+ # Save changes back to DataFrame
+ event_info["isLabeled"] = 1 # Mark as labeled
+ self.data.df_revised[self.data.df_revised["Index"] == index] = event_info
+ # Update table model
+ self.data_model_revised.update_all(self.data.df_revised)
+
+ # Update event index mapping
+ self.data.event_index_revised[event_info["correct_Start"]:event_info["correct_End"]] = event_info["Index"]
+
+ # Update selected event info
+ self.selected_event_info = event_info.copy()
+ if self.event_ploy_collection[event_info["Index"]] is not None:
+ self.event_ploy_collection[event_info["Index"]].remove()
+
+ self.selected_event_rect = None
+ # Redraw rectangle
+ color = self.color_cycle[self.data.event_type_to_value[event_info["correct_EventsType"]]]
+ self.selected_event_rect = self.ax5.axvspan(event_info["correct_Start"], event_info["correct_End"], color=color,
+ alpha=0.4)
+ self.event_ploy_collection[event_info["Index"]] = self.selected_event_rect
+ self.show_selected_event(int(event_info["Index"]))
+
+ def add_event(self):
+ """
+ 新增一个事件到数据表
+ """
+
+ # 获取index
+ if self.data.df_revised is not None:
+ index = self.data.df_revised["Index"].max() + 1 if not self.data.df_revised.empty else 1
+ else:
+ raise ValueError("DataFrame df_revised is not initialized.")
+
+ new_event = Params.SA_LABEL_NEW_EVENT_FORMAT.copy()
+ new_event["Index"] = index
+ new_event = self.__update_label_from_ui__(new_event, is_new=True)
+ new_event["isLabeled"] = 1 # 标记为已标记状态
+
+ # 检查是否已有事件重叠
+ if sum(self.data.event_index_revised[max(0, new_event["correct_Start"] - 1):min(new_event["correct_End"] + 1,
+ self.config[
+ "SignalSecond"])]) != 0:
+ PublicFunc.msgbox_output(self, "新建事件与已有事件重叠,无法新建!", Constants.MSGBOX_TYPE_WARNING)
+ PublicFunc.text_output(self.ui, "新建事件与已有事件重叠,无法新建!", Constants.TIPS_TYPE_ERROR)
+ return
+
+ # 将新事件添加到临时DataFrame
+ temp_df = pd.DataFrame([new_event])
+ temp_df = temp_df[self.data.df_revised.columns] # 确保列顺序一致
+ temp_df.reset_index(drop=True, inplace=True)
+
+ # 将临时DataFrame添加到df_revised
+ if self.data.df_revised is not None:
+ self.data.df_revised = pd.concat([self.data.df_revised, temp_df], ignore_index=True)
+ else:
+ self.data.df_revised = temp_df
+ # 更新表格模型
+ self.data_model_revised.update_all(self.data.df_revised)
+
+ # 更新事件索引映射
+ self.data.event_index_revised[new_event["correct_Start"]:new_event["correct_End"]] = index
+
+ # 更新event_info
+ self.selected_event_info = new_event.copy()
+ if self.selected_event_rect is not None:
+ self.selected_event_rect.remove()
+
+ # 重新绘制矩形框
+ color = self.color_cycle[self.data.event_type_to_value[new_event["correct_EventsType"]]]
+ self.selected_event_rect = self.ax5.axvspan(new_event["correct_Start"], new_event["correct_End"], color=color,
+ alpha=0.4)
+ self.event_ploy_collection[new_event["Index"]] = self.selected_event_rect
+ self.show_selected_event(int(new_event["Index"]))
+
+ def reset_event(self, event_index):
+ """
+ 从df_origin中重置事件信息到df_revised, df_origin只有df_revised的部分列,剩余的列恢复默认值
+ """
+ if self.data is None or self.data.df_revised is None:
+ raise ValueError("Data or df_revised is not initialized.")
+
+ index = self.data.df_revised[self.data.df_revised["Index"] == event_index].index
+ if index < 1 or index > len(self.data.df_revised):
+ raise IndexError("Index out of bounds for df_revised.")
+
+ # 获取原始事件信息
+ original_event_info = self.data.df_origin[self.data.df_origin["Index"] == index].copy()
+ original_event_info["isLabeled"] = -1 # 重置为未标记状态
+ original_event_info["correct_EventsType"] = "" # 重置为None
+ original_event_info["score"] = -1 # 重置为None
+ original_event_info["correct_Start"] = -1 # 重置为原始起始时间
+ original_event_info["correct_End"] = -1 # 重置为原始终止时间
+ original_event_info["remark"] = "" # 重置备注为None
+ # 检查是否有重叠
+ if sum(self.data.event_index_revised[
+ max(0, original_event_info["Start"] - 1):min(original_event_info["End"] + 1,
+ self.config["SignalSecond"])]) != original_event_info[
+ "Index"]:
+ PublicFunc.msgbox_output(self, "重置事件与已有事件重叠,无法重置!", Constants.MSGBOX_TYPE_WARNING)
+ PublicFunc.text_output(self.ui, "重置事件与已有事件重叠,无法重置!", Constants.TIPS_TYPE_ERROR)
+ return
+
+ # 更新事件索引映射
+ self.data.event_index_revised[original_event_info["Start"]:original_event_info["End"]] = original_event_info[
+ "Index"]
+
+ # 重置事件信息到df_revised
+ self.data.df_revised[self.data.df_revised["Index"] == index] = original_event_info
+
+ self.data_model_revised.update_all(self.data.df_revised)
+
+ def __slot_btn_input__(self):
+ PublicFunc.__disableAllButton__(self, ButtonState)
+
+ self.reset_axes()
+ self.canvas.draw()
+
+ self.data = Data(self.config)
+
+ # 导入数据
+ PublicFunc.progressbar_update(self, 1, 9, Constants.INPUTTING_DATA, 0)
+ result = self.data.open_file()
+ if not result.status:
+ PublicFunc.text_output(self.ui, "(1/9)" + 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/9)" + result.info, Constants.TIPS_TYPE_INFO)
+
+ # 获取存档
+ PublicFunc.progressbar_update(self, 2, 9, Constants.LOADING_ARCHIVE, 15)
+ result = self.data.get_archive()
+ if not result.status:
+ PublicFunc.text_output(self.ui, "(2/9)" + 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/9)" + result.info, Constants.TIPS_TYPE_INFO)
+
+ # 保存
+ PublicFunc.progressbar_update(self, 3, 9, Constants.SAVING_DATA, 20)
+ result = self.data.save()
+ if not result.status:
+ PublicFunc.text_output(self.ui, "(3/9)" + 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/9)" + result.info, Constants.TIPS_TYPE_INFO)
+
+ # 保存
+ # PublicFunc.progressbar_update(self, 4, 9, Constants.SAVING_DATA, 25)
+ # result = self.data.save_2()
+ # if not result.status:
+ # PublicFunc.text_output(self.ui, "(4/9)" + 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/9)" + result.info, Constants.TIPS_TYPE_INFO)
+
+ # 数据预处理
+ PublicFunc.progressbar_update(self, 5, 9, Constants.PREPROCESSING_DATA, 30)
+ result = self.data.preprocess()
+ if not result.status:
+ PublicFunc.text_output(self.ui, "(5/9)" + 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/9)" + result.info, Constants.TIPS_TYPE_INFO)
+
+ # 重采样
+ PublicFunc.progressbar_update(self, 6, 9, Constants.RESAMPLING_DATA, 50)
+ result = self.data.resample()
+ for key, value in self.data.channel.items():
+ PublicFunc.text_output(self.ui, key + "重采样后的长度:" + str(len(value)), Constants.TIPS_TYPE_INFO)
+ if not result.status:
+ PublicFunc.text_output(self.ui, "(6/9)" + 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/9)" + result.info, Constants.TIPS_TYPE_INFO)
+
+ # 绘图
+ PublicFunc.progressbar_update(self, 7, 9, Constants.DRAWING_DATA, 70)
+ # result = self.__plot__()
+ result = self.draw_signal()
+ if not result.status:
+ PublicFunc.text_output(self.ui, "(7/9)" + 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, "(7/9)" + result.info, Constants.TIPS_TYPE_INFO)
+
+ # 更新表格
+ PublicFunc.progressbar_update(self, 8, 9, Constants.UPDATING_TABLEWIDGET, 90)
+ result = self.load_data_to_table()
+ if not result.status:
+ PublicFunc.text_output(self.ui, "(8/9)" + 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, "(8/9)" + result.info, Constants.TIPS_TYPE_INFO)
+
+ # 更新信息
+ PublicFunc.progressbar_update(self, 9, 9, Constants.UPDATING_INFO, 95)
+ # result = self.update_UI_Args()
+ # if not result.status:
+ # PublicFunc.text_output(self.ui, "(9/9)" + 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, "(9/9)" + result.info, Constants.TIPS_TYPE_INFO)
+
+ # if (self.data.df_revised["isLabeled"] == 1).all():
+ # self.ui.checkBox_examineLabeled.setChecked(False)
+ # PublicFunc.msgbox_output(self, Constants.SA_LABEL_ALL_LABELED, Constants.MSGBOX_TYPE_INFO)
+
+ self.__reset__()
+ self.setting.close()
+
+ for action in self.figToolbar._actions.values():
+ action.setEnabled(True)
+
+ for key in ButtonState["Current"].keys():
+ ButtonState["Current"][key] = True
+
+ ButtonState["Current"]["pushButton_input"] = False
+ ButtonState["Current"]["pushButton_input_setting"] = False
+
+ PublicFunc.finish_operation(self, ButtonState)
+
+ def __slot_btn_move__(self):
+ sender = self.sender()
+ if sender.objectName().startswith("pushButton_previous") or sender.objectName().startswith("pushButton_next"):
+ offset = sender.property("offset")
+ PublicFunc.text_output(self.ui, f"移动 {offset} 秒", Constants.TIPS_TYPE_INFO)
+ self.__jump_to__by_time__(self.config["WindowStartSecond"], offset)
+ elif sender.objectName() == "pushButton_jump_to":
+ jump_time_str = self.ui.lineEdit_jump_second.text().strip()
+ if not jump_time_str.isdigit():
+ PublicFunc.msgbox_output(self, "请输入有效的时间(秒)", Constants.MSGBOX_TYPE_WARNING)
+ return
+ jump_time = int(jump_time_str)
+ if jump_time < 0 or jump_time > self.config["SignalSecond"]:
+ PublicFunc.msgbox_output(self, "跳转时间必须在信号长度范围内", Constants.MSGBOX_TYPE_WARNING)
+ return
+ PublicFunc.text_output(self.ui, f"跳转到 {jump_time} 秒", Constants.TIPS_TYPE_INFO)
+ self.__jump_to__by_time__(jump_time)
+
+ def __slot_btn_quick_remark__(self):
+ sender = self.sender()
+
+ if sender == self.ui.pushButton_quick_remark_input_waitingForTalk:
+ self.ui.lineEdit_remark.setText("待讨论")
+ elif sender == self.ui.pushButton_quick_remark_input_maybeDesaturation:
+ self.ui.lineEdit_remark.setText("形似潮式呼吸")
+ self.ui.radioButton_1_class.setChecked(True)
+ elif sender == self.ui.pushButton_quick_remark_input_maybeWrongLabeled:
+ self.ui.lineEdit_remark.setText("疑似医生误标")
+ self.ui.radioButton_2_class.setChecked(True)
+ elif sender == self.ui.pushButton_quick_remark_input_durationNoEnough:
+ self.ui.lineEdit_remark.setText("时长不足")
+ self.ui.radioButton_2_class.setChecked(True)
+ elif sender == self.ui.pushButton_quick_remark_input_littleChange:
+ self.ui.lineEdit_remark.setText("起伏变化不大")
+ self.ui.radioButton_2_class.setChecked(True)
+ elif sender == self.ui.pushButton_quick_remark_input_noNormalRespBetweenArtifact:
+ self.ui.lineEdit_remark.setText("体动间无正常呼吸")
+ self.ui.radioButton_2_class.setChecked(True)
+ elif sender == self.ui.pushButton_quick_remark_input_lowSignalNoiseRatio:
+ self.ui.lineEdit_remark.setText("信噪比低")
+ self.ui.radioButton_2_class.setChecked(True)
+ elif sender == self.ui.pushButton_quick_remark_input_changeOnMiddle:
+ self.ui.lineEdit_remark.setText("中间起伏")
+ self.ui.radioButton_2_class.setChecked(True)
+
+ # def __slot_checkBox_examineLabeled__(self):
+ # if self.ui.checkBox_examineLabeled.isChecked():
+ # if (self.data.df_corrected.loc[self.config["EventLabelIndexList"]]["isLabeled"] == 1).all():
+ # self.ui.checkBox_examineLabeled.setChecked(False)
+ # PublicFunc.text_output(self.ui, Constants.SA_LABEL_ALL_LABELED, Constants.TIPS_TYPE_INFO)
+ # PublicFunc.msgbox_output(self, Constants.SA_LABEL_ALL_LABELED, Constants.MSGBOX_TYPE_INFO)
+
+ def reset_axes(self):
+ if self.ax0 is not None:
+ self.ax0.clear()
+ self.ax0.grid(True)
+ 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(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(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(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(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(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(Params.FORMATTER)
+
+ def draw_signal(self):
+ try:
+ self.plt_channel(channel="SpO2", start=0, end=self.config["SignalSecond"],
+ label_list=self.data.event_label_origin, event_code=[5])
+ self.plt_channel(channel="Flow T", start=0, end=self.config["SignalSecond"],
+ label_list=self.data.event_label_origin, event_code=[1, 2, 3, 4])
+ self.plt_channel(channel="Flow P", start=0, end=self.config["SignalSecond"],
+ label_list=self.data.event_label_origin, event_code=[1, 2, 3, 4])
+ self.plt_channel(channel="Effort Tho", start=0, end=self.config["SignalSecond"],
+ label_list=self.data.event_label_origin, event_code=[1, 2, 3, 4])
+ self.plt_channel(channel="Effort Abd", start=0, end=self.config["SignalSecond"],
+ label_list=self.data.event_label_origin, event_code=[1, 2, 3, 4])
+ self.plt_channel(channel="0.7lowpass_resp", start=0, end=self.config["SignalSecond"])
+ self.plt_interactive_event(channel="0.7lowpass_resp", label_df=self.data.df_revised)
+ self.plt_channel(channel="orgdata", start=0, end=self.config["SignalSecond"],
+ label_list=self.data.artifact_label, event_code=[6, 7, 8, 9, 10])
+
+ self.ax0.set_xlim(self.check_start_end(self.config["WindowStartSecond"], 0))
+ self.canvas.draw()
+ except Exception as e:
+ return Result().failure(info=Constants.DRAW_FAILURE + "\n" + format_exc())
+
+ return Result().success(info=Constants.DRAW_FINISHED)
+
+ def check_start_end(self, start, value):
+ if start + value < 0:
+ return 0, self.config["WindowSignalSecond"]
+ elif start + value + self.config["WindowSignalSecond"] > self.config["SignalSecond"]:
+ return start - self.config["WindowSignalSecond"], self.config["SignalSecond"]
+ else:
+ return start + value, start + value + self.config["WindowSignalSecond"]
+
+ def plt_channel(self, channel, start, end, label_list=None, event_code=[1, 2, 3, 4], event_show_under=False):
+ plt_ = self.channel_to_ax[channel]
+ plot_freq = self.config["Config"]["InputConfig"]["PlotFreq"]
+ start = 0 if start < 0 else start
+ plt_.plot(linspace(start, end, (end - start) * plot_freq),
+ self.data.channel[channel][
+ start * plot_freq:end * plot_freq], label=channel,
+ color=self.color_cycle[0])
+ if label_list is not None:
+ for j in event_code:
+ mask = label_list[start * plot_freq:end * plot_freq] == j
+
+ if event_show_under:
+ min_point = self.data.channel[channel][start * plot_freq:end * plot_freq].min()
+ len_segment = end * plot_freq - start * plot_freq
+ y = (min_point.repeat(len_segment) * mask).astype('float')
+ place(y, y == 0, nan)
+ else:
+ y = (self.data.channel[channel][start * plot_freq:end * plot_freq] * mask).astype('float')
+
+ place(y, y == 0, nan)
+ plt_.plot(linspace(start, end, (end - start) * plot_freq), y, color=self.color_cycle[j], linestyle="-")
+ plt_.legend(fontsize=8, loc=1)
+
+ def plt_interactive_event(self, channel, label_df):
+ """
+ 绘制交互式事件标记
+ :param channel: 信号通道名称
+ :param label_df: 包含事件标记的DataFrame
+ """
+ plt_ = self.channel_to_ax[channel]
+ plot_freq = self.config["Config"]["InputConfig"]["PlotFreq"]
+ for _, row in label_df.iterrows():
+ if row["score"] == 3:
+ span = None
+ else:
+ if row["isLabeled"] == -1:
+ start = row["Start"]
+ end = row["End"]
+ event_type = row["Event type"]
+ else:
+ start = row["correct_Start"]
+ end = row["correct_End"]
+ event_type = row["correct_EventsType"]
+
+ color = self.color_cycle[self.data.event_type_to_value[event_type]]
+ span = plt_.axvspan(start, end, color=color, alpha=0.2, label=event_type)
+
+ self.event_ploy_collection.update({
+ row["Index"]: span
+ })
+
+
+class CustomNavigationToolbar(NavigationToolbar2QT):
+ def __init__(self, canvas, parent):
+ super().__init__(canvas, parent)
+ self.edit_active = False
+
+ # 移除原有除了pan的所有按钮
+ for action in list(self._actions.values()):
+ if action.text() != 'Pan':
+ self.removeAction(action)
+
+ # pan禁用按住右键滑动对x轴变化
+ self.edit_action = QAction('编辑模式(Z)', self)
+ self.edit_action.setFont(QFont(Params.FONT, 14))
+ self.edit_action.setCheckable(True)
+ self.edit_action.triggered.connect(self.toggle_edit)
+ self.edit_action.setShortcut(
+ QCoreApplication.translate("MainWindow", Params.SA_LABEL_BTN_EDIT_MODE_SHORTCUT_KEY))
+ self.insertAction(self._actions['pan'], self.edit_action)
+
+ # Connect Pan action to toggle off Edit
+ self._actions['pan'].triggered.connect(self.toggle_pan)
+
+ def drag_pan(self, event):
+ """Callback for dragging in pan/zoom mode."""
+ for ax in self._pan_info.axes:
+ # Using the recorded button at the press is safer than the current
+ # button, as multiple buttons can get pressed during motion.
+ # # 忽略pan按钮右键对时间尺度的拉伸操作
+ # if self._pan_info.button == 3:
+ # ax.drag_pan(self._pan_info.button, event.key, ax._pan_start.x, event.y)
+ # else:
+ # ax.drag_pan(self._pan_info.button, event.key, event.x, event.y)
+ # 忽略对X轴的操作
+ ax.drag_pan(self._pan_info.button, event.key, ax._pan_start.x, event.y)
+
+ self.canvas.draw_idle()
+
+ def toggle_edit(self):
+ """Handle Edit action toggle."""
+ self.edit_active = self.edit_action.isChecked()
+ if self.edit_active:
+ # Uncheck Pan when Edit is active
+ self._actions['pan'].setChecked(False)
+ self._active = 'EDIT'
+ self.mode = 'edit mode'
+ self.set_message(f"编辑事件: {'启用' if self.edit_active else '禁用'}")
+ self.canvas.draw()
+
+ def toggle_pan(self):
+ """Handle Pan action toggle."""
+ if self._actions['pan'].isChecked():
+ # Uncheck Edit when Pan is active
+ self.edit_action.setChecked(False)
+ self.edit_active = False
+ self.set_message("Pan 模式: 启用")
+ else:
+ self.set_message("Pan 模式: 禁用")
+ self.canvas.draw()
diff --git a/func/Module_mainwindow.py b/func/Module_mainwindow.py
index cd836f0..8325858 100644
--- a/func/Module_mainwindow.py
+++ b/func/Module_mainwindow.py
@@ -20,7 +20,7 @@ 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
+from func.Module_SA_label_v2 import MainWindow_SA_label
from func.utils.ConfigParams import Filename, Params
from func.utils.Constants import Constants
diff --git a/func/utils/ConfigParams.py b/func/utils/ConfigParams.py
index 623a953..36a3887 100644
--- a/func/utils/ConfigParams.py
+++ b/func/utils/ConfigParams.py
@@ -343,18 +343,52 @@ class Params:
"Back": 60
}
}
+
+ SA_LABEL_NEW_EVENT_FORMAT: dict = {
+ "Index": "", # 假设Epoch从1开始
+ "Event type": "", # 原始事件类型为空
+ "Stage": "",
+ "Time": "",
+ "Epoch": "",
+ "Date": "",
+ "Duration": "", # 计算持续时间
+ "HR bef.": "",
+ "HR extr.": "",
+ "HR delta": "",
+ "O2 bef.": "",
+ "O2 min.": "",
+ "O2 delta": "",
+ "Body Position": "",
+ "Validation": "",
+ "Start": "",
+ "End": "",
+ "correct_Start": "",
+ "correct_End":"",
+ "correct_EventsType": "", # 修正事件类型为空
+ "score": -1, # 默认分数为-1
+ "isLabeled": -1, # 默认未标记状态
+ "remark": "" # 默认备注为空
+ }
+
SA_LABEL_TRANSPARENCY: float = 0.05
- SA_LABEL_BTN_PREV_SHORTCUT_KEY: str = "A"
- SA_LABEL_BTN_NEXT_SHORTCUT_KEY: str = "D"
+ SA_LABEL_BTN_PREV_10s_SHORTCUT_KEY: str = "Q"
+ SA_LABEL_BTN_NEXT_10s_SHORTCUT_KEY: str = "E"
+ SA_LABEL_BTN_PREV_30s_SHORTCUT_KEY: str = "A"
+ SA_LABEL_BTN_NEXT_30s_SHORTCUT_KEY: str = "D"
+ SA_LABEL_BTN_PREV_HALF_SHORTCUT_KEY: str = "F"
+ SA_LABEL_BTN_NEXT_HALF_SHORTCUT_KEY: str = "G"
+ SA_LABEL_BTN_BEST_FIT_SHORTCUT_KEY: str = "X"
+ SA_LABEL_BTN_EDIT_MODE_SHORTCUT_KEY: str = "Z"
SA_LABEL_BTN_CONFIRMLABEL_SHORTCUT_KEY: str = "S"
SA_LABEL_BTN_QUICK_REMARK_WAITINGFORTALK_SHORTCUT_KEY: str = "J"
- SA_LABEL_RADIOBUTTON_OSA_SHORTCUT_KEY: str = "1"
- SA_LABEL_RADIOBUTTON_CSA_SHORTCUT_KEY: str = "2"
- SA_LABEL_RADIOBUTTON_MSA_SHORTCUT_KEY: str = "3"
- SA_LABEL_RADIOBUTTON_HPY_SHORTCUT_KEY: str = "4"
- SA_LABEL_RADIOBUTTON_1_CLASS_SHORTCUT_KEY: str = "U"
- SA_LABEL_RADIOBUTTON_2_CLASS_SHORTCUT_KEY: str = "I"
- SA_LABEL_RADIOBUTTON_3_CLASS_SHORTCUT_KEY: str = "O"
+ SA_LABEL_RADIOBUTTON_OSA_SHORTCUT_KEY: str = "7"
+ SA_LABEL_RADIOBUTTON_CSA_SHORTCUT_KEY: str = "8"
+ SA_LABEL_RADIOBUTTON_MSA_SHORTCUT_KEY: str = "9"
+ SA_LABEL_RADIOBUTTON_HPY_SHORTCUT_KEY: str = "0"
+ SA_LABEL_RADIOBUTTON_1_CLASS_SHORTCUT_KEY: str = "1"
+ SA_LABEL_RADIOBUTTON_2_CLASS_SHORTCUT_KEY: str = "2"
+ SA_LABEL_RADIOBUTTON_3_CLASS_SHORTCUT_KEY: str = "3"
+
# 禁止实例化
def __new__(cls):
diff --git a/ui/MainWindow/MainWindow_SA_label_v2.py b/ui/MainWindow/MainWindow_SA_label_v2.py
new file mode 100644
index 0000000..cbe6979
--- /dev/null
+++ b/ui/MainWindow/MainWindow_SA_label_v2.py
@@ -0,0 +1,690 @@
+# -*- coding: utf-8 -*-
+
+################################################################################
+## Form generated from reading UI file 'MainWindow_SA_label_v2.ui'
+##
+## Created by: Qt User Interface Compiler version 6.7.0
+##
+## 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 (QAbstractItemView, QAbstractSpinBox, QApplication, QCheckBox,
+ QComboBox, QGridLayout, QGroupBox, QHBoxLayout,
+ QHeaderView, QLabel, QLineEdit, QMainWindow,
+ QPushButton, QRadioButton, QSizePolicy, QSpacerItem,
+ QSpinBox, QStatusBar, QTableView, QTextBrowser,
+ QVBoxLayout, QWidget)
+
+class Ui_MainWindow_SA_label(object):
+ def setupUi(self, MainWindow_SA_label):
+ if not MainWindow_SA_label.objectName():
+ MainWindow_SA_label.setObjectName(u"MainWindow_SA_label")
+ MainWindow_SA_label.resize(1921, 1080)
+ self.centralwidget = QWidget(MainWindow_SA_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.checkBox = QCheckBox(self.groupBox_left)
+ self.checkBox.setObjectName(u"checkBox")
+ self.checkBox.setFont(font1)
+
+ self.verticalLayout_2.addWidget(self.checkBox)
+
+ self.pushButton_best_fit = QPushButton(self.groupBox_left)
+ self.pushButton_best_fit.setObjectName(u"pushButton_best_fit")
+ self.pushButton_best_fit.setFont(font1)
+ self.pushButton_best_fit.setChecked(False)
+
+ self.verticalLayout_2.addWidget(self.pushButton_best_fit)
+
+ self.horizontalLayout_6 = QHBoxLayout()
+ self.horizontalLayout_6.setObjectName(u"horizontalLayout_6")
+ self.label_4 = QLabel(self.groupBox_left)
+ self.label_4.setObjectName(u"label_4")
+ sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
+ sizePolicy1.setHorizontalStretch(0)
+ sizePolicy1.setVerticalStretch(0)
+ sizePolicy1.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth())
+ self.label_4.setSizePolicy(sizePolicy1)
+ self.label_4.setAlignment(Qt.AlignmentFlag.AlignRight|Qt.AlignmentFlag.AlignTrailing|Qt.AlignmentFlag.AlignVCenter)
+
+ self.horizontalLayout_6.addWidget(self.label_4)
+
+ self.comboBox_window_signal_length = QComboBox(self.groupBox_left)
+ self.comboBox_window_signal_length.addItem("")
+ self.comboBox_window_signal_length.addItem("")
+ self.comboBox_window_signal_length.addItem("")
+ self.comboBox_window_signal_length.addItem("")
+ self.comboBox_window_signal_length.addItem("")
+ self.comboBox_window_signal_length.setObjectName(u"comboBox_window_signal_length")
+ sizePolicy1.setHeightForWidth(self.comboBox_window_signal_length.sizePolicy().hasHeightForWidth())
+ self.comboBox_window_signal_length.setSizePolicy(sizePolicy1)
+ self.comboBox_window_signal_length.setEditable(True)
+ self.comboBox_window_signal_length.setInsertPolicy(QComboBox.InsertPolicy.NoInsert)
+
+ self.horizontalLayout_6.addWidget(self.comboBox_window_signal_length)
+
+ self.horizontalSpacer_5 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
+
+ self.horizontalLayout_6.addItem(self.horizontalSpacer_5)
+
+
+ self.verticalLayout_2.addLayout(self.horizontalLayout_6)
+
+ self.groupBox_label = QGroupBox(self.groupBox_left)
+ self.groupBox_label.setObjectName(u"groupBox_label")
+ self.gridLayout_3 = QGridLayout(self.groupBox_label)
+ self.gridLayout_3.setObjectName(u"gridLayout_3")
+ self.label_2 = QLabel(self.groupBox_label)
+ self.label_2.setObjectName(u"label_2")
+ self.label_2.setFont(font1)
+
+ self.gridLayout_3.addWidget(self.label_2, 4, 0, 1, 1)
+
+ self.verticalSpacer_4 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
+
+ self.gridLayout_3.addItem(self.verticalSpacer_4, 2, 0, 1, 2)
+
+ self.lineEdit_filter_label_origin = QLineEdit(self.groupBox_label)
+ self.lineEdit_filter_label_origin.setObjectName(u"lineEdit_filter_label_origin")
+ self.lineEdit_filter_label_origin.setFont(font1)
+
+ self.gridLayout_3.addWidget(self.lineEdit_filter_label_origin, 0, 1, 1, 1)
+
+ self.lineEdit_filter_label_revised = QLineEdit(self.groupBox_label)
+ self.lineEdit_filter_label_revised.setObjectName(u"lineEdit_filter_label_revised")
+ self.lineEdit_filter_label_revised.setFont(font1)
+
+ self.gridLayout_3.addWidget(self.lineEdit_filter_label_revised, 4, 1, 1, 1)
+
+ self.label = QLabel(self.groupBox_label)
+ self.label.setObjectName(u"label")
+ self.label.setFont(font1)
+
+ self.gridLayout_3.addWidget(self.label, 0, 0, 1, 1)
+
+ self.tableView_label = QTableView(self.groupBox_label)
+ self.tableView_label.setObjectName(u"tableView_label")
+ self.tableView_label.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
+
+ self.gridLayout_3.addWidget(self.tableView_label, 1, 0, 1, 2)
+
+ self.tableView_label_revised = QTableView(self.groupBox_label)
+ self.tableView_label_revised.setObjectName(u"tableView_label_revised")
+ self.tableView_label_revised.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
+
+ self.gridLayout_3.addWidget(self.tableView_label_revised, 5, 0, 1, 2)
+
+ self.gridLayout_3.setRowStretch(0, 2)
+
+ self.verticalLayout_2.addWidget(self.groupBox_label)
+
+ self.verticalSpacer_3 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
+
+ self.verticalLayout_2.addItem(self.verticalSpacer_3)
+
+ self.pushButton_save = QPushButton(self.groupBox_left)
+ self.pushButton_save.setObjectName(u"pushButton_save")
+ sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Preferred)
+ sizePolicy2.setHorizontalStretch(0)
+ sizePolicy2.setVerticalStretch(0)
+ sizePolicy2.setHeightForWidth(self.pushButton_save.sizePolicy().hasHeightForWidth())
+ self.pushButton_save.setSizePolicy(sizePolicy2)
+ 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)
+ 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(5, 15)
+ self.verticalLayout_2.setStretch(6, 1)
+ self.verticalLayout_2.setStretch(7, 2)
+ self.verticalLayout_2.setStretch(8, 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_5 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
+
+ self.gridLayout_4.addItem(self.verticalSpacer_5, 1, 0, 1, 2)
+
+ self.groupBox_examineBySecond = QGroupBox(self.groupBox_right)
+ self.groupBox_examineBySecond.setObjectName(u"groupBox_examineBySecond")
+ self.verticalLayout_4 = QVBoxLayout(self.groupBox_examineBySecond)
+ self.verticalLayout_4.setObjectName(u"verticalLayout_4")
+ self.horizontalLayout_5 = QHBoxLayout()
+ self.horizontalLayout_5.setObjectName(u"horizontalLayout_5")
+ self.label_3 = QLabel(self.groupBox_examineBySecond)
+ self.label_3.setObjectName(u"label_3")
+
+ self.horizontalLayout_5.addWidget(self.label_3)
+
+ self.lineEdit_jump_second = QLineEdit(self.groupBox_examineBySecond)
+ self.lineEdit_jump_second.setObjectName(u"lineEdit_jump_second")
+
+ self.horizontalLayout_5.addWidget(self.lineEdit_jump_second)
+
+ self.pushButton_jump_to = QPushButton(self.groupBox_examineBySecond)
+ self.pushButton_jump_to.setObjectName(u"pushButton_jump_to")
+
+ self.horizontalLayout_5.addWidget(self.pushButton_jump_to)
+
+
+ self.verticalLayout_4.addLayout(self.horizontalLayout_5)
+
+ self.gridLayout_8 = QGridLayout()
+ self.gridLayout_8.setObjectName(u"gridLayout_8")
+ self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
+
+ self.gridLayout_8.addItem(self.horizontalSpacer, 0, 1, 1, 1)
+
+ self.pushButton_next_half = QPushButton(self.groupBox_examineBySecond)
+ self.pushButton_next_half.setObjectName(u"pushButton_next_half")
+ self.pushButton_next_half.setFont(font1)
+ self.pushButton_next_half.setProperty("offset", 15)
+
+ self.gridLayout_8.addWidget(self.pushButton_next_half, 1, 4, 1, 1)
+
+ self.pushButton_previous10s = QPushButton(self.groupBox_examineBySecond)
+ self.pushButton_previous10s.setObjectName(u"pushButton_previous10s")
+ self.pushButton_previous10s.setFont(font1)
+ self.pushButton_previous10s.setProperty("offset", -10)
+
+ self.gridLayout_8.addWidget(self.pushButton_previous10s, 0, 0, 1, 1)
+
+ self.pushButton_previous_half = QPushButton(self.groupBox_examineBySecond)
+ self.pushButton_previous_half.setObjectName(u"pushButton_previous_half")
+ self.pushButton_previous_half.setFont(font1)
+ self.pushButton_previous_half.setProperty("offset", -15)
+
+ self.gridLayout_8.addWidget(self.pushButton_previous_half, 0, 4, 1, 1)
+
+ self.pushButton_next30s = QPushButton(self.groupBox_examineBySecond)
+ self.pushButton_next30s.setObjectName(u"pushButton_next30s")
+ self.pushButton_next30s.setFont(font1)
+ self.pushButton_next30s.setProperty("offset", 30)
+
+ self.gridLayout_8.addWidget(self.pushButton_next30s, 1, 2, 1, 1)
+
+ self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
+
+ self.gridLayout_8.addItem(self.horizontalSpacer_2, 1, 1, 1, 1)
+
+ self.pushButton_previous30s = QPushButton(self.groupBox_examineBySecond)
+ self.pushButton_previous30s.setObjectName(u"pushButton_previous30s")
+ self.pushButton_previous30s.setFont(font1)
+ self.pushButton_previous30s.setProperty("offset", -30)
+
+ self.gridLayout_8.addWidget(self.pushButton_previous30s, 0, 2, 1, 1)
+
+ self.pushButton_next10s = QPushButton(self.groupBox_examineBySecond)
+ self.pushButton_next10s.setObjectName(u"pushButton_next10s")
+ self.pushButton_next10s.setFont(font1)
+ self.pushButton_next10s.setProperty("offset", 10)
+
+ self.gridLayout_8.addWidget(self.pushButton_next10s, 1, 0, 1, 1)
+
+ self.horizontalSpacer_3 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
+
+ self.gridLayout_8.addItem(self.horizontalSpacer_3, 0, 3, 1, 1)
+
+ self.horizontalSpacer_4 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
+
+ self.gridLayout_8.addItem(self.horizontalSpacer_4, 1, 3, 1, 1)
+
+ self.gridLayout_8.setColumnMinimumWidth(0, 3)
+ self.gridLayout_8.setColumnMinimumWidth(1, 1)
+ self.gridLayout_8.setColumnMinimumWidth(2, 3)
+ self.gridLayout_8.setColumnMinimumWidth(3, 1)
+ self.gridLayout_8.setColumnMinimumWidth(4, 3)
+
+ self.verticalLayout_4.addLayout(self.gridLayout_8)
+
+ self.verticalLayout_4.setStretch(0, 1)
+ self.verticalLayout_4.setStretch(1, 2)
+
+ self.gridLayout_4.addWidget(self.groupBox_examineBySecond, 2, 0, 1, 2)
+
+ self.groupBox_label_operation = QGroupBox(self.groupBox_right)
+ self.groupBox_label_operation.setObjectName(u"groupBox_label_operation")
+ self.verticalLayout_3 = QVBoxLayout(self.groupBox_label_operation)
+ self.verticalLayout_3.setObjectName(u"verticalLayout_3")
+ self.horizontalLayout_7 = QHBoxLayout()
+ self.horizontalLayout_7.setObjectName(u"horizontalLayout_7")
+ self.label_5 = QLabel(self.groupBox_label_operation)
+ self.label_5.setObjectName(u"label_5")
+ sizePolicy2.setHeightForWidth(self.label_5.sizePolicy().hasHeightForWidth())
+ self.label_5.setSizePolicy(sizePolicy2)
+ self.label_5.setFont(font1)
+ self.label_5.setAlignment(Qt.AlignmentFlag.AlignRight|Qt.AlignmentFlag.AlignTrailing|Qt.AlignmentFlag.AlignVCenter)
+
+ self.horizontalLayout_7.addWidget(self.label_5)
+
+ self.label_BCG_Index = QLabel(self.groupBox_label_operation)
+ self.label_BCG_Index.setObjectName(u"label_BCG_Index")
+ sizePolicy3 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
+ sizePolicy3.setHorizontalStretch(0)
+ sizePolicy3.setVerticalStretch(0)
+ sizePolicy3.setHeightForWidth(self.label_BCG_Index.sizePolicy().hasHeightForWidth())
+ self.label_BCG_Index.setSizePolicy(sizePolicy3)
+ self.label_BCG_Index.setFont(font1)
+ self.label_BCG_Index.setAlignment(Qt.AlignmentFlag.AlignCenter)
+
+ self.horizontalLayout_7.addWidget(self.label_BCG_Index)
+
+ self.horizontalLayout_7.setStretch(0, 1)
+ self.horizontalLayout_7.setStretch(1, 5)
+
+ self.verticalLayout_3.addLayout(self.horizontalLayout_7)
+
+ self.label_BCG_Info = QLabel(self.groupBox_label_operation)
+ self.label_BCG_Info.setObjectName(u"label_BCG_Info")
+ self.label_BCG_Info.setFont(font1)
+ self.label_BCG_Info.setAlignment(Qt.AlignmentFlag.AlignCenter)
+
+ self.verticalLayout_3.addWidget(self.label_BCG_Info)
+
+ self.horizontalLayout_3 = QHBoxLayout()
+ self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
+ self.label_11 = QLabel(self.groupBox_label_operation)
+ self.label_11.setObjectName(u"label_11")
+ self.label_11.setFont(font1)
+
+ self.horizontalLayout_3.addWidget(self.label_11)
+
+ self.radioButton_OSA = QRadioButton(self.groupBox_label_operation)
+ self.radioButton_OSA.setObjectName(u"radioButton_OSA")
+ self.radioButton_OSA.setFont(font1)
+ self.radioButton_OSA.setChecked(True)
+
+ self.horizontalLayout_3.addWidget(self.radioButton_OSA)
+
+ self.radioButton_CSA = QRadioButton(self.groupBox_label_operation)
+ self.radioButton_CSA.setObjectName(u"radioButton_CSA")
+ self.radioButton_CSA.setFont(font1)
+
+ self.horizontalLayout_3.addWidget(self.radioButton_CSA)
+
+ self.radioButton_MSA = QRadioButton(self.groupBox_label_operation)
+ self.radioButton_MSA.setObjectName(u"radioButton_MSA")
+ self.radioButton_MSA.setFont(font1)
+
+ self.horizontalLayout_3.addWidget(self.radioButton_MSA)
+
+ self.radioButton_HPY = QRadioButton(self.groupBox_label_operation)
+ self.radioButton_HPY.setObjectName(u"radioButton_HPY")
+ self.radioButton_HPY.setFont(font1)
+
+ self.horizontalLayout_3.addWidget(self.radioButton_HPY)
+
+
+ self.verticalLayout_3.addLayout(self.horizontalLayout_3)
+
+ self.horizontalLayout_4 = QHBoxLayout()
+ self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
+ self.label_12 = QLabel(self.groupBox_label_operation)
+ self.label_12.setObjectName(u"label_12")
+ self.label_12.setFont(font1)
+
+ self.horizontalLayout_4.addWidget(self.label_12)
+
+ self.radioButton_1_class = QRadioButton(self.groupBox_label_operation)
+ self.radioButton_1_class.setObjectName(u"radioButton_1_class")
+ self.radioButton_1_class.setFont(font1)
+ self.radioButton_1_class.setChecked(True)
+
+ self.horizontalLayout_4.addWidget(self.radioButton_1_class)
+
+ self.radioButton_2_class = QRadioButton(self.groupBox_label_operation)
+ self.radioButton_2_class.setObjectName(u"radioButton_2_class")
+ self.radioButton_2_class.setFont(font1)
+
+ self.horizontalLayout_4.addWidget(self.radioButton_2_class)
+
+ self.radioButton_3_class = QRadioButton(self.groupBox_label_operation)
+ self.radioButton_3_class.setObjectName(u"radioButton_3_class")
+ self.radioButton_3_class.setFont(font1)
+
+ self.horizontalLayout_4.addWidget(self.radioButton_3_class)
+
+
+ self.verticalLayout_3.addLayout(self.horizontalLayout_4)
+
+ self.verticalSpacer_9 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
+
+ self.verticalLayout_3.addItem(self.verticalSpacer_9)
+
+ self.horizontalLayout_2 = QHBoxLayout()
+ self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
+ self.label_6 = QLabel(self.groupBox_label_operation)
+ self.label_6.setObjectName(u"label_6")
+ self.label_6.setFont(font1)
+
+ self.horizontalLayout_2.addWidget(self.label_6)
+
+ self.lineEdit_remark = QLineEdit(self.groupBox_label_operation)
+ self.lineEdit_remark.setObjectName(u"lineEdit_remark")
+ self.lineEdit_remark.setFont(font1)
+
+ self.horizontalLayout_2.addWidget(self.lineEdit_remark)
+
+
+ self.verticalLayout_3.addLayout(self.horizontalLayout_2)
+
+ self.verticalSpacer_8 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
+
+ self.verticalLayout_3.addItem(self.verticalSpacer_8)
+
+ self.label_7 = QLabel(self.groupBox_label_operation)
+ self.label_7.setObjectName(u"label_7")
+ self.label_7.setFont(font1)
+
+ self.verticalLayout_3.addWidget(self.label_7)
+
+ self.gridLayout_5 = QGridLayout()
+ self.gridLayout_5.setObjectName(u"gridLayout_5")
+ self.pushButton_quick_remark_input_durationNoEnough = QPushButton(self.groupBox_label_operation)
+ self.pushButton_quick_remark_input_durationNoEnough.setObjectName(u"pushButton_quick_remark_input_durationNoEnough")
+ sizePolicy2.setHeightForWidth(self.pushButton_quick_remark_input_durationNoEnough.sizePolicy().hasHeightForWidth())
+ self.pushButton_quick_remark_input_durationNoEnough.setSizePolicy(sizePolicy2)
+ self.pushButton_quick_remark_input_durationNoEnough.setFont(font1)
+
+ self.gridLayout_5.addWidget(self.pushButton_quick_remark_input_durationNoEnough, 1, 1, 1, 1)
+
+ self.pushButton_quick_remark_input_maybeWrongLabeled = QPushButton(self.groupBox_label_operation)
+ self.pushButton_quick_remark_input_maybeWrongLabeled.setObjectName(u"pushButton_quick_remark_input_maybeWrongLabeled")
+ sizePolicy2.setHeightForWidth(self.pushButton_quick_remark_input_maybeWrongLabeled.sizePolicy().hasHeightForWidth())
+ self.pushButton_quick_remark_input_maybeWrongLabeled.setSizePolicy(sizePolicy2)
+ self.pushButton_quick_remark_input_maybeWrongLabeled.setFont(font1)
+
+ self.gridLayout_5.addWidget(self.pushButton_quick_remark_input_maybeWrongLabeled, 1, 0, 1, 1)
+
+ self.pushButton_quick_remark_input_noNormalRespBetweenArtifact = QPushButton(self.groupBox_label_operation)
+ self.pushButton_quick_remark_input_noNormalRespBetweenArtifact.setObjectName(u"pushButton_quick_remark_input_noNormalRespBetweenArtifact")
+ sizePolicy2.setHeightForWidth(self.pushButton_quick_remark_input_noNormalRespBetweenArtifact.sizePolicy().hasHeightForWidth())
+ self.pushButton_quick_remark_input_noNormalRespBetweenArtifact.setSizePolicy(sizePolicy2)
+ self.pushButton_quick_remark_input_noNormalRespBetweenArtifact.setFont(font1)
+
+ self.gridLayout_5.addWidget(self.pushButton_quick_remark_input_noNormalRespBetweenArtifact, 2, 1, 1, 1)
+
+ self.pushButton_quick_remark_input_maybeDesaturation = QPushButton(self.groupBox_label_operation)
+ self.pushButton_quick_remark_input_maybeDesaturation.setObjectName(u"pushButton_quick_remark_input_maybeDesaturation")
+ sizePolicy2.setHeightForWidth(self.pushButton_quick_remark_input_maybeDesaturation.sizePolicy().hasHeightForWidth())
+ self.pushButton_quick_remark_input_maybeDesaturation.setSizePolicy(sizePolicy2)
+ self.pushButton_quick_remark_input_maybeDesaturation.setFont(font1)
+
+ self.gridLayout_5.addWidget(self.pushButton_quick_remark_input_maybeDesaturation, 0, 1, 1, 1)
+
+ self.pushButton_quick_remark_input_littleChange = QPushButton(self.groupBox_label_operation)
+ self.pushButton_quick_remark_input_littleChange.setObjectName(u"pushButton_quick_remark_input_littleChange")
+ sizePolicy2.setHeightForWidth(self.pushButton_quick_remark_input_littleChange.sizePolicy().hasHeightForWidth())
+ self.pushButton_quick_remark_input_littleChange.setSizePolicy(sizePolicy2)
+ self.pushButton_quick_remark_input_littleChange.setFont(font1)
+
+ self.gridLayout_5.addWidget(self.pushButton_quick_remark_input_littleChange, 2, 0, 1, 1)
+
+ self.pushButton_quick_remark_input_waitingForTalk = QPushButton(self.groupBox_label_operation)
+ self.pushButton_quick_remark_input_waitingForTalk.setObjectName(u"pushButton_quick_remark_input_waitingForTalk")
+ sizePolicy2.setHeightForWidth(self.pushButton_quick_remark_input_waitingForTalk.sizePolicy().hasHeightForWidth())
+ self.pushButton_quick_remark_input_waitingForTalk.setSizePolicy(sizePolicy2)
+ self.pushButton_quick_remark_input_waitingForTalk.setFont(font1)
+
+ self.gridLayout_5.addWidget(self.pushButton_quick_remark_input_waitingForTalk, 0, 0, 1, 1)
+
+ self.pushButton_quick_remark_input_lowSignalNoiseRatio = QPushButton(self.groupBox_label_operation)
+ self.pushButton_quick_remark_input_lowSignalNoiseRatio.setObjectName(u"pushButton_quick_remark_input_lowSignalNoiseRatio")
+ sizePolicy2.setHeightForWidth(self.pushButton_quick_remark_input_lowSignalNoiseRatio.sizePolicy().hasHeightForWidth())
+ self.pushButton_quick_remark_input_lowSignalNoiseRatio.setSizePolicy(sizePolicy2)
+ self.pushButton_quick_remark_input_lowSignalNoiseRatio.setFont(font1)
+
+ self.gridLayout_5.addWidget(self.pushButton_quick_remark_input_lowSignalNoiseRatio, 3, 0, 1, 1)
+
+ self.pushButton_quick_remark_input_changeOnMiddle = QPushButton(self.groupBox_label_operation)
+ self.pushButton_quick_remark_input_changeOnMiddle.setObjectName(u"pushButton_quick_remark_input_changeOnMiddle")
+ sizePolicy2.setHeightForWidth(self.pushButton_quick_remark_input_changeOnMiddle.sizePolicy().hasHeightForWidth())
+ self.pushButton_quick_remark_input_changeOnMiddle.setSizePolicy(sizePolicy2)
+ self.pushButton_quick_remark_input_changeOnMiddle.setFont(font1)
+
+ self.gridLayout_5.addWidget(self.pushButton_quick_remark_input_changeOnMiddle, 3, 1, 1, 1)
+
+
+ self.verticalLayout_3.addLayout(self.gridLayout_5)
+
+ self.verticalSpacer_7 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
+
+ self.verticalLayout_3.addItem(self.verticalSpacer_7)
+
+ self.gridLayout_6 = QGridLayout()
+ self.gridLayout_6.setObjectName(u"gridLayout_6")
+ self.label_8 = QLabel(self.groupBox_label_operation)
+ self.label_8.setObjectName(u"label_8")
+ self.label_8.setFont(font1)
+
+ self.gridLayout_6.addWidget(self.label_8, 0, 0, 1, 1)
+
+ self.label_9 = QLabel(self.groupBox_label_operation)
+ self.label_9.setObjectName(u"label_9")
+ self.label_9.setFont(font1)
+
+ self.gridLayout_6.addWidget(self.label_9, 1, 0, 1, 1)
+
+ self.spinBox_correctStart = QSpinBox(self.groupBox_label_operation)
+ self.spinBox_correctStart.setObjectName(u"spinBox_correctStart")
+ self.spinBox_correctStart.setFont(font1)
+ self.spinBox_correctStart.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
+ self.spinBox_correctStart.setMaximum(100000)
+
+ self.gridLayout_6.addWidget(self.spinBox_correctStart, 0, 1, 1, 1)
+
+ self.spinBox_correctEnd = QSpinBox(self.groupBox_label_operation)
+ self.spinBox_correctEnd.setObjectName(u"spinBox_correctEnd")
+ self.spinBox_correctEnd.setFont(font1)
+ self.spinBox_correctEnd.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
+ self.spinBox_correctEnd.setMaximum(100000)
+
+ self.gridLayout_6.addWidget(self.spinBox_correctEnd, 1, 1, 1, 1)
+
+
+ self.verticalLayout_3.addLayout(self.gridLayout_6)
+
+ self.verticalSpacer_6 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
+
+ self.verticalLayout_3.addItem(self.verticalSpacer_6)
+
+ self.gridLayout_7 = QGridLayout()
+ self.gridLayout_7.setObjectName(u"gridLayout_7")
+ self.pushButton_prev = QPushButton(self.groupBox_label_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, 0, 0, 1, 1)
+
+ self.pushButton_next = QPushButton(self.groupBox_label_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, 1, 0, 1, 1)
+
+ self.pushButton_confirmLabel = QPushButton(self.groupBox_label_operation)
+ self.pushButton_confirmLabel.setObjectName(u"pushButton_confirmLabel")
+ sizePolicy2.setHeightForWidth(self.pushButton_confirmLabel.sizePolicy().hasHeightForWidth())
+ self.pushButton_confirmLabel.setSizePolicy(sizePolicy2)
+ self.pushButton_confirmLabel.setFont(font1)
+
+ self.gridLayout_7.addWidget(self.pushButton_confirmLabel, 0, 1, 2, 1)
+
+
+ self.verticalLayout_3.addLayout(self.gridLayout_7)
+
+ self.verticalLayout_3.setStretch(0, 1)
+ self.verticalLayout_3.setStretch(1, 1)
+ self.verticalLayout_3.setStretch(2, 2)
+ self.verticalLayout_3.setStretch(3, 2)
+ self.verticalLayout_3.setStretch(4, 1)
+ self.verticalLayout_3.setStretch(5, 2)
+ self.verticalLayout_3.setStretch(6, 1)
+ self.verticalLayout_3.setStretch(7, 1)
+ self.verticalLayout_3.setStretch(8, 6)
+ self.verticalLayout_3.setStretch(9, 1)
+ self.verticalLayout_3.setStretch(10, 2)
+ self.verticalLayout_3.setStretch(11, 1)
+ self.verticalLayout_3.setStretch(12, 3)
+
+ self.gridLayout_4.addWidget(self.groupBox_label_operation, 0, 0, 1, 2)
+
+ self.gridLayout_4.setRowStretch(0, 12)
+
+ self.gridLayout.addWidget(self.groupBox_right, 0, 2, 1, 1)
+
+ self.gridLayout.setColumnStretch(0, 3)
+ self.gridLayout.setColumnStretch(1, 7)
+ self.gridLayout.setColumnStretch(2, 3)
+ MainWindow_SA_label.setCentralWidget(self.centralwidget)
+ self.statusbar = QStatusBar(MainWindow_SA_label)
+ self.statusbar.setObjectName(u"statusbar")
+ MainWindow_SA_label.setStatusBar(self.statusbar)
+
+ self.retranslateUi(MainWindow_SA_label)
+
+ QMetaObject.connectSlotsByName(MainWindow_SA_label)
+ # setupUi
+
+ def retranslateUi(self, MainWindow_SA_label):
+ MainWindow_SA_label.setWindowTitle(QCoreApplication.translate("MainWindow_SA_label", u"\u7761\u7720\u547c\u5438\u6682\u505c\u4e8b\u4ef6\u6807\u6ce8", None))
+ self.groupBox_canvas.setTitle(QCoreApplication.translate("MainWindow_SA_label", u"\u7ed8\u56fe\u533a", None))
+ self.groupBox_left.setTitle(QCoreApplication.translate("MainWindow_SA_label", u"\u7761\u7720\u547c\u5438\u6682\u505c\u4e8b\u4ef6\u6807\u6ce8", None))
+ self.pushButton_input_setting.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u5bfc\u5165\u8bbe\u7f6e", None))
+ self.pushButton_input.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u5f00\u59cb\u5bfc\u5165", None))
+ self.checkBox.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u4fee\u6539\u540e\u81ea\u52a8\u4fdd\u5b58", None))
+ self.pushButton_best_fit.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u81ea\u9002\u5e94\u5e45\u503c\uff08X\uff09", None))
+ self.label_4.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u663e\u793a\u7a97\u53e3\u957f\u5ea6/\u79d2\uff1a", None))
+ self.comboBox_window_signal_length.setItemText(0, QCoreApplication.translate("MainWindow_SA_label", u"30", None))
+ self.comboBox_window_signal_length.setItemText(1, QCoreApplication.translate("MainWindow_SA_label", u"60", None))
+ self.comboBox_window_signal_length.setItemText(2, QCoreApplication.translate("MainWindow_SA_label", u"120", None))
+ self.comboBox_window_signal_length.setItemText(3, QCoreApplication.translate("MainWindow_SA_label", u"300", None))
+ self.comboBox_window_signal_length.setItemText(4, QCoreApplication.translate("MainWindow_SA_label", u"600", None))
+
+ self.groupBox_label.setTitle(QCoreApplication.translate("MainWindow_SA_label", u"\u6807\u7b7e\u8bb0\u5f55", None))
+ self.label_2.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u786e\u8ba4\u540e\u7684\u6807\u7b7e", None))
+ self.lineEdit_filter_label_origin.setPlaceholderText(QCoreApplication.translate("MainWindow_SA_label", u"\u7b5b\u9009\u5668", None))
+ self.lineEdit_filter_label_revised.setPlaceholderText(QCoreApplication.translate("MainWindow_SA_label", u"\u7b5b\u9009\u5668", None))
+ self.label.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u539f\u6570\u636e\u7684\u6807\u7b7e", None))
+ self.pushButton_save.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u624b\u52a8\u4fdd\u5b58", None))
+ self.groupBox_4.setTitle(QCoreApplication.translate("MainWindow_SA_label", u"\u65e5\u5fd7", None))
+ self.groupBox_right.setTitle(QCoreApplication.translate("MainWindow_SA_label", u"\u7761\u7720\u547c\u5438\u6682\u505c\u4e8b\u4ef6\u6807\u6ce8", None))
+ self.groupBox_examineBySecond.setTitle(QCoreApplication.translate("MainWindow_SA_label", u"\u8df3\u8f6c", None))
+ self.label_3.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u8d77\u59cb\u79d2\u6570\uff1a", None))
+ self.pushButton_jump_to.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u8df3\u8f6c", None))
+ self.pushButton_next_half.setText(QCoreApplication.translate("MainWindow_SA_label", u"+\u534a\u7a97(G)", None))
+ self.pushButton_previous10s.setText(QCoreApplication.translate("MainWindow_SA_label", u"-10s(Q)", None))
+ self.pushButton_previous_half.setText(QCoreApplication.translate("MainWindow_SA_label", u"-\u534a\u7a97(F)", None))
+ self.pushButton_next30s.setText(QCoreApplication.translate("MainWindow_SA_label", u"+30s(D)", None))
+ self.pushButton_previous30s.setText(QCoreApplication.translate("MainWindow_SA_label", u"-30s(A)", None))
+ self.pushButton_next10s.setText(QCoreApplication.translate("MainWindow_SA_label", u"+10s(E)", None))
+ self.groupBox_label_operation.setTitle(QCoreApplication.translate("MainWindow_SA_label", u"\u6807\u6ce8\u64cd\u4f5c", None))
+ self.label_5.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u4e8b\u4ef6\u7f16\u53f7\uff1a", None))
+ self.label_BCG_Index.setText("")
+ self.label_BCG_Info.setText("")
+ self.label_11.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u4e8b\u4ef6\u7c7b\u578b", None))
+ self.radioButton_OSA.setText(QCoreApplication.translate("MainWindow_SA_label", u"OSA(1)", None))
+ self.radioButton_CSA.setText(QCoreApplication.translate("MainWindow_SA_label", u"CSA(2)", None))
+ self.radioButton_MSA.setText(QCoreApplication.translate("MainWindow_SA_label", u"MSA(3)", None))
+ self.radioButton_HPY.setText(QCoreApplication.translate("MainWindow_SA_label", u"HPY(4)", None))
+ self.label_12.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u6807\u7b7e\u7c7b\u578b", None))
+ self.radioButton_1_class.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u4e00\u7c7b(U)", None))
+ self.radioButton_2_class.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u4e8c\u7c7b(I)", None))
+ self.radioButton_3_class.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u5220\u9664(O)", None))
+ self.label_6.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u5907\u6ce8\uff1a", None))
+ self.label_7.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u5feb\u901f\u5907\u6ce8\u8f93\u5165", None))
+ self.pushButton_quick_remark_input_durationNoEnough.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u4e8c\u7c7b-\u65f6\u957f\u4e0d\u8db3", None))
+ self.pushButton_quick_remark_input_maybeWrongLabeled.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u4e8c\u7c7b-\u7591\u4f3c\u533b\u751f\u8bef\u6807", None))
+ self.pushButton_quick_remark_input_noNormalRespBetweenArtifact.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u4e8c\u7c7b-\u4f53\u52a8\u95f4\u65e0\u6b63\u5e38\u547c\u5438", None))
+ self.pushButton_quick_remark_input_maybeDesaturation.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u4e00\u7c7b-\u5f62\u4f3c\u6f6e\u5f0f\u547c\u5438", None))
+ self.pushButton_quick_remark_input_littleChange.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u4e8c\u7c7b-\u8d77\u4f0f\u53d8\u5316\u4e0d\u5927", None))
+ self.pushButton_quick_remark_input_waitingForTalk.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u5f85\u8ba8\u8bba(N)", None))
+ self.pushButton_quick_remark_input_lowSignalNoiseRatio.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u4e8c\u7c7b-\u4fe1\u566a\u6bd4\u4f4e", None))
+ self.pushButton_quick_remark_input_changeOnMiddle.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u4e8c\u7c7b-\u4e2d\u95f4\u8d77\u4f0f", None))
+ self.label_8.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u4fee\u6b63\u540e\u8d77\u59cb\u65f6\u95f4(s)", None))
+ self.label_9.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u4fee\u6b63\u540e\u7ec8\u6b62\u65f6\u95f4(s)", None))
+ self.pushButton_prev.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u4e0a\u4e00\u4e2a\u4e8b\u4ef6", None))
+ self.pushButton_next.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u4e0b\u4e00\u4e2a\u4e8b\u4ef6", None))
+ self.pushButton_confirmLabel.setText(QCoreApplication.translate("MainWindow_SA_label", u"\u786e\u5b9a\u6253\u6807\u53c2\u6570(S)", None))
+ # retranslateUi
+
diff --git a/ui/MainWindow/MainWindow_SA_label_v2.ui b/ui/MainWindow/MainWindow_SA_label_v2.ui
new file mode 100644
index 0000000..bc14785
--- /dev/null
+++ b/ui/MainWindow/MainWindow_SA_label_v2.ui
@@ -0,0 +1,1099 @@
+
+
+ MainWindow_SA_label
+
+
+
+ 0
+ 0
+ 1921
+ 1080
+
+
+
+ 睡眠呼吸暂停事件标注
+
+
+
+ -
+
+
+
+ 10
+
+
+
+ 绘图区
+
+
+
-
+
+
+
+
+
+ -
+
+
+
+ 10
+
+
+
+ 睡眠呼吸暂停事件标注
+
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 12
+
+
+
+ 导入设置
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 12
+
+
+
+ 开始导入
+
+
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 修改后自动保存
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 自适应幅值(X)
+
+
+ false
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ 显示窗口长度/秒:
+
+
+ Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ true
+
+
+ QComboBox::InsertPolicy::NoInsert
+
+
-
+
+ 30
+
+
+ -
+
+ 60
+
+
+ -
+
+ 120
+
+
+ -
+
+ 300
+
+
+ -
+
+ 600
+
+
+
+
+ -
+
+
+ Qt::Orientation::Horizontal
+
+
+ QSizePolicy::Policy::Expanding
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ 标签记录
+
+
+
-
+
+
+
+ 12
+
+
+
+ 确认后的标签
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 筛选器
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 筛选器
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 原数据的标签
+
+
+
+ -
+
+
+ QAbstractItemView::EditTrigger::NoEditTriggers
+
+
+
+ -
+
+
+ QAbstractItemView::EditTrigger::NoEditTriggers
+
+
+
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 重置标签
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 12
+
+
+
+ 手动保存
+
+
+
+ -
+
+
+ 日志
+
+
+
-
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 10
+
+
+
+ 睡眠呼吸暂停事件标注
+
+
+
-
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ 跳转
+
+
+
-
+
+
-
+
+
+ 起始秒数:
+
+
+
+ -
+
+
+ -
+
+
+ 跳转
+
+
+
+
+
+ -
+
+
-
+
+
+ Qt::Orientation::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ +半窗(G)
+
+
+ 15
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ -10s(Q)
+
+
+ -10
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ -半窗(F)
+
+
+ -15
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ +30s(D)
+
+
+ 30
+
+
+
+ -
+
+
+ Qt::Orientation::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ -30s(A)
+
+
+ -30
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ +10s(E)
+
+
+ 10
+
+
+
+ -
+
+
+ Qt::Orientation::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::Orientation::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+ -
+
+
+ 标注操作
+
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 12
+
+
+
+ 事件编号:
+
+
+ Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 12
+
+
+
+
+
+
+ Qt::AlignmentFlag::AlignCenter
+
+
+
+
+
+ -
+
+
+
+ 12
+
+
+
+
+
+
+ Qt::AlignmentFlag::AlignCenter
+
+
+
+ -
+
+
-
+
+
+
+ 12
+
+
+
+ 事件类型
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ OSA(7)
+
+
+ true
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ CSA(8)
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ MSA(9)
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ HPY(0)
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 12
+
+
+
+ 标签类型
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 一类(1)
+
+
+ true
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 二类(2)
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 删除(3)
+
+
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
-
+
+
+
+ 12
+
+
+
+ 备注:
+
+
+
+ -
+
+
+
+ 12
+
+
+
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 快速备注输入
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 12
+
+
+
+ 二类-时长不足
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 12
+
+
+
+ 二类-疑似医生误标
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 12
+
+
+
+ 二类-体动间无正常呼吸
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 12
+
+
+
+ 一类-形似潮式呼吸
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 12
+
+
+
+ 二类-起伏变化不大
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 12
+
+
+
+ 待讨论(N)
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 12
+
+
+
+ 二类-信噪比低
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 12
+
+
+
+ 二类-中间起伏
+
+
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
-
+
+
+
+ 12
+
+
+
+ 修正后起始时间(s)
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 修正后终止时间(s)
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ QAbstractSpinBox::ButtonSymbols::NoButtons
+
+
+ 100000
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ QAbstractSpinBox::ButtonSymbols::NoButtons
+
+
+ 100000
+
+
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 12
+
+
+
+ 确定打标参数(S)
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 12
+
+
+
+ 下一个事件
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 12
+
+
+
+ 上一个事件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/setting/SA_label_input_setting_v2.py b/ui/setting/SA_label_input_setting_v2.py
new file mode 100644
index 0000000..0f428ce
--- /dev/null
+++ b/ui/setting/SA_label_input_setting_v2.py
@@ -0,0 +1,361 @@
+# -*- coding: utf-8 -*-
+
+################################################################################
+## Form generated from reading UI file 'SA_label_input_setting_v2.ui'
+##
+## Created by: Qt User Interface Compiler version 6.7.0
+##
+## 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, QLabel, QMainWindow, QPlainTextEdit,
+ QPushButton, QSizePolicy, QSpinBox, QStatusBar,
+ QVBoxLayout, QWidget)
+
+class Ui_MainWindow_SA_label_input_setting(object):
+ def setupUi(self, MainWindow_SA_label_input_setting):
+ if not MainWindow_SA_label_input_setting.objectName():
+ MainWindow_SA_label_input_setting.setObjectName(u"MainWindow_SA_label_input_setting")
+ MainWindow_SA_label_input_setting.resize(848, 859)
+ self.centralwidget = QWidget(MainWindow_SA_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.gridLayout_2 = QGridLayout(self.groupBox)
+ self.gridLayout_2.setObjectName(u"gridLayout_2")
+ self.groupBox_file_path_save_2 = QGroupBox(self.groupBox)
+ self.groupBox_file_path_save_2.setObjectName(u"groupBox_file_path_save_2")
+ self.verticalLayout_10 = QVBoxLayout(self.groupBox_file_path_save_2)
+ self.verticalLayout_10.setObjectName(u"verticalLayout_10")
+ self.plainTextEdit_file_path_save_2 = QPlainTextEdit(self.groupBox_file_path_save_2)
+ self.plainTextEdit_file_path_save_2.setObjectName(u"plainTextEdit_file_path_save_2")
+
+ self.verticalLayout_10.addWidget(self.plainTextEdit_file_path_save_2)
+
+
+ self.gridLayout_2.addWidget(self.groupBox_file_path_save_2, 7, 1, 1, 1)
+
+ self.groupBox_file_path_input_label = QGroupBox(self.groupBox)
+ self.groupBox_file_path_input_label.setObjectName(u"groupBox_file_path_input_label")
+ self.verticalLayout_12 = QVBoxLayout(self.groupBox_file_path_input_label)
+ self.verticalLayout_12.setObjectName(u"verticalLayout_12")
+ self.plainTextEdit_file_path_input_label = QPlainTextEdit(self.groupBox_file_path_input_label)
+ self.plainTextEdit_file_path_input_label.setObjectName(u"plainTextEdit_file_path_input_label")
+
+ self.verticalLayout_12.addWidget(self.plainTextEdit_file_path_input_label)
+
+
+ self.gridLayout_2.addWidget(self.groupBox_file_path_input_label, 6, 1, 1, 1)
+
+ self.groupBox_file_path_input_signal_FlowP = QGroupBox(self.groupBox)
+ self.groupBox_file_path_input_signal_FlowP.setObjectName(u"groupBox_file_path_input_signal_FlowP")
+ self.verticalLayout_8 = QVBoxLayout(self.groupBox_file_path_input_signal_FlowP)
+ self.verticalLayout_8.setObjectName(u"verticalLayout_8")
+ self.horizontalLayout_6 = QHBoxLayout()
+ self.horizontalLayout_6.setObjectName(u"horizontalLayout_6")
+ self.label_6 = QLabel(self.groupBox_file_path_input_signal_FlowP)
+ self.label_6.setObjectName(u"label_6")
+ self.label_6.setFont(font)
+
+ self.horizontalLayout_6.addWidget(self.label_6)
+
+ self.spinBox_input_freq_signal_FlowP = QSpinBox(self.groupBox_file_path_input_signal_FlowP)
+ self.spinBox_input_freq_signal_FlowP.setObjectName(u"spinBox_input_freq_signal_FlowP")
+ self.spinBox_input_freq_signal_FlowP.setFont(font)
+ self.spinBox_input_freq_signal_FlowP.setMinimum(1)
+ self.spinBox_input_freq_signal_FlowP.setMaximum(1000000)
+
+ self.horizontalLayout_6.addWidget(self.spinBox_input_freq_signal_FlowP)
+
+
+ self.verticalLayout_8.addLayout(self.horizontalLayout_6)
+
+ self.plainTextEdit_file_path_input_signal_FlowP = QPlainTextEdit(self.groupBox_file_path_input_signal_FlowP)
+ self.plainTextEdit_file_path_input_signal_FlowP.setObjectName(u"plainTextEdit_file_path_input_signal_FlowP")
+
+ self.verticalLayout_8.addWidget(self.plainTextEdit_file_path_input_signal_FlowP)
+
+ self.verticalLayout_8.setStretch(1, 2)
+
+ self.gridLayout_2.addWidget(self.groupBox_file_path_input_signal_FlowP, 4, 1, 1, 1)
+
+ self.groupBox_file_path_input_signal_Tho = QGroupBox(self.groupBox)
+ self.groupBox_file_path_input_signal_Tho.setObjectName(u"groupBox_file_path_input_signal_Tho")
+ self.verticalLayout_3 = QVBoxLayout(self.groupBox_file_path_input_signal_Tho)
+ self.verticalLayout_3.setObjectName(u"verticalLayout_3")
+ self.horizontalLayout_3 = QHBoxLayout()
+ self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
+ self.label_3 = QLabel(self.groupBox_file_path_input_signal_Tho)
+ self.label_3.setObjectName(u"label_3")
+ self.label_3.setFont(font)
+
+ self.horizontalLayout_3.addWidget(self.label_3)
+
+ self.spinBox_input_freq_signal_Tho = QSpinBox(self.groupBox_file_path_input_signal_Tho)
+ self.spinBox_input_freq_signal_Tho.setObjectName(u"spinBox_input_freq_signal_Tho")
+ self.spinBox_input_freq_signal_Tho.setFont(font)
+ self.spinBox_input_freq_signal_Tho.setMinimum(1)
+ self.spinBox_input_freq_signal_Tho.setMaximum(1000000)
+
+ self.horizontalLayout_3.addWidget(self.spinBox_input_freq_signal_Tho)
+
+
+ self.verticalLayout_3.addLayout(self.horizontalLayout_3)
+
+ self.plainTextEdit_file_path_input_signal_Tho = QPlainTextEdit(self.groupBox_file_path_input_signal_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_signal_Tho)
+
+ self.verticalLayout_3.setStretch(1, 2)
+
+ self.gridLayout_2.addWidget(self.groupBox_file_path_input_signal_Tho, 3, 1, 1, 1)
+
+ self.groupBox_file_path_input_signal_FlowT = QGroupBox(self.groupBox)
+ self.groupBox_file_path_input_signal_FlowT.setObjectName(u"groupBox_file_path_input_signal_FlowT")
+ self.verticalLayout_7 = QVBoxLayout(self.groupBox_file_path_input_signal_FlowT)
+ self.verticalLayout_7.setObjectName(u"verticalLayout_7")
+ self.horizontalLayout_5 = QHBoxLayout()
+ self.horizontalLayout_5.setObjectName(u"horizontalLayout_5")
+ self.label_5 = QLabel(self.groupBox_file_path_input_signal_FlowT)
+ self.label_5.setObjectName(u"label_5")
+ self.label_5.setFont(font)
+
+ self.horizontalLayout_5.addWidget(self.label_5)
+
+ self.spinBox_input_freq_signal_FlowT = QSpinBox(self.groupBox_file_path_input_signal_FlowT)
+ self.spinBox_input_freq_signal_FlowT.setObjectName(u"spinBox_input_freq_signal_FlowT")
+ self.spinBox_input_freq_signal_FlowT.setFont(font)
+ self.spinBox_input_freq_signal_FlowT.setMinimum(1)
+ self.spinBox_input_freq_signal_FlowT.setMaximum(1000000)
+
+ self.horizontalLayout_5.addWidget(self.spinBox_input_freq_signal_FlowT)
+
+
+ self.verticalLayout_7.addLayout(self.horizontalLayout_5)
+
+ self.plainTextEdit_file_path_input_signal_FlowT = QPlainTextEdit(self.groupBox_file_path_input_signal_FlowT)
+ self.plainTextEdit_file_path_input_signal_FlowT.setObjectName(u"plainTextEdit_file_path_input_signal_FlowT")
+
+ self.verticalLayout_7.addWidget(self.plainTextEdit_file_path_input_signal_FlowT)
+
+ self.verticalLayout_7.setStretch(1, 2)
+
+ self.gridLayout_2.addWidget(self.groupBox_file_path_input_signal_FlowT, 4, 0, 1, 1)
+
+ self.groupBox_file_path_input_artifact = QGroupBox(self.groupBox)
+ self.groupBox_file_path_input_artifact.setObjectName(u"groupBox_file_path_input_artifact")
+ self.verticalLayout_11 = QVBoxLayout(self.groupBox_file_path_input_artifact)
+ self.verticalLayout_11.setObjectName(u"verticalLayout_11")
+ 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_11.addWidget(self.plainTextEdit_file_path_input_artifact)
+
+ self.verticalLayout_11.setStretch(0, 2)
+
+ self.gridLayout_2.addWidget(self.groupBox_file_path_input_artifact, 6, 0, 1, 1)
+
+ self.groupBox_file_path_input_signal_SpO2 = QGroupBox(self.groupBox)
+ self.groupBox_file_path_input_signal_SpO2.setObjectName(u"groupBox_file_path_input_signal_SpO2")
+ self.verticalLayout_9 = QVBoxLayout(self.groupBox_file_path_input_signal_SpO2)
+ self.verticalLayout_9.setObjectName(u"verticalLayout_9")
+ self.horizontalLayout_7 = QHBoxLayout()
+ self.horizontalLayout_7.setObjectName(u"horizontalLayout_7")
+ self.label_7 = QLabel(self.groupBox_file_path_input_signal_SpO2)
+ self.label_7.setObjectName(u"label_7")
+ self.label_7.setFont(font)
+
+ self.horizontalLayout_7.addWidget(self.label_7)
+
+ self.spinBox_input_freq_signal_SpO2 = QSpinBox(self.groupBox_file_path_input_signal_SpO2)
+ self.spinBox_input_freq_signal_SpO2.setObjectName(u"spinBox_input_freq_signal_SpO2")
+ self.spinBox_input_freq_signal_SpO2.setFont(font)
+ self.spinBox_input_freq_signal_SpO2.setMinimum(1)
+ self.spinBox_input_freq_signal_SpO2.setMaximum(1000000)
+
+ self.horizontalLayout_7.addWidget(self.spinBox_input_freq_signal_SpO2)
+
+
+ self.verticalLayout_9.addLayout(self.horizontalLayout_7)
+
+ self.plainTextEdit_file_path_input_signal_SpO2 = QPlainTextEdit(self.groupBox_file_path_input_signal_SpO2)
+ self.plainTextEdit_file_path_input_signal_SpO2.setObjectName(u"plainTextEdit_file_path_input_signal_SpO2")
+
+ self.verticalLayout_9.addWidget(self.plainTextEdit_file_path_input_signal_SpO2)
+
+ self.verticalLayout_9.setStretch(1, 2)
+
+ self.gridLayout_2.addWidget(self.groupBox_file_path_input_signal_SpO2, 1, 1, 1, 1)
+
+ self.groupBox_file_path_input_signal_Abd = QGroupBox(self.groupBox)
+ self.groupBox_file_path_input_signal_Abd.setObjectName(u"groupBox_file_path_input_signal_Abd")
+ self.verticalLayout_6 = QVBoxLayout(self.groupBox_file_path_input_signal_Abd)
+ self.verticalLayout_6.setObjectName(u"verticalLayout_6")
+ self.horizontalLayout_4 = QHBoxLayout()
+ self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
+ self.label_4 = QLabel(self.groupBox_file_path_input_signal_Abd)
+ self.label_4.setObjectName(u"label_4")
+ self.label_4.setFont(font)
+
+ self.horizontalLayout_4.addWidget(self.label_4)
+
+ self.spinBox_input_freq_signal_Abd = QSpinBox(self.groupBox_file_path_input_signal_Abd)
+ self.spinBox_input_freq_signal_Abd.setObjectName(u"spinBox_input_freq_signal_Abd")
+ self.spinBox_input_freq_signal_Abd.setFont(font)
+ self.spinBox_input_freq_signal_Abd.setMinimum(1)
+ self.spinBox_input_freq_signal_Abd.setMaximum(1000000)
+
+ self.horizontalLayout_4.addWidget(self.spinBox_input_freq_signal_Abd)
+
+
+ self.verticalLayout_6.addLayout(self.horizontalLayout_4)
+
+ self.plainTextEdit_file_path_input_signal_Abd = QPlainTextEdit(self.groupBox_file_path_input_signal_Abd)
+ self.plainTextEdit_file_path_input_signal_Abd.setObjectName(u"plainTextEdit_file_path_input_signal_Abd")
+
+ self.verticalLayout_6.addWidget(self.plainTextEdit_file_path_input_signal_Abd)
+
+ self.verticalLayout_6.setStretch(1, 2)
+
+ self.gridLayout_2.addWidget(self.groupBox_file_path_input_signal_Abd, 3, 0, 1, 1)
+
+ 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.gridLayout_2.addWidget(self.groupBox_file_path_save, 7, 0, 1, 1)
+
+ self.groupBox_file_path_input_signal_OrgBCG = QGroupBox(self.groupBox)
+ self.groupBox_file_path_input_signal_OrgBCG.setObjectName(u"groupBox_file_path_input_signal_OrgBCG")
+ self.verticalLayout_5 = QVBoxLayout(self.groupBox_file_path_input_signal_OrgBCG)
+ 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_OrgBCG)
+ self.label_2.setObjectName(u"label_2")
+ self.label_2.setFont(font)
+
+ self.horizontalLayout_2.addWidget(self.label_2)
+
+ self.spinBox_input_freq_signal_OrgBCG = QSpinBox(self.groupBox_file_path_input_signal_OrgBCG)
+ self.spinBox_input_freq_signal_OrgBCG.setObjectName(u"spinBox_input_freq_signal_OrgBCG")
+ self.spinBox_input_freq_signal_OrgBCG.setFont(font)
+ self.spinBox_input_freq_signal_OrgBCG.setCursor(QCursor(Qt.ArrowCursor))
+ self.spinBox_input_freq_signal_OrgBCG.setMinimum(1)
+ self.spinBox_input_freq_signal_OrgBCG.setMaximum(1000000)
+
+ self.horizontalLayout_2.addWidget(self.spinBox_input_freq_signal_OrgBCG)
+
+
+ self.verticalLayout_5.addLayout(self.horizontalLayout_2)
+
+ self.plainTextEdit_file_path_input_signal_OrgBCG = QPlainTextEdit(self.groupBox_file_path_input_signal_OrgBCG)
+ self.plainTextEdit_file_path_input_signal_OrgBCG.setObjectName(u"plainTextEdit_file_path_input_signal_OrgBCG")
+
+ self.verticalLayout_5.addWidget(self.plainTextEdit_file_path_input_signal_OrgBCG)
+
+ self.verticalLayout_5.setStretch(0, 2)
+ self.verticalLayout_5.setStretch(1, 3)
+
+ self.gridLayout_2.addWidget(self.groupBox_file_path_input_signal_OrgBCG, 1, 0, 1, 1)
+
+ self.checkBox_auto_find_file = QCheckBox(self.groupBox)
+ self.checkBox_auto_find_file.setObjectName(u"checkBox_auto_find_file")
+
+ self.gridLayout_2.addWidget(self.checkBox_auto_find_file, 0, 0, 1, 1)
+
+
+ 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_SA_label_input_setting.setCentralWidget(self.centralwidget)
+ self.statusbar = QStatusBar(MainWindow_SA_label_input_setting)
+ self.statusbar.setObjectName(u"statusbar")
+ MainWindow_SA_label_input_setting.setStatusBar(self.statusbar)
+
+ self.retranslateUi(MainWindow_SA_label_input_setting)
+
+ QMetaObject.connectSlotsByName(MainWindow_SA_label_input_setting)
+ # setupUi
+
+ def retranslateUi(self, MainWindow_SA_label_input_setting):
+ MainWindow_SA_label_input_setting.setWindowTitle(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u5bfc\u5165\u8bbe\u7f6e", None))
+ self.pushButton_cancel.setText(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u53d6\u6d88", None))
+ self.groupBox.setTitle(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None))
+ self.groupBox_file_path_save_2.setTitle(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u65b0\u589e\u7684\u547c\u5438\u6682\u505c\u6807\u7b7e\u4fdd\u5b58\u8def\u5f84", None))
+ self.plainTextEdit_file_path_save_2.setPlaceholderText(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u4fdd\u5b58\u8def\u5f84", None))
+ self.groupBox_file_path_input_label.setTitle(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u540c\u6b65\u540e\u7684\u547c\u5438\u6682\u505c\u6807\u7b7e\u4fdd\u5b58\u8def\u5f84", None))
+ self.plainTextEdit_file_path_input_label.setPlaceholderText(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None))
+ self.groupBox_file_path_input_signal_FlowP.setTitle(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u540c\u6b65\u540e\u7684Flow P\u8def\u5f84", None))
+ self.label_6.setText(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u91c7\u6837\u7387(Hz)\uff1a", None))
+ self.plainTextEdit_file_path_input_signal_FlowP.setPlainText("")
+ self.plainTextEdit_file_path_input_signal_FlowP.setPlaceholderText(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None))
+ self.plainTextEdit_file_path_input_signal_FlowP.setProperty("signal_type", QCoreApplication.translate("MainWindow_SA_label_input_setting", u"FlowP", None))
+ self.groupBox_file_path_input_signal_Tho.setTitle(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u540c\u6b65\u540e\u7684Effort Tho\u8def\u5f84", None))
+ self.label_3.setText(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u91c7\u6837\u7387(Hz)\uff1a", None))
+ self.plainTextEdit_file_path_input_signal_Tho.setPlainText("")
+ self.plainTextEdit_file_path_input_signal_Tho.setPlaceholderText(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None))
+ self.plainTextEdit_file_path_input_signal_Tho.setProperty("signal_type", QCoreApplication.translate("MainWindow_SA_label_input_setting", u"Tho", None))
+ self.groupBox_file_path_input_signal_FlowT.setTitle(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u540c\u6b65\u540e\u7684Flow T\u8def\u5f84", None))
+ self.label_5.setText(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u91c7\u6837\u7387(Hz)\uff1a", None))
+ self.plainTextEdit_file_path_input_signal_FlowT.setPlainText("")
+ self.plainTextEdit_file_path_input_signal_FlowT.setPlaceholderText(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None))
+ self.plainTextEdit_file_path_input_signal_FlowT.setProperty("signal_type", QCoreApplication.translate("MainWindow_SA_label_input_setting", u"FlowT", None))
+ self.groupBox_file_path_input_artifact.setTitle(QCoreApplication.translate("MainWindow_SA_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_SA_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None))
+ self.groupBox_file_path_input_signal_SpO2.setTitle(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u540c\u6b65\u540e\u7684SpO2\u8def\u5f84", None))
+ self.label_7.setText(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u91c7\u6837\u7387(Hz)\uff1a", None))
+ self.plainTextEdit_file_path_input_signal_SpO2.setPlainText("")
+ self.plainTextEdit_file_path_input_signal_SpO2.setPlaceholderText(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None))
+ self.plainTextEdit_file_path_input_signal_SpO2.setProperty("signal_type", QCoreApplication.translate("MainWindow_SA_label_input_setting", u"SpO2", None))
+ self.groupBox_file_path_input_signal_Abd.setTitle(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u540c\u6b65\u540e\u7684Effort Abd\u8def\u5f84", None))
+ self.label_4.setText(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u91c7\u6837\u7387(Hz)\uff1a", None))
+ self.plainTextEdit_file_path_input_signal_Abd.setPlainText("")
+ self.plainTextEdit_file_path_input_signal_Abd.setPlaceholderText(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None))
+ self.plainTextEdit_file_path_input_signal_Abd.setProperty("signal_type", QCoreApplication.translate("MainWindow_SA_label_input_setting", u"Abd", None))
+ self.groupBox_file_path_save.setTitle(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u4fee\u6b63\u540e\u7684\u547c\u5438\u6682\u505c\u6807\u7b7e\u4fdd\u5b58\u8def\u5f84", None))
+ self.plainTextEdit_file_path_save.setPlaceholderText(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u4fdd\u5b58\u8def\u5f84", None))
+ self.groupBox_file_path_input_signal_OrgBCG.setTitle(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u540c\u6b65\u540e\u7684OrgBCG\u8def\u5f84", None))
+ self.label_2.setText(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u91c7\u6837\u7387(Hz)\uff1a", None))
+ self.spinBox_input_freq_signal_OrgBCG.setPrefix("")
+ self.plainTextEdit_file_path_input_signal_OrgBCG.setPlainText("")
+ self.plainTextEdit_file_path_input_signal_OrgBCG.setPlaceholderText(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u6587\u4ef6\u8def\u5f84", None))
+ self.plainTextEdit_file_path_input_signal_OrgBCG.setProperty("signal_type", QCoreApplication.translate("MainWindow_SA_label_input_setting", u"OrgBCG", None))
+ self.checkBox_auto_find_file.setText(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u5ffd\u7565\u91c7\u6837\u7387 \u81ea\u52a8\u5339\u914d\u6587\u4ef6", None))
+ self.pushButton_confirm.setText(QCoreApplication.translate("MainWindow_SA_label_input_setting", u"\u786e\u5b9a", None))
+ # retranslateUi
+
diff --git a/ui/setting/SA_label_input_setting_v2.ui b/ui/setting/SA_label_input_setting_v2.ui
new file mode 100644
index 0000000..cee78e8
--- /dev/null
+++ b/ui/setting/SA_label_input_setting_v2.ui
@@ -0,0 +1,456 @@
+
+
+ MainWindow_SA_label_input_setting
+
+
+
+ 0
+ 0
+ 848
+ 859
+
+
+
+ 导入设置
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 取消
+
+
+
+ -
+
+
+
+ 10
+
+
+
+ 文件路径
+
+
+
-
+
+
+ false
+
+
+ 新增的呼吸暂停标签保存路径
+
+
+
-
+
+
+ 保存路径
+
+
+
+
+
+
+ -
+
+
+ 体动Artifact_a路径
+
+
+
-
+
+
+
+
+
+ 文件路径
+
+
+
+
+
+
+ -
+
+
+ 同步后的Flow T路径
+
+
+
-
+
+
-
+
+
+
+ 12
+
+
+
+ 采样率(Hz):
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 1
+
+
+ 1000000
+
+
+
+
+
+ -
+
+
+
+
+
+ 文件路径
+
+
+ FlowT
+
+
+
+
+
+
+ -
+
+
+ 修正后的呼吸暂停标签保存路径
+
+
+
-
+
+
+ 保存路径
+
+
+
+
+
+
+ -
+
+
+ 同步后的SpO2路径
+
+
+
-
+
+
-
+
+
+
+ 12
+
+
+
+ 采样率(Hz):
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 1
+
+
+ 1000000
+
+
+
+
+
+ -
+
+
+
+
+
+ 文件路径
+
+
+ SpO2
+
+
+
+
+
+
+ -
+
+
+ 同步后的Effort Tho路径
+
+
+
-
+
+
-
+
+
+
+ 12
+
+
+
+ 采样率(Hz):
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 1
+
+
+ 1000000
+
+
+
+
+
+ -
+
+
+
+
+
+ 文件路径
+
+
+ Tho
+
+
+
+
+
+
+ -
+
+
+ 同步后的呼吸暂停标签保存路径
+
+
+
-
+
+
+ 文件路径
+
+
+
+
+
+
+ -
+
+
+ 同步后的Effort Abd路径
+
+
+
-
+
+
-
+
+
+
+ 12
+
+
+
+ 采样率(Hz):
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 1
+
+
+ 1000000
+
+
+
+
+
+ -
+
+
+
+
+
+ 文件路径
+
+
+ Abd
+
+
+
+
+
+
+ -
+
+
+ 同步后的OrgBCG路径
+
+
+
-
+
+
-
+
+
+
+ 12
+
+
+
+ 采样率(Hz):
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ ArrowCursor
+
+
+
+
+
+ 1
+
+
+ 1000000
+
+
+
+
+
+ -
+
+
+
+
+
+ 文件路径
+
+
+ OrgBCG
+
+
+
+
+
+
+ -
+
+
+ 同步后的Flow P路径
+
+
+
-
+
+
-
+
+
+
+ 12
+
+
+
+ 采样率(Hz):
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 1
+
+
+ 1000000
+
+
+
+
+
+ -
+
+
+
+
+
+ 文件路径
+
+
+ FlowP
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 确定
+
+
+
+
+
+
+
+
+
+