You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Matplotlib中固定Y轴范围并隐藏非整数刻度

心电数据可视化Y轴问题解决

我正在使用Matplotlib开展数据可视化工作,当前使用plot_delineation_comparison函数绘制心电数据对比图(示例图:心电对比图示例),相关代码如下:

#@title Visualizer Function

def plot_delineation_comparison(Xt, yt, Xp, yp, start, stop=None, rec_name = '-', lead_name = '-', pathology_name = '-'):

  if stop is None:
    stop = -1

  Xt = Xt[start:stop]
  yt = yt[start:stop]
  Xp = Xp[start:stop]
  yp = yp[start:stop]

  # Get mask of every class for prediction
  bl_pred = yp == 0
  p_pred = yp == 1
  qrs_pred = yp == 2
  t_pred = yp == 3

  # Get mask of every class for ground truth
  bl_true = yt == 0
  p_true = yt == 1
  qrs_true = yt == 2
  t_true = yt == 3

  # Create figure with two rows and one column
  fig, (ax1, ax2) = plt.subplots(
    2,
    1,
    figsize=(16, 8),
    sharex=True,
    gridspec_kw={"hspace": 0},
  )

  # Plotting for prediction
  prev_class = None
  start_idx = 0
  for i in range(stop - start):
    current_class = None
    if bl_pred[i]:
      current_class = 'grey'
    elif p_pred[i]:
      current_class = 'orange'
    elif qrs_pred[i]:
      current_class = 'green'
    elif t_pred[i]:
      current_class = 'purple'

    if current_class != prev_class:
      if prev_class is not None:
        ax2.axvspan(start_idx, i, color=prev_class, alpha=0.5)
      start_idx = i
      prev_class = current_class
  # Fill the last region
  if prev_class is not None:
      ax2.axvspan(start_idx, stop - start, color=prev_class, alpha=0.5)

  # Plotting for ground truth
  prev_class = None
  start_idx = 0
  for i in range(stop - start):
    current_class = None
    if bl_true[i]:
      current_class = 'grey'
    elif p_true[i]:
      current_class = 'orange'
    elif qrs_true[i]:
      current_class = 'green'
    elif t_true[i]:
      current_class = 'purple'

    if current_class != prev_class:
      if prev_class is not None:
        ax1.axvspan(start_idx, i, color=prev_class, alpha=0.5)
      start_idx = i
      prev_class = current_class
  # Fill the last region
  if prev_class is not None:
    ax1.axvspan(start_idx, stop - start, color=prev_class, alpha=0.5)

  # First row for ground truth (X_unseen, y_true)
  ax1.plot(Xt, color='blue')
  ax1.set_ylabel('Ground Truth')

  # draw baseline at y=0
  ax1.axhline(y=0, color='red', linestyle='-', lw=0.5)

  # Second row for ground truth (X_pred y_pred)
  ax2.plot(Xp, color='blue')
  ax2.axhline(y=0, color='red', linestyle='-', lw=0.5)
  ax2.set_xlim([0, stop - start])
  ax2.set_ylabel('Prediction')
  ax2.set_xlabel('Index')

  # Retrieve the current x-tick locations
  current_xticks = ax2.get_xticks()

  # Define the new x-tick labels based on absolute start and end
  new_xtick_labels = [int(x + start) for x in current_xticks]

  with warnings.catch_warnings():
    warnings.simplefilter("ignore", UserWarning)
    ax2.set_xticklabels(new_xtick_labels)

  cm = ConfusionMatrix(actual_vector=yt.flatten(), predict_vector=yp.flatten(), transpose=True)

  # Handle if not number type
  cm.PPV = [0 if not type(x) == float else x for _,x in cm.PPV.items()]
  cm.TPR = [0 if not type(x) == float else x for _,x in cm.TPR.items()]

  # Make length of PPV and TPR consistent, fill with zero if not
  if len(cm.PPV) < 4:
    cm.PPV += [0] * (4 - len(cm.PPV))
  if len(cm.TPR) < 4:
    cm.TPR += [0] * (4 - len(cm.TPR))
  if len(cm.F1) < 4:
    # convert F1 to list and fixed it with length 4
    cm.F1 = list(cm.F1.values())
    cm.F1 += [0] * (4 - len(cm.F1))

  notes_list = [
    f"Recall",
    f"BL         : {cm.TPR[0]:.2f}",
    f"P          : {cm.TPR[1]:.2f}",
    f"QRS        : {cm.TPR[2]:.2f}",
    f"T          : {cm.TPR[3]:.2f}",
    f"",
    f"Rec Name   : {rec_name}",
    f"Lead       : {lead_name}",
    f"Pathology  : {pathology_name}",
    f"Unit       : mV",
    f"Sample Rate: 360Hz",
    f"SNR(Pr./GT): {calculate_snr(Xp, Xt)}dB",
    f"",
    f"Precission",
    f"BL         : {cm.PPV[0]:.2f}",
    f"P          : {cm.PPV[1]:.2f}",
    f"QRS        : {cm.PPV[2]:.2f}",
    f"T          : {cm.PPV[3]:.2f}",
  ]

  # notes_list += catatan

  ax1.set_title(f"F1-Score | BL: {cm.F1[0]:.2f} | P: {cm.F1[1]:.2f} | QRS: {cm.F1[2]:.2f} | T: {cm.F1[3]:.2f}")

  code_font = FontProperties(family='monospace', style='normal', variant='normal', size=8)

  for i, note in enumerate(notes_list[:]):
    plt.text(1.01, 0.95 - i * 0.1, note, transform=ax1.transAxes, fontsize=10, va='top', ha='left', fontproperties=code_font)

  # for i, note in enumerate(notes_list[5:]):
    # plt.text(1.01, 0.95 - i * 0.1, note, transform=ax2.transAxes, fontsize=10, va='top', ha='left', fontproperties=code_font)

  plt.subplots_adjust(top=0.5)

  # add legend with offset


  # Create custom Line2D objects with desired colors
  custom_lines = [
    Line2D([0], [0], color='grey', lw=4, alpha=0.5),
    Line2D([0], [0], color='orange', lw=4, alpha=0.5),
    Line2D([0], [0], color='green', lw=4, alpha=0.5),
    Line2D([0], [0], color='purple', lw=4, alpha=0.5)
  ]

  # Add legend with custom lines
  ax1.legend(custom_lines, ['BL', 'P', 'QRS', 'T'], loc='upper left')

  plt.show()

