单击 pcolormesh 正方形的中心时使用 matplotlib 选择事件触发?

Posted

技术标签:

【中文标题】单击 pcolormesh 正方形的中心时使用 matplotlib 选择事件触发?【英文标题】:Use matplotlib pick event to trigger when center of pcolormesh squares are clicked? 【发布时间】:2017-05-15 12:46:43 【问题描述】:

我正在从事一个更广泛的项目,但在使用带有 pcolormesh 的 matplotlibs picker=Truepick_event 时遇到了问题。它有效,但不直观,因为仅当我沿热图“框”的边缘单击时才会触发选择事件,并且它返回周围的索引(因此,如果您单击一个角,则 4 个索引由 4 个的交集返回框)。

例如,在下图中,当我在黄色圆圈附近单击时,我的选择器返回索引 [5 8](5 是下面的框,8 是上面的框)。相反,我只想在单击“框”时返回索引 5。

这是我用来举例说明我的问题的代码:

import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
#import matplotlib.animation as animation
#from matplotlib import style
import numpy as np

import Tkinter as tk
import ttk

def customplot(f,X):
    try:
        f.clf()
    except:
        None
    try:
        ax=ax
    except:
        ax=f.add_subplot(111)
    ax.pcolormesh(X,picker=True)
    ax.set_yticks(arange(0.5,len(X)+0.5))
    ax.set_xticks(arange(0.5,len(X)+0.5))
    ax.set_yticklabels(["LabY"+str(l) for l in range(len(X))])
    ax.set_xticklabels(["LabX"+str(l) for l in range(len(X))])

class My_GUI:

    def __init__(self,master):
        self.master=master
        self.f = Figure(figsize=(5,5), dpi=100)
        self.canvas1=FigureCanvasTkAgg(self.f,self.master)
        self.canvas1.get_tk_widget().pack(side="top",fill='x',expand=True)
        self.canvas1.mpl_connect('pick_event',self.onpick)
        self.toolbar=NavigationToolbar2TkAgg(self.canvas1,master)
        self.toolbar.update()
        self.toolbar.pack(side='top',fill='x')           
        self.drawcustomplot()

    def drawcustomplot(self):
        self.X=array(np.random.normal(size=[3,3]))
        customplot(self.f,self.X)
        #plt.xticks([1,2,3],['one','two','three'])
        self.canvas1.show()

    def onpick(self,event):
        print('Returned indices')
        print(event.ind)
        print('mapping back:')
        self.myxlabels=["LabX"+str(l) for l in range(len(self.X))]
        self.myylabels=["LabY"+str(l) for l in range(len(self.X))]
        self.ypos=event.ind[0] / 3
        self.xpos=event.ind[0] % 3
        print("Y: "+str(self.myylabels[self.ypos])+'  X:'+str(self.myxlabels[self.xpos]))


root=tk.Tk()
gui=My_GUI(root)
root.mainloop()

这是对此处发现的问题的进一步说明:Can matplotlib pick_event return array indeces rather than values or pixels?。我想避免尝试绘制一个被 pcolormesh 掩盖的底层散点图,但如果可能的话会处理选择器事件,因为我觉得必须有一种更简单的方法来实现所需的结果。

【问题讨论】:

【参考方案1】:

我建议在这里使用button_press_event。从中您可以轻松获取单击像素的坐标。在imshow 情节的情况下,它更容易,

x = int(np.round(event.xdata))
y = int(np.round(event.ydata))

完整示例(使用imshow):

import numpy as np
import matplotlib.pyplot as plt

X=np.array(np.random.normal(size=[3,3]))

myxlabels=["LabX"+str(l) for l in range(len(X[0,:]))]
myylabels=["LabY"+str(l) for l in range(len(X))]
plt.imshow(X)
plt.xticks(range(len(X[0,:])),myxlabels )
plt.yticks(range(len(X)),myylabels )

def onclick(event):
    print('Returned indices')
    print(event.xdata, event.ydata)
    print('mapping back:')
    x = int(np.round(event.xdata))
    y = int(np.round(event.ydata))
    tx = "Y: , X: , Value: :.2f".format(myylabels[y], myxlabels[x], X[y,x])
    print(tx)

plt.gcf().canvas.mpl_connect('button_press_event', onclick)

plt.show()

【讨论】:

啊哈,谢谢,button_press_event 太完美了!我仍然更喜欢使用 pcolormesh,因为我使用了 .set_bad() 和其他 pcolormesh 特定的(据我所知)功能。我知道使用 imshow 仍然可以进行类似的操作,但是在我刚刚测试过的情况下更改 IMO 没有任何意义,并且您的修复适用于 pcolormesh,因为我得到了返回的坐标,并且可以轻松地将其转换回我需要的坐标。 是的,所以区别只是在 pcolormesh 中坐标偏移了 0.5,您需要考虑到这一点。 啊,是的,imshow 坐标系统也以 (0,0) 开头,位于图的左上角与左下角,但在任何一种情况下都不难修改。 imshow-0.5 开始,因为0 是第一个像素的中心。这肯定很容易适应。

以上是关于单击 pcolormesh 正方形的中心时使用 matplotlib 选择事件触发?的主要内容,如果未能解决你的问题,请参考以下文章

切蛋糕

Matplotlib:如何使用大型数据集为pcolormesh设置动画

求两个正方形重叠部分的面积是怎样变化的?

如何在 PyQt5 GUI python 中单击按钮时绘制方形图

如何使用现有的 3D 数组为 python pcolormesh 设置动画,其中第三轴是时间步长?

matplotlib.pyplot.pcolormesh