2017-09-29 47 views
0

作为一个更大的项目的一部分,我正在更新Pyqt5中嵌入的matplotlib上的图形。我有一个onpick事件,它将注释添加到散点并将其删除。在以类似于下面的方式更新我的绘图后,onPick功能会注册两次。有一些潜在的问题没有被正确删除。除了这个数字之外,我还想知道我可以清楚哪些可以纠正我的问题。matplotlib onPick事件注册两次

简单的例子突出问题:

import sys 

from PyQt5.QtGui import * 
from PyQt5.QtWidgets import * 
from PyQt5.QtCore import * 

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas 
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar 
from mpl_toolkits.mplot3d import Axes3D 
import matplotlib.pyplot as plt 

class plot(QWidget): 
    def __init__(self): 
     super().__init__() 
    self.figure = plt.figure() 
    self.canvas = FigureCanvas(self.figure) 

    self.Layout = QVBoxLayout() 

    self.xarray = [1,2,3,4,5,6] 
    self.yarray = [6,7,5,4,2,1] 

    update_btn = QPushButton("Update Plot", self) 
    self.Layout.addWidget(update_btn, 1) 
    update_btn.clicked.connect(self.updateplot) 

    self.createplot() 

    self.setLayout(self.Layout) 

def updateplot(self): 

    self.xarray = [6,7,5,3,2,1] 
    self.figure.clear() 
    self.createplot() 

def createplot(self): 

    ax = self.figure.add_subplot(1,1,1) 
    ax.grid() 
    val = self.displayval(ax) 
    self.plot = ax.plot(self.xarray, self.yarray,'o', marker = 'o', c= 'b', picker = 5)[0] 

    self.Layout.addWidget(self.canvas, 2) 
    self.canvas.draw() 

def displayval(self, ax): 
    def onPick(event): 
     print("connecting") 
     plot = event.artist 

     xval = plot.get_xdata() 
     yval = plot.get_ydata() 
     ind = event.ind 

     if xval[ind].size > 1 or yval[ind].size > 1: return 

     xy = (xval[ind][0], yval[ind][0]) 

     ann = ax.annotate('(%f , %f)' % xy, xy= xy) 

     self.figure.canvas.draw() 

    self.figure.canvas.mpl_connect('pick_event', onPick) 
    return onPick 

if __name__ == '__main__': 
    appl = QApplication(sys.argv) 
    main = plot() 
    main.show() 
    sys.exit(appl.exec_()) 

注:我曾尝试更新的东西轴线值一样

ax.set_xaxis() 

然而,这并不正确地呈现在我的程序中的数据,因此一备选答案将是首选。

+1

我想每次更新情节时都会注册一个新的pick_event。所以,如果你更新一次,你会有onpick调用两次,如果你更新了两次,你会有三次调用,等等。您需要确保只注册一次,独立于更新功能。 – ImportanceOfBeingErnest

+1

我同意@ImportanceOfBeingErnest。在清除图形时,例如在“figure.clear()”之后,或者在将其连接到displayval()之前,必须断开信号/插槽。 – bnaecker

+0

@bnacker在'displayval()'中清除信号/事件队列是解决方法的好主意。我会看看如果我能弄清楚如何做到这一点。然而,我不这样解决了为什么在清除数字后在画布上注册两个动作的问题的根源。 –

回答

0

下面是解决问题的方法。感谢@ImportanceOfBeingErnest解释问题发生的原因。从那里我能够解决这个问题。一旦更新,点击注释只出现一次。该解决方案仅调用displayval一次,并将ax更改为'self.ax'并更新对象变量。

import sys 

from PyQt5.QtGui import * 
from PyQt5.QtWidgets import * 
from PyQt5.QtCore import * 

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas 
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar 
from mpl_toolkits.mplot3d import Axes3D 
import matplotlib.pyplot as plt 

class plot(QWidget): 
    def __init__(self): 
     super().__init__() 

     self.figure = plt.figure() 
     self.canvas = FigureCanvas(self.figure) 

     self.Layout = QVBoxLayout() 

     self.xarray = [1,2,3,4,5,6] 
     self.yarray = [6,7,5,4,2,1] 
     self.init_trigger = True 

     update_btn = QPushButton("Update Plot", self) 
     self.Layout.addWidget(update_btn, 1) 
     update_btn.clicked.connect(self.updateplot) 

     self.createplot() 

     self.setLayout(self.Layout) 

    def updateplot(self): 

     self.xarray = [6,7,5,3,2,1] 
     self.figure.clear() 
     self.createplot() 

    def createplot(self): 


     self.ax = self.figure.add_subplot(1,1,1) 
     self.ax.grid() 
     if self.init_trigger: val = self.displayval() 
     self.plot = self.ax.plot(self.xarray, self.yarray,'o', marker = 'o', c= 'b', picker = 5)[0] 

     self.Layout.addWidget(self.canvas, 2) 
     self.canvas.draw() 
     self.init_trigger = False 

    def displayval(self): 
     def onPick(event): 
      print("connecting") 
      plot = event.artist 

      xval = plot.get_xdata() 
      yval = plot.get_ydata() 
      ind = event.ind 

      if xval[ind].size > 1 or yval[ind].size > 1: return 

      xy = (xval[ind][0], yval[ind][0]) 

      ann = self.ax.annotate('(%f , %f)' % xy, xy= xy) 

      self.figure.canvas.draw() 

     self.figure.canvas.mpl_connect('pick_event', onPick) 
     return onPick 

if __name__ == '__main__': 
    appl = QApplication(sys.argv) 
    main = plot() 
    main.show() 
    sys.exit(appl.exec_())