【问题标题】:Python 2.7 Qt Matplotlib : subplot ID reference from eventPython 2.7 Qt Matplotlib:来自事件的子图 ID 参考
【发布时间】:2023-04-05 13:11:01
【问题描述】:

我的目标是确定用户点击了哪个子图。更准确地说,在 matplotlib 类中,我可以使用 event.inaxes 识别子图。伟大的。但我无法在 Qt 小部件类中获得该事件。 我肯定错过了一些东西...... 这是我最近一次“尴尬”尝试的代码。关于如何进行的任何建议?

我不是 Python 专家。必须使用 Python 2.7(别无选择)

from __future__ import print_function
from __future__ import division

import sys

from PyQt4 import QtGui
from PyQt4 import QtCore
from PyQt4.QtCore import *
from PyQt4.QtGui import *

from matplotlib.figure import Figure
from matplotlib.backend_bases import key_press_handler
from matplotlib.backend_bases import Event
from matplotlib.backends.backend_qt4agg import (
FigureCanvasQTAgg as FigureCanvas,
NavigationToolbar2QT as NavigationToolbar)

#Connect InventoryChartsWidget to ChartFigure: QT
class TheConnector(QtCore.QObject):

   selecteddataregion=pyqtSignal(name='selecteddataregion')

   def emitsignal(self,xmin,xmax,ymin,ymax):
       self.selecteddataregion.emit()

#Chart including events: MATPLOTLIB
class ChartFigure(Figure):

def onclick(self,event):
    #MAIN ISSUE
    #HOW TO RETURN THE subplot axes to class InventoryChartsWidget?    

    if event.button==1 :
       self.ConnSbPlt.emitsignal(1.0,1.0,2.0,2.0)
       print('OK: Axes is ... ', event.inaxes)

def __init__(self,Conn):
    #Init the Matplotlib      
    Figure.__init__(self) #initialize the orginal class, see also super()
    super(ChartFigure, self).__init__()
    self.canvas=FigureCanvas(self)
    self.ConnSbPlt=Conn

#Chart including events: QT  
class InventoryChartsWidget(QtGui.QDialog):

def __init__(self, parent=None,xlimlow=0,xlimhigh=100,ylimlow=0,ylimhigh=100, G_array=[], N_array=[], ddom_array=[], hdom_array=[], speciesDict={}):

    QMainWindow.__init__(self, parent)

    #Fake stupid data 
    self.mG_array  = [2] * 10
    self.mHdom_array = [0.5] * 10

    #jte to make sur I have it
    self.xdata_start=-1.0

    #fake plot to get a member of type subplot: UGLY!
    #Attempt to create a member object "axes"
    self.tabFake = QtGui.QWidget()
    self.tabFake = self.create_tab(self.tabFake)
    self.tabFake.plots = []
    self.subPlotFake = self.tabFake.fig.add_subplot(111)

    print("here is OK; it exists ...", self.subPlotFake)

    self.create_main_frame()

    self.setModal(False)
    self.setVisible(True)
    self.show()


def create_main_frame(self):
    #Associate a Qwidget with the InventoryChartsWidget widget

    print("OK here too; it exists ... ",self.subPlotFake)

    self.main_frame = QtGui.QWidget()
    LesTabs = QtGui.QTabWidget()
    self.tabG   = QtGui.QWidget()   

    #Fill the tab with Matplotlib object and draw the charts 
    self.tabG=self.create_tab(self.tabG)
    self.on_draw_G(self.tabG)
    self.tabG.fig.subplots_adjust(left=0.02,bottom=0.05,right=1,top=0.95,wspace=0.2,hspace=0.2)

    LesTabs.addTab(self.tabG,"Chart")

    grid = QGridLayout()
    grid.addWidget(LesTabs, 0, 0)
    self.main_frame.setLayout(grid)
    self.setLayout(grid)
    self.layout().addWidget(self.main_frame)


def UpdatePlot_DataSelection(self):
    #SLOT
    print("Get connected here process the data in the subplot XX...")


def on_draw_G(self,tab):
    #Juts one subplot for test purpose
    tab.fig.clear()
    tab.plots = []
    subPlot = tab.fig.add_subplot(111)
    subPlot.hold(False)
    tab.plots.append(subPlot)
    self.PlotData_G(subPlot,self.mG_array,self.mHdom_array)
    subPlot = tab.fig.add_subplot(122)
    subPlot.hold(False)
    tab.plots.append(subPlot)
    self.PlotData_G(subPlot,self.mG_array,self.mHdom_array)
    tab.canvas.draw()    

