簡體   English   中英

matplotlib 子圖之間的箭頭

[英]Arrows between matplotlib subplots

我決定稍微玩一下這個示例代碼。 我能夠弄清楚如何在兩個子圖之間畫一條直線,即使這條線超出了其中一個子圖的邊界。

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類來做到這一點?

我也想在兩個子圖之間畫一個箭頭,但我什至不知道從哪里開始! 然而,原始問題中子圖示例之間的線給了我足夠的線索來開始......

首先,我將原始問題中的代碼簡化為一個最小的工作示例:

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

這會產生以下輸出:

子圖之間的線

然后,使用這篇博客文章,我認為答案是創建一個matplotlib.patches.FancyArrowPatch並將其附加到fig.patches (而不是創建一個matplotlib.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.2matplotlib 3.4.2產生正確的輸出,如下所示:

在此處輸入圖片說明

要在matplotlib 3.4.2繪制連接兩個子圖的正確定位的線,請使用上面的ConnectionPatch但使用arrowstyle="-" (即沒有箭頭,所以只有一條線)。

注意:您不能使用:

  • plt.arrow因為它會自動添加到當前軸,所以只出現在一個子圖中

  • matplotlib.patches.Arrow作為軸圖變換傾斜箭頭

  • matplotlib.patches.FancyArrow因為這也會導致傾斜的箭頭

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM