我正在尝试绘制心电图波形数据以复制 12 导联心电图打印输出的样子,其中所有导联为 3X4 网格(截断为 2.5 秒),导联 II 的完整 10 秒波形位于底部,类似到附图(但底部有引线 II)。
我能够使多图和单导 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
首先,准备好了样本数据,谢谢!
对于您的解决方案,我遵循了 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],否则主要刻度线不会正确出现。
希望有帮助。