2017-05-15 4 views
0

Ich arbeite an einem breiteren Projekt, aber bin ein Problem mit Matplotlibs picker=True und pick_event mit einem Pcolormesh. Es funktioniert, ist aber nicht intuitiv, da das Pick-Ereignis nur ausgelöst wird, wenn ich entlang der Kanten der Heatmap-Felder klicke und die umgebenden Indizes zurückgibt (wenn Sie also auf eine Ecke klicken, werden 4 Indizes durch den Schnittpunkt der 4 zurückgegeben Boxen an diesem Punkt).Verwenden Sie das matplotlib-Pick-Ereignis, um auszulösen, wenn die Mitte von pcolormesh-Quadraten angeklickt wird?

Zum Beispiel, in dem folgenden Bild, wenn ich in der Nähe des gelben Kreises klicke, gibt mein Picker Indizes [5 8] zurück (5 ist die Box unten und 8 oben). Stattdessen möchte ich nur Index 5 zurückgeben, wenn diese "Box" angeklickt wird. pcolormesh picker

Hier ist der Code habe ich mein Problem zu veranschaulichen:

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

ist dies auf die Frage hier gefunden: Can matplotlib pick_event return array indeces rather than values or pixels?. Ich möchte vermeiden, zu versuchen, ein zugrunde liegendes Streudiagramm zu zeichnen, das von dem pcolormesh maskiert wird, aber die Auswahlereignisse wenn möglich handhabt, da ich denke, dass es eine einfachere Weise geben muss, um das gewünschte Ergebnis zu erzielen.

Antwort

1

Ich würde vorschlagen, ein button_press_event hier zu verwenden. Daraus können Sie leicht die Koordinaten des angeklickten Pixels erhalten. Im Fall einer imshow Handlung ist es noch einfacher,

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

Komplettes Beispiel (unter Verwendung von 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() 
+0

Aha, danke, 'button_press_event' war perfekt! Ich benutze immer noch lieber pcolormesh, da ich '.set_bad()' und andere pcolormesh-spezifische (soweit ich es verstehe) Funktionalität verwende. Ich weiß, dass ähnliche Dinge mit IMshow noch möglich sind, aber es macht keinen Sinn, IMO zu ändern, da ich gerade getestet habe und Ihr Fix funktioniert mit pcolormesh, da ich die Koordinaten zurückbekomme und das wieder in das umsetzen kann, was ich brauche. – Vlox

+0

Ja, so ist der Unterschied nur, dass in pcolormesh die Koordinaten um 0,5 verschoben sind, was Sie berücksichtigen müssen. – ImportanceOfBeingErnest

+0

Ah ja, auch imshow Koordinatensystem beginnt mit (0,0) oben links im Plot vs. unten links, aber nicht schwer zu modifizieren, um in jedem Fall zu funktionieren. – Vlox

Verwandte Themen