我还想在两个子图之间画一个箭头,但我什至不知道从哪里开始!但是,原始问题中子图示例之间的界线给了我足够的线索来开始......
首先,我将原始问题中的代码简化为一个最小的工作示例:
from matplotlib import lines, pyplot as plt
fig = plt.figure()
# First subplot
ax1 = fig.add_subplot(121)
plt.plot([0, 1], [0, 1])
# Second subplot
ax2 = fig.add_subplot(122)
plt.plot([0, 1], [0, 1])
# Add line from one subplot to the other
xyA = [0.5, 1.0]
ax1.plot(*xyA, "o")
xyB = [0.75, 0.25]
ax2.plot(*xyB, "o")
transFigure = fig.transFigure.inverted()
coord1 = transFigure.transform(ax1.transData.transform(xyA))
coord2 = transFigure.transform(ax2.transData.transform(xyB))
line = lines.Line2D(
(coord1[0], coord2[0]), # xdata
(coord1[1], coord2[1]), # ydata
transform=fig.transFigure,
color="black",
)
fig.lines.append(line)
# Show figure
plt.show()
这会产生以下输出:
然后,使用this blog post,我认为答案是创建一个matplotlib.patches.FancyArrowPatch 并将其附加到fig.patches(而不是创建一个matplotlib.lines.Line2D 并将其附加到fig.lines )。在咨询了matplotlib.patches.FancyArrowPatch documentation 之后,加上一些试验和错误,我想出了一些在matplotlib 3.1.2 中工作的东西:
from matplotlib import patches, pyplot as plt
fig = plt.figure()
# First subplot
ax1 = fig.add_subplot(121)
plt.plot([0, 1], [0, 1])
# Second subplot
ax2 = fig.add_subplot(122)
plt.plot([0, 1], [0, 1])
# Add line from one subplot to the other
xyA = [0.5, 1.0]
ax1.plot(*xyA, "o")
xyB = [0.75, 0.25]
ax2.plot(*xyB, "o")
transFigure = fig.transFigure.inverted()
coord1 = transFigure.transform(ax1.transData.transform(xyA))
coord2 = transFigure.transform(ax2.transData.transform(xyB))
arrow = patches.FancyArrowPatch(
coord1, # posA
coord2, # posB
shrinkA=0, # so tail is exactly on posA (default shrink is 2)
shrinkB=0, # so head is exactly on posB (default shrink is 2)
transform=fig.transFigure,
color="black",
arrowstyle="-|>", # "normal" arrow
mutation_scale=30, # controls arrow head size
linewidth=3,
)
fig.patches.append(arrow)
# Show figure
plt.show()
但是,根据下面的 cmets,这在 matplotlib 3.4.2 中不起作用,您可以从那里得到:
请注意,箭头的末端不与目标点(橙色圆圈)对齐,他们应该这样做。
此matplotlib 版本更改也会导致原始行示例以同样的方式失败。
但是,有一个更好的补丁!使用ConnectionPatch (docs),它是FancyArrowPatch 的子类,而不是直接使用FancyArrowPatch,因为ConnectionPatch 是专门为此用例设计的,可以更正确地处理转换,如下所示matplotlib documentation example:
fig = plt.figure()
# First subplot
ax1 = fig.add_subplot(121)
plt.plot([0, 1], [0, 1])
# Second subplot
ax2 = fig.add_subplot(122)
plt.plot([0, 1], [0, 1])
# Add line from one subplot to the other
xyA = [0.5, 1.0]
ax1.plot(*xyA, "o")
xyB = [0.75, 0.25]
ax2.plot(*xyB, "o")
# ConnectionPatch handles the transform internally so no need to get fig.transFigure
arrow = patches.ConnectionPatch(
xyA,
xyB,
coordsA=ax1.transData,
coordsB=ax2.transData,
# Default shrink parameter is 0 so can be omitted
color="black",
arrowstyle="-|>", # "normal" arrow
mutation_scale=30, # controls arrow head size
linewidth=3,
)
fig.patches.append(arrow)
# Show figure
plt.show()
这会在matplotlib 3.1.2 和matplotlib 3.4.2 中产生正确的输出,如下所示:
要绘制一条连接matplotlib 3.4.2 中两个子图的正确定位线,请使用ConnectionPatch 和arrowstyle="-"(即没有箭头,所以只有一条线)。
注意:您不能使用:
-
plt.arrow 因为它会自动添加到当前坐标区,所以只出现在一个子图中
-
matplotlib.patches.Arrow 轴图形变换使箭头倾斜
-
matplotlib.patches.FancyArrow 因为这也会导致箭头倾斜