Python 如何在matplotlib(点区域的扩展)的子地块中拾取点并在相邻子地块中高亮显示该点

Python 如何在matplotlib(点区域的扩展)的子地块中拾取点并在相邻子地块中高亮显示该点,python,arrays,matplotlib,plot,scatter-plot,Python,Arrays,Matplotlib,Plot,Scatter Plot,我想创建一个散点图矩阵,它将由一些子图组成。我从一个.txt文件中提取了我的数据,并创建了一个形状数组(x、y、z、p1、p2、p3)。数组的前三列表示这些数据来自原始图像的x、y、z坐标,最后三列(p1、p2、p3)表示一些其他参数。因此,在数组的每一行中,参数p1、p2、p3具有相同的坐标(x、y、z)。在散点图中,我想在第一阶段将p1参数与p2、p3参数进行可视化。对于我拾取的每个点,我希望对数组前三列中的(x、y、z)参数进行注释,并高亮显示相邻子图中具有相同坐标的点或修改其颜色 在我的

我想创建一个散点图矩阵,它将由一些子图组成。我从一个.txt文件中提取了我的数据,并创建了一个形状数组(x、y、z、p1、p2、p3)。数组的前三列表示这些数据来自原始图像的x、y、z坐标,最后三列(p1、p2、p3)表示一些其他参数。因此,在数组的每一行中,参数p1、p2、p3具有相同的坐标(x、y、z)。在散点图中,我想在第一阶段将p1参数与p2、p3参数进行可视化。对于我拾取的每个点,我希望对数组前三列中的(x、y、z)参数进行注释,并高亮显示相邻子图中具有相同坐标的点或修改其颜色

在我的代码中,创建了两个子批次,并在终端中打印通过拾取点获得的(p1、p2或p3)值、相邻子批次中相同点的相应值以及该点的(x、y、z)参数

此外,当我在第一个子图中拾取一个点时,第二个子图中对应点的颜色会发生变化,但反之亦然。只有手动调整图形的大小,才能识别此颜色修改。如何在不调整图形以注意任何更改的情况下为两个子图形添加交互性?我应该做什么样的修改才能使这种互动在简化的散点图矩阵中可行,如问题“”中所示。我不是一个有经验的python、matplotlib用户,因此任何帮助都将不胜感激

import numpy as np
import matplotlib.pyplot as plt
import pylab as pl



def main():


    #load data from file
    data = np.loadtxt(r"data.txt")

    plt.close("all")
    x = data[:, 3]
    y = data[:, 4]
    y1 = data[:, 5]
    fig1 = plt.figure(1)
    #subplot p1 vs p2
    plt.subplot(121)
    subplot1, = plt.plot(x, y, 'bo', picker=3)
    plt.xlabel('p1')
    plt.ylabel('p2')

    #subplot p1 vs p3
    plt.subplot(122)
    subplot2, = plt.plot(x, y1, 'bo', picker=3)
    plt.xlabel('p1')
    plt.ylabel('p3')

    plt.subplots_adjust(left=0.1, right=0.95, wspace=0.3, hspace=0.45)
    #  art.getp(fig1.patch)
    def onpick(event):

        thisevent = event.artist
        valx = thisevent.get_xdata()
        valy = thisevent.get_ydata()
        ind = event.ind

        print 'index', ind
        print 'selected point:', zip(valx[ind], valy[ind])
        print 'point in the adjacent subplot', x[ind], y1[ind]
        print '(x,y,z):', data[:, 0][ind], data[:, 1][ind], data[:, 2][ind]

        for xcord,ycord in zip(valx[ind], valy[ind]):
            plt.annotate("(x,y,z):", xy = (x[ind], y1[ind]), xycoords = ('data' ),
                xytext=(x[ind] - .5, y1[ind]- .5), textcoords='data',
                arrowprops=dict(arrowstyle="->",
                                connectionstyle="arc3"),
                )
            subplot2, = plt.plot(x[ind], y[ind], 'ro', picker=3)
            subplot1  = plt.plot(x[ind], y[ind], 'ro', picker=3)


    fig1.canvas.mpl_connect('pick_event', onpick)

    plt.show()



main()

总之,当我选择一个点时,信息打印在终端上,与子批次无关。但是,当我在左子图中拾取一个点时,仅在右子图的点中修改颜色,反之亦然。此外,在我调整图形(例如,移动或调整其大小)并且选择第二个点时,前一个点保持彩色之前,颜色的变化不会明显


