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

Python中如何在Matplotlib子图间添加跨子图连接线?

问题描述

我现有单图绘制代码(可添加竖线):

mid = d[d.Position==0].Price.mean()
b_a = d[(d.Position==0) & (d.Side == 0)].Price.values
b_b = d[(d.Position==0) & (d.Side == 1)].Price.values

f, ax = plt.subplots()
sns.set_color_codes('muted')

sns.barplot(data = d[d.Side==0], x = 'Price', y = 'Size', color = 'b',  native_scale=True)
sns.barplot(data = d[d.Side==1], x = 'Price', y = 'Size', color = 'r',  native_scale=True)

ax.xaxis.set_major_locator(ticker.MultipleLocator(.0001))
plt.axvline(x=mid, color = 'b', lw = 1.5)
plt.axvline(x=b_a, color = 'k', lw = 1, ls='--')
plt.axvline(x=b_b, color = 'k', lw = 1, ls='--')

数据示例:

Position    Operation   Side    Price   Size
9   9   0   1   0.7289  -16
8   8   0   1   0.729   -427
7   7   0   1   0.7291  -267
6   6   0   1   0.7292  -15
5   5   0   1   0.7293  -16
4   4   0   1   0.7294  -16
3   3   0   1   0.7295  -426
2   2   0   1   0.7296  -8
1   1   0   1   0.7297  -14
0   0   0   1   0.7298  -37
10  0   0   0   0.7299  6
11  1   0   0   0.73    34
12  2   0   0   0.7301  7
13  3   0   0   0.7302  9
14  4   0   0   0.7303  16
15  5   0   0   0.7304  15
16  6   0   0   0.7305  429
17  7   0   0   0.7306  16
18  8   0   0   0.7307  265
19  9   0   0   0.7308  18

我计划用Matplotlib的subplots绘制多个此类子图,代码如下:

cnt = 5

f, ax = plt.subplots(cnt, 1, sharex=True)
sns.set_color_codes('muted')

for i in range(cnt):
    sns.barplot(x = x.iloc[i, 10:].values, y = y.iloc[i, 10:].values, color = 'b',  native_scale=True, ax = ax[i])
    sns.barplot(x = x.iloc[i, :10].values, y = y.iloc[i, 10:].values, color = 'r',  native_scale=True, ax = ax[i])
    ax[i].xaxis.set_major_locator(ticker.MultipleLocator(.0001))

请问是否可以在这些子图之间添加连接线,类似示例图中的效果?


解决方案

完全可以在子图之间添加连接线。核心思路是利用Matplotlib的transFigure画布坐标系,将子图内的关键竖线端点坐标转换为画布坐标,再在相邻子图的对应端点间绘制线段。

结合你的代码,修改后的实现如下:

import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib.ticker as ticker

cnt = 5

# 预计算每个子图的关键竖线位置(实际使用时替换为你的真实计算逻辑)
mid_list = [0.7299 + i*0.0001 for i in range(cnt)]
b_a_list = [0.73 + i*0.0001 for i in range(cnt)]
b_b_list = [0.7298 + i*0.0001 for i in range(cnt)]

f, ax = plt.subplots(cnt, 1, sharex=True, figsize=(8, 10))
sns.set_color_codes('muted')

# 先绘制所有子图和内部竖线,同时记录关键端点坐标
for i in range(cnt):
    # 绘制买卖盘柱状图
    sns.barplot(x=x.iloc[i, 10:].values, y=y.iloc[i, 10:].values, color='b', native_scale=True, ax=ax[i])
    sns.barplot(x=x.iloc[i, :10].values, y=y.iloc[i, 10:].values, color='r', native_scale=True, ax=ax[i])
    ax[i].xaxis.set_major_locator(ticker.MultipleLocator(.0001))
    
    # 绘制子图内的竖线
    ax[i].axvline(x=mid_list[i], color='b', lw=1.5)
    ax[i].axvline(x=b_a_list[i], color='k', lw=1, ls='--')
    ax[i].axvline(x=b_b_list[i], color='k', lw=1, ls='--')
    
    # 转换坐标:子图数据坐标 → 画布坐标
    y_top = ax[i].get_ylim()[1]
    y_bottom = ax[i].get_ylim()[0]
    
    mid_pos_top = ax[i].transData.transform((mid_list[i], y_top))
    b_a_pos_top = ax[i].transData.transform((b_a_list[i], y_top))
    b_b_pos_top = ax[i].transData.transform((b_b_list[i], y_top))
    
    mid_pos_bottom = ax[i].transData.transform((mid_list[i], y_bottom))
    b_a_pos_bottom = ax[i].transData.transform((b_a_list[i], y_bottom))
    b_b_pos_bottom = ax[i].transData.transform((b_b_list[i], y_bottom))
    
    # 相邻子图间连线
    if i > 0:
        # 连接mid线
        line_mid = plt.Line2D([prev_mid_top[0], mid_pos_bottom[0]], 
                              [prev_mid_top[1], mid_pos_bottom[1]],
                              color='b', lw=1.5, transform=f.transFigure)
        f.add_artist(line_mid)
        
        # 连接b_a线
        line_a = plt.Line2D([prev_b_a_top[0], b_a_pos_bottom[0]], 
                            [prev_b_a_top[1], b_a_pos_bottom[1]],
                            color='k', lw=1, ls='--', transform=f.transFigure)
        f.add_artist(line_a)
        
        # 连接b_b线
        line_b = plt.Line2D([prev_b_b_top[0], b_b_pos_bottom[0]], 
                            [prev_b_b_top[1], b_b_pos_bottom[1]],
                            color='k', lw=1, ls='--', transform=f.transFigure)
        f.add_artist(line_b)
    
    # 更新上一个子图的顶部坐标
    prev_mid_top = mid_pos_top
    prev_b_a_top = b_a_pos_top
    prev_b_b_top = b_b_pos_top

plt.tight_layout()
plt.show()

关键说明

  • 使用transData.transform()将子图内的数据坐标转换为画布坐标,避免因子图布局变化导致连线错位。
  • 每个子图绘制完成后,记录关键竖线的上下端点,相邻子图的对应端点用Line2D连接,并添加到画布对象中。
  • 实际使用时,需将模拟的mid_list、b_a_list、b_b_list替换为你针对每个子图计算的真实竖线位置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 16:58:15