获取Matplotlib注释中的箭头坐标

时间:2016-12-22 16:50:33

标签: python matplotlib

my previous question开始,我在图形分数坐标中有文本标签框的坐标,并尝试以相同的方式获取箭头补丁的坐标。

但是我得到的坐标与箭头不对应,因为当我在同一坐标上绘制一条线时,它不会位于它上面:

import numpy as np
import matplotlib
matplotlib.use('agg')
import matplotlib.pyplot as plt

def f(x):
    return 10 * np.sin(3*x)**4

x = np.linspace(0, 2*np.pi, 100)
y = f(x)

fig, ax = plt.subplots()
ax.plot(x,y)

xpt = 1.75
ypt = f(xpt)
xy = ax.transData.transform([xpt, ypt])
xy = fig.transFigure.inverted().transform(xy)

xytext = xy + [0.1, -0.1]
rdx, rdy = 0, 1
ann = ax.annotate('A point', xy=xy, xycoords='figure fraction',
             xytext=xytext, textcoords='figure fraction',
             arrowprops=dict(arrowstyle='->', connectionstyle="arc3",
                             relpos=(rdx, rdy)),
             bbox=dict(fc='gray', edgecolor='k', alpha=0.5),
             ha='left', va='top'
            )
fig.canvas.draw()

leader_line_box = ann.arrow_patch.get_extents()
print(leader_line_box)
leader_line_box = fig.transFigure.inverted().transform(leader_line_box) 
print(leader_line_box)

from matplotlib.lines import Line2D
line = Line2D(leader_line_box.T[0], leader_line_box.T[1],transform=fig.transFigure, lw=2, color='m')
ax.add_line(line)

plt.savefig('test.png')

enter image description here

如何以图形分数单位获取注释箭头的((x0,y0), (x1,y1))坐标以及我在此处尝试出错的地方?

2 个答案:

答案 0 :(得分:2)

在这种非常具体的情况下,最简单的方法就是反向绘制x坐标

[warn]  Foo
[warn]  Runner.Foo
I am Bar
I am Runner.Foo

[warn]  Foo2
I am Bar
I am Foo2

如果您需要更通用的解决方案,

line = Line2D(leader_line_box.T[0][::-1], leader_line_box.T[1],transform=fig.transFigure, lw=2, color='m')

这适用于任何箭头方向(向上或向下,向东或向西),但特定于verts = ann.arrow_patch.get_path()._vertices tverts= fig.transFigure.inverted().transform(verts) index = [0,2] line = Line2D([tverts[index[0],0],tverts[index[1],0]], [tverts[index[0],1],tverts[index[1],1]], transform=fig.transFigure, lw=2, color='m') ax.add_line(line) 参数arrowpropsarrowstyle='->'。使用不同的箭头样式或连接样式需要将connectionstyle="arc3"设置为不同的值,这些值可以通过从index中存储的数组中选择适当的索引来找到。

<小时/> 在一般情况下,您还可以查看以下内容:

verts

然而,这将使您获得注释点和文本本身之间的界限。通常,此行可能与实际箭头不同,具体取决于使用的箭头样式。

答案 1 :(得分:1)

You're almost there, you have the coordinates of the bounding box of the arrow, which is the box drawn using the arrow as the diagonal. From that, we can find the head / tail coordinates.

The bounding box coordinates are given in the order [[left, bottom], [right, top]]. Here, the arrow head is at the top left, and tail is bottom right. So we can draw two lines to visually mark these. Replacing that section in your code with this:

from matplotlib.lines import Line2D
dl = 0.01 # some arbitrary length for the marker line
head = [leader_line_box.T[0][0], leader_line_box.T[1][1]]
line_head = Line2D([head[0],head[0]+dl], [head[1],head[1]+dl],
    transform=fig.transFigure, lw=2, color='r') # mark head with red
ax.add_line(line_head)

tail = [leader_line_box.T[0][1], leader_line_box.T[1][0]]
line_tail = Line2D([tail[0],tail[0]+dl], [tail[1],tail[1]+dl],
    transform=fig.transFigure, lw=2, color='g') # mark tail with green
ax.add_line(line_tail)

results in the following plot:

plot with arrow head and tail marked

时出错