def create_tab(self,tab):    
    #Create the tab widget, associated with Matplotlib plot

    print("OK member exists ... ", self.xdata_start)
    print("OK member exists ",self.tabFake)

    #ISSUE HERE: don't understand
    #print("NOT OK !!! member does not exist Why ? ",self.subPlotFake)

    Conn=TheConnector()
    #MATPLOTLIB
    tab.fig = ChartFigure(Conn)
    tab.canvas = FigureCanvas(tab.fig)
    tab.canvas.setParent(tab)
    tab.canvas.setFocusPolicy(Qt.StrongFocus)
    tab.canvas.setFocus()

    #connect signal to slot 
    Conn.selecteddataregion.connect(self.UpdatePlot_DataSelection)

    tab.mpl_toolbar = NavigationToolbar(tab.canvas, tab)

    vbox = QVBoxLayout()
    vbox.addWidget(tab.canvas)  
    vbox.addWidget(tab.mpl_toolbar)
    tab.setLayout(vbox)  

    tab.canvas.mpl_connect('button_press_event', tab.fig.onclick)

    return tab    

def on_key_press(self, event):
    #Keyboard input: standard mpl key press
    key_press_handler(event, self.canvas, self.mpl_toolbar)

def PlotData_G(self, plot, G_array, hdom_array):
    # Plot G
    plot.hold(False)
    plot.scatter(x=hdom_array, y=G_array, marker='+',linewidths=1.5)
    plot.set_autoscaley_on(True)
    plot.tick_params(labelsize=8)

def main():
app = QApplication(sys.argv)
form = InventoryChartsWidget(xlimlow=0,xlimhigh=60,ylimlow=0,ylimhigh=80)
form.show()
app.exec_()

if __name__ == "__main__":
main()

有 3 个类: TheConnector 是一个 Signal/Slot QT 类 ChartFigure 是 matplotlib 类(包括所需的鼠标事件) InventoryChartsWidget是主widget(Qt;这里我需要subplot的ID)

任何帮助将不胜感激。谢谢你。

【问题讨论】:

  • “尴尬”可能是正确的词。我无法想象这样的结构会有意义的情况。为了解决此代码的问题,您可能最好发出一个包含 matplotlib 事件的信号,以便插槽可以处理它。更一般地说,我认为拥有这三个课程并在其中一个课程中捕获事件然后将其转移到另一个课程没有任何意义。
  • 感谢您以新鲜和独立的方式查看插图代码。这当然是一个非常简化和非常简短的原始代码版本来解释问题的本质。那么这三个类是有意义的(至少在要求改变之前......再次)。关于捕获事件并传递它,原因是保持层次结构而不是类的纠缠(->结构)。

标签: python events matplotlib pyqt subplot


【解决方案1】:

这是一个可行的解决方案。真正的限制是我在 python 中的想法(更具体地说,缺少正确声明的变量......无法使用它)

from __future__ import print_function
from __future__ import division

import sys

from PyQt4 import QtGui
from PyQt4 import QtCore
from PyQt4.QtCore import *
from PyQt4.QtGui import *

from matplotlib.figure import Figure
from matplotlib.backend_bases import key_press_handler
from matplotlib.backend_bases import Event
from matplotlib.backends.backend_qt4agg import (
FigureCanvasQTAgg as FigureCanvas,
NavigationToolbar2QT as NavigationToolbar)


#Connect InventoryChartsWidget to ChartFigure: QT
class TheConnector(QtCore.QObject):

   selecteddataregionARG=pyqtSignal(object,name='selecteddataregionIN')

   def emitsignalEvent(self,TheEvent):
       self.selecteddataregionARG.emit(TheEvent)    

#Chart including events: MATPLOTLIB
class ChartFigure(Figure):

def onclick(self,event):
    #MAIN ISSUE
    #HOW TO RETURN THE subplot axes to class InventoryChartsWidget class?    

    if event.button==1 :
       print('Event: Axes is ... ', event.inaxes)
       self.ConnSbPlt.emitsignalEvent(event.inaxes)

def __init__(self,Conn):
    #Init the Matplotlib      
    Figure.__init__(self) #initialize the orginal class, see also super()
    super(ChartFigure, self).__init__()
    self.canvas=FigureCanvas(self)
    self.ConnSbPlt=Conn

#Chart including events: QT  
class InventoryChartsWidget(QtGui.QDialog):

def __init__(self, parent=None,xlimlow=0,xlimhigh=100,ylimlow=0,ylimhigh=100, G_array=[], N_array=[], ddom_array=[], hdom_array=[], speciesDict={}):

    QMainWindow.__init__(self, parent)

    #Fake stupid data 
    self.mG_array  = [2] * 10
    self.mHdom_array = [0.5] * 10

    #jte to make sur I have it
    self.xdata_start=-1.0

    self.create_main_frame()

    self.setModal(False)
    self.setVisible(True)
    self.show()


