diff --git a/func/Module_cut_PSG.py b/func/Module_cut_PSG.py
new file mode 100644
index 0000000..f30d40a
--- /dev/null
+++ b/func/Module_cut_PSG.py
@@ -0,0 +1,307 @@
+from ast import literal_eval
+from gc import collect
+from math import floor
+from pathlib import Path
+
+from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication
+from numpy import array
+from overrides import overrides
+from pandas import read_csv, DataFrame
+from yaml import dump, load, FullLoader
+
+from func.utils.PublicFunc import PublicFunc
+from func.utils.Constants import Constants, ConfigParams
+
+from ui.MainWindow.MainWindow_cut_PSG import Ui_MainWindow_cut_PSG
+
+
+Config = {
+
+}
+
+ButtonState = {
+ "Default": {
+ "pushButton_execute": True
+ },
+ "Current": {
+ "pushButton_execute": True
+ }
+}
+
+
+class MainWindow_cut_PSG(QMainWindow):
+
+ def __init__(self):
+ super(MainWindow_cut_PSG, self).__init__()
+ self.ui = Ui_MainWindow_cut_PSG()
+ self.ui.setupUi(self)
+
+ self.root_path = None
+ self.sampID = None
+
+ self.__read_config__()
+
+ self.data = None
+
+ # 初始化进度条
+ self.ui.progressbar.setStyleSheet(Constants.PROGRESSBAR_STYLE)
+ self.progressbar = self.ui.progressbar
+
+ self.msgBox = QMessageBox()
+ self.msgBox.setWindowTitle(Constants.MAINWINDOW_MSGBOX_TITLE)
+
+ @overrides
+ def show(self, root_path, sampID):
+ super().show()
+ self.root_path = root_path
+ self.sampID = sampID
+
+ PublicFunc.__resetAllButton__(self, ButtonState)
+
+ Config.update({
+ "Path": {
+ "InputFolder": str(Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_TEXT / Path(str(self.sampID))),
+ "SaveFolder": str(Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_ALIGNED / Path(str(self.sampID))),
+ "InputAlignInfo": str(Path(self.root_path) / ConfigParams.PUBLIC_PATH_PSG_ALIGNED / Path(str(self.sampID)) / (ConfigParams.CUT_PSG_SAVE_ECG_ALIGNINFO_FILENAME + ConfigParams.ENDSWITH_TXT))
+ }
+ })
+
+ self.ui.plainTextEdit_channel.setPlainText(', '.join(Config["ChannelInput"].keys()))
+ self.ui.plainTextEdit_label.setPlainText(', '.join(Config["LabelInput"].keys()))
+
+ self.ui.pushButton_execute.clicked.connect(self.__slot_btn_execute__)
+
+ @overrides
+ def closeEvent(self, event):
+ PublicFunc.__disableAllButton__(self, ButtonState)
+
+ PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg(Constants.SHUTTING_DOWN))
+ QApplication.processEvents()
+
+ # 释放资源
+ del self.data
+ self.deleteLater()
+ collect()
+ event.accept()
+
+ @staticmethod
+ def __reset__():
+ ButtonState["Current"].update(ButtonState["Default"].copy())
+
+ def __read_config__(self):
+ if not Path(ConfigParams.CUT_PSG_CONFIG_FILE_PATH).exists():
+ with open(ConfigParams.CUT_PSG_CONFIG_FILE_PATH, "w") as f:
+ dump(ConfigParams.CUT_PSG_CONFIG_NEW_CONTENT, f)
+
+ with open(ConfigParams.CUT_PSG_CONFIG_FILE_PATH, "r") as f:
+ file_config = load(f.read(), Loader=FullLoader)
+ Config.update(file_config)
+
+ # 数据回显
+ self.ui.spinBox_ECGFreq.setValue(Config["ECGFreq"])
+
+ def __slot_btn_execute__(self):
+ PublicFunc.__disableAllButton__(self, ButtonState)
+
+ self.data = Data()
+ Config["ECGFreq"] = self.ui.spinBox_ECGFreq.value()
+
+ # 检查文件是否存在并获取其数据采样率
+ PublicFunc.progressbar_update(self, 1, 5, Constants.CUT_PSG_GETTING_FILE_AND_FREQ, 0)
+ status, info = self.data.get_file_and_freq()
+ if not status:
+ PublicFunc.text_output(self.ui, "(1/5)" + info, Constants.TIPS_TYPE_ERROR)
+ PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR)
+ PublicFunc.finish_operation(self, ButtonState)
+ return
+ else:
+ PublicFunc.text_output(self.ui, "(1/5)" + info, Constants.TIPS_TYPE_INFO)
+
+ PublicFunc.finish_operation(self, ButtonState)
+
+ # 导入数据
+ PublicFunc.progressbar_update(self, 2, 5, Constants.INPUTTING_DATA, 10)
+ status, info = self.data.open_file()
+ if not status:
+ PublicFunc.text_output(self.ui, "(2/5)" + info, Constants.TIPS_TYPE_ERROR)
+ PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR)
+ PublicFunc.finish_operation(self, ButtonState)
+ return
+ else:
+ PublicFunc.text_output(self.ui, "(2/5)" + info, Constants.TIPS_TYPE_INFO)
+
+ PublicFunc.finish_operation(self, ButtonState)
+
+ # 切割数据
+ PublicFunc.progressbar_update(self, 3, 5, Constants.CUT_PSG_CUTTING_DATA, 40)
+ status, info = self.data.cut_data()
+ if not status:
+ PublicFunc.text_output(self.ui, "(3/5)" + info, Constants.TIPS_TYPE_ERROR)
+ PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR)
+ PublicFunc.finish_operation(self, ButtonState)
+ return
+ else:
+ PublicFunc.text_output(self.ui, "(3/5)" + info, Constants.TIPS_TYPE_INFO)
+
+ PublicFunc.finish_operation(self, ButtonState)
+
+ # 标签映射
+ PublicFunc.progressbar_update(self, 4, 5, Constants.CUT_PSG_ALIGNING_LABEL, 60)
+ status, info = self.data.align_label()
+ if not status:
+ PublicFunc.text_output(self.ui, "(4/5)" + info, Constants.TIPS_TYPE_ERROR)
+ PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR)
+ PublicFunc.finish_operation(self, ButtonState)
+ return
+ else:
+ PublicFunc.text_output(self.ui, "(4/5)" + info, Constants.TIPS_TYPE_INFO)
+
+ PublicFunc.finish_operation(self, ButtonState)
+
+ # 切割数据
+ PublicFunc.progressbar_update(self, 5, 5, Constants.SAVING_DATA, 70)
+ status, info = self.data.save()
+ if not status:
+ PublicFunc.text_output(self.ui, "(5/5)" + info, Constants.TIPS_TYPE_ERROR)
+ PublicFunc.msgbox_output(self, info, Constants.MSGBOX_TYPE_ERROR)
+ PublicFunc.finish_operation(self, ButtonState)
+ return
+ else:
+ PublicFunc.text_output(self.ui, "(5/5)" + info, Constants.TIPS_TYPE_INFO)
+ PublicFunc.msgbox_output(self, info, Constants.TIPS_TYPE_INFO)
+
+ PublicFunc.finish_operation(self, ButtonState)
+
+
+class Data:
+
+ def __init__(self):
+ self.alignInfo = None
+
+ self.raw = {key: array([]) for key in Config["ChannelInput"]}
+ self.freq = {key: 0 for key in Config["ChannelInput"]}
+
+ self.SALabel = None
+ self.startTime = None
+
+ def get_file_and_freq(self):
+ try:
+ for file_path in Path(Config["Path"]["InputFolder"]).glob('*'):
+ if file_path.is_file():
+ file_stem = Path(file_path).stem
+ for key, prefix in Config["ChannelInput"].items():
+ if file_stem.startswith(prefix):
+ freq_str = file_stem.rsplit('_', 1)[1]
+ try:
+ freq = int(freq_str)
+ self.freq[key] = freq
+ except ValueError:
+ return False, Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Filename_Format_not_Correct"]
+ for value in self.freq.values():
+ if value == 0:
+ return False, Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Filename_Format_not_Correct"]
+ if not any((Config["LabelInput"]["SA Label"] + Config["EndWith"]["SA Label"]) in str(file) for file in Path(Config["Path"]["InputFolder"]).glob('*')):
+ return False, Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE + Constants.CUT_PSG_FAILURE_REASON["File_not_Exist"]
+ if not any((Config["StartTime"] + Config["EndWith"]["StartTime"]) in str(file) for file in Path(Config["Path"]["InputFolder"]).glob('*')):
+ return False, Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE + Constants.CUT_PSG_FAILURE_REASON["File_not_Exist"]
+ if not Path(Config["Path"]["InputAlignInfo"]).exists():
+ return False, Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE + Constants.CUT_PSG_FAILURE_REASON["File_not_Exist"]
+ except Exception:
+ return False, Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE + Constants.CUT_PSG_GET_FILE_AND_FREQ_FAILURE["Get_File_and_Freq_Excepetion"]
+
+ return True, Constants.CUT_PSG_GET_FILE_AND_FREQ_FINISHED
+
+ def open_file(self):
+ try:
+ for key in Config["ChannelInput"].keys():
+ self.raw[key] = read_csv(Path(Config["Path"]["InputFolder"]) / Path((Config["ChannelInput"][key] + str(self.freq[key]) + Config["EndWith"][key])),
+ encoding=ConfigParams.UTF8_ENCODING,
+ header=None).to_numpy().reshape(-1)
+ self.SALabel = read_csv(Path(Config["Path"]["InputFolder"]) / Path((Config["LabelInput"]["SA Label"] + Config["EndWith"]["SA Label"])),
+ encoding=ConfigParams.GBK_ENCODING)
+ self.startTime = read_csv(Path(Config["Path"]["InputFolder"]) / Path((Config["StartTime"] + Config["EndWith"]["StartTime"])),
+ encoding=ConfigParams.UTF8_ENCODING,
+ header=None).to_numpy().reshape(-1)
+ self.alignInfo = read_csv(Path(Config["Path"]["InputAlignInfo"]),
+ encoding=ConfigParams.UTF8_ENCODING,
+ header=None).to_numpy().reshape(-1)
+ self.alignInfo = literal_eval(self.alignInfo[0])
+ except Exception:
+ return False, Constants.INPUT_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Read_Data_Exception"]
+
+ return True, Constants.INPUT_FINISHED
+
+ def cut_data(self):
+ try:
+ for key, raw in self.raw.items():
+ # 转换切割点
+ ECG_freq = Config["ECGFreq"]
+ raw_freq = self.freq[key]
+ duration_second = ((self.alignInfo["cut_index"]["back_ECG"] - self.alignInfo["cut_index"]["front_ECG"]) // 1000) + 1
+ start_index_cut = floor(self.alignInfo["cut_index"]["front_ECG"] * (raw_freq / ECG_freq))
+ end_index_cut = start_index_cut + (duration_second * raw_freq)
+
+ try:
+ # 切割信号
+ self.raw[key] = self.raw[key][start_index_cut:end_index_cut]
+ except Exception:
+ return False, Constants.CUT_PSG_CUT_DATA_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Cut_Data_Length_not_Correct"]
+ except Exception:
+ return False, Constants.CUT_PSG_CUT_DATA_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Cut_Data_Exception"]
+
+ return True, Constants.CUT_PSG_CUT_DATA_FINISHED
+
+ def align_label(self):
+ try:
+ # 读取SA标签
+ self.SALabel = self.SALabel.loc[:, ~self.SALabel.columns.str.contains("^Unnamed")]
+ self.SALabel = self.SALabel[self.SALabel["Event type"].isin(ConfigParams.CUT_PSG_SALABEL_EVENT)]
+ self.SALabel["Duration"] = self.SALabel["Duration"].astype(str)
+ self.SALabel["Duration"] = self.SALabel["Duration"].str.replace(r' \(.*?\)', '', regex=True)
+ except Exception:
+ return False, Constants.CUT_PSG_ALIGN_LABEL_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Align_Label_SALabel_Format_not_Correct"]
+
+ try:
+ # 获取记录开始时间
+ start_time = str(self.startTime[0]).split(" ")[1]
+ start_time = Data.get_time_to_seconds(start_time)
+
+ # 计算起始时间秒数和终止时间秒数
+ self.SALabel["Start"] = (self.SALabel["Time"].apply(self.get_time_to_seconds) - start_time).apply(
+ lambda x: x + 24 * 3600 if x < 0 else x).astype(int)
+ self.SALabel["End"] = self.SALabel["Start"] + self.SALabel["Duration"].astype(float).round(0).astype(int)
+
+ # 标签映射
+ ECG_length = self.alignInfo["cut_index"]["back_ECG"] - self.alignInfo["cut_index"]["front_ECG"]
+ self.SALabel["Start"] = self.SALabel["Start"] - round((self.alignInfo["cut_index"]["front_ECG"] / 1000))
+ self.SALabel["End"] = self.SALabel["End"] - round((self.alignInfo["cut_index"]["front_ECG"] / 1000))
+ self.SALabel = self.SALabel[self.SALabel["End"] >= 0]
+ self.SALabel.loc[self.SALabel["Start"] < 0, "Start"] = 0
+ self.SALabel = self.SALabel[self.SALabel["Start"] < ECG_length]
+ self.SALabel.loc[self.SALabel["End"] >= ECG_length, "End"] = ECG_length - 1
+ except Exception:
+ return False, Constants.CUT_PSG_ALIGN_LABEL_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Align_Label_Exception"]
+
+ return True, Constants.CUT_PSG_ALIGN_LABEL_FINISHED
+
+ def save(self):
+ for raw in self.raw.values():
+ if len(raw) == 0:
+ return False, Constants.SAVING_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Save_Data_not_Exist"]
+
+ try:
+ for key, raw in self.raw.items():
+ DataFrame(raw.reshape(-1)).to_csv(Path(Config["Path"]["SaveFolder"]) / Path((Config["ChannelSave"][key] + str(self.freq[key]) + Config["EndWith"][key])),
+ index=False, header=False)
+ self.SALabel.to_csv(Path(Config["Path"]["SaveFolder"]) / Path((Config["LabelSave"]["SA Label"] + Config["EndWith"]["SA Label"])),
+ index=False,
+ encoding="gbk")
+ except Exception:
+ return False, Constants.SAVING_FAILURE + Constants.CUT_PSG_FAILURE_REASON["Save_Exception"]
+
+ return True, Constants.SAVING_FINISHED
+
+ @staticmethod
+ def get_time_to_seconds(time_str):
+ h, m, s = map(int, time_str.split(":"))
+ return h * 3600 + m * 60 + s
\ No newline at end of file
diff --git a/func/Module_detect_Jpeak.py b/func/Module_detect_Jpeak.py
index 91df024..c49358a 100644
--- a/func/Module_detect_Jpeak.py
+++ b/func/Module_detect_Jpeak.py
@@ -41,7 +41,6 @@ ButtonState = {
class SettingWindow(QMainWindow):
def __init__(self, root_path, sampID):
-
super(SettingWindow, self).__init__()
self.ui = Ui_MainWindow_detect_Jpeak_input_setting()
self.ui.setupUi(self)
@@ -58,7 +57,6 @@ class SettingWindow(QMainWindow):
self.ui.pushButton_cancel.clicked.connect(self.close)
def __read_config__(self):
-
if not Path(ConfigParams.DETECT_JPEAK_CONFIG_FILE_PATH).exists():
with open(ConfigParams.DETECT_JPEAK_CONFIG_FILE_PATH, "w") as f:
dump(ConfigParams.DETECT_JPEAK_CONFIG_NEW_CONTENT, f)
@@ -87,7 +85,6 @@ class SettingWindow(QMainWindow):
self.ui.plainTextEdit_file_path_save.setPlainText(Config["Path"]["Save"])
def __write_config__(self):
-
# 从界面写入配置
Config["InputConfig"]["Freq"] = self.ui.spinBox_input_freq.value()
Config["Path"]["Input"] = self.ui.plainTextEdit_file_path_input.toPlainText()
@@ -104,11 +101,9 @@ class SettingWindow(QMainWindow):
self.close()
def __rollback_config__(self):
-
self.__read_config__()
def __update_ui__(self):
-
self.ui.plainTextEdit_file_path_input.setPlainText(
str((Path(self.root_path) /
ConfigParams.PUBLIC_PATH_ORGBCG_TEXT /
@@ -117,10 +112,10 @@ class SettingWindow(QMainWindow):
str(self.ui.spinBox_input_freq.value()) +
ConfigParams.ENDSWITH_TXT))))
+
class MainWindow_detect_Jpeak(QMainWindow):
def __init__(self):
-
super(MainWindow_detect_Jpeak, self).__init__()
self.ui = Ui_MainWindow_detect_Jpeak()
self.ui.setupUi(self)
@@ -149,7 +144,6 @@ class MainWindow_detect_Jpeak(QMainWindow):
@overrides
def show(self, root_path, sampID):
-
super().show()
self.root_path = root_path
self.sampID = sampID
@@ -196,7 +190,6 @@ class MainWindow_detect_Jpeak(QMainWindow):
@overrides
def closeEvent(self, event):
-
PublicFunc.__disableAllButton__(self, ButtonState)
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg(Constants.SHUTTING_DOWN))
@@ -217,12 +210,10 @@ class MainWindow_detect_Jpeak(QMainWindow):
@staticmethod
def __reset__():
-
ButtonState["Current"].update(ButtonState["Default"].copy())
ButtonState["Current"]["pushButton_view"] = True
def __plot__(self):
-
# 清空画框
self.reset_axes()
@@ -249,7 +240,6 @@ class MainWindow_detect_Jpeak(QMainWindow):
return status, info
def __update_config__(self):
-
Config["Filter"]["BandPassLow"] = self.ui.doubleSpinBox_bandPassLow.value()
Config["Filter"]["BandPassHigh"] = self.ui.doubleSpinBox_bandPassHigh.value()
Config["PeaksValue"] = self.ui.spinBox_peaksValue.value()
@@ -260,7 +250,6 @@ class MainWindow_detect_Jpeak(QMainWindow):
Config["DetectMethod"] = self.ui.comboBox_model.currentText()
def __slot_btn_input__(self):
-
PublicFunc.__disableAllButton__(self, ButtonState)
# 清空画框
@@ -300,7 +289,6 @@ class MainWindow_detect_Jpeak(QMainWindow):
PublicFunc.finish_operation(self, ButtonState)
def __slot_btn_view__(self):
-
PublicFunc.__disableAllButton__(self, ButtonState)
# 数据预处理
@@ -348,7 +336,6 @@ class MainWindow_detect_Jpeak(QMainWindow):
PublicFunc.finish_operation(self, ButtonState)
def __slot_btn_save__(self):
-
reply = QMessageBox.question(self, Constants.QUESTION_TITLE,
Constants.QUESTION_CONTENT + Config["Path"]["Save"],
QMessageBox.Yes | QMessageBox.No,
@@ -382,13 +369,11 @@ class MainWindow_detect_Jpeak(QMainWindow):
PublicFunc.finish_operation(self, ButtonState)
def reset_axes(self):
-
self.ax0.clear()
self.ax0.grid(True)
self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER)
def update_ui_comboBox_model(self, model_list):
-
self.ui.comboBox_model.clear()
self.ui.comboBox_model.addItems(model_list)
@@ -396,31 +381,25 @@ class MainWindow_detect_Jpeak(QMainWindow):
class Data:
def __init__(self):
-
- self.file_path_input = Config["Path"]["Input"]
- self.file_path_save = Config["Path"]["Save"]
-
self.raw_data = None
self.processed_data = None
self.peak = None
self.interval = None
def open_file(self):
-
if not Path(Config["Path"]["Input"]).exists():
return False, Constants.INPUT_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Data_Path_Not_Exist"]
try:
- self.raw_data = read_csv(self.file_path_input,
- encoding=ConfigParams.UTF8_ENCODING,
- header=None).to_numpy().reshape(-1)
+ self.raw_data = read_csv(Config["Path"]["Input"],
+ encoding=ConfigParams.UTF8_ENCODING,
+ header=None).to_numpy().reshape(-1)
except Exception:
return False, Constants.INPUT_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Read_Data_Exception"]
return True, Constants.INPUT_FINISHED
def preprocess(self):
-
if self.raw_data is None:
return False, Constants.DETECT_JPEAK_PROCESS_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Raw_Data_Not_Exist"]
@@ -436,7 +415,6 @@ class Data:
return True, Constants.DETECT_JPEAK_PROCESS_FINISHED
def predict_Jpeak(self, model):
-
if not (Path(model.model_folder_path) / Path(model.selected_model)).exists():
return False, Constants.DETECT_JPEAK_PREDICT_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Model_File_Not_Exist"]
@@ -458,12 +436,11 @@ class Data:
return True, Constants.DETECT_JPEAK_PREDICT_FINISHED
def save(self, chunk):
-
if self.peak is None:
return False, Constants.SAVING_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Peak_Not_Exist"]
try:
- chunk.to_csv(self.file_path_save, mode='a', index=False, header=False)
+ chunk.to_csv(Config["Path"]["Save"], mode='a', index=False, header=False)
except Exception:
return False, Constants.SAVING_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Save_Exception"]
@@ -473,14 +450,12 @@ class Data:
class Model:
def __init__(self):
-
self.model_folder_path = Config["ModelFolderPath"]
self.model_list = None
self.selected_model_path = None
self.selected_model = None
def seek_model(self):
-
if not Path(Config["ModelFolderPath"]).exists():
return False, Constants.DETECT_JPEAK_LOAD_FAILURE + Constants.DETECT_JPEAK_FAILURE_REASON["Model_Path_Not_Exist"]
diff --git a/func/Module_detect_Rpeak.py b/func/Module_detect_Rpeak.py
index 6c35c67..3fee804 100644
--- a/func/Module_detect_Rpeak.py
+++ b/func/Module_detect_Rpeak.py
@@ -41,7 +41,6 @@ ButtonState = {
class SettingWindow(QMainWindow):
def __init__(self, root_path, sampID):
-
super(SettingWindow, self).__init__()
self.ui = Ui_MainWindow_detect_Rpeak_input_setting()
self.ui.setupUi(self)
@@ -58,7 +57,6 @@ class SettingWindow(QMainWindow):
self.ui.pushButton_cancel.clicked.connect(self.close)
def __read_config__(self):
-
if not Path(ConfigParams.DETECT_RPEAK_CONFIG_FILE_PATH).exists():
with open(ConfigParams.DETECT_RPEAK_CONFIG_FILE_PATH, "w") as f:
dump(ConfigParams.DETECT_RPEAK_CONFIG_NEW_CONTENT, f)
@@ -86,7 +84,6 @@ class SettingWindow(QMainWindow):
self.ui.plainTextEdit_file_path_save.setPlainText(Config["Path"]["Save"])
def __write_config__(self):
-
# 从界面写入配置
Config["InputConfig"]["Freq"] = self.ui.spinBox_input_freq.value()
Config["Path"]["Input"] = self.ui.plainTextEdit_file_path_input.toPlainText()
@@ -101,11 +98,9 @@ class SettingWindow(QMainWindow):
self.close()
def __rollback_config__(self):
-
self.__read_config__()
def __update_ui__(self):
-
self.ui.plainTextEdit_file_path_input.setPlainText(
str((Path(self.root_path) /
ConfigParams.PUBLIC_PATH_PSG_TEXT /
@@ -118,7 +113,6 @@ class SettingWindow(QMainWindow):
class MainWindow_detect_Rpeak(QMainWindow):
def __init__(self):
-
super(MainWindow_detect_Rpeak, self).__init__()
self.ui = Ui_MainWindow_detect_Rpeak()
self.ui.setupUi(self)
@@ -147,7 +141,6 @@ class MainWindow_detect_Rpeak(QMainWindow):
@overrides
def show(self, root_path, sampID):
-
super().show()
self.root_path = root_path
self.sampID = sampID
@@ -190,7 +183,6 @@ class MainWindow_detect_Rpeak(QMainWindow):
@overrides
def closeEvent(self, event):
-
PublicFunc.__disableAllButton__(self, ButtonState)
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg(Constants.SHUTTING_DOWN))
@@ -211,12 +203,10 @@ class MainWindow_detect_Rpeak(QMainWindow):
@staticmethod
def __reset__():
-
ButtonState["Current"].update(ButtonState["Default"].copy())
ButtonState["Current"]["pushButton_view"] = True
def __plot__(self):
-
# 清空画框
self.reset_axes()
@@ -247,14 +237,12 @@ class MainWindow_detect_Rpeak(QMainWindow):
return status, info
def __update_config__(self):
-
Config["Filter"]["BandPassLow"] = self.ui.doubleSpinBox_bandPassLow.value()
Config["Filter"]["BandPassHigh"] = self.ui.doubleSpinBox_bandPassHigh.value()
Config["PeaksValue"] = self.ui.spinBox_peaksValue.value()
Config["DetectMethod"] = self.ui.comboBox_method.currentText()
def __slot_btn_input__(self):
-
PublicFunc.__disableAllButton__(self, ButtonState)
# 清空画框
@@ -300,7 +288,6 @@ class MainWindow_detect_Rpeak(QMainWindow):
PublicFunc.finish_operation(self, ButtonState)
def __slot_btn_view__(self):
-
PublicFunc.__disableAllButton__(self, ButtonState)
# 数据预处理
@@ -347,7 +334,6 @@ class MainWindow_detect_Rpeak(QMainWindow):
PublicFunc.finish_operation(self, ButtonState)
def __slot_btn_save__(self):
-
reply = QMessageBox.question(self, Constants.QUESTION_TITLE,
Constants.QUESTION_CONTENT + Config["Path"]["Save"],
QMessageBox.Yes | QMessageBox.No,
@@ -381,7 +367,6 @@ class MainWindow_detect_Rpeak(QMainWindow):
PublicFunc.finish_operation(self, ButtonState)
def reset_axes(self):
-
self.ax0.clear()
self.ax1.clear()
self.ax0.grid(True)
@@ -391,7 +376,6 @@ class MainWindow_detect_Rpeak(QMainWindow):
self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER)
def update_ui_comboBox_method(self, method_list):
-
self.ui.comboBox_method.clear()
self.ui.comboBox_method.addItems(method_list)
@@ -399,9 +383,6 @@ class MainWindow_detect_Rpeak(QMainWindow):
class Data:
def __init__(self):
- self.file_path_input = Config["Path"]["Input"]
- self.file_path_save = Config["Path"]["Save"]
-
self.raw_data = None
self.processed_data = None
self.peak = None
@@ -409,21 +390,19 @@ class Data:
self.RRIV = None
def open_file(self):
-
if not Path(Config["Path"]["Input"]).exists():
return False, Constants.INPUT_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Data_Path_Not_Exist"]
try:
- self.raw_data = read_csv(self.file_path_input,
- encoding=ConfigParams.UTF8_ENCODING,
- header=None).to_numpy().reshape(-1)
+ self.raw_data = read_csv(Config["Path"]["Input"],
+ encoding=ConfigParams.UTF8_ENCODING,
+ header=None).to_numpy().reshape(-1)
except Exception:
return False, Constants.INPUT_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Read_Data_Exception"]
return True, Constants.INPUT_FINISHED
def preprocess(self):
-
if self.raw_data is None:
return False, Constants.DETECT_RPEAK_PROCESS_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Raw_Data_Not_Exist"]
@@ -438,7 +417,6 @@ class Data:
return True, Constants.DETECT_RPEAK_PROCESS_FINISHED
def predict_Rpeak(self):
-
if self.processed_data is None:
return False, Constants.DETECT_RPEAK_PREDICT_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Processed_Data_Not_Exist"]
@@ -453,12 +431,11 @@ class Data:
return True, Constants.DETECT_RPEAK_PREDICT_FINISHED
def save(self, chunk):
-
if self.peak is None:
return False, Constants.SAVING_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Peak_Not_Exist"]
try:
- chunk.to_csv(self.file_path_save, mode='a', index=False, header=False)
+ chunk.to_csv(Config["Path"]["Save"], mode='a', index=False, header=False)
except Exception:
return False, Constants.SAVING_FAILURE + Constants.DETECT_RPEAK_FAILURE_REASON["Save_Exception"]
diff --git a/func/Module_label_check.py b/func/Module_label_check.py
index 7b79b5e..c9553e8 100644
--- a/func/Module_label_check.py
+++ b/func/Module_label_check.py
@@ -49,7 +49,6 @@ ButtonState = {
class SettingWindow(QMainWindow):
def __init__(self, mode, root_path, sampID):
-
super(SettingWindow, self).__init__()
self.ui = Ui_MainWindow_label_check_input_setting()
self.ui.setupUi(self)
@@ -70,7 +69,6 @@ class SettingWindow(QMainWindow):
self.ui.pushButton_cancel.clicked.connect(self.close)
def __read_config__(self):
-
if not Path(ConfigParams.LABEL_CHECK_CONFIG_FILE_PATH).exists():
with open(ConfigParams.LABEL_CHECK_CONFIG_FILE_PATH, "w") as f:
dump(ConfigParams.LABEL_CHECK_CONFIG_NEW_CONTENT, f)
@@ -132,7 +130,6 @@ class SettingWindow(QMainWindow):
raise ValueError("模式不存在")
def __write_config__(self):
-
# 从界面写入配置
Config["InputConfig"]["Freq"] = self.ui.spinBox_input_freq_signal.value()
Config["Path"]["Input_Signal"] = self.ui.plainTextEdit_file_path_input_signal.toPlainText()
@@ -158,11 +155,9 @@ class SettingWindow(QMainWindow):
self.close()
def __rollback_config__(self):
-
self.__read_config__()
def __update_ui__(self):
-
if self.mode == "BCG":
self.ui.plainTextEdit_file_path_input_signal.setPlainText(
str((Path(self.root_path) /
@@ -186,7 +181,6 @@ class SettingWindow(QMainWindow):
class MainWindow_label_check(QMainWindow):
def __init__(self):
-
super(MainWindow_label_check, self).__init__()
self.ui = Ui_MainWindow_label_check()
self.ui.setupUi(self)
@@ -236,7 +230,6 @@ class MainWindow_label_check(QMainWindow):
@overrides
def show(self, mode, root_path, sampID):
-
super().show()
self.mode = mode
self.root_path = root_path
@@ -307,7 +300,6 @@ class MainWindow_label_check(QMainWindow):
@overrides
def closeEvent(self, event):
-
PublicFunc.__disableAllButton__(self, ButtonState)
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg(Constants.SHUTTING_DOWN))
@@ -331,11 +323,9 @@ class MainWindow_label_check(QMainWindow):
@staticmethod
def __reset__():
-
ButtonState["Current"].update(ButtonState["Default"].copy())
def __plot__(self):
-
# 清空画框
if self.point_peak_original is not None:
self.point_peak_original.remove()
@@ -373,7 +363,6 @@ class MainWindow_label_check(QMainWindow):
return status, info
def __plot_peaks__(self):
-
try:
self.point_peak_original, = self.ax0.plot(self.data.original_peak, self.data.original_peak_y, 'ro',
label=Constants.LABEL_CHECK_PLOT_LABEL_PEAK_ORIGINAL)
@@ -389,14 +378,12 @@ class MainWindow_label_check(QMainWindow):
return True, Constants.DRAWING_FINISHED
def __redraw_peaks__(self):
-
self.point_peak_corrected.remove()
self.point_peak_corrected, = self.ax1.plot(self.data.corrected_peak, self.data.corrected_peak_y, 'ro',
label=Constants.LABEL_CHECK_PLOT_LABEL_PEAK_CORRECTED)
self.canvas.draw()
def __update_tableWidget_and_info__(self):
-
if self.data.original_peak is None or self.data.corrected_peak is None:
return False, Constants.LABEL_CHECK_FAILURE_REASON["Peak_Not_Exist"]
@@ -419,7 +406,6 @@ class MainWindow_label_check(QMainWindow):
return status, info
def __update_config__(self):
-
Config["FindPeaks"]["MinInterval"] = self.ui.doubleSpinBox_findpeaks_min_interval.value()
Config["FindPeaks"]["MinHeight"] = self.ui.doubleSpinBox_findpeaks_min_height.value()
Config["CustomAutoplayArgs"]["MoveLength"] = self.ui.spinBox_moveLength.value()
@@ -427,7 +413,6 @@ class MainWindow_label_check(QMainWindow):
Config["CustomAutoplayArgs"]["MoveSpeed"] = self.ui.spinBox_moveSpeed.value()
def __slot_btn_input__(self):
-
PublicFunc.__disableAllButton__(self, ButtonState)
# 清空画框
@@ -526,7 +511,6 @@ class MainWindow_label_check(QMainWindow):
PublicFunc.finish_operation(self, ButtonState)
def __slot_btn_save__(self):
-
reply = QMessageBox.question(self, Constants.QUESTION_TITLE,
Constants.QUESTION_CONTENT + Config["Path"]["Save"],
QMessageBox.Yes | QMessageBox.No,
@@ -560,7 +544,6 @@ class MainWindow_label_check(QMainWindow):
PublicFunc.finish_operation(self, ButtonState)
def __slot_btn_move__(self):
-
if self.data is None:
return
@@ -594,7 +577,6 @@ class MainWindow_label_check(QMainWindow):
PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_PAUSE, Constants.TIPS_TYPE_INFO)
def __change_autoplay_args__(self):
-
sender = self.sender()
if sender == self.ui.radioButton_move_preset_1 and self.ui.radioButton_move_preset_1.isChecked():
@@ -637,7 +619,6 @@ class MainWindow_label_check(QMainWindow):
self.timer_autoplay.stop()
def __slot_tableWidget_on_cell_double_clicked__(self, row, col):
-
if Config["AutoplayArgs"]["AutoplayMode"] != "pause":
self.ui.pushButton_pause.click()
@@ -657,7 +638,6 @@ class MainWindow_label_check(QMainWindow):
PublicFunc.text_output(self.ui, f"{Constants.LABEL_CHECK_JUMP_X_INDEX}{str(int(x))}", Constants.TIPS_TYPE_INFO)
def reset_axes(self):
-
self.ax0.clear()
self.ax1.clear()
self.ax0.grid(True)
@@ -667,7 +647,6 @@ class MainWindow_label_check(QMainWindow):
self.ax1.xaxis.set_major_formatter(ConfigParams.FORMATTER)
def on_xlim_change(self, event_ax):
-
try:
if self.annotation_tableWidget is not None:
self.annotation_tableWidget.remove()
@@ -676,7 +655,6 @@ class MainWindow_label_check(QMainWindow):
pass
def autoplay_move_xlim(self):
-
if Config["AutoplayArgs"]["AutoplayMode"] == "prev" and self.autoplay_xlim_start < 0:
Config["AutoplayArgs"]["AutoplayMode"] = "pause"
self.timer_autoplay.stop()
@@ -694,7 +672,6 @@ class MainWindow_label_check(QMainWindow):
self.canvas.draw()
def on_motion(self, event):
-
if event.inaxes and self.ui.checkBox_show_reference_line.isChecked():
# Clear previous reference lines and temporary points
for line in self.ax0.lines[1:]:
@@ -715,7 +692,6 @@ class MainWindow_label_check(QMainWindow):
self.canvas.draw()
def toggle_home(self):
-
if Config["AutoplayArgs"]["AutoplayMode"] != "pause":
self.ui.pushButton_pause.click()
self.ax0.autoscale(True)
@@ -728,7 +704,6 @@ class MainWindow_label_check(QMainWindow):
PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_RECOVER_SCALE, Constants.TIPS_TYPE_INFO)
def toggle_changeLabel(self, state):
-
if state:
self.deactivate_figToolbar_buttons()
self.figToolbar.action_Label_Multiple.setChecked(True)
@@ -750,7 +725,6 @@ class MainWindow_label_check(QMainWindow):
self.figToolbar.cid_mouse_hold = None
def deactivate_figToolbar_buttons(self):
-
for action in self.figToolbar._actions.values():
if action.isChecked() == True:
if action == self.figToolbar._actions['pan']:
@@ -759,7 +733,6 @@ class MainWindow_label_check(QMainWindow):
self.figToolbar.zoom()
def on_click(self, event):
-
if self.figToolbar.action_Label_Multiple.isChecked():
if event.button == 1 or event.button == 3: # 左键或右键
if event.button == 1:
@@ -776,7 +749,6 @@ class MainWindow_label_check(QMainWindow):
self.canvas.draw()
def on_release(self, event):
-
if self.figToolbar.action_Label_Multiple.isChecked():
if self.figToolbar.rect_start_x is not None:
self.figToolbar.rect_end_x = event.xdata
@@ -839,8 +811,7 @@ class MainWindow_label_check(QMainWindow):
self.data.corrected_peak.sort()
self.data.corrected_peak_y = [self.data.processed_data[x] for x in self.data.corrected_peak]
self.__update_tableWidget_and_info__()
- DataFrame(self.data.corrected_peak).to_csv(self.data.file_path_save,
- index=False, header=False)
+ DataFrame(self.data.corrected_peak).to_csv(Config["Path"]["Save"], index=False, header=False)
# 移除矩形patch
if self.figToolbar.rect_patch_ax0 is not None and self.figToolbar.rect_patch_ax1 is not None:
self.figToolbar.rect_patch_ax0.remove()
@@ -850,7 +821,6 @@ class MainWindow_label_check(QMainWindow):
self.canvas.draw()
def on_hold(self, event):
-
if self.figToolbar.rect_start_x is not None and event.xdata is not None:
self.figToolbar.rect_end_x = event.xdata
@@ -896,10 +866,6 @@ class MainWindow_label_check(QMainWindow):
class Data:
def __init__(self):
- self.file_path_input_signal = Config["Path"]["Input_Signal"]
- self.file_path_input_peak = Config["Path"]["Input_Peak"]
- self.file_path_save = Config["Path"]["Save"]
-
self.raw_data = None
self.processed_data = None
self.original_peak = None
@@ -908,15 +874,14 @@ class Data:
self.corrected_peak_y = None
def open_file(self):
-
if (not Path(Config["Path"]["Input_Signal"]).exists()) or (not Path(Config["Path"]["Input_Peak"]).exists()):
return False, Constants.INPUT_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Data_Path_Not_Exist"]
try:
- self.raw_data = read_csv(self.file_path_input_signal,
- encoding=ConfigParams.UTF8_ENCODING,
- header=None).to_numpy().reshape(-1)
- self.original_peak = read_csv(self.file_path_input_peak,
+ self.raw_data = read_csv(Config["Path"]["Input_Signal"],
+ encoding=ConfigParams.UTF8_ENCODING,
+ header=None).to_numpy().reshape(-1)
+ self.original_peak = read_csv(Config["Path"]["Input_Peak"],
encoding=ConfigParams.UTF8_ENCODING,
header=None).to_numpy().reshape(-1)
except Exception:
@@ -925,18 +890,16 @@ class Data:
return True, Constants.INPUT_FINISHED
def get_archive(self):
-
if not Path(Config["Path"]["Save"]).exists():
self.corrected_peak = self.original_peak
return True, Constants.LABEL_CHECK_ARCHIVE_NOT_EXIST
else:
- self.corrected_peak = read_csv(self.file_path_save,
- encoding=ConfigParams.UTF8_ENCODING,
- header=None).to_numpy().reshape(-1)
+ self.corrected_peak = read_csv(Config["Path"]["Save"],
+ encoding=ConfigParams.UTF8_ENCODING,
+ header=None).to_numpy().reshape(-1)
return True, Constants.LABEL_CHECK_ARCHIVE_EXIST
def preprocess(self):
-
if self.raw_data is None:
return False, Constants.LABEL_CHECK_PROCESS_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Raw_Data_Not_Exist"]
@@ -963,12 +926,11 @@ class Data:
return True, Constants.LABEL_CHECK_PROCESS_FINISHED
def save(self, chunk):
-
if self.corrected_peak is None:
return False, Constants.SAVING_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Peak_Not_Exist"]
try:
- chunk.to_csv(self.file_path_save, mode='a', index=False, header=False)
+ chunk.to_csv(Config["Path"]["Save"], mode='a', index=False, header=False)
except Exception:
return False, Constants.SAVING_FAILURE + Constants.LABEL_CHECK_FAILURE_REASON["Save_Exception"]
@@ -1007,21 +969,17 @@ class CustomNavigationToolbar(NavigationToolbar2QT):
self.rect_patch_ax1 = None # 用于绘制矩形的patch
def home(self, *args):
-
pass
def zoom(self, *args):
-
super().zoom(*args)
self.deactivate_figToorbar_changeLabel_mode()
def pan(self, *args):
-
super().pan(*args)
self.deactivate_figToorbar_changeLabel_mode()
def deactivate_figToorbar_changeLabel_mode(self):
-
if self.action_Label_Multiple.isChecked():
self.action_Label_Multiple.setChecked(False)
if self.cid_mouse_press is not None:
diff --git a/func/Module_mainwindow.py b/func/Module_mainwindow.py
index f18e683..4210251 100644
--- a/func/Module_mainwindow.py
+++ b/func/Module_mainwindow.py
@@ -12,6 +12,7 @@ from func.Module_detect_Jpeak import MainWindow_detect_Jpeak
from func.Module_detect_Rpeak import MainWindow_detect_Rpeak
from func.Module_label_check import MainWindow_label_check
from func.Module_precisely_align import MainWindow_precisely_align
+from func.Module_cut_PSG import MainWindow_cut_PSG
from func.utils.Constants import Constants, ConfigParams
@@ -27,7 +28,6 @@ Config = {
class MainWindow(QMainWindow, Ui_Signal_Label):
def __init__(self):
-
super(MainWindow, self).__init__()
self.ui = Ui_Signal_Label()
self.ui.setupUi(self)
@@ -45,6 +45,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label):
self.detect_Rpeak = None
self.label_check = None
self.precisely_align = None
+ self.cut_PSG = None
# 绑定槽函数
self.ui.pushButton_open.clicked.connect(self.__slot_btn_open__)
@@ -55,10 +56,10 @@ class MainWindow(QMainWindow, Ui_Signal_Label):
self.ui.pushButton_label_check_BCG.clicked.connect(self.__slot_btn_label_check__)
self.ui.pushButton_label_check_ECG.clicked.connect(self.__slot_btn_label_check__)
self.ui.pushButton_precisely_align.clicked.connect(self.__slot_btn_precisely_align__)
+ self.ui.pushButton_cut_PSG.clicked.connect(self.__slot_btn_cut_PSG__)
@staticmethod
def __read_config__():
-
if not Path(ConfigParams.PUBLIC_CONFIG_FILE_PATH).exists():
with open(ConfigParams.PUBLIC_CONFIG_FILE_PATH, "w") as f:
dump(ConfigParams.PUBLIC_CONFIG_NEW_CONTENT, f)
@@ -69,12 +70,10 @@ class MainWindow(QMainWindow, Ui_Signal_Label):
@staticmethod
def __write_config__():
-
with open(Path(ConfigParams.PUBLIC_CONFIG_FILE_PATH), "w") as f:
dump(Config, f)
def __slot_btn_open__(self):
-
file_dialog = QFileDialog()
file_dialog.setFileMode(QFileDialog.Directory)
file_dialog.setOption(QFileDialog.ShowDirsOnly, True)
@@ -89,7 +88,6 @@ class MainWindow(QMainWindow, Ui_Signal_Label):
PublicFunc.msgbox_output(self, Constants.OPERATION_CANCELED, Constants.MSGBOX_TYPE_INFO)
def __slot_btn_preprocess__(self):
-
self.preprocess = MainWindow_preprocess()
sender = self.sender()
@@ -104,21 +102,18 @@ class MainWindow(QMainWindow, Ui_Signal_Label):
self.preprocess.show(mode, root_path, sampID)
def __slot_btn_detect_Jpeak__(self):
-
self.detect_Jpeak = MainWindow_detect_Jpeak()
root_path = self.ui.plainTextEdit_root_path.toPlainText()
sampID = int(self.ui.comboBox_sampID.currentText())
self.detect_Jpeak.show(root_path, sampID)
def __slot_btn_detect_Rpeak__(self):
-
self.detect_Rpeak = MainWindow_detect_Rpeak()
root_path = self.ui.plainTextEdit_root_path.toPlainText()
sampID = int(self.ui.comboBox_sampID.currentText())
self.detect_Rpeak.show(root_path, sampID)
def __slot_btn_label_check__(self):
-
self.label_check = MainWindow_label_check()
sender = self.sender()
@@ -133,14 +128,18 @@ class MainWindow(QMainWindow, Ui_Signal_Label):
self.label_check.show(mode, root_path, sampID)
def __slot_btn_precisely_align__(self):
-
self.precisely_align = MainWindow_precisely_align()
root_path = self.ui.plainTextEdit_root_path.toPlainText()
sampID = int(self.ui.comboBox_sampID.currentText())
self.precisely_align.show(root_path, sampID)
- def seek_sampID(self, path):
+ def __slot_btn_cut_PSG__(self):
+ self.cut_PSG = MainWindow_cut_PSG()
+ root_path = self.ui.plainTextEdit_root_path.toPlainText()
+ sampID = int(self.ui.comboBox_sampID.currentText())
+ self.cut_PSG.show(root_path, sampID)
+ def seek_sampID(self, path):
if not Path(path).exists():
PublicFunc.msgbox_output(self, Constants.MAINWINDOW_ROOT_PATH_NOT_EXIST, Constants.MSGBOX_TYPE_ERROR)
return
diff --git a/func/Module_precisely_align.py b/func/Module_precisely_align.py
index 20dcb73..410795f 100644
--- a/func/Module_precisely_align.py
+++ b/func/Module_precisely_align.py
@@ -82,7 +82,6 @@ ButtonState = {
class SettingWindow(QMainWindow):
def __init__(self, root_path, sampID):
-
super(SettingWindow, self).__init__()
self.ui = Ui_MainWindow_precisely_align_input_setting()
self.ui.setupUi(self)
@@ -99,7 +98,6 @@ class SettingWindow(QMainWindow):
self.ui.pushButton_cancel.clicked.connect(self.close)
def __read_config__(self):
-
if not Path(ConfigParams.PRECISELY_ALIGN_CONFIG_FILE_PATH).exists():
with open(ConfigParams.PRECISELY_ALIGN_CONFIG_FILE_PATH, "w") as f:
dump(ConfigParams.PRECISELY_ALIGN_CONFIG_NEW_CONTENT, f)
@@ -213,7 +211,6 @@ class SettingWindow(QMainWindow):
self.ui.plainTextEdit_file_path_save_Rpeak.setPlainText(Config["Path"]["Save_Rpeak"])
def __write_config__(self):
-
# 从界面写入配置
Config["InputConfig"]["ECGFreq"] = self.ui.spinBox_input_freq_ECG.value()
Config["Path"]["Input_orgBcg"] = self.ui.plainTextEdit_file_path_input_orgBcg.toPlainText()
@@ -238,11 +235,9 @@ class SettingWindow(QMainWindow):
self.close()
def __rollback_config__(self):
-
self.__read_config__()
def __update_ui__(self):
-
self.ui.plainTextEdit_file_path_input_orgBcg.setPlainText(
str((Path(self.root_path) /
ConfigParams.PUBLIC_PATH_ORGBCG_TEXT /
@@ -302,7 +297,6 @@ class SettingWindow(QMainWindow):
class MainWindow_precisely_align(QMainWindow):
def __init__(self):
-
super(MainWindow_precisely_align, self).__init__()
self.ui = Ui_MainWindow_precisely_align()
self.ui.setupUi(self)
@@ -356,7 +350,6 @@ class MainWindow_precisely_align(QMainWindow):
@overrides
def show(self, root_path, sampID):
-
super().show()
self.root_path = root_path
self.sampID = sampID
@@ -408,7 +401,6 @@ class MainWindow_precisely_align(QMainWindow):
@overrides
def closeEvent(self, event):
-
PublicFunc.__disableAllButton__(self, ButtonState)
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg(Constants.SHUTTING_DOWN))
@@ -449,11 +441,9 @@ class MainWindow_precisely_align(QMainWindow):
@staticmethod
def __reset__():
-
ButtonState["Current"].update(ButtonState["Default"].copy())
def __plot__(self, plot_element=None):
-
# 清空画框
if self.figToolbar.ax0_BCG_rectangle_front is not None:
self.figToolbar.ax0_BCG_rectangle_front.remove()
@@ -526,11 +516,11 @@ class MainWindow_precisely_align(QMainWindow):
label=Constants.PRECISELY_ALIGN_PLOT_LABEL_SELECTED_POINT)
self.ax0.plot(plot_element["front"]["corre"], 'o', color=Constants.PLOT_COLOR_BLUE,
markersize=3, picker=True, pickradius=5)
- self.ax1.stem(plot_element["front"]["RRIVs"], markerfmt="b.",
+ self.ax1.stem(plot_element["front"]["RRIVs"], markerfmt="b.", linefmt=Constants.PLOT_COLOR_ORANGE,
label=Constants.PRECISELY_ALIGN_PLOT_LABEL_RRIV)
self.stem_black0 = self.ax1.stem(arange(plot_element["front"]["shift"],
plot_element["front"]["shift"] + len(plot_element["front"]["JJIVs"])),
- plot_element["front"]["JJIVs"], markerfmt="ko",
+ plot_element["front"]["JJIVs"], markerfmt="ko", linefmt=Constants.PLOT_COLOR_GREEN,
label=Constants.PRECISELY_ALIGN_PLOT_LABEL_JJIV)
self.ax2.set_title(
"back\ncorre_IIV: {}, corre_II: {}\nsame_sign_rate:{}, total_time_ratio: {}\nshift: {}, alignment offset: {} seconds\noffset_interval: {}, anchor_J: {}, anchor_R: {}".format(
@@ -547,11 +537,11 @@ class MainWindow_precisely_align(QMainWindow):
label=Constants.PRECISELY_ALIGN_PLOT_LABEL_SELECTED_POINT)
self.ax2.plot(plot_element["back"]["corre"], 'o', color=Constants.PLOT_COLOR_BLUE,
markersize=3, picker=True, pickradius=5)
- self.ax3.stem(plot_element["back"]["RRIVs"], markerfmt="b.",
+ self.ax3.stem(plot_element["back"]["RRIVs"], markerfmt="b.", linefmt=Constants.PLOT_COLOR_ORANGE,
label=Constants.PRECISELY_ALIGN_PLOT_LABEL_RRIV)
self.stem_black1 = self.ax3.stem(arange(plot_element["back"]["shift"],
plot_element["back"]["shift"] + len(plot_element["back"]["JJIVs"])),
- plot_element["back"]["JJIVs"], markerfmt="ko",
+ plot_element["back"]["JJIVs"], markerfmt="ko", linefmt=Constants.PLOT_COLOR_GREEN,
label=Constants.PRECISELY_ALIGN_PLOT_LABEL_JJIV)
self.ax0.legend(loc=Constants.PLOT_UPPER_RIGHT)
@@ -607,7 +597,6 @@ class MainWindow_precisely_align(QMainWindow):
return status, info
def __update_info__(self):
-
self.ui.spinBox_BCG_front_JJIV_1.setValue(Config["IV_Coordinate"]["BCG_front_1"])
self.ui.spinBox_BCG_front_JJIV_2.setValue(Config["IV_Coordinate"]["BCG_front_2"])
self.ui.spinBox_BCG_back_JJIV_1.setValue(Config["IV_Coordinate"]["BCG_back_1"])
@@ -626,7 +615,6 @@ class MainWindow_precisely_align(QMainWindow):
self.ui.spinBox_ECG_back_Signal_2.setValue(Config["Coordinate"]["ECG_back_2"])
def __slot_btn_input__(self):
-
PublicFunc.__disableAllButton__(self, ButtonState)
# 清空画框
@@ -679,7 +667,6 @@ class MainWindow_precisely_align(QMainWindow):
def __slot_btn_calculate_correlation__(self, test1=None, shift_front=None, shift_back=None):
# TODO:这里有个未知的问BUG,虽然不影响功能,但会影响代码整洁性,第一个形参赋值为None时,之后使用变量时将会变成False,不知道为什么
-
PublicFunc.__disableAllButton__(self, ButtonState)
sender = self.sender()
@@ -740,7 +727,6 @@ class MainWindow_precisely_align(QMainWindow):
PublicFunc.finish_operation(self, ButtonState)
def __slot_btn_correlation_align__(self):
-
PublicFunc.__disableAllButton__(self, ButtonState)
sender = self.sender()
@@ -783,7 +769,6 @@ class MainWindow_precisely_align(QMainWindow):
PublicFunc.finish_operation(self, ButtonState)
def __slot_btn_view_align__(self):
-
PublicFunc.__disableAllButton__(self, ButtonState)
# 数据后处理
@@ -812,7 +797,6 @@ class MainWindow_precisely_align(QMainWindow):
PublicFunc.finish_operation(self, ButtonState)
def __slot_btn_save__(self):
-
reply = QMessageBox.question(self, Constants.QUESTION_TITLE, Constants.QUESTION_CONTENT,
QMessageBox.Yes | QMessageBox.No,
QMessageBox.Yes)
@@ -944,7 +928,6 @@ class MainWindow_precisely_align(QMainWindow):
PublicFunc.finish_operation(self, ButtonState)
def __update_coordinate__(self):
-
try:
if self.data is not None:
if self.data.Jpeak is None or self.data.Rpeak is None:
@@ -1005,7 +988,6 @@ class MainWindow_precisely_align(QMainWindow):
pass
def reset_axes(self):
-
for ax in self.fig.axes:
self.fig.delaxes(ax)
if self.ax0 is not None:
@@ -1030,7 +1012,6 @@ class MainWindow_precisely_align(QMainWindow):
self.ax4.xaxis.set_major_formatter(ConfigParams.FORMATTER)
def redraw_calculate_coordination(self, plot_element=None):
-
if plot_element is not None and plot_element["mode"] == "select":
if self.selected_point0 is not None:
self.selected_point0.remove()
@@ -1065,7 +1046,7 @@ class MainWindow_precisely_align(QMainWindow):
label=Constants.PRECISELY_ALIGN_PLOT_LABEL_SELECTED_POINT)
self.stem_black0 = self.ax1.stem(arange(plot_element["front"]["shift"],
plot_element["front"]["shift"] + len(plot_element["front"]["JJIVs"])),
- plot_element["front"]["JJIVs"], markerfmt="ko",
+ plot_element["front"]["JJIVs"], markerfmt="ko", linefmt=Constants.PLOT_COLOR_GREEN,
label=Constants.PRECISELY_ALIGN_PLOT_LABEL_JJIV)
self.selected_point1, = self.ax2.plot(plot_element["back"]["shift"],
plot_element["back"]["corre"][plot_element["back"]["shift"]] + 1, 'v',
@@ -1073,7 +1054,7 @@ class MainWindow_precisely_align(QMainWindow):
label=Constants.PRECISELY_ALIGN_PLOT_LABEL_SELECTED_POINT)
self.stem_black1 = self.ax3.stem(arange(plot_element["back"]["shift"],
plot_element["back"]["shift"] + len(plot_element["back"]["JJIVs"])),
- plot_element["back"]["JJIVs"], markerfmt="ko",
+ plot_element["back"]["JJIVs"], markerfmt="ko", linefmt=Constants.PLOT_COLOR_GREEN,
label=Constants.PRECISELY_ALIGN_PLOT_LABEL_JJIV)
self.ax0.autoscale(False)
@@ -1090,7 +1071,6 @@ class MainWindow_precisely_align(QMainWindow):
return False, Constants.DRAWING_FAILURE
def redraw_correlation_align(self, plot_element=None):
-
if plot_element is not None and plot_element["mode"] == "select":
if self.selected_point0 is not None:
self.selected_point0.remove()
@@ -1129,7 +1109,6 @@ class MainWindow_precisely_align(QMainWindow):
return False, Constants.DRAWING_FAILURE
def toggle_home(self):
-
if self.ax0 is not None:
self.ax0.autoscale(True)
self.ax0.relim()
@@ -1164,7 +1143,6 @@ class MainWindow_precisely_align(QMainWindow):
PublicFunc.text_output(self.ui, Constants.LABEL_CHECK_RECOVER_SCALE, Constants.TIPS_TYPE_INFO)
def toggle_getRange(self, state):
-
if state:
self.deactivate_figToolbar_buttons()
self.figToolbar.action_Get_Range.setChecked(True)
@@ -1186,7 +1164,6 @@ class MainWindow_precisely_align(QMainWindow):
self.figToolbar.cid_mouse_hold = None
def deactivate_figToolbar_buttons(self):
-
for action in self.figToolbar._actions.values():
if action.isChecked() == True:
if action == self.figToolbar._actions['pan']:
@@ -1195,7 +1172,6 @@ class MainWindow_precisely_align(QMainWindow):
self.figToolbar.zoom()
def on_click(self, event):
-
if self.figToolbar.action_Get_Range.isChecked():
if event.button == 1:
self.is_left_button_pressed = True
@@ -1222,7 +1198,6 @@ class MainWindow_precisely_align(QMainWindow):
self.canvas.draw()
def on_release(self, event):
-
if self.figToolbar.action_Get_Range.isChecked():
if self.figToolbar.rect_start_x is not None:
self.figToolbar.rect_end_x = event.xdata
@@ -1321,7 +1296,6 @@ class MainWindow_precisely_align(QMainWindow):
self.canvas.draw()
def on_hold(self, event):
-
if event.button == 1:
if self.figToolbar.rect_start_x is not None and event.xdata is not None:
self.figToolbar.rect_end_x = event.xdata
@@ -1376,7 +1350,6 @@ class MainWindow_precisely_align(QMainWindow):
self.canvas.draw()
def on_pick(self, event):
-
this_line = event.artist
if this_line.axes == self.ax0:
xdata = this_line.get_xdata()
@@ -1412,20 +1385,6 @@ class MainWindow_precisely_align(QMainWindow):
class Data:
def __init__(self):
-
- self.file_path_input_orgBcg = Config["Path"]["Input_orgBcg"]
- self.file_path_input_BCG = Config["Path"]["Input_BCG"]
- self.file_path_input_Jpeak = Config["Path"]["Input_Jpeak"]
- self.file_path_input_ECG = Config["Path"]["Input_ECG"]
- self.file_path_input_Rpeak = Config["Path"]["Input_Rpeak"]
- self.file_path_save_BCG_AlignInfo = Config["Path"]["Save_BCG_AlignInfo"]
- self.file_path_save_ECG_AlignInfo = Config["Path"]["Save_ECG_AlignInfo"]
- self.file_path_save_orgBcg = Config["Path"]["Save_orgBcg"]
- self.file_path_save_BCG = Config["Path"]["Save_BCG"]
- self.file_path_save_ECG = Config["Path"]["Save_ECG"]
- self.file_path_save_Jpeak = Config["Path"]["Save_Jpeak"]
- self.file_path_save_Rpeak = Config["Path"]["Save_Rpeak"]
-
self.raw_orgBcg = None
self.raw_BCG = None
self.Jpeak = None
@@ -1461,7 +1420,6 @@ class Data:
self.argmax_ECG = None
def open_file(self):
-
if ((not Path(Config["Path"]["Input_BCG"]).exists())
or (not Path(Config["Path"]["Input_Jpeak"]).exists())
or (not Path(Config["Path"]["Input_ECG"]).exists())
@@ -1469,19 +1427,19 @@ class Data:
return False, Constants.INPUT_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Data_Path_Not_Exist"]
try:
- self.raw_orgBcg = read_csv(self.file_path_input_orgBcg,
+ self.raw_orgBcg = read_csv(Config["Path"]["Input_orgBcg"],
+ encoding=ConfigParams.UTF8_ENCODING,
+ header=None).to_numpy().reshape(-1)
+ self.raw_BCG = read_csv(Config["Path"]["Input_BCG"],
encoding=ConfigParams.UTF8_ENCODING,
header=None).to_numpy().reshape(-1)
- self.raw_BCG = read_csv(self.file_path_input_BCG,
- encoding=ConfigParams.UTF8_ENCODING,
- header=None).to_numpy().reshape(-1)
- self.Jpeak = read_csv(self.file_path_input_Jpeak,
+ self.Jpeak = read_csv(Config["Path"]["Input_Jpeak"],
encoding=ConfigParams.UTF8_ENCODING,
header=None).to_numpy().reshape(-1)
- self.raw_ECG = read_csv(self.file_path_input_ECG,
+ self.raw_ECG = read_csv(Config["Path"]["Input_ECG"],
encoding=ConfigParams.UTF8_ENCODING,
header=None).to_numpy().reshape(-1)
- self.Rpeak = read_csv(self.file_path_input_Rpeak,
+ self.Rpeak = read_csv(Config["Path"]["Input_Rpeak"],
encoding=ConfigParams.UTF8_ENCODING,
header=None).to_numpy().reshape(-1)
self.argmax_BCG = np_argmax(self.raw_BCG)
@@ -1492,7 +1450,6 @@ class Data:
return True, Constants.INPUT_FINISHED
def data_process_for_calculate_correlation(self):
-
result = {}
if self.Jpeak is None or self.Rpeak is None:
@@ -1511,7 +1468,6 @@ class Data:
return True, Constants.PRECISELY_ALIGN_PROCESS_FINISHED, result
def calculate_correlation_front(self, mode, shift_front=None):
-
result = {}
if ((Config["IV_Coordinate"]["BCG_front_1"] == Config["IV_Coordinate"]["BCG_front_2"])
@@ -1579,7 +1535,6 @@ class Data:
return True, Constants.PRECISELY_ALIGN_CALCULATE_FINISHED_FRONT, result
def calculate_correlation_back(self, mode, shift_back=None):
-
result = {}
if ((Config["IV_Coordinate"]["BCG_back_1"] == Config["IV_Coordinate"]["BCG_back_2"])
@@ -1647,7 +1602,6 @@ class Data:
return True, Constants.PRECISELY_ALIGN_CALCULATE_FINISHED_BACK, result
def correlation_align(self, mode):
-
result = {}
try:
@@ -1734,7 +1688,6 @@ class Data:
return True, Constants.PRECISELY_ALIGN_ALIGN_CORRELATION_FINISHED, result
def data_postprocess(self):
-
try:
if len(self.correlation_align_point_match_ECG) != 2 and len(self.correlation_align_point_match_BCG) != 2:
off = 0
@@ -1790,7 +1743,6 @@ class Data:
return True, f"{Constants.PRECISELY_ALIGN_POSTPROCESS_VIEW_FINISHED},BCG前后段被切割的坐标值为[{frontcut_index_BCG}, {backcut_index_BCG}],ECG前后段被切割的坐标值为[{frontcut_index_ECG}, {backcut_index_ECG}]"
def save_alignInfo(self):
-
try:
save_data = {
"front": {
@@ -1823,69 +1775,63 @@ class Data:
}
}
save_data = [str(save_data)]
- DataFrame(save_data).to_csv(self.file_path_save_BCG_AlignInfo, index=False, header=False)
- DataFrame(save_data).to_csv(self.file_path_save_ECG_AlignInfo, index=False, header=False)
- except Exception as e:
- print(e)
+ DataFrame(save_data).to_csv(Config["Path"]["Save_BCG_AlignInfo"], index=False, header=False)
+ DataFrame(save_data).to_csv(Config["Path"]["Save_ECG_AlignInfo"], index=False, header=False)
+ except Exception:
return False, Constants.PRECISELY_ALIGN_SAVING_ALIGNINFO_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"]
return True, Constants.PRECISELY_ALIGN_SAVING_ALIGNINFO_FINISHED
def save_res_orgBcg(self, chunk):
-
if self.res_orgBcg is None:
return False, Constants.PRECISELY_ALIGN_SAVING_RES_ORGBCG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["res_orgBcg_Not_Exist"]
try:
- chunk.to_csv(self.file_path_save_orgBcg, mode='a', index=False, header=False)
+ chunk.to_csv(Config["Path"]["Save_orgBcg"], mode='a', index=False, header=False)
except Exception:
return False, Constants.PRECISELY_ALIGN_SAVING_RES_ORGBCG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"]
return True, Constants.PRECISELY_ALIGN_SAVING_RES_ORGBCG_FINISHED
def save_res_BCG(self, chunk):
-
if self.res_BCG is None:
return False, Constants.PRECISELY_ALIGN_SAVING_RES_BCG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["res_BCG_Not_Exist"]
try:
- chunk.to_csv(self.file_path_save_BCG, mode='a', index=False, header=False)
+ chunk.to_csv(Config["Path"]["Save_BCG"], mode='a', index=False, header=False)
except Exception:
return False, Constants.PRECISELY_ALIGN_SAVING_RES_BCG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"]
return True, Constants.PRECISELY_ALIGN_SAVING_RES_BCG_FINISHED
def save_cut_ECG(self, chunk):
-
if self.cut_ECG is None:
return False, Constants.PRECISELY_ALIGN_SAVING_CUT_ECG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["cut_ECG_Not_Exist"]
try:
- chunk.to_csv(self.file_path_save_ECG, mode='a', index=False, header=False)
+ chunk.to_csv(Config["Path"]["Save_ECG"], mode='a', index=False, header=False)
except Exception:
return False, Constants.PRECISELY_ALIGN_SAVING_CUT_ECG_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"]
return True, Constants.PRECISELY_ALIGN_SAVING_CUT_ECG_FINISHED
def save_Jpeak(self, chunk):
-
if self.cut_Jpeak is None:
return False, Constants.PRECISELY_ALIGN_SAVING_CUT_JPEAK_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["cut_Jpeak_Not_Exist"]
try:
- chunk.to_csv(self.file_path_save_Jpeak, mode='a', index=False, header=False)
+ chunk.to_csv(Config["Path"]["Save_Jpeak"], mode='a', index=False, header=False)
except Exception:
return False, Constants.PRECISELY_ALIGN_SAVING_CUT_JPEAK_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"]
return True, Constants.PRECISELY_ALIGN_SAVING_CUT_JPEAK_FINISHED
def save_Rpeak(self, chunk):
-
if self.cut_Rpeak is None:
return False, Constants.PRECISELY_ALIGN_SAVING_CUT_RPEAK_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["cut_Rpeak_Not_Exist"]
try:
- chunk.to_csv(self.file_path_save_Rpeak, mode='a', index=False, header=False)
+ chunk.to_csv(Config["Path"]["Save_Rpeak"], mode='a', index=False, header=False)
except Exception:
return False, Constants.PRECISELY_ALIGN_SAVING_CUT_RPEAK_FAILURE + Constants.PRECISELY_ALIGN_FAILURE_REASON["Save_Exception"]
@@ -1926,21 +1872,17 @@ class CustomNavigationToolbar(NavigationToolbar2QT):
self.ax1_ECG_rectangle_back = None
def home(self, *args):
-
pass
def zoom(self, *args):
-
super().zoom(*args)
self.deactivate_figToorbar_getRange_mode()
def pan(self, *args):
-
super().pan(*args)
self.deactivate_figToorbar_getRange_mode()
def deactivate_figToorbar_getRange_mode(self):
-
if self.action_Get_Range.isChecked():
self.action_Get_Range.setChecked(False)
if self.cid_mouse_press is not None:
diff --git a/func/Module_preprocess.py b/func/Module_preprocess.py
index e0b8b84..690818f 100644
--- a/func/Module_preprocess.py
+++ b/func/Module_preprocess.py
@@ -42,7 +42,6 @@ ButtonState = {
class SettingWindow(QMainWindow):
def __init__(self, mode, root_path, sampID):
-
super(SettingWindow, self).__init__()
self.ui = Ui_MainWindow_preprocess_input_setting()
self.ui.setupUi(self)
@@ -61,7 +60,6 @@ class SettingWindow(QMainWindow):
self.ui.pushButton_cancel.clicked.connect(self.close)
def __read_config__(self):
-
if not Path(ConfigParams.PREPROCESS_CONFIG_FILE_PATH).exists():
with open(ConfigParams.PREPROCESS_CONFIG_FILE_PATH, "w") as f:
dump(ConfigParams.PREPROCESS_CONFIG_NEW_CONTENT, f)
@@ -109,7 +107,6 @@ class SettingWindow(QMainWindow):
self.ui.plainTextEdit_file_path_save.setPlainText(Config["Path"]["Save"])
def __write_config__(self):
-
# 从界面写入配置
Config["InputConfig"]["Freq"] = self.ui.spinBox_input_freq.value()
Config["OutputConfig"]["Freq"] = self.ui.spinBox_output_freq.value()
@@ -126,11 +123,9 @@ class SettingWindow(QMainWindow):
self.close()
def __rollback_config__(self):
-
self.__read_config__()
def __update_ui__(self):
-
if self.mode == "BCG":
self.ui.plainTextEdit_file_path_input.setPlainText(
str((Path(self.root_path) /
@@ -168,7 +163,6 @@ class SettingWindow(QMainWindow):
class MainWindow_preprocess(QMainWindow):
def __init__(self):
-
super(MainWindow_preprocess, self).__init__()
self.ui = Ui_MainWindow_preprocess()
self.ui.setupUi(self)
@@ -197,7 +191,6 @@ class MainWindow_preprocess(QMainWindow):
@overrides
def show(self, mode, root_path, sampID):
-
super().show()
self.mode = mode
self.root_path = root_path
@@ -244,7 +237,6 @@ class MainWindow_preprocess(QMainWindow):
@overrides
def closeEvent(self, event):
-
PublicFunc.__disableAllButton__(self, ButtonState)
PublicFunc.statusbar_show_msg(self, PublicFunc.format_status_msg(Constants.SHUTTING_DOWN))
@@ -264,12 +256,10 @@ class MainWindow_preprocess(QMainWindow):
@staticmethod
def __reset__():
-
ButtonState["Current"].update(ButtonState["Default"].copy())
ButtonState["Current"]["pushButton_view"] = True
def __plot__(self):
-
# 清空画框
self.reset_axes()
@@ -293,7 +283,6 @@ class MainWindow_preprocess(QMainWindow):
return status, info
def __update_config__(self):
-
if self.mode == "BCG":
Config["Filter"]["BCGBandPassOrder"] = self.ui.spinBox_bandPassOrder.value()
Config["Filter"]["BCGBandPassLow"] = self.ui.doubleSpinBox_bandPassLow.value()
@@ -306,7 +295,6 @@ class MainWindow_preprocess(QMainWindow):
raise ValueError("模式不存在")
def __slot_btn_input__(self):
-
PublicFunc.__disableAllButton__(self, ButtonState)
# 清空画框
@@ -331,7 +319,6 @@ class MainWindow_preprocess(QMainWindow):
PublicFunc.finish_operation(self, ButtonState)
def __slot_btn_view__(self):
-
PublicFunc.__disableAllButton__(self, ButtonState)
# 数据预处理
@@ -360,7 +347,6 @@ class MainWindow_preprocess(QMainWindow):
PublicFunc.finish_operation(self, ButtonState)
def __slot_btn_save__(self):
-
reply = QMessageBox.question(self, Constants.QUESTION_TITLE,
Constants.QUESTION_CONTENT + Config["Path"]["Save"],
QMessageBox.Yes | QMessageBox.No,
@@ -394,7 +380,6 @@ class MainWindow_preprocess(QMainWindow):
PublicFunc.finish_operation(self, ButtonState)
def reset_axes(self):
-
self.ax0.clear()
self.ax0.grid(True)
self.ax0.xaxis.set_major_formatter(ConfigParams.FORMATTER)
@@ -403,20 +388,15 @@ class MainWindow_preprocess(QMainWindow):
class Data:
def __init__(self):
-
- self.file_path_input = Config["Path"]["Input"]
- self.file_path_save = Config["Path"]["Save"]
-
self.raw_data = None
self.processed_data = None
def open_file(self):
-
if not Path(Config["Path"]["Input"]).exists():
return False, Constants.INPUT_FAILURE + Constants.PREPROCESS_FAILURE_REASON["Data_Path_Not_Exist"]
try:
- self.raw_data = read_csv(self.file_path_input,
+ self.raw_data = read_csv(Config["Path"]["Input"],
encoding=ConfigParams.UTF8_ENCODING,
header=None).to_numpy().reshape(-1)
except Exception:
@@ -425,7 +405,6 @@ class Data:
return True, Constants.INPUT_FINISHED
def preprocess(self):
-
if self.raw_data is None:
return False, Constants.PREPROCESS_PROCESS_FAILURE + Constants.PREPROCESS_FAILURE_REASON["Raw_Data_Not_Exist"]
@@ -454,12 +433,11 @@ class Data:
return True, Constants.PREPROCESS_PROCESS_FINISHED
def save(self, chunk):
-
if self.processed_data is None:
return False, Constants.SAVING_FAILURE + Constants.PREPROCESS_FAILURE_REASON["Processed_Data_Not_Exist"]
try:
- chunk.to_csv(self.file_path_save, mode='a', index=False, header=False, float_format='%.4f')
+ chunk.to_csv(Config["Path"]["Save"], mode='a', index=False, header=False, float_format='%.4f')
except Exception:
return False, Constants.SAVING_FAILURE + Constants.PREPROCESS_FAILURE_REASON["Save_Exception"]
diff --git a/func/utils/ConfigParams.py b/func/utils/ConfigParams.py
index 9c94d2e..8513331 100644
--- a/func/utils/ConfigParams.py
+++ b/func/utils/ConfigParams.py
@@ -33,7 +33,7 @@ class ConfigParams:
# 预处理
PREPROCESS_CONFIG_FILE_PATH: str = "./config/Config_preprocess.yaml"
- PREPROCESS_CONFIG_NEW_CONTENT = {
+ PREPROCESS_CONFIG_NEW_CONTENT: dict = {
"InputConfig": {
"Freq": 1000
},
@@ -57,7 +57,7 @@ class ConfigParams:
# BCG的J峰算法定位
DETECT_JPEAK_CONFIG_FILE_PATH: str = "./config/Config_detect_Jpeak.yaml"
- DETECT_JPEAK_CONFIG_NEW_CONTENT = {
+ DETECT_JPEAK_CONFIG_NEW_CONTENT: dict = {
"InputConfig": {
"Freq": 1000
},
@@ -79,7 +79,7 @@ class ConfigParams:
# ECG的R峰算法定位
DETECT_RPEAK_CONFIG_FILE_PATH: str = "./config/Config_detect_Rpeak.yaml"
- DETECT_RPEAK_CONFIG_NEW_CONTENT = {
+ DETECT_RPEAK_CONFIG_NEW_CONTENT: dict = {
"InputConfig": {
"Freq": 1000
},
@@ -96,7 +96,7 @@ class ConfigParams:
# 人工纠正
LABEL_CHECK_CONFIG_FILE_PATH: str = "./config/Config_label_check.yaml"
- LABEL_CHECK_CONFIG_NEW_CONTENT = {
+ LABEL_CHECK_CONFIG_NEW_CONTENT: dict = {
"InputConfig": {
"Freq": 1000
},
@@ -130,7 +130,7 @@ class ConfigParams:
# 数据精同步
PRECISELY_ALIGN_CONFIG_FILE_PATH: str = "./config/Config_precisely_align.yaml"
- PRECISELY_ALIGN_CONFIG_NEW_CONTENT = {
+ PRECISELY_ALIGN_CONFIG_NEW_CONTENT: dict = {
"InputConfig": {
"ECGFreq": 1000
}
@@ -152,10 +152,46 @@ class ConfigParams:
PRECISELY_ALIGN_SAVE_PEAK_CHUNK_SIZE: int = 100
# 冗余数据切割和标签映射
+ CUT_PSG_CONFIG_FILE_PATH: str = "./config/Config_cut_PSG.yaml"
+ CUT_PSG_CONFIG_NEW_CONTENT: dict = {
+ "ECGFreq": 1000,
+ "ChannelInput": {
+ "Effort Tho": "Effort Tho_Raw_",
+ "Effort Abd": "Effort Abd_Raw_",
+ "Flow Patient": "Flow Patient_Raw_",
+ "Snore": "Snore_Raw_",
+ "SpO2": "SpO2_Raw_",
+ "5_class": "5_class_Raw_"
+ },
+ "LabelInput": {
+ "SA Label": "SA Label_Raw"
+ },
+ "StartTime": "StartTime_Raw",
+ "ChannelSave": {
+ "Effort Tho": "Effort Tho_Sync_",
+ "Effort Abd": "Effort Abd_Sync_",
+ "Flow Patient": "Flow Patient_Sync_",
+ "Snore": "Snore_Sync_",
+ "SpO2": "SpO2_Sync_",
+ "5_class": "5_class_Sync_"
+ },
+ "LabelSave": {
+ "SA Label": "SA Label_Sync"
+ },
+ "EndWith": {
+ "Effort Tho": ENDSWITH_TXT,
+ "Effort Abd": ENDSWITH_TXT,
+ "Flow Patient": ENDSWITH_TXT,
+ "Snore": ENDSWITH_TXT,
+ "SpO2": ENDSWITH_TXT,
+ "5_class": ENDSWITH_TXT,
+ "SA Label": ENDSWITH_CSV,
+ "StartTime": ENDSWITH_TXT
+ },
+ }
+ CUT_PSG_SAVE_ECG_ALIGNINFO_FILENAME: str = "Align_info"
+ CUT_PSG_SALABEL_EVENT: list = ["Hypopnea", "Central apnea", "Obstructive apnea", "Mixed apnea"]
- CUT_PSG_CHANNEL_LIST: list = ["Effort Abd_Raw_", "Effort Tho_Raw_", "Flow Patient_Raw_", "Snore_Raw_", "SpO2_Raw_"]
- CUT_PST_LABEL_LIST: list = ["5_class_Raw_", "SA Label_Raw"]
- CUT_PST_STARTTIME: list = ["StartTime_Raw"]
# 体动标注
diff --git a/func/utils/Constants.py b/func/utils/Constants.py
index 435c123..4fbc214 100644
--- a/func/utils/Constants.py
+++ b/func/utils/Constants.py
@@ -269,6 +269,32 @@ class Constants:
PRECISELY_ALIGN_NO_POINT_IN_THE_INTERVAL: str = "所选区间内无有效点"
PRECISELY_ALIGN_ACTION_GET_RANGE_NAME: str = f"设置范围({ConfigParams.PRECISELY_ALIGN_ACTION_GET_RANGE_SHORTCUT_KEY})"
+ # 冗余数据切割和标签映射
+ CUT_PSG_GETTING_FILE_AND_FREQ: str = "正在获取文件及其采样率"
+ CUT_PSG_GET_FILE_AND_FREQ_FINISHED: str = "获取文件及其采样率完成"
+ CUT_PSG_GET_FILE_AND_FREQ_FAILURE: str = "获取文件及其采样率失败"
+
+ CUT_PSG_CUTTING_DATA: str = "正在切割数据"
+ CUT_PSG_CUT_DATA_FINISHED: str = "切割数据完成"
+ CUT_PSG_CUT_DATA_FAILURE: str = "切割数据失败"
+
+ CUT_PSG_ALIGNING_LABEL: str = "正在映射标签"
+ CUT_PSG_ALIGN_LABEL_FINISHED: str = "映射标签完成"
+ CUT_PSG_ALIGN_LABEL_FAILURE: str = "映射标签失败"
+
+ CUT_PSG_FAILURE_REASON: str = {
+ "Filename_Format_not_Correct": "(文件名格式不正确)",
+ "File_not_Exist": "(需要处理的文件不存在)",
+ "Get_File_and_Freq_Excepetion": "(检查文件是否存在并获取其数据采样率异常)",
+ "Read_Data_Exception": "(读取数据异常)",
+ "Cut_Data_Length_not_Correct": "(切割数据时长度不正确)",
+ "Cut_Data_Exception": "(切割数据异常)",
+ "Align_Label_SALabel_Format_not_Correct": "(映射标签时SA Label中的文件格式不正确)",
+ "Align_Label_Exception": "(映射标签异常)",
+ "Save_Data_not_Exist": "(需要保存的数据不存在)",
+ "Save_Exception": "(保存异常)"
+ }
+
# 体动标注
# TODO:弃用
diff --git a/func/utils/PublicFunc.py b/func/utils/PublicFunc.py
index 651ab43..4bc75f5 100644
--- a/func/utils/PublicFunc.py
+++ b/func/utils/PublicFunc.py
@@ -130,7 +130,6 @@ class PublicFunc:
@staticmethod
def add_progressbar(mainWindow):
-
mainWindow.progressbar = QProgressBar()
mainWindow.progressbar.setRange(0, 100)
mainWindow.progressbar.setValue(0)
@@ -139,17 +138,14 @@ class PublicFunc:
@staticmethod
def statusbar_show_msg(mainWindow, msg):
-
mainWindow.ui.statusbar.showMessage(msg)
@staticmethod
def statusbar_clear_msg(mainWindow):
-
mainWindow.ui.statusbar.clearMessage()
@staticmethod
def finish_operation(mainWindow, buttonState):
-
PublicFunc.statusbar_show_msg(mainWindow, PublicFunc.format_status_msg(Constants.OPERATION_FINISHED))
mainWindow.progressbar.setValue(100)
QApplication.processEvents()
@@ -158,7 +154,6 @@ class PublicFunc:
@staticmethod
def progressbar_update(mainWindow, current: int, total: int, msg: str, progressbarState: int):
-
if current > total:
raise ValueError("当前进度值大于总进度值")
if progressbarState < 0 or progressbarState > 100:
diff --git a/ui/MainWindow/MainWindow_cut_PSG.py b/ui/MainWindow/MainWindow_cut_PSG.py
index bfca523..a093573 100644
--- a/ui/MainWindow/MainWindow_cut_PSG.py
+++ b/ui/MainWindow/MainWindow_cut_PSG.py
@@ -18,8 +18,8 @@ from PySide6.QtGui import (QAction, QBrush, QColor, QConicalGradient,
QTransform)
from PySide6.QtWidgets import (QApplication, QGridLayout, QGroupBox, QHBoxLayout,
QLabel, QMainWindow, QPlainTextEdit, QProgressBar,
- QPushButton, QSizePolicy, QSpacerItem, QStatusBar,
- QTextBrowser, QVBoxLayout, QWidget)
+ QPushButton, QSizePolicy, QSpacerItem, QSpinBox,
+ QStatusBar, QTextBrowser, QVBoxLayout, QWidget)
class Ui_MainWindow_cut_PSG(object):
def setupUi(self, MainWindow_cut_PSG):
@@ -82,6 +82,7 @@ class Ui_MainWindow_cut_PSG(object):
self.plainTextEdit_channel = QPlainTextEdit(self.groupBox_2)
self.plainTextEdit_channel.setObjectName(u"plainTextEdit_channel")
+ self.plainTextEdit_channel.setEnabled(False)
self.horizontalLayout.addWidget(self.plainTextEdit_channel)
@@ -100,6 +101,7 @@ class Ui_MainWindow_cut_PSG(object):
self.plainTextEdit_label = QPlainTextEdit(self.groupBox_2)
self.plainTextEdit_label.setObjectName(u"plainTextEdit_label")
+ self.plainTextEdit_label.setEnabled(False)
self.horizontalLayout_6.addWidget(self.plainTextEdit_label)
@@ -108,6 +110,27 @@ class Ui_MainWindow_cut_PSG(object):
self.verticalLayout_5.addLayout(self.horizontalLayout_6)
+ self.horizontalLayout_7 = QHBoxLayout()
+ self.horizontalLayout_7.setObjectName(u"horizontalLayout_7")
+ self.label_7 = QLabel(self.groupBox_2)
+ self.label_7.setObjectName(u"label_7")
+ self.label_7.setFont(font)
+
+ self.horizontalLayout_7.addWidget(self.label_7)
+
+ self.spinBox_ECGFreq = QSpinBox(self.groupBox_2)
+ self.spinBox_ECGFreq.setObjectName(u"spinBox_ECGFreq")
+ self.spinBox_ECGFreq.setFont(font)
+ self.spinBox_ECGFreq.setMinimum(1)
+ self.spinBox_ECGFreq.setMaximum(1000000)
+
+ self.horizontalLayout_7.addWidget(self.spinBox_ECGFreq)
+
+ self.horizontalLayout_7.setStretch(0, 1)
+ self.horizontalLayout_7.setStretch(1, 1)
+
+ self.verticalLayout_5.addLayout(self.horizontalLayout_7)
+
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
self.verticalLayout_5.addItem(self.verticalSpacer)
@@ -124,23 +147,24 @@ class Ui_MainWindow_cut_PSG(object):
self.verticalLayout_5.addLayout(self.horizontalLayout_2)
- self.progressBar = QProgressBar(self.groupBox_2)
- self.progressBar.setObjectName(u"progressBar")
+ self.progressbar = QProgressBar(self.groupBox_2)
+ self.progressbar.setObjectName(u"progressbar")
sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
sizePolicy1.setHorizontalStretch(0)
sizePolicy1.setVerticalStretch(0)
- sizePolicy1.setHeightForWidth(self.progressBar.sizePolicy().hasHeightForWidth())
- self.progressBar.setSizePolicy(sizePolicy1)
- self.progressBar.setStyleSheet(u"")
- self.progressBar.setValue(0)
+ sizePolicy1.setHeightForWidth(self.progressbar.sizePolicy().hasHeightForWidth())
+ self.progressbar.setSizePolicy(sizePolicy1)
+ self.progressbar.setStyleSheet(u"")
+ self.progressbar.setValue(0)
- self.verticalLayout_5.addWidget(self.progressBar)
+ self.verticalLayout_5.addWidget(self.progressbar)
self.verticalLayout_5.setStretch(0, 2)
self.verticalLayout_5.setStretch(1, 2)
- self.verticalLayout_5.setStretch(2, 2)
- self.verticalLayout_5.setStretch(3, 1)
+ self.verticalLayout_5.setStretch(2, 1)
+ self.verticalLayout_5.setStretch(3, 2)
self.verticalLayout_5.setStretch(4, 1)
+ self.verticalLayout_5.setStretch(5, 1)
self.gridLayout_2.addWidget(self.groupBox_2, 0, 0, 1, 2)
@@ -182,6 +206,7 @@ class Ui_MainWindow_cut_PSG(object):
self.groupBox_2.setTitle(QCoreApplication.translate("MainWindow_cut_PSG", u"\u786e\u5b9a\u6570\u636e", None))
self.label_2.setText(QCoreApplication.translate("MainWindow_cut_PSG", u"\u9700\u8981\u5207\u5272\u7684\u901a\u9053\u540d\uff1a", None))
self.label_6.setText(QCoreApplication.translate("MainWindow_cut_PSG", u"\u9700\u8981\u6620\u5c04\u7684\u6807\u7b7e\uff1a", None))
+ self.label_7.setText(QCoreApplication.translate("MainWindow_cut_PSG", u"\u6570\u636e\u7cbe\u540c\u6b65\u65f6ECG\u7684\u91c7\u6837\u7387\uff1a", None))
self.label_show.setText(QCoreApplication.translate("MainWindow_cut_PSG", u"\u70b9\u51fb\u6267\u884c\u4ee5\u5f00\u59cb...", None))
self.pushButton_execute.setText(QCoreApplication.translate("MainWindow_cut_PSG", u"\u6267\u884c", None))
# retranslateUi
diff --git a/ui/MainWindow/MainWindow_cut_PSG.ui b/ui/MainWindow/MainWindow_cut_PSG.ui
index ae28df2..00f2dc2 100644
--- a/ui/MainWindow/MainWindow_cut_PSG.ui
+++ b/ui/MainWindow/MainWindow_cut_PSG.ui
@@ -57,7 +57,7 @@
确定数据
-
+
-
-
@@ -76,7 +76,11 @@
-
-
+
+
+ false
+
+
@@ -95,7 +99,42 @@
-
-
+
+
+ false
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 12
+
+
+
+ 数据精同步时ECG的采样率:
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ 1
+
+
+ 1000000
+
+
@@ -132,7 +171,7 @@
-
-
+
0
diff --git a/ui/MainWindow/MainWindow_menu.py b/ui/MainWindow/MainWindow_menu.py
index 6470880..eefa04f 100644
--- a/ui/MainWindow/MainWindow_menu.py
+++ b/ui/MainWindow/MainWindow_menu.py
@@ -151,13 +151,28 @@ class Ui_Signal_Label(object):
self.verticalLayout.addLayout(self.horizontalLayout_6)
+ self.horizontalLayout_4 = QHBoxLayout()
+ self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
self.pushButton_precisely_align = QPushButton(self.centralwidget)
self.pushButton_precisely_align.setObjectName(u"pushButton_precisely_align")
sizePolicy.setHeightForWidth(self.pushButton_precisely_align.sizePolicy().hasHeightForWidth())
self.pushButton_precisely_align.setSizePolicy(sizePolicy)
self.pushButton_precisely_align.setFont(font)
- self.verticalLayout.addWidget(self.pushButton_precisely_align)
+ self.horizontalLayout_4.addWidget(self.pushButton_precisely_align)
+
+ self.pushButton_cut_PSG = QPushButton(self.centralwidget)
+ self.pushButton_cut_PSG.setObjectName(u"pushButton_cut_PSG")
+ sizePolicy.setHeightForWidth(self.pushButton_cut_PSG.sizePolicy().hasHeightForWidth())
+ self.pushButton_cut_PSG.setSizePolicy(sizePolicy)
+ self.pushButton_cut_PSG.setFont(font)
+
+ self.horizontalLayout_4.addWidget(self.pushButton_cut_PSG)
+
+ self.horizontalLayout_4.setStretch(0, 3)
+ self.horizontalLayout_4.setStretch(1, 1)
+
+ self.verticalLayout.addLayout(self.horizontalLayout_4)
self.pushButton_artifact_label = QPushButton(self.centralwidget)
self.pushButton_artifact_label.setObjectName(u"pushButton_artifact_label")
@@ -226,6 +241,7 @@ class Ui_Signal_Label(object):
self.pushButton_label_check_BCG.setText(QCoreApplication.translate("Signal_Label", u"BCG\u7684J\u5cf0\u4eba\u5de5\u7ea0\u6b63", None))
self.pushButton_label_check_ECG.setText(QCoreApplication.translate("Signal_Label", u"ECG\u7684R\u5cf0\u4eba\u5de5\u7ea0\u6b63", None))
self.pushButton_precisely_align.setText(QCoreApplication.translate("Signal_Label", u"\u6570\u636e\u7cbe\u540c\u6b65", None))
+ self.pushButton_cut_PSG.setText(QCoreApplication.translate("Signal_Label", u"\u5197\u4f59\u6570\u636e\u5207\u5272\u548c\u6807\u7b7e\u6620\u5c04", None))
self.pushButton_artifact_label.setText(QCoreApplication.translate("Signal_Label", u"\u4f53\u52a8\u6807\u6ce8", None))
self.pushButton_bcg_quality_label.setText(QCoreApplication.translate("Signal_Label", u"BCG\u7684\u8d28\u91cf\u6807\u6ce8", None))
self.pushButton_resp_quality_label.setText(QCoreApplication.translate("Signal_Label", u"\u547c\u5438\u53ef\u7528\u6027\u53ca\u95f4\u671f\u6807\u6ce8", None))
diff --git a/ui/MainWindow/MainWindow_menu.ui b/ui/MainWindow/MainWindow_menu.ui
index caad66b..0ce6795 100644
--- a/ui/MainWindow/MainWindow_menu.ui
+++ b/ui/MainWindow/MainWindow_menu.ui
@@ -223,22 +223,44 @@
-
-
-
-
- 0
- 0
-
-
-
-
- 14
-
-
-
- 数据精同步
-
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 14
+
+
+
+ 数据精同步
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 14
+
+
+
+ 冗余数据切割和标签映射
+
+
+
+
-
diff --git a/数据结构化输入和输出命名规范.md b/数据结构化输入和输出命名规范.md
index b9f5c09..145ee7d 100644
--- a/数据结构化输入和输出命名规范.md
+++ b/数据结构化输入和输出命名规范.md
@@ -16,7 +16,7 @@
|-SA Label_corrected.csv
|-SA Label_add.csv`
.../OrgBCG_Aligned/
- |-Align_info.txt
+ |-Align_info.yaml
|-BCG_Sync_采样率.txt
|-orgBcg_Sync_采样率.txt
|-Jpeak_Sync.txt
@@ -28,7 +28,7 @@
.../OrgBCG_Origin/
|-...
.../PSG_Aligned/
- |-Align_info.txt
+ |-Align_info.yaml
|-ECG_Sync_采样率.txt
|-Rpeak_Sync.txt
|-5_class_Sync_1.txt
@@ -168,13 +168,13 @@
输出:
-PSG的对齐信息:`./PSG_Aligned//Align_info.txt`
+PSG的对齐信息:`./PSG_Aligned//Align_info.yaml`
同步后的ECG信号:`./PSG_Aligned//ECG_Sync_采样率.txt`
同步后的R峰坐标:`./PSG_Aligned//Rpeak_Sync.txt`
-BCG的对齐信息:`./OrgBCG_Aligned//Align_info.txt`
+BCG的对齐信息:`./OrgBCG_Aligned//Align_info.yaml`
同步后的BCG信号:`./OrgBCG_Aligned//BCG_Sync_采样率.txt`
@@ -188,9 +188,9 @@ BCG的对齐信息:`./OrgBCG_Aligned//Align_info.txt`
输入:
-PSG的对齐信息:`./PSG_Aligned//Align_info.txt`
+PSG的对齐信息:`./PSG_Aligned//Align_info.yaml`
-BCG的对齐信息:`./OrgBCG_Aligned//Align_info.txt`
+BCG的对齐信息:`./OrgBCG_Aligned//Align_info.yaml`
原始的其他PSG通道信号:`./PSG_Text//通道名_Raw_采样率.txt`(通道名包括:Effort Abd, Effort Tho, Flow Patient, Snore, SpO2)