240 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			240 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
 | ||
| import numpy as np
 | ||
| 
 | ||
| from matplotlib import pyplot as plt
 | ||
| plt.rcParams['font.sans-serif'] = ['SimSun']  # 使用宋体
 | ||
| plt.rcParams['axes.unicode_minus'] = False  # 正常显示负号
 | ||
| 
 | ||
| from global_var import global_var_init
 | ||
| cycle, fs, record_name, data_path = global_var_init()
 | ||
| 
 | ||
| from processing import processing
 | ||
| (signal_dwt , waves_dwt , rpeaks , ecg_signal,
 | ||
|  signal, signal.v, signal.fs, rows_to_extract, t_ecg, t_ppg,
 | ||
|  on_column_list, on_column_list_toArea, on_values, on_values_toArea,
 | ||
|  sp_column_list, sp_values, dn_column_list, dn_values, dp_column_list,
 | ||
|  dp_values, u_column_list, u_column_list_toArea, u_values, u_values_toArea,
 | ||
|  v_column_list, v_values, w_column_list, w_values, a_column_list, a_column_list_toArea,
 | ||
|  a_values, a_values_toArea, b_column_list, b_values, c_column_list, c_values,
 | ||
|  e_column_list, e_values, f_column_list, f_values,
 | ||
|  signal.ppg, signal.vpg, signal.apg, signal.jpg) = processing()
 | ||
| 
 | ||
| from ecg_peaks_val import ecg_peaks_val
 | ||
| (P_peaks, Q_peaks, R_peaks, S_peaks, T_peaks,
 | ||
| P_onsets, P_offsets, T_onsets, T_offsets,
 | ||
| P_peaks_values, Q_peaks_values, R_peaks_values, S_peaks_values, T_peaks_values, 
 | ||
| P_onsets_values, P_offsets_values, T_onsets_values, T_offsets_values,
 | ||
| PQ_baseline) = ecg_peaks_val()
 | ||
| 
 | ||
| from ppg_peaks_val import ppg_peaks_val
 | ||
| (on, on_toArea, sp, dn, dp,
 | ||
| on_values, on_toArea_values, sp_values, dn_values, dp_values,
 | ||
| u, u_toArea, v, w,
 | ||
| u_values, u_toArea_values, v_values, w_values,
 | ||
| a, a_toArea, b, c, e, f,
 | ||
| a_values, a_toArea_values, b_values, c_values, e_values, f_values) = ppg_peaks_val()
 | ||
| 
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #-----------------------------------          创建拖动类          ----------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| 
 | ||
| class DraggablePoints:
 | ||
|     def __init__(self, ax, points, signal_type, signal_name):
 | ||
|         self.ax = ax
 | ||
|         self.points = points  # 这里是 Line2D 对象的列表
 | ||
|         self.signal_type = signal_type
 | ||
|         self.signal_name = signal_name
 | ||
| 
 | ||
|         self.selected_point = None
 | ||
|         self.press = None
 | ||
|         self.new_x = None
 | ||
|         self.real_y = None # 最终获得的点,其纵坐标数值应在信号线上
 | ||
|         self.point_x = None
 | ||
| 
 | ||
| 
 | ||
|         # 连接鼠标事件
 | ||
|         self.cidpress = ax.figure.canvas.mpl_connect('button_press_event', self.on_press)
 | ||
|         self.cidmotion = ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion)
 | ||
|         self.cidrelease = ax.figure.canvas.mpl_connect('button_release_event', self.on_release)
 | ||
| 
 | ||
|     def on_press(self, event):
 | ||
|         if self.ax == event.inaxes:  
 | ||
| 
 | ||
|             for point in self.points:
 | ||
|                 point_x = point.get_xdata()
 | ||
|                 point_y = point.get_ydata()
 | ||
|                 distance = np.hypot(point_x - event.xdata, point_y - event.ydata)
 | ||
| 
 | ||
|                 if distance < 0.05:  # 可以根据需要调整这个阈值
 | ||
|                     self.selected_point = point
 | ||
|                     self.point_x = point.get_xdata()
 | ||
|                     self.point_y = point.get_ydata()
 | ||
|                     self.press = (point_x, point_y, event.xdata, event.ydata)
 | ||
|                     break
 | ||
| 
 | ||
|     def on_motion(self, event):
 | ||
|         
 | ||
|         if self.selected_point is None or event.inaxes != self.ax:
 | ||
|             return
 | ||
|         
 | ||
|         if self.signal_name == "ECG":
 | ||
|             # 计算点的新的位置
 | ||
