2

我决定稍微尝试一下这个示例代码。我能够弄清楚如何在两个子图之间画一条直线,即使这条线超出了其中一个子图的范围。

import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np

fig = plt.figure(figsize=(10, 5))
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
axs = [ax1, ax2]

# Fixing random state for reproducibility
np.random.seed(19680801)

# generate some random test data
all_data = [np.random.normal(0, std, 100) for std in range(6, 10)]

# plot violin plot
axs[0].violinplot(all_data,
                  showmeans=False,
                  showmedians=True)
axs[0].set_title('Violin plot')

# plot box plot
axs[1].boxplot(all_data)
axs[1].set_title('Box plot')

# adding horizontal grid lines
for ax in axs:
    ax.yaxis.grid(True)
    ax.set_xticks([y + 1 for y in range(len(all_data))])
    ax.set_xlabel('Four separate samples')
    ax.set_ylabel('Observed values')

for tick in ax.xaxis.get_major_ticks():
    tick.label.set_fontsize(20)
plt.setp(axs[0], xticklabels=['x1', 'x2', 'x3', 'x4'])

transFigure = fig.transFigure.inverted()
coord1 = transFigure.transform(ax1.transData.transform([5,10]))
coord2 = transFigure.transform(ax2.transData.transform([2,-10]))
line = mpl.lines.Line2D((coord1[0],coord2[0]),(coord1[1],coord2[1]),
                        c='k', lw=5, transform=fig.transFigure)
fig.lines.append(line)

是的,添加的那条线很丑,但我只是想让它发挥作用。

然而,我真正想做的是在子情节之间画一个箭头,如果没有陪审团操纵我自己的箭头尾巴,我不知道怎么做。有没有办法使用类来做到这一点matplotlib.pyplot.arrow

4

1 回答 1

3

我还想在两个子图之间画一个箭头,但我什至不知道从哪里开始!但是,原始问题中子图示例之间的界线给了我足够的线索来开始......

首先,我将原始问题中的代码简化为一个最小的工作示例:

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()

这会产生以下输出:

子图之间的线

然后,使用这篇博文,我认为答案是创建 amatplotlib.patches.FancyArrowPatch并将其附加到fig.patches(而不是创建 amatplotlib.lines.Line2D并将其附加到fig.lines)。在查阅了matplotlib.patches.FancyArrowPatch文档,加上一些试验和错误之后,我想出了一些在 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()

但是,根据下面的评论,这在你得到这个的地方不起作用matplotlib 3.4.2

子图之间的箭头 - 不正确

请注意,箭头的末端不与目标点(橙色圆圈)对齐,这是他们应该做的。

matplotlib版本更改也会导致原始行示例以相同的方式失败。

但是,有一个更好的补丁!使用ConnectionPatch( docs ),它是 的子类FancyArrowPatch,而不是FancyArrowPatch直接使用,因为它ConnectionPatch是专门为此用例设计的,并且更正确地处理转换,如本matplotlib文档示例所示:

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="-"(即没有箭头,所以只有一条线)的 a。

注意:您不能使用:

  • plt.arrow因为它会自动添加到当前坐标区,所以只出现在一个子图中

  • matplotlib.patches.Arrow由于轴-图形变换使箭头倾斜

  • matplotlib.patches.FancyArrow因为这也会导致倾斜的箭头

于 2021-05-14T09:10:41.753 回答