1、完善命名规范
2、完成<冗余数据切割和标签映射>的全部代码
This commit is contained in:
307
func/Module_cut_PSG.py
Normal file
307
func/Module_cut_PSG.py
Normal 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
|
||||
@ -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,22 +381,17 @@ 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,
|
||||
self.raw_data = read_csv(Config["Path"]["Input"],
|
||||
encoding=ConfigParams.UTF8_ENCODING,
|
||||
header=None).to_numpy().reshape(-1)
|
||||
except Exception:
|
||||
@ -420,7 +400,6 @@ class Data:
|
||||
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"]
|
||||
|
||||
|
||||
@ -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,12 +390,11 @@ 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,
|
||||
self.raw_data = read_csv(Config["Path"]["Input"],
|
||||
encoding=ConfigParams.UTF8_ENCODING,
|
||||
header=None).to_numpy().reshape(-1)
|
||||
except Exception:
|
||||
@ -423,7 +403,6 @@ class Data:
|
||||
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"]
|
||||
|
||||
|
||||
@ -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,
|
||||
self.raw_data = read_csv(Config["Path"]["Input_Signal"],
|
||||
encoding=ConfigParams.UTF8_ENCODING,
|
||||
header=None).to_numpy().reshape(-1)
|
||||
self.original_peak = read_csv(self.file_path_input_peak,
|
||||
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,
|
||||
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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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(self.file_path_input_BCG,
|
||||
self.raw_BCG = read_csv(Config["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:
|
||||
|
||||
@ -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"]
|
||||
|
||||
|
||||
@ -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"]
|
||||
|
||||
# 体动标注
|
||||
|
||||
|
||||
@ -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:弃用
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -222,6 +222,8 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4" stretch="3,1">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_precisely_align">
|
||||
<property name="sizePolicy">
|
||||
@ -240,6 +242,26 @@
|
||||
</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">
|
||||
<property name="sizePolicy">
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user