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

Matplotlib内嵌轴(inset axes)导出截断及连线优化问题求助

Matplotlib 3.0.3外部放大子图问题解决

问题背景

使用Matplotlib 3.0.3,通过inset axes对imshow绘图的指定区域放大并放置在主图外部,测试代码如下:

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots(figsize=(6,6))
Z2 = np.random.rand(512, 512)

ax.imshow(Z2, interpolation='gaussian', cmap = 'RdBu', origin='lower')
ax.tick_params(axis='both', bottom=False, top=False, right=False, left=False, labelbottom=False, labelleft=False, labeltop=False, labelright=False)

# 左下角外部子图
axins_1 = ax.inset_axes([0, -1, 1, 1])
axins_1.imshow(Z2, interpolation="gaussian", cmap = 'RdBu', origin='lower')
axins_1.tick_params(axis='both', bottom=False, top=False, right=False, left=False, labelbottom=False, labelleft=False, labeltop=False, labelright=False)
axins_1.set_xlim(100, 150)
axins_1.set_ylim(85, 135)
ax.indicate_inset_zoom(axins_1, edgecolor='0')

# 右下角外部子图
axins_2 = ax.inset_axes([1, -1, 1, 1])
axins_2.imshow(Z2, interpolation="gaussian", cmap = 'RdBu', origin='lower')
axins_2.tick_params(axis='both', bottom=False, top=False, right=False, left=False, labelbottom=False, labelleft=False, labeltop=False, labelright=False)
axins_2.set_xlim(400, 450)
axins_2.set_ylim(200, 250)
ax.indicate_inset_zoom(axins_2, edgecolor='0')

# 右上角外部子图
axins_3 = ax.inset_axes([1, 0, 1, 1])
axins_3.imshow(Z2, interpolation="gaussian", cmap = 'RdBu', origin='lower')
axins_3.tick_params(axis='both', bottom=False, top=False, right=False, left=False, labelbottom=False, labelleft=False, labeltop=False, labelright=False)
axins_3.set_xlim(400, 450)
axins_3.set_ylim(400, 450)
ax.indicate_inset_zoom(axins_3, edgecolor='0')

plt.show()

当前存在两个问题:

  1. 保存绘图时,外部放大的子图被明显截断;
  2. 主图放大区域与对应子图的连线交叉,希望修改连线为箭头/标记,或改用独立子图方案并关联区域。

问题1:修复子图保存截断问题

原因是外部inset axes超出了主图默认的布局范围,保存时未被纳入画布。可通过两种方式解决:

方法1:调整布局并指定保存参数

在plt.show()前添加布局调整代码,保存时使用bbox_inches='tight'自动包含所有元素:

# 调整主图周围的空白空间,容纳外部子图
fig.subplots_adjust(bottom=0.25, right=0.75, top=0.75)
# 保存图片,确保所有元素被包含
plt.savefig('output.png', bbox_inches='tight', dpi=150)
  • subplots_adjust的参数根据外部子图的位置调整,bottom给下方子图留空间,right给右侧子图留空间;
  • bbox_inches='tight'会自动扩展画布边界,包含所有可见的绘图元素。

方法2:手动设置画布边界

如果需要更精确的控制,可以手动计算并设置画布的bbox范围:

# 获取所有axes的边界
bbox = fig.get_tightbbox(fig.canvas.get_renderer())
# 保存时使用计算出的bbox
plt.savefig('output.png', bbox_inches=bbox.transformed(fig.dpi_scale_trans.inverted()), dpi=150)

问题2:修改连线或改用独立子图

方案1:替换默认连线为箭头

Matplotlib 3.0.3的indicate_inset_zoom不支持直接生成箭头,可手动绘制主图边框和箭头来替代:

以axins_1为例,替换ax.indicate_inset_zoom(axins_1, edgecolor='0')为以下代码:

# 绘制主图上的放大区域边框
x1, x2 = 100, 150
y1, y2 = 85, 135
rect = plt.Rectangle((x1, y1), x2-x1, y2-y1, fill=False, edgecolor='black', lw=1)
ax.add_patch(rect)

# 获取主图区域中心和inset axes的位置
rect_center = ((x1+x2)/2, (y1+y2)/2)
inset_pos = axins_1.get_position()
# 绘制箭头从主图区域指向子图
ax.annotate('', 
            xy=(inset_pos.x0 + inset_pos.width/2, inset_pos.y1),  # 子图顶部中心
            xytext=rect_center,  # 主图区域中心
            arrowprops=dict(arrowstyle='->', color='black', lw=1))

此方法可完全自定义箭头样式、位置,避免连线交叉。

方案2:改用独立子图关联区域

如果希望更灵活的子图布局,可使用fig.add_axes()创建独立子图,再绘制关联标记:

示例代码片段:

# 创建主图
fig, ax = plt.subplots(figsize=(6,6))
ax.imshow(Z2, interpolation='gaussian', cmap='RdBu', origin='lower')
ax.tick_params(axis='both', bottom=False, top=False, right=False, left=False, labelbottom=False, labelleft=False, labeltop=False, labelright=False)

# 创建左下角独立子图(位置参数:左, 下, 宽, 高,单位为画布比例)
axins_1 = fig.add_axes([0.05, 0.05, 0.3, 0.3])
axins_1.imshow(Z2, interpolation='gaussian', cmap='RdBu', origin='lower')
axins_1.set_xlim(100, 150)
axins_1.set_ylim(85, 135)
axins_1.tick_params(axis='both', bottom=False, top=False, right=False, left=False, labelbottom=False, labelleft=False, labeltop=False, labelright=False)

# 绘制主图边框和关联箭头
x1, x2 = 100, 150
y1, y2 = 85, 135
rect = plt.Rectangle((x1, y1), x2-x1, y2-y1, fill=False, edgecolor='black', lw=1)
ax.add_patch(rect)

# 箭头从主图区域底部指向子图顶部
ax.annotate('', 
            xy=(axins_1.get_position().x0 + axins_1.get_position().width/2, axins_1.get_position().y1),
            xytext=((x1+x2)/2, y1),
            arrowprops=dict(arrowstyle='->', color='black', lw=1))

独立子图的位置更易控制,也不会出现inset axes的布局截断问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 23:54:05