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

如何将Matplotlib的fig.add_axes局部坐标与真实世界坐标关联?

问题:Matplotlib嵌入轴与真实世界坐标的自动关联实现

受Matplotlib官方示例启发,想要实现嵌入轴(inset_axis)效果,但核心难题是如何将Matplotlib绘图坐标与真实世界坐标关联。

场景说明

  • 需要将inset_axis精准定位在指定的真实坐标点(比如红色标记点)处
  • 测试过fig.add_axes([1, 0, .05, .05], facecolor='k')用于四角定位,但绘图区域内的(0..1,0..1)局部坐标无法直接对应外部真实坐标
  • 官方缩放嵌入轴示例属于手动定制,需要无需硬编码的自动化方案
  • 涉及多类嵌入图形,部分在极坐标环境下生成(如极坐标折线图、柱状图),这类坐标难以直接缩放

尝试过的方案及问题

参考相关方案生成二维数据、选择测试点并缩放至(0..1)坐标后添加inset_axis,但发现绘图坐标与用户真实坐标分离,无法实现精准关联。

附测试代码:

import numpy as np
import matplotlib.pyplot as plt

def scaleXY(xgr,ygr,xT,yT): 
    xgr = (xgr-xT.min())/(xT.max()-xT.min())
    ygr = (ygr-yT.min())/(yT.max()-yT.min())
    return xgr, ygr

nx, ny = 150, 60                                            # 数据点数量
ix = np.linspace(-5, 20, nx)*100
iy = np.linspace(-1, 15, ny)*100
xq, yq = np.meshgrid(ix,iy, indexing='ij')                   # 生成基础数据
dx, dy = 50, 30                                              # 采样间隔
xp,yp = xq[::dx,::dy], yq[::dx,::dy]                         # 选取测试点

xgr, ygr = scaleXY(xp,yp,xq,yq)                              # 缩放至(0..1)范围

with plt.style.context('fast'): 
    fig = plt.figure(figsize=(10,10)) 
    ax1 = fig.add_subplot(111)

    ax1.scatter(xq,yq, s=5)                               # 绘制基础数据
    ax1.scatter(xp,yp, c='lime', s=300, alpha = 0.6)      # 绘制测试点

    # 尝试定位嵌入轴,但位置不准确
    ins = ax1.inset_axes([xgr[2,1], ygr[2,1],  0.2,0.2])  
    ins = ax1.inset_axes([xgr[1,1], ygr[1,1],  0.2,0.2])  
    ins = ax1.inset_axes([xgr[0,0], ygr[0,0],  0.2,0.2])  
    ins = ax1.inset_axes([xgr[2,0], ygr[2,0],  0.2,0.2])  

    ax1.set_aspect('equal')
    title = 'Even more dangerous area'
    ax1.set_title(title,fontweight='bold', fontsize=17)
    ax1.set_xlabel('x-direction', fontsize=17)
    ax1.set_ylabel('y-direction', fontsize=17)        

plt.show() 

解决方案:利用坐标转换函数实现自动关联

Matplotlib提供了ax.transData和ax.transAxes两个坐标转换对象,可以实现真实世界坐标与绘图区域局部坐标的自动转换,无需手动硬编码缩放。

1. 笛卡尔坐标下的实现

核心思路是将真实世界坐标(data坐标)转换为绘图区域的归一化坐标(axes坐标,范围0-1),再用该坐标定位inset_axis。

修正后的代码

import numpy as np
import matplotlib.pyplot as plt

nx, ny = 150, 60                                            # 数据点数量
ix = np.linspace(-5, 20, nx)*100
iy = np.linspace(-1, 15, ny)*100
xq, yq = np.meshgrid(ix,iy, indexing='ij')                   # 生成基础数据
dx, dy = 50, 30                                              # 采样间隔
xp,yp = xq[::dx,::dy], yq[::dx,::dy]                         # 选取测试点

with plt.style.context('fast'): 
    fig = plt.figure(figsize=(10,10)) 
    ax1 = fig.add_subplot(111)

    ax1.scatter(xq,yq, s=5)                               # 绘制基础数据
    ax1.scatter(xp,yp, c='lime', s=300, alpha = 0.6)      # 绘制测试点

    # 遍历所有测试点,自动转换坐标并添加嵌入轴
    for x, y in zip(xp.flat, yp.flat):
        # 将真实世界坐标转换为axes归一化坐标
        ax_coord = ax1.transData.transform((x, y))
        ax_coord = ax1.transAxes.inverted().transform(ax_coord)
        # 添加嵌入轴,位置为转换后的坐标,大小固定为0.2x0.2
        ins = ax1.inset_axes([ax_coord[0], ax_coord[1], 0.2, 0.2])
        # 给嵌入轴添加示例内容,比如简单折线图
        ins.plot([0,1,2], [0,1,0], c='r')
        # 隐藏嵌入轴的刻度,避免干扰
        ins.set_xticks([])
        ins.set_yticks([])

    ax1.set_aspect('equal')
    title = 'Even more dangerous area'
    ax1.set_title(title,fontweight='bold', fontsize=17)
    ax1.set_xlabel('x-direction', fontsize=17)
    ax1.set_ylabel('y-direction', fontsize=17)        

plt.show() 

2. 极坐标下的实现

极坐标的坐标转换逻辑与笛卡尔坐标一致,同样使用transData和transAxes进行转换,无需单独处理极坐标的角度/半径转换。

示例代码

import numpy as np
import matplotlib.pyplot as plt

# 生成极坐标基础数据
theta = np.linspace(0, 2*np.pi, 100)
r = np.sin(3*theta) + 2

# 选取几个测试点
test_thetas = [np.pi/4, np.pi, 3*np.pi/2]
test_rs = [r[np.argmin(np.abs(theta - t))] for t in test_thetas]

fig = plt.figure(figsize=(8,8))
ax_polar = fig.add_subplot(111, polar=True)
ax_polar.plot(theta, r, c='b')
# 绘制测试点
ax_polar.scatter(test_thetas, test_rs, c='red', s=200, alpha=0.6)

# 给每个测试点添加嵌入轴
for theta_t, r_t in zip(test_thetas, test_rs):
    # 极坐标下的真实坐标转换为axes归一化坐标
    ax_coord = ax_polar.transData.transform((theta_t, r_t))
    ax_coord = ax_polar.transAxes.inverted().transform(ax_coord)
    # 添加嵌入轴
    ins = ax_polar.inset_axes([ax_coord[0], ax_coord[1], 0.15, 0.15])
    # 嵌入轴示例内容:柱状图
    ins.bar([0,1,2], [3,1,4], color='orange')
    ins.set_xticks([])
    ins.set_yticks([])

plt.show()

关键原理说明

  • ax.transData.transform((x,y)):将真实世界坐标(data坐标)转换为图窗的像素坐标
  • ax.transAxes.inverted().transform(pixel_coord):将像素坐标转换为绘图区域的归一化坐标(axes坐标,范围0-1)
  • 这种转换会自动适配坐标轴的缩放、刻度变化,无需手动计算缩放比例,完全自动化

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 19:20:06