问题描述

当前遇到两个Y轴显示问题:

  • Y轴存在非整数刻度,需隐藏这些刻度仅保留整数
  • 需将两个子图的Y轴范围固定在-2到2,确保子图间Y轴显示一致

解决方案

在函数中添加Y轴配置代码,具体修改如下:

1. 导入必要工具

在文件顶部或函数开头添加:

from matplotlib.ticker import MultipleLocator

2. 添加Y轴设置代码

在绘制完基线后(ax1.axhline(...)之后)插入以下代码:

# 固定两个子图的Y轴范围为-2到2
ax1.set_ylim(-2, 2)
ax2.set_ylim(-2, 2)

# 设置Y轴仅显示整数刻度
# 主刻度间隔设为1(整数)
ax1.yaxis.set_major_locator(MultipleLocator(1))
ax2.yaxis.set_major_locator(MultipleLocator(1))

# 隐藏次要刻度(非整数刻度)
ax1.yaxis.set_minor_locator(MultipleLocator(0.5))
ax1.yaxis.set_minor_formatter(plt.NullFormatter())
ax2.yaxis.set_minor_locator(MultipleLocator(0.5))
ax2.yaxis.set_minor_formatter(plt.NullFormatter())

修改后代码位置示例

# draw baseline at y=0
ax1.axhline(y=0, color='red', linestyle='-', lw=0.5)

# ========= 新增Y轴配置 =========
from matplotlib.ticker import MultipleLocator
# 固定Y轴范围
ax1.set_ylim(-2, 2)
ax2.set_ylim(-2, 2)
# 设置整数刻度
ax1.yaxis.set_major_locator(MultipleLocator(1))
ax2.yaxis.set_major_locator(MultipleLocator(1))
# 隐藏次要刻度
ax1.yaxis.set_minor_locator(MultipleLocator(0.5))
ax1.yaxis.set_minor_formatter(plt.NullFormatter())
ax2.yaxis.set_minor_locator(MultipleLocator(0.5))
ax2.yaxis.set_minor_formatter(plt.NullFormatter())
# ==============================

# Second row for ground truth (X_pred y_pred)
ax2.plot(Xp, color='blue')
ax2.axhline(y=0, color='red', linestyle='-', lw=0.5)

修改完成后,两个子图的Y轴会被锁定在-2到2的范围,且仅显示整数刻度,完全满足需求。

内容的提问来源于stack exchange,提问作者Muhammad Ikhwan Perwira

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 00:45:54