【问题标题】: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