简体   繁体   English

matplotlib mark_inset与插图中的不同数据

[英]matplotlib mark_inset with different data in inset plot

This is a slightly tricky one to explain. 这是一个有点棘手的解释。 Basically, I want to make an inset plot and then utilize the convenience of mpl_toolkits.axes_grid1.inset_locator.mark_inset, but I want the data in the inset plot to be completely independent of the data in the parent axes. 基本上,我想制作一个插入图,然后利用mpl_toolkits.axes_grid1.inset_locator.mark_inset的便利性,但是我希望插入图中的数据完全独立于父轴中的数据。

Example code with the functions I'd like to use: 具有我要使用的功能的示例代码:

import numpy as np

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
from mpl_toolkits.axes_grid1.inset_locator import mark_inset
from mpl_toolkits.axes_grid1.inset_locator import InsetPosition

data = np.random.normal(size=(2000,2000))
plt.imshow(data, origin='lower')
parent_axes = plt.gca()

ax2 = inset_axes(parent_axes, 1, 1)
ax2.plot([900,1100],[900,1100])

# I need more control over the position of the inset axes than is given by the inset_axes function
ip = InsetPosition(parent_axes,[0.7,0.7,0.3,0.3])
ax2.set_axes_locator(ip)

# I want to be able to control where the mark is connected to, independently of the data in the ax2.plot call
mark_inset(parent_axes, ax2, 2,4)

# plt.savefig('./inset_example.png')
plt.show()

The example code produces the following image: 示例代码将产生以下图像: 在此处输入图片说明

So to sum up: The location of the blue box is entire controlled by the input data to ax2.plot(). 总结一下:蓝色框的位置完全由ax2.plot()的输入数据控制。 I would like to manually place the blue box and enter whatever I want into ax2. 我想手动放置蓝色框,然后将想要输入的内容输入到ax2中。 Is this possible? 这可能吗?

quick edit: to be clear, I understand why inset plots would have the data linked, as that's the most likely usage. 快速编辑:明确地说,我了解为什么插图会链接数据,因为这是最可能的用法。 So if there's a completely different way in matplotlib to accomplish this, do feel free to reply with that. 因此,如果matplotlib中有一种完全不同的方式来完成此任务,请随时回复。 However, I am trying to avoid manually placing boxes and lines to all of the axes I would place, as I need quite a few insets into a large image. 但是,我试图避免将框和线手动放置到要放置的所有轴上,因为我需要在大图像中插入很多插图。

If I understand correctly, you want an arbitrarily scaled axis at a given position that looks like a zoomed inset, but has no connection to the inset marker's position. 如果我理解正确,则您希望在给定位置上任意缩放的轴看起来像缩放的插图,但与插图标记的位置没有关系。

Following your approach you can simply add another axes to the plot and position it at the same spot of the true inset, using the set_axes_locator(ip) function. 按照您的方法,您可以简单地使用set_axes_locator(ip)函数将另一个轴添加到绘图并将其放置在真实插图的同一位置。 Since this axis is drawn after the original inset, it will be on top of it and you'll only need to hide the tickmarks of the original plot to let it disappear completely ( set_visible(False) does not work here, as it would hide the lines between the inset and the marker position). 由于此轴是在原始插图之后绘制的,因此它将位于其顶部,您只需要隐藏原始图的刻度线即可使其完全消失( set_visible(False)在这里不起作用,因为它将隐藏插图和标记位置之间的线)。

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

data = np.random.normal(size=(200,200))
plt.imshow(data, origin='lower')
parent_axes = plt.gca()

ax2 = inset_axes(parent_axes, 1, 1)
ax2.plot([60,75],[90,110])
# hide the ticks of the linked axes
ax2.set_xticks([])
ax2.set_yticks([])

#add a new axes to the plot and plot whatever you like
ax3 = plt.gcf().add_axes([0,0,1,1])
ax3.plot([0,3,4], [2,3,1], marker=ur'$\u266B$' , markersize=30, linestyle="") 
ax3.set_xlim([-1,5])
ax3.set_ylim([-1,5])


ip = InsetPosition(parent_axes,[0.7,0.7,0.3,0.3])
ax2.set_axes_locator(ip)
# set the new axes (ax3) to the position of the linked axes
ax3.set_axes_locator(ip)
# I want to be able to control where the mark is connected to, independently of the data in the ax2.plot call
mark_inset(parent_axes, ax2, 2,4)

plt.show()

在此处输入图片说明

FWIW, I came up with a hack that works. FWIW,我想出了一个可行的方法。

In the source code for inset_locator, I added a version of mark_inset that takes another set of axes used to define the TransformedBbox: 在inset_locator的源代码中,我添加了一个mark_inset版本,该版本采用了另一组用于定义TransformedBbox的轴:

def mark_inset_hack(parent_axes, inset_axes, hack_axes, loc1, loc2, **kwargs):
    rect = TransformedBbox(hack_axes.viewLim, parent_axes.transData)

    pp = BboxPatch(rect, **kwargs)
    parent_axes.add_patch(pp)

    p1 = BboxConnector(inset_axes.bbox, rect, loc1=loc1, **kwargs)
    inset_axes.add_patch(p1)
    p1.set_clip_on(False)
    p2 = BboxConnector(inset_axes.bbox, rect, loc1=loc2, **kwargs)
    inset_axes.add_patch(p2)
    p2.set_clip_on(False)

    return pp, p1, p2

Then in my original-post code I make an inset axis where I want the box to be, pass it to my hacked function, and make it invisible: 然后在我的原始帖子代码中,创建一个插入轴,将框放置在其中,将其传递给被黑的函数,并使它不可见:

# location of desired axes
axdesire = inset_axes(parent_axes,1,1)
axdesire.plot([100,200],[100,200])

mark_inset_hack(parent_axes, ax2, axdesire, 2,4)

axdesire.set_visible(False)

Now I have a marked box at a different location in data units than the inset that I'm marking: 现在,我在数据单元中与我标记的插图不同的位置有一个标记框:

在此处输入图片说明

It is certainly a total hack, and at this point I'm not sure it's cleaner than simply drawing lines manually, but I think for a lot of insets this will keep things conceptually cleaner. 当然,这绝对是一个hack,目前还不确定它是否比手动绘制线条更干净,但是我认为对于很多插图而言,这将使概念更清晰。

Other ideas are still welcome. 仍然欢迎其他想法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM