python - 将线条更改为插入轴

标签 python matplotlib

我正在使用 matplotlib v.3.0.3。我想使用插入轴放大 imshow 图中的某个位置,然后在主图像之外绘制放大的部分。我正在使用以下代码来处理插入轴

import matplotlib.pyplot as plt
import numpy as np
#from mpl_toolkits.axes_grid1.inset_locator import (inset_axes, InsetPosition, mark_inset)

fig, ax = plt.subplots(figsize=(6,6))
Z2 = np.random.rand(512, 512)

ax.imshow(Z2, interpolation='gaussian', cmap = 'RdBu', origin='lower')
ax.tick_params(axis='both', bottom=False, top=False, right=False, left=False, labelbottom=False, labelleft=False, labeltop=False, labelright=False)

# inset axes...
axins_1 = ax.inset_axes([0, -1, 1, 1]) # bottom left, outside main plot
axins_1.imshow(Z2, interpolation="gaussian", cmap = 'RdBu', origin='lower')
axins_1.tick_params(axis='both', bottom=False, top=False, right=False, left=False, labelbottom=False, labelleft=False, labeltop=False, labelright=False)
# sub region of the original image
axins_1.set_xlim(100, 150)
axins_1.set_ylim(85, 135)

ax.indicate_inset_zoom(axins_1, edgecolor='0')
#mark_inset(ax, axins_1, loc1=2, loc2=3, fc="none", lw=1, ec='k')

# inset axes...
axins_2 = ax.inset_axes([1, -1, 1, 1]) # bottom right, outside main plot
axins_2.imshow(Z2, interpolation="gaussian", cmap = 'RdBu', origin='lower')
axins_2.tick_params(axis='both', bottom=False, top=False, right=False, left=False, labelbottom=False, labelleft=False, labeltop=False, labelright=False)
# sub region of the original image
axins_2.set_xlim(400, 450)
axins_2.set_ylim(200, 250)

ax.indicate_inset_zoom(axins_2, edgecolor='0')
#mark_inset(ax, axins_2, loc1=2, loc2=3, fc="none", lw=1, ec='k')

# inset axes...
axins_3 = ax.inset_axes([1, 0, 1, 1]) # top right, outside main plot
axins_3.imshow(Z2, interpolation="gaussian", cmap = 'RdBu', origin='lower')
axins_3.tick_params(axis='both', bottom=False, top=False, right=False, left=False, labelbottom=False, labelleft=False, labeltop=False, labelright=False)
# sub region of the original image
axins_3.set_xlim(400, 450)
axins_3.set_ylim(400, 450)

ax.indicate_inset_zoom(axins_3, edgecolor='0')
#mark_inset(ax, axins_3, loc1=2, loc2=3, fc="none", lw=1, ec='k')

plt.show()

这里,主图是左上图,右上图和下图都是放大后的量。这几乎完全生成了我在 Jupyter 笔记本中想要的图。不过,我有两个问题需要解决。

我的第一个问题是,当我保存绘图时,结果如下

enter image description here

它清楚地切断了缩放图像。我想知道如何解决这个问题?

第二个问题是从主图的各个部分到缩放图像的线条在多个地方交叉。我想要的是保留小节周围的框,但更改行。然而,从 the documentation看来您不能仅删除线条,因为更改边缘颜色会同时为框和线条着色。

我想要的是有一个从该部分指向正确的缩放图像的箭头,或者以其他方式标记该部分及其相应的缩放图像。但是,我一直无法找到一种方法来做到这一点。这可能吗?如果是这样,我们该怎么做?

执行此操作的另一种方法是制作子图并简单地在子图中绘制缩放区域。然而,在这种方法中,我不知道如何用相应的缩放图来识别每个小节。

最佳答案

您始终可以推出自己的简化inset 函数。

在这里,我使用subplots来控制我的布局,以帮助确保我不会在Figure的边界之外绘制(这就是为什么你的保存到文件时,图会剪辑您的)。

此外,我还设置了自己的矩形和 ConnectionPatch,这样我只需使用所需的参数为每个所需的插图绘制一个 ConnectionPatch。这使我能够明确控制箭头的开始和结束位置。

在我提供的函数中

  • arrow_start 是矩形上按比例单位表示的 xy 坐标 (例如,(0, 0) 是矩形的左下角,(0, .5) 是左中角,(0, 1) 是左上角,(1, 1) 是右上角,等等。
  • arrow_end 是插入轴上按比例单位表示的 xy 坐标(例如,(0, 0) 是插入轴的左下角,依此类推。

您可以使用这两个参数将箭头明确放置在您认为最适合图形的位置,以免与其他重叠

我还将您的一些样式设置代码移至顶部作为要使用的默认设置。

import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, ConnectionPatch
import numpy as np

plt.rc('xtick', bottom=False, top=False, labelbottom=False)
plt.rc('ytick', left=False, right=False, labelleft=False)
plt.rc('figure', facecolor='white')

def indicate_inset(axin, axout, arrow_start=(0, 0), arrow_end=(0, 0)):
    (x0, x1), (y0, y1) = axin.get_xlim(), axin.get_ylim()
    width = x1 - x0
    height = y1 - y0
    
    rect = Rectangle(
        [x0, y0], width=width, height=height, 
        transform=axout.transData, fc='none', ec='black'
    )
    axout.add_patch(rect)
    
    conn = ConnectionPatch(
        xyA=arrow_start, coordsA=rect.get_transform(),
        xyB=arrow_end, coordsB=axin.transAxes,
        arrowstyle='->'
    )
    fig.add_artist(conn)
    return rect, conn


fig, axes = plt.subplots(
    2, 2, figsize=(6, 6), 
    gridspec_kw={'wspace': 0.05, 'hspace': 0.05, 'left':.1, 'right': .9}
)
Z2 = np.random.rand(512, 512)

imshow_kws = dict(interpolation='gaussian', cmap='RdBu', origin='lower')
raw_ax = axes[0, 0]
raw_ax.imshow(Z2, **imshow_kws)

# inset axes...
axes[1, 0].imshow(Z2, **imshow_kws)
axes[1, 0].set(xlim=(100, 150), ylim=(85, 135))
indicate_inset(axes[1, 0], raw_ax, arrow_start=(.5, 0), arrow_end=(.5, 1))

# # inset axes...
axes[1, 1].imshow(Z2, **imshow_kws)
axes[1, 1].set(xlim=(400, 450), ylim=(200, 250))
indicate_inset(axes[1, 1], raw_ax, arrow_start=(.5, 0), arrow_end=(0, 1))

# # # inset axes...
axes[0, 1].imshow(Z2, **imshow_kws)
axes[0, 1].set(xlim=(400, 450), ylim=(400, 450))
indicate_inset(axes[0, 1], raw_ax, arrow_start=(1, 0), arrow_end=(0, .5))

fig.savefig('test.png') # This is the image uploaded to this answer

enter image description here

关于python - 将线条更改为插入轴,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73306492/

相关文章:

python - 如何像Plotly一样在Matplotlib中注释pandas日期时间格式?

python - 基于密度阈值的聚类点

python - 在 matplotlib 图例中使用 TeX 表达式 "\tanh"

python - 用阿拉伯字符绘制直方图

python - 通过颜色定义从绘图中排除点?

python - 如何比较两种类型的自定义类

python - python 中的整数自增

python - numpy 数组索引器中的冒号、无、切片(无)

python - Pandas 数据框计算

python - 使用 Python 下载并解压文件