将单图附加到多图网格以模拟心电图打印输出

问题描述 投票:0回答:1

我正在尝试绘制心电图波形数据以复制 12 导联心电图打印输出的样子,其中所有导联为 3X4 网格(截断为 2.5 秒),导联 II 的完整 10 秒波形位于底部,类似到附图(但底部有引线 II)。 ECG printout

我能够使多图和单导 II 图很好,但在将它们附加在一起而不弄乱轴时遇到困难。这是我的代码:

import os, numpy as np,pandas as pd,sys,random,matplotlib.pyplot as plt,matplotlib.ticker as ticker,os,pprint
from matplotlib.ticker import AutoLocator, AutoMinorLocator
from scipy.io import loadmat
from tqdm import tqdm 

def plot_individual(ax, x, y,label):
    ax.plot(x, y, color='black', linewidth=0.5)
    ax.minorticks_on()
    #ax.xaxis.set_major_locator(ticker.MultipleLocator(200))
    #ax.yaxis.set_major_locator(ticker.MultipleLocator(10))
    ax.xaxis.set_major_locator(AutoLocator())
    ax.xaxis.set_minor_locator(AutoMinorLocator())
    ax.yaxis.set_major_locator(AutoLocator())
    ax.yaxis.set_minor_locator(AutoMinorLocator())
    ax.annotate(label, xy=(0.02, 0.50), xycoords='axes fraction', fontsize=12, ha='left', va='bottom', fontfamily='serif')
    ax.grid(which='major', linestyle='-', linewidth='0.5', color='red')
    ax.grid(which='minor', linestyle='-', linewidth='0.5', color=(1, 0.7, 0.7))
    ax.tick_params(which='both', left=False, bottom=False, labelleft=False, labelbottom=False)
    ax.spines['top'].set_visible(False)  # Hide the top spine
    ax.spines['right'].set_visible(False)  # Hide the right spine
    ax.spines['bottom'].set_visible(False)  # Hide the bottom spine
    ax.spines['left'].set_visible(False)  # Hide the left spine
    ax.set_facecolor('white')