def create_main_frame(self):
    #Associate a Qwidget with the InventoryChartsWidget widget

    self.main_frame = QtGui.QWidget()
    LesTabs = QtGui.QTabWidget()
    self.tabG   = QtGui.QWidget()   

    #Fill the tab with Matplotlib object and draw the charts 
    self.tabG=self.create_tab(self.tabG)
    self.on_draw_G(self.tabG)
    self.tabG.fig.subplots_adjust(left=0.02,bottom=0.05,right=1,top=0.95,wspace=0.2,hspace=0.2)

    LesTabs.addTab(self.tabG,"Chart")

    grid = QGridLayout()
    grid.addWidget(LesTabs, 0, 0)
    self.main_frame.setLayout(grid)
    self.setLayout(grid)
    self.layout().addWidget(self.main_frame)


def UpdatePlot_DataSelection_withArg(self,TheEvent):
    #SLOT
    print("WITH ARG : Get connected here process the data in the subplot XX...",TheEvent)


def on_draw_G(self,tab):
    #Juts one subplot for test purpose
    tab.fig.clear()
    tab.plots = []
    subPlot = tab.fig.add_subplot(111)
    subPlot.hold(False)
    tab.plots.append(subPlot)
    self.PlotData_G(subPlot,self.mG_array,self.mHdom_array)
    subPlot = tab.fig.add_subplot(122)
    subPlot.hold(False)
    tab.plots.append(subPlot)
    self.PlotData_G(subPlot,self.mG_array,self.mHdom_array)
    tab.canvas.draw()    

def create_tab(self,tab):    
    #Create the tab widget, associated with Matplotlib plot

    Conn=TheConnector()
    #MATPLOTLIB
    tab.fig = ChartFigure(Conn)
    tab.canvas = FigureCanvas(tab.fig)
    tab.canvas.setParent(tab)
    tab.canvas.setFocusPolicy(Qt.StrongFocus)
    tab.canvas.setFocus()

    #connect signal to slot 
    Conn.selecteddataregionARG.connect(lambda who="Three": self.UpdatePlot_DataSelection_withArg(who))

    tab.mpl_toolbar = NavigationToolbar(tab.canvas, tab)

    vbox = QVBoxLayout()
    vbox.addWidget(tab.canvas)  
    vbox.addWidget(tab.mpl_toolbar)
    tab.setLayout(vbox)  

    tab.canvas.mpl_connect('button_press_event', tab.fig.onclick)

    return tab    

def on_key_press(self, event):
    #Keyboard input: standard mpl key press
    key_press_handler(event, self.canvas, self.mpl_toolbar)

def PlotData_G(self, plot, G_array, hdom_array):
    # Plot G
    plot.hold(False)
    plot.scatter(x=hdom_array, y=G_array, marker='+',linewidths=1.5)
    plot.set_autoscaley_on(True)

def main():
app = QApplication(sys.argv)
form = InventoryChartsWidget(xlimlow=0,xlimhigh=60,ylimlow=0,ylimhigh=80)
form.show()
app.exec_()

if __name__ == "__main__":
main()

也许它可以帮助某人...... 我们当然可以争论这 3 个类是否有意义,但这是另一个话题。