|             self.new_x = self.press[0] + (event.xdata - self.press[2])
 | ||
| 
 | ||
|             self.real_y = self.signal_type[int(self.new_x*fs)]
 | ||
|             self.real_y = np.array([self.real_y]) #格式转换,从float64 转换成了 ndarray,为了set_data()能读取
 | ||
| 
 | ||
|             # 更新选中点的位置
 | ||
|             self.selected_point.set_data(self.new_x, self.real_y)
 | ||
|             self.ax.figure.canvas.draw()  # 使用 draw 更新
 | ||
|         
 | ||
|         else :
 | ||
|             # 计算点的新的位置
 | ||
|             self.new_x = self.press[0] + (event.xdata - self.press[2])
 | ||
| 
 | ||
|             self.real_y = self.signal_type[int(self.new_x*fs)]
 | ||
|             self.real_y = np.array([self.real_y]) #格式转换,从float64 转换成了 ndarray,为了set_data()能读取
 | ||
| 
 | ||
|             # 更新选中点的位置
 | ||
|             self.selected_point.set_data(self.new_x, self.real_y)
 | ||
|             self.ax.figure.canvas.draw()  # 使用 draw 更新
 | ||
| 
 | ||
|         
 | ||
| 
 | ||
|     def on_release(self, event):
 | ||
|         if self.selected_point:
 | ||
|             if self.signal_name == "ECG":
 | ||
|                 print("      点所属的信号          :",self.signal_name)
 | ||
|                 print("       点的坐标(t)          :",self.point_x, self.point_y)
 | ||
|                 print("     更新后点坐标(t)        :",np.round(self.new_x, 3)  , "[", self.real_y, "]" )
 | ||
|                 print("        点的位置            : ",int(self.point_x*fs))
 | ||
|                 print("     更新后点的位置         :",int(self.new_x*fs) )            
 | ||
|                 print("------------------------------------------")
 | ||
|             else:
 | ||
|                 print("      点所属的信号          :",self.signal_name)
 | ||
|                 print("       点的坐标(t)          :",self.point_x, self.point_y)
 | ||
|                 print("     更新后点坐标(t)        :",np.round(self.new_x, 3)  , "[", self.real_y, "]" )
 | ||
|                 print("        点的位置            : ",int(self.point_x*fs))
 | ||
|                 print("     更新后点的位置         :",int(self.new_x*fs) )            
 | ||
|                 print("------------------------------------------")
 | ||
| 
 | ||
|         self.selected_point = None
 | ||
|         self.press = None
 | ||
|         self.new_x = None
 | ||
| 
 | ||
| 
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #-----------------------------------           创建绘图函数       ----------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| 
 | ||
| def create_plot_with_draggable_points(save_path = None):
 | ||
| 
 | ||
|     fig, (ax1, ax2, ax3, ax4) = plt.subplots(4, 1, sharex=True)
 | ||
|     
 | ||
|     # 绘制归一化后的ECG信号
 | ||
| 
 | ||
|     ax1.plot(t_ecg, ecg_signal)
 | ||
|     ax1.set(xlabel='', ylabel='ECG')
 | ||
|   
 | ||
|     # 绘制归一化后的PPG信号
 | ||
|     ax2.plot(t_ppg, signal.ppg)
 | ||
|     ax2.set(xlabel='', ylabel='PPG')
 | ||
| 
 | ||
|     # 绘制归一化后的一阶导数
 | ||
|     ax3.plot(t_ppg, signal.vpg)
 | ||
|     ax3.set(xlabel='', ylabel='vpg')
 | ||
| 
 | ||
|     # 绘制归一化后的二阶导数
 | ||
|     ax4.plot(t_ppg, signal.apg)
 | ||
|     ax4.set(xlabel='Time (s)', ylabel='apg')
 | ||
| 
 | ||
|     # 存储并绘制这些点对象
 | ||
|     points_1 = [ax1.plot(x, y, 'o')[0] for x, y in zip(t_ecg[P_peaks], P_peaks_values)]
 | ||
|     points_1 += [ax1.plot(x, y, 'o', color='cyan')[0] for x, y in zip(t_ecg[Q_peaks], Q_peaks_values)]
 | ||
|     points_1 += [ax1.plot(x, y, 'o', color='purple')[0] for x, y in zip(t_ecg[R_peaks], R_peaks_values)]
 | ||
|     points_1 += [ax1.plot(x, y, 'o', color='blue')[0] for x, y in zip(t_ecg[S_peaks], S_peaks_values)]
 | ||
|     points_1 += [ax1.plot(x, y, 'o', color='black')[0] for x, y in zip(t_ecg[T_peaks], T_peaks_values)]
 | ||