任何形式的贡献都将不胜感激。提前感谢您。

您的当前代码已经在正确的轨道上了。基本上,您只是缺少了对
onpick
函数中的
plt.draw()
的调用

然而,在我们在评论中的讨论中,出现了
mpldatacursor
,您询问了一个这样做的示例

mpldatacursor
中当前的
HighlightingDataCursor
是围绕着突出显示整个
Line2D
艺术家而设置的,而不仅仅是它的特定索引。(这是故意限制的,因为在matplotlib中没有好的方法为任何艺术家绘制任意高光,所以我将高光部分保持为小。)

但是,您可以对类似的内容进行子类化(假设您使用的是
plot
,并且希望使用在每个轴中绘制的第一个内容)。我还演示了如何使用
点标签
,以防您希望显示的每个点都有不同的标签:

import numpy as np
import matplotlib.pyplot as plt
from mpldatacursor import HighlightingDataCursor, DataCursor

def main():
    fig, axes = plt.subplots(nrows=2, ncols=2)
    for ax, marker in zip(axes.flat, ['o', '^', 's', '*']):
        x, y = np.random.random((2,20))
        ax.plot(x, y, ls='', marker=marker)
    IndexedHighlight(axes.flat, point_labels=[str(i) for i in range(20)])
    plt.show()

class IndexedHighlight(HighlightingDataCursor):
    def __init__(self, axes, **kwargs):
        # Use the first plotted Line2D in each axes
        artists = [ax.lines[0] for ax in axes]

        kwargs['display'] = 'single'
        HighlightingDataCursor.__init__(self, artists, **kwargs)
        self.highlights = [self.create_highlight(artist) for artist in artists]
        plt.setp(self.highlights, visible=False)

    def update(self, event, annotation):
        # Hide all other annotations
        plt.setp(self.highlights, visible=False)

        # Highlight everything with the same index.
        artist, ind = event.artist, event.ind
        for original, highlight in zip(self.artists, self.highlights):
            x, y = original.get_data()
            highlight.set(visible=True, xdata=x[ind], ydata=y[ind])
        DataCursor.update(self, event, annotation)

main()

同样,这假设您使用的是
plot
,而不是,比如说,
scatter
。可以通过
分散
来实现这一点,但您需要更改大量令人烦恼的细节。(没有突出显示任意matplotlib艺术家的常规方法,因此必须有大量非常详细的代码来单独处理每种类型的艺术家。)


无论如何,希望它有用。

问得好!首先,在
onpick
函数中缺少
plt.draw()
。其次,如果您愿意添加依赖项,您可能会发现这很有用:谢谢Joe。这个模块似乎非常方便!我将添加它。@JoeKington我添加了模块,它工作得非常好。您能否将您的评论升级为答案,以便将其作为我问题的适当答案?@JoeKington-我试图扩展更多子批次的功能,但收到了有关dict命令的错误。我想创建一个带有突出显示功能的简化散点图矩阵。你的模块可以这样做吗?我必须修改哪个类?谢谢你advance@JoeKington-使用新的实现,尽管可以突出显示和注释点,但我无法从原始数据打印正确的event.ind和x、y、z坐标。你知道为什么会发生这样的事吗?对于ind,它总是打印0,对于x,y,z,它总是打印数组的第一个值。看起来必须迭代onpick函数。代码如下:您的示例非常有用,非常接近我想要实现的内容。我希望在每个子图中从我从文件中提取的数据中绘制不同类型的数据。你能解释一下
main
函数中的
for
循环吗,因为我正试图控制每个子批次。例如,在
子批次(1,2,1)
中,我想绘制参数
p1 vs p2
子批次(1,2,2)
p1 vs p2
。问题已解决。我对每个子地块使用了
轴.flat[]绘图。谢谢你的帮助。这非常关键如果上面的代码是用散布命令而不是
绘图
实现的,应该做什么样的更改?我尝试用
分散实现它,我得到的错误与
索引高光(axes.flat)
艺术家=[ax.lines[0]表示ax in axes]->索引器:列表索引超出范围有关。我不能完全理解为什么这种修改会导致这种错误。这可能与
绘图
分散
可视化数据的方式有关。
scatter
的kwargs属性为
Collection
属性,
plot
的kwargs属性为Line2D。你能推荐点什么吗?给你