【讨论】:

    【解决方案2】:

    以下是将事件转移到主类的方法:

    from __future__ import print_function
    from __future__ import division
    
    import sys
    
    from PyQt4 import QtGui
    from PyQt4 import QtCore
    
    from matplotlib.figure import Figure
    from matplotlib.backend_bases import key_press_handler
    from matplotlib.backends.backend_qt4agg import (
    FigureCanvasQTAgg as FigureCanvas,
    NavigationToolbar2QT as NavigationToolbar)
    
    #Connect InventoryChartsWidget to ChartFigure: QT
    class TheConnector(QtCore.QObject):
    
        selecteddataregion=QtCore.pyqtSignal(object, name='selecteddataregion')
    
        def emitsignal(self,xmin,xmax,ymin,ymax, event):
            self.selecteddataregion.emit((xmin,xmax,ymin,ymax, event))
    
    #Chart including events: MATPLOTLIB
    class ChartFigure(Figure):
    
        def onclick(self,event):
            #MAIN ISSUE
            #HOW TO RETURN THE subplot axes to class InventoryChartsWidget?    
    
            if event.button==1 :
                print('OK: Axes is ... ', event.inaxes)
                self.ConnSbPlt.emitsignal(1.0,1.0,2.0,2.0, event)
    
    
        def __init__(self,Conn):
            #Init the Matplotlib      
            Figure.__init__(self) #initialize the orginal class, see also super()
            super(ChartFigure, self).__init__()
            self.canvas=FigureCanvas(self)
            self.ConnSbPlt=Conn
    
    #Chart including events: QT  
    class InventoryChartsWidget(QtGui.QDialog):
    
        def __init__(self, parent=None,xlimlow=0,xlimhigh=100,ylimlow=0,ylimhigh=100, G_array=[], N_array=[], ddom_array=[], hdom_array=[], speciesDict={}):
    
            QtGui.QMainWindow.__init__(self, parent)
    
            #Fake stupid data 
            self.mG_array  = [2] * 10
            self.mHdom_array = [0.5] * 10
    
            #jte to make sur I have it
            self.xdata_start=-1.0
    
            #fake plot to get a member of type subplot: UGLY!
            #Attempt to create a member object "axes"
            self.tabFake = QtGui.QWidget()
            self.tabFake = self.create_tab(self.tabFake)
            self.tabFake.plots = []
            self.subPlotFake = self.tabFake.fig.add_subplot(111)
    
            print("here is OK; it exists ...", self.subPlotFake)
    
            self.create_main_frame()
    
            self.setModal(False)
            self.setVisible(True)
            self.show()
    
    
        def create_main_frame(self):
            #Associate a Qwidget with the InventoryChartsWidget widget
    
            print("OK here too; it exists ... ",self.subPlotFake)
    
            self.main_frame = QtGui.QWidget()
            LesTabs = QtGui.QTabWidget()
            self.tabG   = QtGui.QWidget()   
    
            #Fill the tab with Matplotlib object and draw the charts 
            self.tabG=self.create_tab(self.tabG)
            self.on_draw_G(self.tabG)
            self.tabG.fig.subplots_adjust(left=0.02,bottom=0.05,right=1,top=0.95,wspace=0.2,hspace=0.2)
    
            LesTabs.addTab(self.tabG,"Chart")
    
            grid = QtGui.QGridLayout()
            grid.addWidget(LesTabs, 0, 0)
            self.main_frame.setLayout(grid)
            self.setLayout(grid)
            self.layout().addWidget(self.main_frame)
    
    
        def UpdatePlot_DataSelection(self, transfer_object):
            #SLOT
            xmin,xmax,ymin,ymax, event = transfer_object
            print ("Axes are now in the InventoryChartsWidget: ", event.inaxes)
    
    
        def on_draw_G(self,tab):
            #Juts one subplot for test purpose
            tab.fig.clear()
            tab.plots = []
            subPlot = tab.fig.add_subplot(111)
            #subPlot.hold(False)
            tab.plots.append(subPlot)
            self.PlotData_G(subPlot,self.mG_array,self.mHdom_array)
            subPlot = tab.fig.add_subplot(122)
            #subPlot.hold(False)
            tab.plots.append(subPlot)
            self.PlotData_G(subPlot,self.mG_array,self.mHdom_array)
            tab.canvas.draw()    
    
        def create_tab(self,tab):    
            #Create the tab widget, associated with Matplotlib plot
    
            print("OK member exists ... ", self.xdata_start)
            print("OK member exists ",self.tabFake)
    
            #ISSUE HERE: don't understand
            #print("NOT OK !!! member does not exist Why ? ",self.subPlotFake)
            # reason: self.subPlotFake does not yet exist 
    
            Conn=TheConnector()
            #MATPLOTLIB
            tab.fig = ChartFigure(Conn)
            tab.canvas = FigureCanvas(tab.fig)
            tab.canvas.setParent(tab)
            tab.canvas.setFocusPolicy(QtCore.Qt.StrongFocus)
            tab.canvas.setFocus()
    
            #connect signal to slot 
            Conn.selecteddataregion.connect(self.UpdatePlot_DataSelection)
    
            tab.mpl_toolbar = NavigationToolbar(tab.canvas, tab)
    
            vbox = QtGui.QVBoxLayout()
            vbox.addWidget(tab.canvas)  
            vbox.addWidget(tab.mpl_toolbar)
            tab.setLayout(vbox)  
    
            tab.canvas.mpl_connect('button_press_event', tab.fig.onclick)
    
            return tab    
    
        def on_key_press(self, event):
            #Keyboard input: standard mpl key press
            key_press_handler(event, self.canvas, self.mpl_toolbar)
    
        def PlotData_G(self, plot, G_array, hdom_array):
            # Plot G
            #plot.hold(False) #axes.hold is deprecated.
            plot.scatter(x=hdom_array, y=G_array, marker='+',linewidths=1.5)
            plot.set_autoscaley_on(True)
            plot.tick_params(labelsize=8)
    
    def main():
        app = QtGui.QApplication(sys.argv)
        form = InventoryChartsWidget(xlimlow=0,xlimhigh=60,ylimlow=0,ylimhigh=80)
        form.show()
        app.exec_()
    
    if __name__ == "__main__":
        main()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      • 1970-01-01
      • 2020-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多