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

Matplotlib循环绘图:多ID数据同图实现断轴子图叠加

解决DataFrame多ID断轴图叠加在同一画布的问题

需求说明

我有一个包含多个ID的DataFrame,希望为每个ID绘制断轴图,且所有图形都叠加在同一个figure中,而非每个ID对应单独figure。当前示例代码生成多个独立figure,需要实现如下叠加效果。

示例数据与原代码

import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame({'id':['id1','id1','id1','id1','id1','id1','id1','id1','id1','id1',
                   'id2','id2','id2','id2','id2','id2','id2','id2','id2','id2'],
               'x': [0, 1, 2, 3, 4, 5, 1000, 2000, 3000, 4000,
                     0, 1, 2, 3, 4, 5, 1000, 2000, 3000, 4000,],
               'y': [5, 4, 5, 4, 7, 6, 5, 4, 3, 2,
                     1, 2, 3, 4, 7, 7, 8, 7, 9, 5]})

def _custom_plot(frame):
    x = frame['x']
    y = frame['y']
    
    f,(ax,ax2) = plt.subplots(1,2,sharey=True, facecolor='w', figsize=(15, 5))

    # plot the same data on both axes
    ax.plot(x, y, 'o--', color='grey', alpha=0.3)
    ax2.plot(x, y, 'o--', color='grey', alpha=0.3)

    ax.set_xlim(0,100)
    ax2.set_xlim(1e3,5e3)

    # hide the spines between ax and ax2
    ax.spines['right'].set_visible(False)
    ax2.spines['left'].set_visible(False)
    ax.yaxis.tick_left()
    ax2.yaxis.tick_right()

    d = .015 # how big to make the diagonal lines in axes coordinates
    # arguments to pass plot, just so we don't keep repeating them
    kwargs = dict(transform=ax.transAxes, color='k', clip_on=False)
    ax.plot((1-d,1+d), (-d,+d), **kwargs)
    ax.plot((1-d,1+d),(1-d,1+d), **kwargs)

    kwargs.update(transform=ax2.transAxes)  # switch to the bottom axes
    ax2.plot((-d,+d), (1-d,1+d), **kwargs)
    ax2.plot((-d,+d), (-d,+d), **kwargs)
    
    plt.yticks([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    
    plt.show()
        

for id in df['id'].unique():
    _custom_plot(df[df['id']==id])

当前效果

当前效果

期望效果

期望效果

解决方案

修改思路

  1. 提前创建全局的断轴画布(两个子轴),避免循环中重复生成新figure
  2. 让绘图函数接收已创建的轴对象,在指定轴上绘制每个ID的曲线
  3. 为不同ID设置差异化的样式(颜色、标记),提升辨识度
  4. 统一在最后配置断轴样式、轴范围和显示参数,减少重复操作

修改后的代码

import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame({'id':['id1','id1','id1','id1','id1','id1','id1','id1','id1','id1',
                   'id2','id2','id2','id2','id2','id2','id2','id2','id2','id2'],
               'x': [0, 1, 2, 3, 4, 5, 1000, 2000, 3000, 4000,
                     0, 1, 2, 3, 4, 5, 1000, 2000, 3000, 4000,],
               'y': [5, 4, 5, 4, 7, 6, 5, 4, 3, 2,
                     1, 2, 3, 4, 7, 7, 8, 7, 9, 5]})

# 定义样式映射,区分不同ID
style_map = {
    'id1': ('o--', '#1f77b4'),
    'id2': ('s-.', '#ff7f0e')
}

def _custom_plot(frame, ax, ax2, style):
    x = frame['x']
    y = frame['y']
    # 在已有的轴上绘图
    ax.plot(x, y, style[0], color=style[1], alpha=0.8, label=frame['id'].iloc[0])
    ax2.plot(x, y, style[0], color=style[1], alpha=0.8)

# 提前创建全局画布和轴
f,(ax,ax2) = plt.subplots(1,2,sharey=True, facecolor='w', figsize=(15, 5))

# 循环每个ID绘图
for id in df['id'].unique():
    subset = df[df['id']==id]
    _custom_plot(subset, ax, ax2, style_map[id])

# 统一设置轴范围
ax.set_xlim(0,100)
ax2.set_xlim(1e3,5e3)

# 隐藏中间的轴脊
ax.spines['right'].set_visible(False)
ax2.spines['left'].set_visible(False)
ax.yaxis.tick_left()
ax2.yaxis.tick_right()

# 添加断轴斜线
d = .015 
kwargs = dict(transform=ax.transAxes, color='k', clip_on=False)
ax.plot((1-d,1+d), (-d,+d), **kwargs)
ax.plot((1-d,1+d),(1-d,1+d), **kwargs)

kwargs.update(transform=ax2.transAxes)
ax2.plot((-d,+d), (1-d,1+d), **kwargs)
ax2.plot((-d,+d), (-d,+d), **kwargs)

# 设置刻度和图例
plt.yticks(range(0,10))
ax.legend()

plt.tight_layout()
plt.show()

关键说明

  • 全局画布创建:将plt.subplots移到循环外,确保所有绘图都在同一个figure中进行
  • 样式映射:通过字典为每个ID分配独特的线条样式和颜色,方便区分不同曲线
  • 轴对象传递:绘图函数接收已有的ax和ax2,直接在上面绘制数据,避免重复创建轴
  • 统一配置:将轴范围、断轴样式、刻度设置等操作放在循环后,只执行一次,提升效率

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 06:15:33