|     points_1 += [ax1.plot(x, y, 'x', color='red')[0] for x, y in zip(t_ecg[P_onsets], P_onsets_values)]
 | ||
|     points_1 += [ax1.plot(x, y, 'x', color='magenta')[0] for x, y in zip(t_ecg[P_offsets], P_offsets_values)]
 | ||
|     points_1 += [ax1.plot(x, y, 'x', color='black')[0] for x, y in zip(t_ecg[T_onsets], T_onsets_values)]
 | ||
|     points_1 += [ax1.plot(x, y, 'x', color='gold')[0] for x, y in zip(t_ecg[T_offsets], T_offsets_values)]
 | ||
| 
 | ||
|     points_2 = [ax2.plot(x, y, 'o', color='red')[0] for x, y in zip(t_ppg[on], on_values)]
 | ||
|     points_2 += [ax2.plot(x, y, 'o', color='blue')[0] for x, y in zip(t_ppg[sp], sp_values)]
 | ||
|     points_2 += [ax2.plot(x, y, 'x', color='orange')[0] for x, y in zip(t_ppg[dn], dn_values)]
 | ||
|     points_2 += [ax2.plot(x, y, 'o', color='purple')[0] for x, y in zip(t_ppg[dp], dp_values)]
 | ||
| 
 | ||
|     points_3 = [ax3.plot(x, y, 'o', color='cyan')[0] for x, y in zip(t_ppg[u], u_values)]
 | ||
|     points_3 += [ax3.plot(x, y, 'o', color='magenta')[0] for x, y in zip(t_ppg[v], v_values)]
 | ||
|     points_3 += [ax3.plot(x, y, 'o', color='black')[0] for x, y in zip(t_ppg[w], w_values)]
 | ||
| 
 | ||
|     points_4 = [ax4.plot(x, y, 'o', color='black')[0] for x, y in zip(t_ppg[a], a_values)]
 | ||
|     points_4 += [ax4.plot(x, y, 'o', color='blue')[0] for x, y in zip(t_ppg[b], b_values)]
 | ||
|     points_4 += [ax4.plot(x, y, 'o', color='green')[0] for x, y in zip(t_ppg[c], c_values)]
 | ||
|     points_4 += [ax4.plot(x, y, 'o', color='orange')[0] for x, y in zip(t_ppg[e], e_values)]
 | ||
|     points_4 += [ax4.plot(x, y, 'o', color='purple')[0] for x, y in zip(t_ppg[f], f_values)]
 | ||
| 
 | ||
| 
 | ||
|     draggable_points_1 = DraggablePoints(ax1, points_1, ecg_signal, signal_name = "ECG")  
 | ||
|     draggable_points_2 = DraggablePoints(ax2, points_2, signal.ppg, signal_name = "PPG")
 | ||
|     draggable_points_3 = DraggablePoints(ax3, points_3, signal.vpg, signal_name = "VPG")
 | ||
|     draggable_points_4 = DraggablePoints(ax4, points_4, signal.apg, signal_name = "APG")
 | ||
| 
 | ||
|     # 如果指定了保存路径,则保存图像
 | ||
|     if save_path:
 | ||
|         plt.savefig(save_path)
 | ||
| 
 | ||
|     plt.tight_layout()
 | ||
|     plt.show()
 | ||
| 
 | ||
| 
 | ||
|     # 将图形嵌入到 Qt 的 canvas 中
 | ||
|     # canvas.figure = fig
 | ||
|     # canvas.draw()
 | ||
| 
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #-----------------------------------          调用绘图函数        ----------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| #--------------------------------------------------------------------------------------------------------
 | ||
| 
 | ||
| if __name__ == '__main__':
 | ||
|     print(len(P_peaks))
 | ||
|     print(len(Q_peaks))
 | ||
|     print(len(R_peaks))
 | ||
|     print(len(S_peaks))
 | ||
|     print(len(T_peaks))
 | ||
| 
 | ||
|     print(len(P_onsets))
 | ||
|     print(len(P_offsets))
 | ||
|     print(len(T_onsets))
 | ||
|     print(len(T_offsets))
 | ||
| 
 | ||
|     print(len(u))
 | ||
|     print(len(v))
 | ||
|     print(len(w))
 | ||
|     
 | ||
|     print(len(a))
 | ||
|     print(len(b))
 | ||
|     print(len(c))
 | ||
|     print(len(e))
 | ||
|     print(len(f))
 | ||
| 
 | ||
|     create_plot_with_draggable_points()
 |