1、完善命名规范

2、完成<冗余数据切割和标签映射>的全部代码
This commit is contained in:
2025-05-09 17:21:55 +08:00
parent 9dd7689756
commit aad3dfba49
15 changed files with 567 additions and 272 deletions

307
func/Module_cut_PSG.py Normal file
View File

@ -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

View File

@ -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"]

View File

@ -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"]

View File

@ -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:

View File

@ -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

View File

@ -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:

View File

@ -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"]

View File

@ -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"]
# 体动标注

View File

@ -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弃用

View File

@ -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:

View File

@ -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

View File

@ -57,7 +57,7 @@
<property name="title">
<string>确定数据</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5" stretch="2,2,2,1,1">
<layout class="QVBoxLayout" name="verticalLayout_5" stretch="2,2,1,2,1,1">
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1">
<item>
@ -76,7 +76,11 @@
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="plainTextEdit_channel"/>
<widget class="QPlainTextEdit" name="plainTextEdit_channel">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
@ -95,7 +99,42 @@
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="plainTextEdit_label"/>
<widget class="QPlainTextEdit" name="plainTextEdit_label">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7" stretch="1,1">
<item>
<widget class="QLabel" name="label_7">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>数据精同步时ECG的采样率</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_ECGFreq">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000000</number>
</property>
</widget>
</item>
</layout>
</item>
@ -132,7 +171,7 @@
</layout>
</item>
<item>
<widget class="QProgressBar" name="progressBar">
<widget class="QProgressBar" name="progressbar">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>

View File

@ -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))

View File

@ -223,22 +223,44 @@
</layout>
</item>
<item>
<widget class="QPushButton" name="pushButton_precisely_align">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>数据精同步</string>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_4" stretch="3,1">
<item>
<widget class="QPushButton" name="pushButton_precisely_align">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>数据精同步</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_cut_PSG">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>冗余数据切割和标签映射</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="pushButton_artifact_label">

View File

@ -16,7 +16,7 @@
|-SA Label_corrected.csv
|-SA Label_add.csv`
.../OrgBCG_Aligned/<sampID>
|-Align_info.txt
|-Align_info.yaml
|-BCG_Sync_采样率.txt
|-orgBcg_Sync_采样率.txt
|-Jpeak_Sync.txt
@ -28,7 +28,7 @@
.../OrgBCG_Origin/<sampID>
|-...
.../PSG_Aligned/<sampID>
|-Align_info.txt
|-Align_info.yaml
|-ECG_Sync_采样率.txt
|-Rpeak_Sync.txt
|-5_class_Sync_1.txt
@ -168,13 +168,13 @@
输出:
PSG的对齐信息`./PSG_Aligned/<sampID>/Align_info.txt`
PSG的对齐信息`./PSG_Aligned/<sampID>/Align_info.yaml`
同步后的ECG信号`./PSG_Aligned/<sampID>/ECG_Sync_采样率.txt`
同步后的R峰坐标`./PSG_Aligned/<sampID>/Rpeak_Sync.txt`
BCG的对齐信息`./OrgBCG_Aligned/<sampID>/Align_info.txt`
BCG的对齐信息`./OrgBCG_Aligned/<sampID>/Align_info.yaml`
同步后的BCG信号`./OrgBCG_Aligned/<sampID>/BCG_Sync_采样率.txt`
@ -188,9 +188,9 @@ BCG的对齐信息`./OrgBCG_Aligned/<sampID>/Align_info.txt`
输入:
PSG的对齐信息`./PSG_Aligned/<sampID>/Align_info.txt`
PSG的对齐信息`./PSG_Aligned/<sampID>/Align_info.yaml`
BCG的对齐信息`./OrgBCG_Aligned/<sampID>/Align_info.txt`
BCG的对齐信息`./OrgBCG_Aligned/<sampID>/Align_info.yaml`
原始的其他PSG通道信号`./PSG_Text/<sampID>/通道名_Raw_采样率.txt`通道名包括Effort Abd, Effort Tho, Flow Patient, Snore, SpO2