如何将FancyArrowPatch连接到已知大小的标记边缘?

3 投票
1 回答
1849 浏览
提问于 2025-04-17 14:08

我之前在matplotlib用户邮件列表上问过这个问题,所以在这里重复一下,抱歉。

假设我有一个已知大小的标记(用点数表示),我想画一条箭头指向这个标记。请问我该如何找到箭头的起止点?如下面所示,箭头和标记重叠了。我想让箭头指向标记的边缘。我可以使用shrinkA和shrinkB来实现这个目标,但我不明白它们和点的大小**.5有什么关系。或者我应该用已知的两个点之间的角度和这个点本身来进行某种变换。我不知道如何在数据坐标中移动一个点,并在某个方向上偏移**.5个点的大小。有人能帮我理清这个思路吗?

import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch

point1 = (138.21, 19.5)
x1, y1 = point1
point2 = (67.0, 30.19)
x2, y2 = point2
size = 700

fig, ax = plt.subplots()
ax.scatter(*zip(point1, point2), marker='o', s=size)

# if I need to get and use the angles
dx = x2 - x1
dy = y2 - y1
d = np.sqrt(dx**2 + dy**2)

arrows = FancyArrowPatch(posA=(x1, y1), posB=(x2, y2),
                            color = 'k',
                            arrowstyle="-|>",
                            mutation_scale=700**.5,
                            connectionstyle="arc3")

ax.add_patch(arrows)

编辑:我有了一些进展。如果我正确理解了变换教程,那么这应该能给我一个在标记半径上的点。然而,一旦你调整了坐标轴的大小,变换就会失效。我对该使用什么感到困惑。

from matplotlib.transforms import ScaledTranslation
# shift size points over and size points down so you should be on radius
# a point is 1/72 inches
dpi = ax.figure.get_dpi()
node_size = size**.5 / 2. # this is the radius of the marker
offset = ScaledTranslation(node_size/dpi, -node_size/dpi, fig.dpi_scale_trans)
shadow_transform = ax.transData + offset
ax.plot([x2], [y2], 'o', transform=shadow_transform, color='r')

示例

1 个回答

0
import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch
from matplotlib.transforms import ScaledTranslation

point1 = (138.21, 19.5)
x1, y1 = point1
point2 = (67.0, 30.19)
x2, y2 = point2
size = 700

fig, ax = plt.subplots()
ax.scatter(*zip(point1, point2), marker='o', s=size)

# if I need to get and use the angles
dx = x2 - x1
dy = y2 - y1
d = np.sqrt(dx**2 + dy**2)

arrows = FancyArrowPatch(posA=(x1, y1), posB=(x2, y2),
                            color = 'k',
                            arrowstyle="-|>",
                            mutation_scale=700**.5,
                            connectionstyle="arc3")

ax.add_patch(arrows)


# shift size points over and size points down so you should be on radius
# a point is 1/72 inches
def trans_callback(event):
    dpi = fig.get_dpi()
    node_size = size**.5 / 2. # this is the radius of the marker
    offset = ScaledTranslation(node_size/dpi, -node_size/dpi, fig.dpi_scale_trans)
    shadow_transform = ax.transData + offset
    arrows.set_transform(shadow_transform)


cid = fig.canvas.mpl_connect('resize_event', trans_callback)

你还需要提到一下坐标轴的宽高比,因为如果宽高比不等于1,数据单位中的标记形状会变成椭圆,而不是圆形。

撰写回答