def plot_12(plot_df):
    x = [i for i in range(1250)]
    df_12 = plot_df.T
    df_short = df_12.iloc[:,0:1250]
    df_short = df_short.T
    df_short = df_short[['I','aVR','V1','V4','II','aVL','V2','V5','III','aVF','V3','V6']].T

    fig, axs = plt.subplots(3,4, figsize=(16,9),sharex=True,sharey=True, gridspec_kw={'wspace': 0,'hspace':0})  # Adjust figsize as desired
    plt.subplots_adjust(
            hspace = 0, 
            wspace = 0.04,
            left   = 0.04,  # the left side of the subplots of the figure
            right  = 0.98,  # the right side of the subplots of the figure
            bottom = 0.06,  # the bottom of the subplots of the figure
            top    = 0.95)
    num_columns = 1250

    for i, (idx, row) in enumerate(df_short.iterrows()):
        x_vals = [i for i in range(1250)]
        y_vals = row.to_list()
        plotvals = pd.DataFrame({'x':x_vals,'y':y_vals})
        x = plotvals['x']
        y=plotvals['y']
        ax = axs[i // 4, i % 4] 
        plot_individual(ax, x, y,label=idx)
    #return fig, axs

    #plt.tight_layout()  # Adjust the spacing between subplots
    plt.show()
    #plt.savefig(save_path, dpi=300)
    #plt.close()
plot_12(plot_df)

def plot_ii(plot_df):
    df_ii = plot_df
    df_ii = df_ii['II']

    fig_ii, ax_ii = plt.subplots(figsize=(16,3))

    x_vals = [i for i in range(5000)]
    y_vals = df_ii.to_list()
    plotvals = pd.DataFrame({'x':x_vals,'y':y_vals})
    x = plotvals['x']
    y=plotvals['y']

    plot_individual(ax_ii, x, y,label='II')
    
    #return fig, ax

    #plt.show()

plot_ii(plot_df)


这是一些模拟数据的代码:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# Define parameters
sampling_rate = 1000    # Samples per second
total_rows = 5000       # Total number of rows
duration = total_rows / sampling_rate  # Duration of the ECG signal in seconds
num_samples = total_rows
time = np.linspace(0, duration, num_samples)

# Create baseline ECG waveform (sinus rhythm)
heart_rate = 75  # Beats per minute
heartbeat_duration = 60 / heart_rate
baseline_ecg = np.sin(2 * np.pi * time / heartbeat_duration)

# Create noise
noise = np.random.normal(0, 0.1, num_samples)

# Simulate 12-lead ECG data
leads = {
    'I': baseline_ecg + noise,
    'II': baseline_ecg + 0.5 * np.roll(baseline_ecg, -sampling_rate) + noise,
    'III': 0.5 * np.roll(baseline_ecg, -sampling_rate) + noise,
    'aVR': -0.5 * baseline_ecg + noise,
    'aVL': baseline_ecg - 0.5 * np.roll(baseline_ecg, -sampling_rate) + noise,
    'aVF': baseline_ecg - 0.5 * baseline_ecg + noise,
    'V1': 0.1 * baseline_ecg + noise,
    'V2': 0.2 * baseline_ecg + noise,
    'V3': 0.3 * baseline_ecg + noise,
    'V4': 0.4 * baseline_ecg + noise,
    'V5': 0.5 * baseline_ecg + noise,
    'V6': 0.6 * baseline_ecg + noise,
}

# Create a DataFrame to store the leads
ecg_dataframe = pd.DataFrame(data=leads, index=time)

如果您可以调整代码以使网格线像心电图打印输出一样自动靠得更近,那就加分了 - 我有数十万张图像,因此需要自动进行。谢谢!

尝试了各种版本的更改轴、在多图上腾出空间以及更改网格空间以添加 LeadII

python matplotlib plot graphing
1个回答
0
投票

首先,准备好了样本数据,谢谢!

对于您的解决方案,我遵循了 matplotlib example

要附加你的图,以下内容对我有用:

fig = plt.figure(figsize=(16,12))
subfigs = fig.subfigures(2, 1, wspace=0.07, height_ratios=[3, 1])
plot_12(plot_df, subfigs[0])

plot_ii(plot_df, subfigs[1])
plt.show()

虽然我必须对你的功能进行一些调整:

def plot_12(plot_df, subfig): # <-- added subfig as an argument
    x = [i for i in range(1250)]
    df_12 = plot_df.T
    df_short = df_12.iloc[:, 0:1250]
    df_short = df_short.T
    df_short = df_short[['I', 'aVR', 'V1', 'V4', 'II', 'aVL', 'V2', 'V5', 'III', 'aVF', 'V3', 'V6']].T

    # removed fig, as subfig.subplots only returns one object
    axs = subfig.subplots(3, 4, sharex=True, sharey=True,
                            gridspec_kw={'wspace': 0, 'hspace': 0})  # Adjust figsize as desired
    subfig.subplots_adjust(
        hspace=0,
        wspace=0.04,
        left=0.0,  # the left side of the subplots of the figure <--- changed for your second question
        right=1.,  # the right side of the subplots of the figure <--- changed for your second question
        bottom=0.06,  # the bottom of the subplots of the figure
        top=0.95)
    num_columns = 1250

    for i, (idx, row) in enumerate(df_short.iterrows()):
        x_vals = [i for i in range(1250)]
        y_vals = row.to_list()
        plotvals = pd.DataFrame({'x': x_vals, 'y': y_vals})
        x = plotvals['x']
        y = plotvals['y']
        ax = axs[i // 4, i % 4]
        plot_individual(ax, x, y, label=idx)

def plot_ii(plot_df, subfig): # <-- added subfig as an argument
    df_ii = plot_df
    df_ii = df_ii['II']

    # removed fig_ii, as subfig.subplots only returns one object
    ax_ii = subfig.subplots()

    x_vals = [i for i in range(5000)]
    y_vals = df_ii.to_list()
    plotvals = pd.DataFrame({'x': x_vals, 'y': y_vals})
    x = plotvals['x']
    y = plotvals['y']

    plot_individual(ax_ii, x, y, label='II')

关于你的第二个问题。我必须更改plot_12 中的左右调整(请参阅上面的评论)。此外,还需要添加以下内容,否则 matplotlib 似乎会自行调整限制,而您希望有明确定义的限制:

def plot_individual(..., limits):
    ...
    ax.set_xlim(limits)

在您的示例中,plot_12需要调用plot_individual(),且limits = [0, 1200],否则主要刻度线不会正确出现。

希望有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.