如何将II导联单图添加到12导联ECG网格图中模拟打印输出
12导联ECG打印式波形绘制解决方案
需求概述
- 上方采用3×4网格布局,展示12导联各2.5秒的截断波形
- 底部添加II导联的完整10秒波形(模拟临床ECG打印件样式)
- 自动调整网格线密度,匹配标准ECG打印件的1mm小格/5mm大格规范
- 解决多图合并时坐标轴混乱、布局错位的问题
完整实现代码
import numpy as np import matplotlib.pyplot as plt from matplotlib.gridspec import GridSpec # ---------------------- 模拟ECG数据生成 ---------------------- def generate_ecg_data(sampling_rate=250, duration=10): """生成模拟12导联ECG数据""" t = np.linspace(0, duration, int(sampling_rate * duration)) # 基础心电波形(QRS波、P波、T波) def ecg_wave(t): qrs = np.exp(-((t - 0.2)**2)/0.001) - 0.5*np.exp(-((t - 0.22)**2)/0.0005) p_wave = 0.3*np.exp(-((t - 0.1)**2)/0.002) t_wave = 0.4*np.exp(-((t - 0.3)**2)/0.003) return p_wave + qrs + t_wave + 0.1*np.random.randn(len(t)) # 12导联:I, II, III, aVR, aVL, aVF, V1-V6 leads = [] for i in range(12): # 每个导联添加微小差异模拟实际数据 wave = ecg_wave(t % 0.8) + 0.05*i*np.sin(2*np.pi*0.5*t) leads.append(wave) return t, np.array(leads) # ---------------------- 绘图核心逻辑 ---------------------- def plot_ecg_print_style(t, ecg_leads, sampling_rate=250): # 标准ECG网格参数:25mm/s(0.04s/mm),10mm/mV(0.1mV/mm) small_grid_x = 0.04 # 小格时间间隔(秒) large_grid_x = 0.2 # 大格时间间隔(秒) small_grid_y = 0.1 # 小格电压间隔(mV) large_grid_y = 0.5 # 大格电压间隔(mV) # 初始化画布,设置合适的尺寸(模拟打印纸比例) fig = plt.figure(figsize=(12, 8), dpi=100) # 使用GridSpec布局:上方3行4列,底部1行1列 gs = GridSpec(4, 4, figure=fig, height_ratios=[1,1,1,2]) # ---------------------- 绘制3×4导联网格(2.5秒截断) ---------------------- lead_names = ['I', 'II', 'III', 'aVR', 'aVL', 'aVF', 'V1', 'V2', 'V3', 'V4', 'V5', 'V6'] # 2.5秒对应的采样点索引 truncate_idx = int(2.5 * sampling_rate) t_trunc = t[:truncate_idx] for i in range(12): row = i // 4 col = i % 4 ax = fig.add_subplot(gs[row, col]) # 绘制导联波形 ax.plot(t_trunc, ecg_leads[i][:truncate_idx], color='black', linewidth=0.8) # 设置网格线:先画大格(灰色粗线),再画小格(浅灰色细线) ax.grid(True, which='major', linestyle='-', linewidth=1, color='#cccccc') ax.grid(True, which='minor', linestyle='-', linewidth=0.5, color='#eeeeee') # 设置主副刻度间隔 ax.set_xticks(np.arange(0, 2.6, large_grid_x)) ax.set_xticks(np.arange(0, 2.6, small_grid_x), minor=True) ax.set_yticks(np.arange(-1.5, 1.6, large_grid_y)) ax.set_yticks(np.arange(-1.5, 1.6, small_grid_y), minor=True) # 调整坐标轴范围,匹配ECG标准 ax.set_xlim(0, 2.5) ax.set_ylim(-1.5, 1.5) # 添加导联名称 ax.set_title(lead_names[i], fontsize=10, y=0.9) # 隐藏底部x轴刻度(避免重叠) if row != 2: ax.set_xticklabels([]) else: ax.set_xlabel('Time (s)', fontsize=8) # 统一y轴标签 ax.set_ylabel('mV', fontsize=8) ax.tick_params(axis='both', labelsize=7) # ---------------------- 绘制底部II导联完整10秒波形 ---------------------- ax_bottom = fig.add_subplot(gs[3, :]) lead_ii_idx = lead_names.index('II') ax_bottom.plot(t, ecg_leads[lead_ii_idx], color='black', linewidth=0.8) # 设置网格线 ax_bottom.grid(True, which='major', linestyle='-', linewidth=1, color='#cccccc') ax_bottom.grid(True, which='minor', linestyle='-', linewidth=0.5, color='#eeeeee') # 主副刻度间隔匹配标准 ax_bottom.set_xticks(np.arange(0, 10.1, large_grid_x)) ax_bottom.set_xticks(np.arange(0, 10.1, small_grid_x), minor=True) ax_bottom.set_yticks(np.arange(-1.5, 1.6, large_grid_y)) ax_bottom.set_yticks(np.arange(-1.5, 1.6, small_grid_y), minor=True) # 坐标轴范围与标签 ax_bottom.set_xlim(0, 10) ax_bottom.set_ylim(-1.5, 1.5) ax_bottom.set_xlabel('Time (s)', fontsize=10) ax_bottom.set_ylabel('Lead II (mV)', fontsize=10) ax_bottom.tick_params(axis='both', labelsize=8) # 调整子图间距,避免重叠 plt.tight_layout() return fig # ---------------------- 运行示例 ---------------------- if __name__ == '__main__': sampling_rate = 250 t, ecg_leads = generate_ecg_data(sampling_rate=sampling_rate) fig = plot_ecg_print_style(t, ecg_leads, sampling_rate=sampling_rate) plt.savefig('ecg_print_style.png', dpi=150, bbox_inches='tight') plt.show()
关键细节说明
- 布局控制:使用
GridSpec精确分配上下区域的高度比例,避免手动调整子图位置带来的坐标轴错位问题 - 网格线匹配:严格按照临床ECG打印件标准设置主副刻度间隔,大格为5mm对应0.2秒(x轴)/0.5mV(y轴),小格为1mm对应0.04秒/0.1mV
- 坐标轴优化:隐藏上方网格的多余x轴刻度,统一标签样式,避免多图合并后的视觉混乱
- 批量生成适配:代码支持直接循环调用
plot_ecg_print_style生成大量图片,网格与布局参数无需手动调整
内容的提问来源于stack exchange,提问作者leoverflow
相关产品推荐
相关产品推荐

