ecg_label_check/ecg_label_check.py
2025-02-21 20:41:11 +08:00

1030 lines
54 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
@author:Yosa
@file:ecg_label_check.py
@email:2023025086@m.scnu.edu.cn
@time:2025/2/5
"""
import sys
from logging import NOTSET, getLogger, FileHandler, Formatter, StreamHandler, info, error, debug
from time import time, strftime, localtime
import pandas as pd
import numpy as np
from PyQt5 import QtGui
from PyQt5.QtGui import QFont, QDoubleValidator, QIntValidator
from matplotlib.ticker import FuncFormatter
from numpy import append
from matplotlib import use
from matplotlib import pyplot as plt, gridspec
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT
from datetime import datetime
from pathlib import Path
from PyQt5.QtCore import QCoreApplication, QTimer
from PyQt5.QtWidgets import QFileDialog, QMainWindow, QMessageBox, QButtonGroup, QApplication, QTableWidgetItem, \
QLineEdit, QAction, QTableWidget, QDialog, QVBoxLayout, QLabel, QDialogButtonBox
from scipy.signal import butter, filtfilt, find_peaks
import append
from MainWindow import Ui_MainWindow
use("Qt5Agg") # 声明使用QT5
# 设置日志
logger = getLogger()
logger.setLevel(NOTSET)
realtime = strftime('%Y%m%d', localtime(time()))
if not Path("logs").exists():
Path("logs").mkdir(exist_ok=True)
fh = FileHandler(Path("logs") / (realtime + ".log"), mode='a')
fh.setLevel(NOTSET)
fh.setFormatter(Formatter("%(asctime)s: %(message)s"))
logger.addHandler(fh)
ch = StreamHandler()
ch.setLevel(NOTSET)
ch.setFormatter(Formatter("%(asctime)s: %(message)s"))
logger.addHandler(ch)
getLogger('matplotlib.font_manager').disabled = True
info("------------------------------------")
info("---------ecg_label_check.py---------")
class MainWindow(QMainWindow, Ui_MainWindow):
# 全局变量初始化
data1 = np.array([])
data1 = data1.astype(np.float64)
data2 = np.array([])
data2 = data2.astype(np.float64)
label1 = np.array([])
label1 = label1.astype(np.int64)
label2 = np.array([])
label2 = label2.astype(np.int64)
# 程序初始化操作
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
# 设置画框
self.figure = plt.figure(figsize=(12, 6), dpi=150)
self.canvas = FigureCanvasQTAgg(self.figure)
self.figToolbar = CustomNavigationToolbar(self.canvas, self)
self.verticalLayout_canvas.addWidget(self.canvas)
self.verticalLayout_canvas.addWidget(self.figToolbar)
self.figToolbar._actions['home'].triggered.connect(self.toggle_home)
self.figToolbar.action_Label_Single.triggered.connect(self.toggle_changeLabel_Single_mode)
self.figToolbar.action_Label_Multiple.triggered.connect(self.toggle_changeLabel_Multiple_mode)
# 画框子图初始化
self.gs = gridspec.GridSpec(2, 1, height_ratios=[1, 1])
self.figure.subplots_adjust(top=1, bottom=0, right=1, left=0, hspace=0, wspace=0)
plt.margins(0, 0)
plt.tight_layout()
plt.xticks([])
plt.yticks([])
# 单选框组件分组
self.buttonGroup_inputMode = QButtonGroup()
self.buttonGroup_inputMode.addButton(self.radioButton_inputMode_auto)
self.buttonGroup_inputMode.addButton(self.radioButton_inputMode_manual)
self.buttonGroup_data1_preprocess = QButtonGroup()
self.buttonGroup_data1_preprocess.addButton(self.radioButton_data1_fillterMode)
self.buttonGroup_data2_preprocess = QButtonGroup()
self.buttonGroup_data2_preprocess.addButton(self.radioButton_data2_fillterMode)
self.buttonGroup_move_preset = QButtonGroup()
self.buttonGroup_move_preset.addButton(self.radioButton_move_preset_1)
self.buttonGroup_move_preset.addButton(self.radioButton_move_preset_2)
self.buttonGroup_move_preset.addButton(self.radioButton_move_preset_3)
self.buttonGroup_move_preset.addButton(self.radioButton_move_custom)
# 设置表格属性
self.tableWidget_label1.setHorizontalHeaderLabels(['label1'])
self.tableWidget_label2.setHorizontalHeaderLabels(['label2'])
self.tableWidget_label1.setEditTriggers(QTableWidget.NoEditTriggers)
self.tableWidget_label2.setEditTriggers(QTableWidget.NoEditTriggers)
self.tableWidget_label1.horizontalHeader().setStretchLastSection(True)
self.tableWidget_label1.horizontalHeader().setSectionResizeMode(1)
self.tableWidget_label2.horizontalHeader().setStretchLastSection(True)
self.tableWidget_label2.horizontalHeader().setSectionResizeMode(1)
# 槽函数连接控件初始化
self.pushButton_savepath_open.clicked.connect(self.slot_btn_selectPath)
self.pushButton_rootpath_open.clicked.connect(self.slot_btn_selectPath)
self.pushButton_data1path_open.clicked.connect(self.slot_btn_selectPath)
self.pushButton_data2path_open.clicked.connect(self.slot_btn_selectPath)
self.pushButton_label1path_open.clicked.connect(self.slot_btn_selectPath)
self.pushButton_label2path_open.clicked.connect(self.slot_btn_selectPath)
self.pushButton_dataInput.clicked.connect(self.slot_btn_dataInput)
self.pushButton_append.clicked.connect(self.slot_btn_append)
self.pushButton_outputLabel.clicked.connect(self.slot_btn_outputLabel)
self.comboBox_choose.currentTextChanged.connect(self.slot_comboBox_textChanged)
self.radioButton_inputMode_auto.clicked.connect(self.slot_radioBtn_inputMode_auto)
self.radioButton_inputMode_manual.clicked.connect(self.slot_radioBtn_inputMode_manual)
self.pushButton_left_move.clicked.connect(self.slot_btn_left_move)
self.pushButton_pause.clicked.connect(self.slot_btn_pause)
self.pushButton_right_move.clicked.connect(self.slot_btn_right_move)
self.radioButton_move_preset_1.clicked.connect(self.slot_radioBtn_move_preset_1)
self.radioButton_move_preset_2.clicked.connect(self.slot_radioBtn_move_preset_2)
self.radioButton_move_preset_3.clicked.connect(self.slot_radioBtn_move_preset_3)
self.radioButton_move_custom.clicked.connect(self.slot_radioBtn_move_custom)
self.tableWidget_label1.cellDoubleClicked.connect(self.slot_tableWidget_1_on_cell_double_clicked)
self.tableWidget_label2.cellDoubleClicked.connect(self.slot_tableWidget_2_on_cell_double_clicked)
# 初始化按钮快捷键
self.pushButton_left_move.setShortcut(QCoreApplication.translate("MainWindow", "A"))
self.pushButton_pause.setShortcut(QCoreApplication.translate("MainWindow", "S"))
self.pushButton_right_move.setShortcut(QCoreApplication.translate("MainWindow", "D"))
# 界面控件状态初始化
self.lineEdit_rootpath.setEnabled(False)
self.lineEdit_savepath.setEnabled(False)
self.lineEdit_data1path.setEnabled(False)
self.lineEdit_data2path.setEnabled(False)
self.lineEdit_label1path.setEnabled(False)
self.lineEdit_label2path.setEnabled(False)
self.label_choose.setEnabled(False)
self.comboBox_choose.setEnabled(False)
self.groupBox_save.setEnabled(False)
self.groupBox_data1.setEnabled(False)
self.groupBox_data2.setEnabled(False)
self.groupBox_label1.setEnabled(False)
self.groupBox_label2.setEnabled(False)
self.groupBox_autoplay.setEnabled(False)
self.groupBox_labelDisplay.setEnabled(False)
self.radioButton_inputMode_auto.setChecked(True)
self.radioButton_data1_fillterMode.setChecked(True)
self.radioButton_data2_fillterMode.setChecked(True)
self.radioButton_move_preset_1.setChecked(True)
self.pushButton_outputLabel.setEnabled(False)
self.figToolbar.action_Label_Single.setEnabled(False)
self.figToolbar.action_Label_Multiple.setEnabled(False)
for action in self.figToolbar._actions.values():
action.setEnabled(False)
# 消息弹窗初始化
self.msgBox = QMessageBox()
self.msgBox.setWindowTitle("消息")
# 自动播放参数初始化
self.autoplay_mode = "pause"
self.autoplay_moveLength = int(self.label_moveLength_preset_1.text())
self.autoplay_maxRange = int(self.label_maxRange_preset_1.text())
self.autoplay_moveSpeed = int(self.label_moveSpeed_preset_1.text())
# 初始化自动播放定时器
self.timer_autoplay = QTimer()
self.timer_autoplay.timeout.connect(self.autoplay_move_xlim)
# 绘图工具初始化
self.points_y = np.array([])
self.temp_point = None
self.is_left_button_pressed = False
self.is_right_button_pressed = False
# 定义验证器用于规范lineEdit的输入内容
validator_double = QDoubleValidator(-1e100, 1e100, 10)
validator_integer = QIntValidator(-2**31, 2**31 - 1)
self.lineEdit_data1_fillterNum.setValidator(validator_integer)
self.lineEdit_data2_fillterNum.setValidator(validator_integer)
self.lineEdit_data1_fillterFrequency_min.setValidator(validator_double)
self.lineEdit_data1_fillterFrequency_max.setValidator(validator_double)
self.lineEdit_data2_fillterFrequency_min.setValidator(validator_double)
self.lineEdit_data2_fillterFrequency_max.setValidator(validator_double)
self.lineEdit_frequency.setValidator(validator_double)
self.lineEdit_moveLength.setValidator(validator_integer)
self.lineEdit_maxRange.setValidator(validator_double)
self.lineEdit_moveSpeed.setValidator(validator_integer)
self.lineEdit_findpeaks_min_interval.setValidator(validator_integer)
self.lineEdit_findpeaks_min_height.setValidator(validator_double)
self.textBrowser_update("程序启动成功,导入数据以开始任务")
info("Program Started.")
def slot_btn_selectPath(self):
fileDialog = QFileDialog()
if self.sender() == self.pushButton_rootpath_open:
fileDialog.setFileMode(QFileDialog.Directory)
fileDialog.setOption(QFileDialog.ShowDirsOnly, True)
if fileDialog.exec_() == QFileDialog.Accepted:
file_path = fileDialog.selectedFiles()[0]
if not file_path:
error("Root Path not Exist...")
self.textBrowser_update("操作:根目录路径输入错误")
self.msgBox.setText("根目录路径输入错误")
self.msgBox.setIcon(QMessageBox.Critical)
self.msgBox.exec()
return
self.lineEdit_rootpath.setText(file_path)
file_path = Path(file_path)
info("Loading Root Path...")
self.data_and_label_Path = file_path / "label"
if self.data_and_label_Path.exists():
# 检查路径下的hecg.txt和hRpeak.txt文件是否一一对应
data_files = sorted(self.data_and_label_Path.glob('*ecg.txt'))
label_files = sorted(self.data_and_label_Path.glob('*Rpeak.txt'))
if len(data_files) != len(label_files):
error("Data Quantity not Match...")
self.textBrowser_update(f"操作数据导入错误ecg.txt和Rpeak.txt文件数量不匹配分别是{str(len(data_files))}{str(len(label_files))}")
self.msgBox.setText(f"数据导入错误ecg.txt和Rpeak.txt文件数量不匹配分别是{str(len(data_files))}{str(len(label_files))}")
self.msgBox.setIcon(QMessageBox.Critical)
self.msgBox.exec()
return
for data_file, label_file in zip(data_files, label_files):
if data_file.stem.replace('ecg', '') != label_file.stem.replace('Rpeak', ''):
self.textBrowser_update(f"操作:数据导入错误,文件名称存在不匹配,分别是{str(data_file.stem)}{str(label_file.stem)}")
self.msgBox.setText(f"操作:数据导入错误,文件名称存在不匹配,分别是{str(data_file.stem)}{str(label_file.stem)}")
self.msgBox.setIcon(QMessageBox.Critical)
self.msgBox.exec()
return
nums_for_comboBox = np.array([])
for data_file in data_files:
prefix = data_file.stem.replace('ecg', '')
nums_for_comboBox = np.append(nums_for_comboBox, prefix)
nums_for_comboBox = nums_for_comboBox.astype(np.int8)
nums_for_comboBox.sort()
nums_for_comboBox = nums_for_comboBox.astype(str)
self.comboBox_choose.clear()
self.comboBox_choose.addItems(nums_for_comboBox)
self.label_choose.setEnabled(True)
self.comboBox_choose.setEnabled(True)
self.groupBox_save.setEnabled(True)
self.groupBox_data1.setEnabled(True)
self.groupBox_data2.setEnabled(True)
self.groupBox_label1.setEnabled(True)
self.groupBox_label2.setEnabled(True)
# 更新数据路径文本框
self.lineEdit_savepath.setText(
str(self.data_and_label_Path) + "\\" + self.comboBox_choose.currentText() + "location_J.txt")
self.lineEdit_data1path.setText(
str(self.data_and_label_Path) + "\\" + self.comboBox_choose.currentText() + "ecg.txt")
self.lineEdit_data2path.setText(
str(self.data_and_label_Path) + "\\" + self.comboBox_choose.currentText() + "ecg.txt")
self.lineEdit_label1path.setText(
str(self.data_and_label_Path) + "\\" + self.comboBox_choose.currentText() + "Rpeak.txt")
self.lineEdit_label2path.setText(
str(self.data_and_label_Path) + "\\" + self.comboBox_choose.currentText() + "Rpeak.txt")
info("Successfully Loaded Root Path.")
self.textBrowser_update("操作:根目录路径选择成功")
else:
info("Failed to Load Root Path.")
self.textBrowser_update("操作:根目录路径选择错误,缺乏必要数据文件夹")
self.msgBox.setText("根目录路径选择错误,缺乏必要数据文件夹")
self.msgBox.setIcon(QMessageBox.Critical)
self.msgBox.exec()
return
else:
info("Canceled Loading Root Path.")
self.textBrowser_update("提示:根目录路径选择取消")
self.msgBox.setText("根目录路径选择取消")
self.msgBox.setIcon(QMessageBox.Warning)
self.msgBox.exec()
elif self.sender() == self.pushButton_savepath_open:
fileDialog.setFileMode(QFileDialog.Directory)
fileDialog.setOption(QFileDialog.ShowDirsOnly, True)
if fileDialog.exec_() == QFileDialog.Accepted:
file_path = fileDialog.selectedFiles()[0]
self.lineEdit_savepath.setText(str(Path(file_path) / "newlocation_J.txt"))
info("Successfully Loaded Save Path.")
self.textBrowser_update("操作:保存路径选择成功")
else:
info("Canceled Loading Save Path.")
self.textBrowser_update("提示:保存路径选择取消")
self.msgBox.setText("保存路径选择取消")
self.msgBox.setIcon(QMessageBox.Warning)
self.msgBox.exec()
else:
fileDialog.setFileMode(QFileDialog.ExistingFile)
fileDialog.setOption(QFileDialog.ReadOnly, True)
fileDialog.setNameFilter("Text Files (*.txt)")
if fileDialog.exec_() == QFileDialog.Accepted:
file_path = fileDialog.selectedFiles()[0]
if self.sender() == self.pushButton_data1path_open:
self.lineEdit_data1path.setText(file_path)
elif self.sender() == self.pushButton_data2path_open:
self.lineEdit_data2path.setText(file_path)
elif self.sender() == self.pushButton_label1path_open:
self.lineEdit_label1path.setText(file_path)
elif self.sender() == self.pushButton_label2path_open:
self.lineEdit_label2path.setText(file_path)
info("Successfully Loaded Data Path.")
self.textBrowser_update("操作:数据路径选择成功")
else:
info("Canceled Loading Data Path.")
self.textBrowser_update("提示:数据路径选择取消")
self.msgBox.setText("数据路径选择取消")
self.msgBox.setIcon(QMessageBox.Warning)
self.msgBox.exec()
def slot_btn_dataInput(self):
if self.lineEdit_data1path.text() != "" or self.lineEdit_data2path.text() != "" or self.lineEdit_label1path.text() != "" or self.lineEdit_label2path.text() != "" or self.lineEdit_savepath.text() != "":
info("Inputing Data...")
self.textBrowser_update("提示:开始导入数据")
# 导入数据
self.label1 = np.array([])
self.label2 = np.array([])
file = open(str(self.lineEdit_data1path.text()), 'r')
self.data1 = file.readlines()
self.data1 = list(map(float, self.data1))
self.data2 = self.data1
self.data1 = self.data_preprocess(self.data1, int(self.lineEdit_data1_fillterNum.text()),
float(self.lineEdit_data1_fillterFrequency_min.text()),
float(self.lineEdit_data1_fillterFrequency_max.text()),
float(self.lineEdit_frequency.text()))
self.data2 = self.data_preprocess(self.data2, int(self.lineEdit_data2_fillterNum.text()),
float(self.lineEdit_data2_fillterFrequency_min.text()),
float(self.lineEdit_data2_fillterFrequency_max.text()),
float(self.lineEdit_frequency.text()))
file = open(str(self.lineEdit_label1path.text()), 'r')
self.label1 = np.array(file.readlines())
self.label2 = self.label1
self.data1 = self.data1.astype(np.float64)
self.data2 = self.data2.astype(np.float64)
self.label1 = self.label1.astype(np.int64)
self.label2 = self.label2.astype(np.int64)
self.points_y_1 = [self.data1[x] for x in self.label1]
self.points_y_2 = [self.data2[x] for x in self.label2]
# 更新tableWidget
self.tableWidget_label1.setRowCount(len(self.label1))
for row, value in enumerate(self.label1):
item = QTableWidgetItem(str(value).strip())
self.tableWidget_label1.setItem(row, 0, item)
self.tableWidget_label2.setRowCount(self.label2.__len__())
for row, value in enumerate(self.label2):
item = QTableWidgetItem(str(value).strip())
self.tableWidget_label2.setItem(row, 0, item)
self.groupBox_labelDisplay.setEnabled(True)
# 更新界面
self.groupBox_inputSetting.setEnabled(False)
self.groupBox_autoplay.setEnabled(True)
self.pushButton_outputLabel.setEnabled(True)
self.figToolbar.action_Label_Single.setEnabled(True)
self.figToolbar.action_Label_Multiple.setEnabled(True)
MainWindow.setWindowTitle(self, QCoreApplication.translate("MainWindow",
"ECG_Label_Check - Data Path: " + self.lineEdit_rootpath.text()))
for action in self.figToolbar._actions.values():
action.setEnabled(True)
# 更新信息
self.label_data1_length.setText(str(len(self.data1)))
self.label_data2_length.setText(str(len(self.data2)))
self.label_label1_length.setText(str(len(self.label1)))
self.label_label2_length.setText(str(len(self.label2)))
# 更新画框
self.figure.clear()
self.plot_data_and_label()
# 连接画框中的槽函数
# Connect mouse events
self.canvas.mpl_connect('motion_notify_event', self.on_motion)
# 保存路径文件是否存在的检查
if not Path(self.lineEdit_savepath.text()).exists():
Path(self.lineEdit_savepath.text()).touch()
np.savetxt(Path(self.lineEdit_savepath.text()), self.label2, fmt='%d', newline='\n')
info("Finished Input Data.")
self.textBrowser_update("提示:导入数据完成")
else:
info("Failed to Input Data!")
self.textBrowser_update("操作:导入数据失败")
self.msgBox.setText("导入失败,请正确输入路径")
self.msgBox.setIcon(QMessageBox.Critical)
self.msgBox.exec()
def slot_radioBtn_inputMode_auto(self):
self.pushButton_rootpath_open.setEnabled(True)
self.label_choose.setEnabled(False)
self.comboBox_choose.setEnabled(False)
self.groupBox_save.setEnabled(False)
self.groupBox_data1.setEnabled(False)
self.groupBox_data2.setEnabled(False)
self.groupBox_label1.setEnabled(False)
self.groupBox_label2.setEnabled(False)
self.lineEdit_savepath.setText("")
self.lineEdit_rootpath.setText("")
self.lineEdit_data1path.setText("")
self.lineEdit_data2path.setText("")
self.lineEdit_label1path.setText("")
self.lineEdit_label2path.setText("")
self.comboBox_choose.clear()
info("Switched to inputMode_auto.")
self.textBrowser_update("操作:切换到输入模式-自动识别")
def slot_radioBtn_inputMode_manual(self):
self.pushButton_rootpath_open.setEnabled(False)
self.label_choose.setEnabled(False)
self.comboBox_choose.setEnabled(False)
self.groupBox_save.setEnabled(True)
self.groupBox_data1.setEnabled(True)
self.groupBox_data2.setEnabled(True)
self.groupBox_label1.setEnabled(True)
self.groupBox_label2.setEnabled(True)
self.lineEdit_rootpath.setText("")
self.comboBox_choose.clear()
info("Switched to inputMode_manual.")
self.textBrowser_update("操作:切换到输入模式-手动输入")
def slot_comboBox_textChanged(self):
# 更新数据路径文本框
self.lineEdit_savepath.setText(
str(self.data_and_label_Path) + "\\" + self.comboBox_choose.currentText() + "location_J.txt")
self.lineEdit_data1path.setText(
str(self.data_and_label_Path) + "\\" + self.comboBox_choose.currentText() + "ecg.txt")
self.lineEdit_data2path.setText(
str(self.data_and_label_Path) + "\\" + self.comboBox_choose.currentText() + "ecg.txt")
self.lineEdit_label1path.setText(
str(self.data_and_label_Path) + "\\" + self.comboBox_choose.currentText() + "Rpeak.txt")
self.lineEdit_label2path.setText(
str(self.data_and_label_Path) + "\\" + self.comboBox_choose.currentText() + "Rpeak.txt")
def slot_btn_left_move(self):
self.autoplay_mode = "left"
self.autoplay_xlim_start = int(self.ax0.get_xlim()[1] - self.autoplay_maxRange)
self.autoplay_xlim_end = int(self.ax0.get_xlim()[1])
if self.autoplay_xlim_end > self.data2.__len__():
self.autoplay_xlim_start = int(self.data2.__len__() - self.autoplay_maxRange)
self.autoplay_xlim_end = int(self.data2.__len__())
self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end)
self.canvas.draw()
self.timer_autoplay.start(self.autoplay_moveSpeed)
info("Started Autoplay left_mode.")
self.textBrowser_update("操作:开始自动播放-向左")
def slot_btn_pause(self):
self.autoplay_mode = "pause"
self.timer_autoplay.stop()
info("Paused Autoplay.")
self.textBrowser_update("操作:暂停自动播放")
def slot_btn_right_move(self):
self.autoplay_mode = "right"
self.autoplay_xlim_start = int(self.ax0.get_xlim()[0])
self.autoplay_xlim_end = int(self.ax0.get_xlim()[0] + self.autoplay_maxRange)
if self.autoplay_xlim_start < 0:
self.autoplay_xlim_start = 0
self.autoplay_xlim_end = 0 + self.autoplay_maxRange
self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end)
self.canvas.draw()
self.timer_autoplay.start(self.autoplay_moveSpeed)
info("Started Autoplay right_mode.")
self.textBrowser_update("操作:开始自动播放-向右")
def slot_radioBtn_move_preset_1(self):
self.autoplay_moveLength = int(self.label_moveLength_preset_1.text())
self.autoplay_maxRange = int(self.label_maxRange_preset_1.text())
self.autoplay_moveSpeed = int(self.label_moveSpeed_preset_1.text())
if self.autoplay_mode != "pause":
if self.autoplay_mode == "right":
self.autoplay_xlim_start = int(self.ax0.get_xlim()[0])
self.autoplay_xlim_end = int(self.ax0.get_xlim()[0] + self.autoplay_maxRange)
self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end)
self.canvas.draw()
elif self.autoplay_mode == "left":
self.autoplay_xlim_start = int(self.ax0.get_xlim()[1] - self.autoplay_maxRange)
self.autoplay_xlim_end = int(self.ax0.get_xlim()[1])
self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end)
self.canvas.draw()
self.timer_autoplay.start(self.autoplay_moveSpeed)
info("Switched to Autoplay preset_1.")
self.textBrowser_update("操作:切换到自动播放-预设1")
def slot_radioBtn_move_preset_2(self):
self.autoplay_moveLength = int(self.label_moveLength_preset_2.text())
self.autoplay_maxRange = int(self.label_maxRange_preset_2.text())
self.autoplay_moveSpeed = int(self.label_moveSpeed_preset_2.text())
if self.autoplay_mode != "pause":
if self.autoplay_mode == "right":
self.autoplay_xlim_start = int(self.ax0.get_xlim()[0])
self.autoplay_xlim_end = int(self.ax0.get_xlim()[0] + self.autoplay_maxRange)
self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end)
self.canvas.draw()
elif self.autoplay_mode == "left":
self.autoplay_xlim_start = int(self.ax0.get_xlim()[1] - self.autoplay_maxRange)
self.autoplay_xlim_end = int(self.ax0.get_xlim()[1])
self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end)
self.canvas.draw()
self.timer_autoplay.start(self.autoplay_moveSpeed)
info("Switched to Autoplay preset_2.")
self.textBrowser_update("操作:切换到自动播放-预设2")
def slot_radioBtn_move_preset_3(self):
self.autoplay_moveLength = int(self.label_moveLength_preset_3.text())
self.autoplay_maxRange = int(self.label_maxRange_preset_3.text())
self.autoplay_moveSpeed = int(self.label_moveSpeed_preset_3.text())
if self.autoplay_mode != "pause":
if self.autoplay_mode == "right":
self.autoplay_xlim_start = int(self.ax0.get_xlim()[0])
self.autoplay_xlim_end = int(self.ax0.get_xlim()[0] + self.autoplay_maxRange)
self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end)
self.canvas.draw()
elif self.autoplay_mode == "left":
self.autoplay_xlim_start = int(self.ax0.get_xlim()[1] - self.autoplay_maxRange)
self.autoplay_xlim_end = int(self.ax0.get_xlim()[1])
self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end)
self.canvas.draw()
self.timer_autoplay.start(self.autoplay_moveSpeed)
info("Switched to Autoplay preset_3.")
self.textBrowser_update("操作:切换到自动播放-预设3")
def slot_radioBtn_move_custom(self):
self.autoplay_moveLength = int(self.lineEdit_moveLength.text())
self.autoplay_maxRange = int(self.lineEdit_maxRange.text())
self.autoplay_moveSpeed = int(self.lineEdit_moveSpeed.text())
if self.autoplay_mode != "pause":
if self.autoplay_mode == "right":
self.autoplay_xlim_start = int(self.ax0.get_xlim()[0])
self.autoplay_xlim_end = int(self.ax0.get_xlim()[0] + self.autoplay_maxRange)
self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end)
self.canvas.draw()
elif self.autoplay_mode == "left":
self.autoplay_xlim_start = int(self.ax0.get_xlim()[1] - self.autoplay_maxRange)
self.autoplay_xlim_end = int(self.ax0.get_xlim()[1])
self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end)
self.canvas.draw()
self.timer_autoplay.start(self.autoplay_moveSpeed)
info("Switched to Autoplay custom.")
self.textBrowser_update("操作:切换到自动播放-自定义")
self.msgBox.setText("自定义的输入参数未做任何检查,请斟酌输入参数,否则可能会导致程序异常")
self.msgBox.setIcon(QMessageBox.Warning)
self.msgBox.exec()
def slot_tableWidget_1_on_cell_double_clicked(self, row, column):
x = float(self.tableWidget_label1.item(row, column).text())
self.ax0.set_xlim(x - 5000, x + 5000)
self.annotation_tableWidget = self.ax0.annotate(f'x={int(x)}', xy=(int(x), self.ax0.get_ylim()[0]), xytext=(int(x), self.ax0.get_ylim()[0] + (self.ax0.get_ylim()[1] - self.ax0.get_ylim()[0]) * 0.1),
arrowprops=dict(facecolor='black', shrink=0.1))
self.canvas.draw()
info(f"Jumped to x_axis: {str(int(x))}.")
self.textBrowser_update(f"操作跳转到x坐标: {str(int(x))}")
def slot_tableWidget_2_on_cell_double_clicked(self, row, column):
x = float(self.tableWidget_label2.item(row, column).text())
self.ax0.set_xlim(x - 5000, x + 5000)
self.annotation_tableWidget = self.ax0.annotate(f'x={int(x)}', xy=(int(x), self.ax0.get_ylim()[0]), xytext=(int(x), self.ax0.get_ylim()[0] + (self.ax0.get_ylim()[1] - self.ax0.get_ylim()[0]) * 0.1),
arrowprops=dict(facecolor='black', shrink=0.1))
self.canvas.draw()
info(f"Jumped to x_axis: {str(int(x))}.")
self.textBrowser_update(f"操作跳转到x坐标: {str(int(x))}")
def slot_btn_append(self):
dialog = CustomMessageBox(self)
reply = dialog.exec_()
if reply == QDialog.Accepted:
if self.lineEdit_rootpath.text() == "" or len(list((Path(self.lineEdit_rootpath.text()) / "label").rglob("*location_J.txt"))) == 0:
info(f"*location_J.txt Files not Exist in the Directory.")
self.textBrowser_update(f"错误:无法进行<片段合并>")
self.msgBox.setText(f"目录下不存在*location_J.txt文件")
self.msgBox.setIcon(QMessageBox.Warning)
self.msgBox.exec()
return
final_Rpeak = append.Rpeak_Detection(self.lineEdit_rootpath.text(), int(dialog.lineEdit_fs.text()), int(dialog.lineEdit_th1.text()))
pd.DataFrame(final_Rpeak).to_csv(Path(self.lineEdit_rootpath.text()) / "final_Rpeak.txt", index=False, header=None)
info(f"Saved final_Rpeak to Directory {self.lineEdit_rootpath.text()}.")
self.textBrowser_update(f"提示保存final_Rpeak.txt成功至文件夹{self.lineEdit_rootpath.text()}")
self.msgBox.setText(f"保存成功至{self.lineEdit_rootpath.text()}")
self.msgBox.setIcon(QMessageBox.Information)
self.msgBox.exec()
else:
self.textBrowser_update("提示:操作取消")
def slot_btn_outputLabel(self):
np.savetxt(Path(self.lineEdit_savepath.text()), self.label2, fmt='%d', newline='\n')
info(f"Manually Saved Data to: {str(Path(self.lineEdit_savepath.text()))}.")
self.textBrowser_update(f"操作:手动保存数据至{str(Path(self.lineEdit_savepath.text()))}")
def data_preprocess(self, data, n, f1, f2, fs):
f1 = f1 / (fs / 2.0)
f2 = f2 / (fs / 2.0)
b, a = butter(n, [f1, f2], btype = 'bandpass')
data = np.array(filtfilt(b, a, data))
return data
def update_tableWidget_and_info(self):
self.tableWidget_label2.setRowCount(self.label2.__len__())
for row, value in enumerate(self.label2):
item = QTableWidgetItem(str(value).strip())
self.tableWidget_label2.setItem(row, 0, item)
self.groupBox_labelDisplay.setEnabled(True)
self.label_label2_length.setText(str(len(self.label2)))
def textBrowser_update(self, message):
self.textBrowser_infoOutput.append(str(datetime.now().strftime("%H:%M:%S")) + ": " + message)
self.textBrowser_infoOutput.verticalScrollBar().setValue(self.textBrowser_infoOutput.verticalScrollBar().maximum())
def autoplay_move_xlim(self):
if self.autoplay_mode == "left" and self.autoplay_xlim_start < 0:
self.autoplay_mode = "pause"
self.timer_autoplay.stop()
info("Paused Autoplay.")
self.textBrowser_update("操作:暂停自动播放")
elif self.autoplay_mode == "right" and self.autoplay_xlim_end > self.data2.__len__():
self.autoplay_mode = "pause"
self.timer_autoplay.stop()
info("Paused Autoplay.")
self.textBrowser_update("操作:暂停自动播放")
else:
if self.autoplay_mode == "right":
self.autoplay_xlim_start += self.autoplay_moveLength
self.autoplay_xlim_end += self.autoplay_moveLength
elif self.autoplay_mode == "left":
self.autoplay_xlim_start -= self.autoplay_moveLength
self.autoplay_xlim_end -= self.autoplay_moveLength
self.ax0.set_xlim(self.autoplay_xlim_start, self.autoplay_xlim_end)
self.canvas.draw()
def plot_data_and_label(self, ax_top=True, ax_bottom=True, ax_left=True, ax_right=True):
self.ax0 = self.figure.add_subplot(self.gs[0])
self.ax0.plot(self.data1, label="data1", color='b')
self.ax0.plot(self.label1, self.points_y_1, 'ro', label='label1')
self.ax0 = plt.gca()
self.ax0.grid(True)
self.ax0.spines["top"].set_visible(ax_top)
self.ax0.spines["right"].set_visible(ax_right)
self.ax0.spines["bottom"].set_visible(ax_bottom)
self.ax0.spines["left"].set_visible(ax_left)
self.ax0.tick_params(axis='x', colors='white')
self.ax0.xaxis.set_major_formatter(FuncFormatter(lambda x, p: f"{x:.0f}"))
self.ax1 = self.figure.add_subplot(self.gs[1], sharex=self.ax0, sharey=self.ax0)
self.line_data2, = self.ax1.plot(self.data2, label="data2", color='b')
self.point_label2, = self.ax1.plot(self.label2, self.points_y_2, 'ro', label='label2')
self.ax1 = plt.gca()
self.ax1.grid(True)
self.ax1.spines["top"].set_visible(ax_top)
self.ax1.spines["right"].set_visible(ax_right)
self.ax1.spines["bottom"].set_visible(ax_bottom)
self.ax1.spines["left"].set_visible(ax_left)
self.ax0.autoscale(False)
self.ax0.callbacks.connect('xlim_changed', lambda ax: self.on_xlim_change(ax))
def toggle_home(self):
if self.timer_autoplay.isActive() == True:
self.autoplay_mode = "pause"
self.timer_autoplay.stop()
info("Paused Autoplay.")
self.textBrowser_update("操作:暂停自动播放")
self.ax0.autoscale(True)
self.ax0.relim()
self.ax0.autoscale_view()
self.canvas.draw()
self.ax0.autoscale(False)
self.textBrowser_update("操作:尺度恢复")
def toggle_changeLabel_Single_mode(self, state):
if state:
self.deactivate_figToolbar_buttons()
self.figToolbar.action_Label_Single.setChecked(True)
self.figToolbar.action_Label_Multiple.setChecked(False)
self.figToolbar.cid_mouse_press = self.canvas.mpl_connect('button_press_event', self.on_click)
self.figToolbar.cid_mouse_release = self.canvas.mpl_connect('button_release_event', self.on_release)
else:
if self.figToolbar.cid_mouse_press is not None:
self.canvas.mpl_disconnect(self.figToolbar.cid_mouse_press)
self.figToolbar.cid_mouse_press = None
if self.figToolbar.cid_mouse_release is not None:
self.canvas.mpl_disconnect(self.figToolbar.cid_mouse_release)
self.figToolbar.cid_mouse_release = None
def toggle_changeLabel_Multiple_mode(self, state):
if state:
self.deactivate_figToolbar_buttons()
self.figToolbar.action_Label_Single.setChecked(False)
self.figToolbar.action_Label_Multiple.setChecked(True)
self.figToolbar.cid_mouse_press = self.canvas.mpl_connect('button_press_event', self.on_click)
self.figToolbar.cid_mouse_release = self.canvas.mpl_connect('button_release_event', self.on_release)
self.figToolbar.cid_mouse_hold = self.canvas.mpl_connect('motion_notify_event', self.on_hold)
else:
if self.figToolbar.cid_mouse_press is not None:
self.canvas.mpl_disconnect(self.figToolbar.cid_mouse_press)
self.figToolbar.cid_mouse_press = None
if self.figToolbar.cid_mouse_release is not None:
self.canvas.mpl_disconnect(self.figToolbar.cid_mouse_release)
self.figToolbar.cid_mouse_release = None
if self.figToolbar.cid_mouse_hold:
self.canvas.mpl_disconnect(self.figToolbar.cid_mouse_hold)
self.figToolbar.cid_mouse_hold = None
def deactivate_figToolbar_buttons(self):
for action in self.figToolbar._actions.values():
if action.isChecked() == True:
if action == self.figToolbar._actions['pan']:
self.figToolbar.pan()
if action == self.figToolbar._actions['zoom']:
self.figToolbar.zoom()
def on_click(self, event):
if self.figToolbar.action_Label_Single.isChecked():
if event.button == 1:
self.is_left_button_pressed = True
self.add_temp_point(event)
elif event.button == 3:
self.is_right_button_pressed = True
self.remove_temp_point(event)
elif self.figToolbar.action_Label_Multiple.isChecked():
if event.button == 1 or event.button == 3: # 左键或右键
if event.button == 1:
self.is_left_button_pressed = True
elif event.button == 3:
self.is_right_button_pressed = True
self.figToolbar.rect_start_x = event.xdata
# 如果矩形patch已存在先移除
if self.figToolbar.rect_patch is not None:
self.figToolbar.rect_patch.remove()
self.figToolbar.rect_patch = None
self.canvas.draw()
def on_release(self, event):
if self.figToolbar.action_Label_Single.isChecked():
if event.button == 1 and self.is_left_button_pressed:
self.is_left_button_pressed = False
if self.temp_point:
self.label2 = np.append(self.label2, self.temp_point[0])
self.points_y_2 = np.append(self.points_y_2, self.temp_point[1])
info(f"Added point: ({str(self.temp_point[0])},{str(self.temp_point[1])}).")
self.textBrowser_update(f"操作:新增点:({str(self.temp_point[0])},{str(self.temp_point[1])})")
self.temp_point = None
self.redraw_plot()
elif event.button == 3 and self.is_right_button_pressed:
self.is_right_button_pressed = False
if self.temp_point:
distances = np.abs(np.array(self.label2) - self.temp_point[0])
if len(distances) > 0:
idx = distances.argmin()
info(f"Removed point {idx + 1}: ({str(self.label2[idx])},{str(self.points_y_2[idx])}).")
self.textBrowser_update(f"操作:删除第{idx + 1}点:({str(self.label2[idx])},{str(self.points_y_2[idx])})")
self.label2 = np.delete(self.label2, idx)
self.points_y_2 = np.delete(self.points_y_2, idx)
self.temp_point = None
self.redraw_plot()
self.label2.sort()
self.points_y_2 = [self.data2[x] for x in self.label2]
self.update_tableWidget_and_info()
np.savetxt(Path(self.lineEdit_savepath.text()), self.label2, fmt='%d', newline='\n')
elif self.figToolbar.action_Label_Multiple.isChecked():
if self.figToolbar.rect_start_x is not None:
self.figToolbar.rect_end_x = event.xdata
if self.figToolbar.rect_start_x is not None and self.figToolbar.rect_end_x is not None:
if self.figToolbar.rect_start_x < self.figToolbar.rect_end_x:
rect_left = self.figToolbar.rect_start_x
rect_right = self.figToolbar.rect_end_x
elif self.figToolbar.rect_start_x > self.figToolbar.rect_end_x:
rect_left = self.figToolbar.rect_end_x
rect_right = self.figToolbar.rect_start_x
else:
rect_left = self.figToolbar.rect_start_x
rect_right = self.figToolbar.rect_start_x
else:
rect_left = self.figToolbar.rect_start_x
rect_right = self.figToolbar.rect_start_x
if event.button == 1 and self.is_left_button_pressed:
self.is_left_button_pressed = False
if rect_left < 0:
rect_left = 0
if rect_right >= len(self.data2):
rect_right = len(self.data2) - 1
selected_area_for_add_points = self.data2[int(rect_left):int(rect_right)]
peaks_idx, _ = find_peaks(selected_area_for_add_points, height=float(self.lineEdit_findpeaks_min_height.text()), distance=float(self.lineEdit_findpeaks_min_interval.text()))
peaks_idx = peaks_idx + int(rect_left)
if len(peaks_idx) != 0:
info(f"Added {len(peaks_idx)} points.")
self.textBrowser_update(f"操作:新增{len(peaks_idx)}个点")
else:
info(f"No point added in selected area.")
self.textBrowser_update(f"操作:所选区间内无新增点")
self.label2 = np.append(self.label2, peaks_idx)
self.points_y_2 = np.append(self.points_y_2, self.data2[peaks_idx])
self.redraw_plot()
elif event.button == 3 and self.is_right_button_pressed:
self.is_right_button_pressed = False
left_label2_to_delete = self.label2 - rect_left
right_label2_to_delete = self.label2 - rect_right
self.left_label2_to_delete_idx = len(left_label2_to_delete[left_label2_to_delete < 0])
self.right_label2_to_delete_idx = len(right_label2_to_delete[right_label2_to_delete < 0])
if self.left_label2_to_delete_idx != self.right_label2_to_delete_idx:
info(f"Removed points from {self.left_label2_to_delete_idx + 1} to {self.right_label2_to_delete_idx}.")
self.textBrowser_update(f"操作:删除第{self.left_label2_to_delete_idx + 1}{self.right_label2_to_delete_idx}")
else:
info(f"No point to delete in selected area.")
self.textBrowser_update(f"操作:所选区间内无删除点")
self.label2 = np.delete(self.label2, np.arange(self.left_label2_to_delete_idx, self.right_label2_to_delete_idx))
self.points_y_2 = np.delete(self.points_y_2, np.arange(self.left_label2_to_delete_idx, self.right_label2_to_delete_idx))
self.redraw_plot()
self.figToolbar.rect_start_x = None
self.figToolbar.rect_end_x = None
self.label2.sort()
self.points_y_2 = [self.data2[x] for x in self.label2]
self.update_tableWidget_and_info()
np.savetxt(Path(self.lineEdit_savepath.text()), self.label2, fmt='%d', newline='\n')
# 移除矩形patch
if self.figToolbar.rect_patch is not None:
self.figToolbar.rect_patch.remove()
self.figToolbar.rect_patch = None
self.canvas.draw()
def on_hold(self, event):
if self.figToolbar.rect_start_x is not None and event.xdata is not None:
self.figToolbar.rect_end_x = event.xdata
# 如果矩形patch不存在则创建一个新的
if self.figToolbar.rect_patch is None:
if self.is_left_button_pressed:
self.figToolbar.rect_patch = plt.Rectangle((0, 0), 1, 1, fill=True, alpha=0.2, color='#ff00ff')
elif self.is_right_button_pressed:
self.figToolbar.rect_patch = plt.Rectangle((0, 0), 1, 1, fill=True, alpha=0.2, color='r')
self.ax1.add_patch(self.figToolbar.rect_patch)
# 更新矩形patch的位置和大小
x_start = self.figToolbar.rect_start_x
x_end = self.figToolbar.rect_end_x
y_min, y_max = self.ax1.get_ylim()
self.figToolbar.rect_patch.set_xy((min(x_start, x_end), y_min))
self.figToolbar.rect_patch.set_width(abs(x_end - x_start))
self.figToolbar.rect_patch.set_height(y_max - y_min)
self.canvas.draw()
def on_motion(self, event):
if event.inaxes:
# Clear previous reference lines and temporary points
for line in self.ax0.lines[1:]:
if line.get_label() == 'vline' or line.get_label() == 'hline' or line.get_label() == 'temp_point':
line.remove()
for line in self.ax1.lines[1:]:
if line.get_label() == 'vline' or line.get_label() == 'hline' or line.get_label() == 'temp_point':
line.remove()
# Draw vertical and horizontal reference lines
self.ax0.axvline(event.xdata, color='gray', linestyle='--', label='vline')
self.ax0.axhline(event.ydata, color='gray', linestyle='--', label='hline')
self.ax1.axvline(event.xdata, color='gray', linestyle='--', label='vline')
self.ax1.axhline(event.ydata, color='gray', linestyle='--', label='hline')
# Draw temporary point if left button is pressed
if self.is_left_button_pressed:
self.add_temp_point(event)
elif self.is_right_button_pressed:
self.remove_temp_point(event)
self.canvas.draw()
def add_temp_point(self, event):
if self.figToolbar.action_Label_Single.isChecked():
# Find the closest x value on the curve
idx = np.abs(np.arange(len(self.data2)) - event.xdata).argmin()
x_point = np.arange(len(self.data2))[idx]
y_point = self.data2[idx]
# Store the temporary point
self.temp_point = (x_point, y_point)
# Plot the temporary point
self.ax1.plot(x_point, y_point, marker='o', color='#ff00ff', label='temp_point')
self.ax1.plot(x_point, y_point, marker='x', color='#ff00ff', markersize=30, label='temp_point')
def remove_temp_point(self, event):
if self.figToolbar.action_Label_Single.isChecked():
if self.label2.any():
# Find the closest point to the current x coordinate
distances = np.abs(np.array(self.label2) - event.xdata)
idx = distances.argmin()
x_point = self.label2[idx]
y_point = self.points_y_2[idx]
# Store the temporary point to be removed
self.temp_point = (x_point, y_point)
# Plot the temporary point to be removed
self.ax1.plot(x_point, y_point, marker='x', color='r', markersize=30, label='temp_point')
def redraw_plot(self):
self.point_label2.remove()
self.point_label2, = self.ax1.plot(self.label2, self.points_y_2, 'ro', label='label2')
self.canvas.draw()
def on_xlim_change(self, event_ax):
try:
if self.annotation_tableWidget:
self.annotation_tableWidget.remove()
except AttributeError:
pass
self.annotation_tableWidget = None
self.canvas.draw()
class CustomNavigationToolbar(NavigationToolbar2QT):
def __init__(self, canvas, parent):
super().__init__(canvas, parent)
# 初始化画框工具栏
self.action_Label_Single = QAction('逐一更改标签(Z)', self)
self.action_Label_Single.setFont(QFont("黑体", 14))
self.action_Label_Single.setCheckable(True)
self.action_Label_Single.setShortcut(QCoreApplication.translate("MainWindow", "Z"))
self.action_Label_Multiple = QAction('批量更改标签(X)', self)
self.action_Label_Multiple.setFont(QFont("黑体", 14))
self.action_Label_Multiple.setCheckable(True)
self.action_Label_Multiple.setShortcut(QCoreApplication.translate("MainWindow", "X"))
self.insertAction(self._actions['pan'], self.action_Label_Single)
self.insertAction(self._actions['pan'], self.action_Label_Multiple)
self._actions['pan'].setShortcut(QCoreApplication.translate("MainWindow", "C"))
# 用于存储事件连接ID
self.cid_mouse_press = None
self.cid_mouse_release = None
self.cid_mouse_hold = None
# 初始化矩形选择区域
self.rect_start_x = None
self.rect_end_x = None
self.rect_patch = 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_Single.isChecked():
self.action_Label_Single.setChecked(False)
if self.cid_mouse_press is not None:
self.canvas.mpl_disconnect(self.cid_mouse_press)
self.cid_mouse_press = None
if self.cid_mouse_release is not None:
self.canvas.mpl_disconnect(self.cid_mouse_release)
self.cid_mouse_release = None
elif self.action_Label_Multiple.isChecked():
self.action_Label_Multiple.setChecked(False)
if self.cid_mouse_press is not None:
self.canvas.mpl_disconnect(self.cid_mouse_press)
self.cid_mouse_press = None
if self.cid_mouse_release is not None:
self.canvas.mpl_disconnect(self.cid_mouse_release)
self.cid_mouse_release = None
if self.cid_mouse_hold is not None:
self.canvas.mpl_disconnect(self.cid_mouse_hold)
self.cid_mouse_hold = None
class CustomMessageBox(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.resize(300, 300)
self.setWindowTitle("警告:确认操作")
layout = QVBoxLayout()
self.label = QLabel("是否执行<片段合并>?请在执行前确保此份数据的所有片段都已被打标!请输入相应参数后执行任务。")
self.label1 = QLabel(" ")
self.label_fs = QLabel("信号采样率(Hz)")
self.label_th1 = QLabel("寻峰阈值(个)")
self.lineEdit_fs = QLineEdit()
self.lineEdit_th1 = QLineEdit()
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.label.setFont(font)
self.label1.setFont(font)
self.label_fs.setFont(font)
self.label_th1.setFont(font)
self.lineEdit_fs.setFont(font)
self.lineEdit_th1.setFont(font)
self.label.setWordWrap(True)
self.label.setFixedWidth(300)
self.lineEdit_fs.setText("1000")
self.lineEdit_th1.setText("130")
layout.addWidget(self.label)
layout.addWidget(self.label1)
layout.addWidget(self.label_fs)
layout.addWidget(self.lineEdit_fs)
layout.addWidget(self.label_th1)
layout.addWidget(self.lineEdit_th1)
self.button_box = QDialogButtonBox(QDialogButtonBox.Yes | QDialogButtonBox.No)
self.button_box.setFont(font)
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.reject)
layout.addWidget(self.button_box)
self.setLayout(layout)
# 主函数
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
sys.exit(app.exec_())