Intéraction PyQT et MatplotLib

Intéraction PyQT et MatplotLib - Python - Programmation

Marsh Posté le 23-08-2007 à 22:11:26    

Bonjour à tous
 
Je commence à bosser avec MatPlotLib (http://matplotlib.sourceforge.net) qui est une librairie pour générer des graphiques mais j'ai un mal fou à le faire tourner avec PyQT. J'ai l'impression qu'il y a une sale intéraction entre le gestionnaire d'évènements PyQT et le gestionnaire d'évènements MatPlotLib... ou alors j'ai pas encore compris comment bien intégrer un graphique MatPlotLib dans des widgets QT.
 
J'ai pu voir avec divers exemples que MatPlotLib contient un objet "FigureCanvas" qui peut être intégré comme widget dans QT. Quand on utilise cette méthode, on ne passe plus par le gestionnaire d'évènements MatPlotLib car c'est QT qui prend tout en charge. Mais la fenêtre qui apparaît n'est plus celle qui apparait quand on tape directement les ordres Pylab (il n'y a plus de menu pour zoomer, etc).
J'ai eu un autre exemple où c'est dans MatPlotLib qu'on pouvait intégrer des QObject mais dans ce cas là, cela signifie qu'il faut utiliser MatPlotLib pour faire toute l'application et probablement donc ne plus passer par une QApplication.
 
A titre d'exemple, j'a écrit un tout petit programme PyQT qui affiche 2 boutons

  • Le premier fait apparaître une widget QT qui intègre 2 courbes et qui contient elle-même 2 boutons. Chaque bouton fait apparaître/disparaître une des 2 courbes => ça marche mais

1) la fenêtre n'est donc pas une fenêtre typique de matplotlib (il n'y a pas le menu classique qui permet de déplacer/zoomer/sauvegarder
2) l'intéraction bouton <=> affichage/masquage de chaque courbe est moyenne => il est nécessaire de a) cliquer sur le bouton et b) cliquer dans le graphique pour que l'action se passe

  • Le second bouton lance directement un simple graphique en appelant le gestionnaire d'évènements "show()" de matplotlib => là, c'est la cata => la première fois le graphique s'affiche bien mais tant que la fenêtre est affichée, j'ai plus accès à l'IHM PyQt... et si je ferme la fenêtre puis que je la réappelle par le biais du bouton => la fenêtre apparaît mais ne se ferme plus


Voici le code

Code :
  1. #!/usr/bin/python
  2. # coding: Latin-1 -*-
  3. import sys
  4. from qt import *
  5. from pylab import *
  6. from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas
  7. from matplotlib.figure import Figure
  8.  
  9. class QtAppli(QApplication):
  10.     "Fenêtre de l'application"
  11.  
  12.     # Constructeur fenêtre
  13.     def __init__(self,
  14.             argv):
  15.  
  16.         # Appel constructeur de l'objet hértié
  17.         QApplication.__init__(self, argv)
  18.  
  19.         # Attributs de l'application
  20.         self.argv=argv
  21.  
  22.         # Widget principale
  23.         self.wid=QMainWindow()
  24.         self.setMainWidget(self.wid)
  25.         self.wid.setCentralWidget(QWidget(self.wid))
  26.         self.wid.statusBar()
  27.  
  28.         # Titre
  29.         self.wid.setCaption("toto" )
  30.  
  31.         # Un espace de rangement
  32.         box=QVBoxLayout(self.wid.centralWidget())
  33.  
  34.         # Le bouton n° 1
  35.         btn1=QPushButton(self.wid.centralWidget())
  36.         btn1.setText("Essai Qt" )
  37.         self.connect(btn1, SIGNAL("clicked()" ), self.slotQt)
  38.         box.addWidget(btn1)
  39.     
  40.         # Le bouton n° 2
  41.         btn2=QPushButton(self.wid.centralWidget())
  42.         btn2.setText("Essai MatPlotLib" )
  43.         self.connect(btn2, SIGNAL("clicked()" ), self.slotMatPlotLib)
  44.         box.addWidget(btn2)
  45.  
  46.     # Affichage et lancement application
  47.     def run(self):
  48.         self.wid.show()
  49.         self.exec_loop()
  50.  
  51.     # Slot qui affiche une fenêtre Qt avec un module matplotlib
  52.     def slotQt(self):
  53.         print "clicked qt"
  54.         graph=QtMatPlotLib(self.wid.centralWidget(), "GraphQT" )
  55.         graph.show()
  56.  
  57.     # Slot qui appelle directement matplotlib
  58.     def slotMatPlotLib(self):
  59.         print "clicked matplotlib"
  60.         x=arange(0, 100, 0.01)
  61.         lab=subplot(111)
  62.         lab.g=plot(x, sqrt(x))
  63.         matplotlib.interactive(True)
  64.         show()
  65.  
  66. # Objet pour gérer la fenêtre Qt avec matplotlib
  67. class QtMatPlotLib(QDialog):
  68.     def __init__(self,parent,titre, modal = 0,fl = 0):
  69.         QDialog.__init__(self,parent,titre,modal,fl)
  70.  
  71.         self.setName(titre)
  72.         self.setCaption("QtMatPlotLib" )
  73.  
  74.         self.Layout = QVBoxLayout(self)
  75.         self.Layout.setGeometry(QRect(30,30,531,331))
  76.  
  77.         self.fig=Figure(figsize=(5, 4), dpi=100)
  78.         self.sub=self.fig.add_subplot(111)
  79.         t=arange(0, 100, 0.1)
  80.         self.l1,=self.sub.plot(t, sqrt(t))
  81.         self.l2,=self.sub.plot(t, sin(t))
  82.         can=FigureCanvas(self.fig)
  83.         can.reparent(self, QPoint(0, 0))
  84.         self.Layout.addWidget(can)
  85.  
  86.         btn1=QPushButton(self)
  87.         btn1.setText("ligne 1" )
  88.         self.connect(btn1, SIGNAL("clicked()" ), self.changel1)
  89.         self.Layout.addWidget(btn1)
  90.  
  91.         btn2=QPushButton(self)
  92.         btn2.setText("ligne 2" )
  93.         self.connect(btn2, SIGNAL("clicked()" ), self.changel2)
  94.         self.Layout.addWidget(btn2)
  95.  
  96.         self.resize(QSize(600, 300).expandedTo(self.minimumSizeHint()))
  97.  
  98.     def changel1(self):
  99.         print "clicked l1"
  100.         self.l1.set_visible(not self.l1.get_visible())
  101.         self.sub.draw()
  102.  
  103.     def changel2(self):
  104.         print "clicked l2"
  105.         self.l2.set_visible(not self.l2.get_visible())
  106.         self.sub.draw()
  107.  
  108.     def __del__(self):
  109.         print "QMatPlotLib deleted"
  110.  
  111. Appli=QtAppli(sys.argv)
  112. Appli.run()


 
J'ai cherché de partout mais j'arrive pas à trouver une bonne doc expliquant bien comment intégrer matplotlib dans une application. La doc de matplotlib est bourrée d'exemples mais chaque exemple est écrit comme un programme unique se finissant par un show() final et aucun n'est vu comme un élément pouvant être intégré dans un ensemble plus vaste.
Si quelqu'un pouvait m'aider ce serait sympa. Sinon j'ai vu que d'autres librairies de plotting existent comme veusz ou bien gnuplot ou bien chaco qui a l'air toute nouvelle (http://code.enthought.com/chaco)...
 
PS: Je bosse avec PyQT issu de QT3 et Python2.4 (et avant que tous les boulettos du monde viennent me dire que Python2.5 + QT4 sont sortis depuis des lustres, je précise que je travaille avec plusieurs systèmes dont un vieux solaris de 1996 et que j'ai pas réussi à compiler QT4 sur ce système donc je peux pas me disperser à bosser sur plusieurs versions de QT)
 
Voilà. Merci à ceux qui peuvent m'aider... et merci à ceux qui le voudraient mais qui ne savent pas comment  ;)


Message édité par Sve@r le 23-08-2007 à 22:56:14

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 23-08-2007 à 22:11:26   

Reply

Marsh Posté le 27-08-2007 à 17:12:23    

Bon, j'ai vu que beaucoup de monde avait lu mon pb mais il semble trop pointu et personne n'a trouvé. Donc j'abandonne matplotlib pour me consacrer à PyQWT (librairie plot faite pour qt) => http://pyqwt.sourceforge.net
 
Merci à tous.


Message édité par Sve@r le 27-08-2007 à 17:13:05

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 06-01-2008 à 21:57:25    

Bonjour,
 
Je ne suis pas en mesure d'apporter une solution à ton problème (il est de toute façon certainement trop tard !), mais je serai très intéressé que tu nous exposes brièvement ton retour d'expérience sur l'utilisation de PyQwt pour afficher des graphes (2D ou 3D avec PyQwt3D ?) dans une IHM programmée avec la librairie Qt.
 
En effet, de mon côté, je découvre à peine le développement d'applications scientifiques avec Python (que je souhaite utiliser pour remplacer MATLAB et IDL). Et d'après mes recherches sur le net, PyQt semble la meilleure librairie d'IHM actuellement (juste devant wxPython, qui est paraît-il moins performante, moins complète et moins documentée). Je comptais donc beaucoup sur l'utilisation de matplotlib avec PyQt pour intégré des graphes 2D et 3D dans des IHM.
 
Merci d'avance, et bonne continuation,
PR

Reply

Marsh Posté le 08-03-2008 à 16:16:59    

Moi aussi, je me suis lancé dans la programmation avec python et pyQt4 pour avoir un équivalent libre à Matlab.
J'ai fait un petit programme en m'inspirant de wxCursor_demo que l'on trouve sur le site Matplotlib dans la section embedded.
 
Le premier fichier est issu de QtDesigner

Code :
  1. # -*- coding: utf-8 -*-
  2. # Form implementation generated from reading ui file
  3. #
  4. # Created: Tue Mar 11 16:40:38 2008
  5. #      by: PyQt4 UI code generator 4.3.3
  6. #
  7. # WARNING! All changes made in this file will be lost!
  8. from PyQt4 import QtCore, QtGui
  9. class Ui_mainWindow(object):
  10.     def setupUi(self, mainWindow):
  11.         mainWindow.setObjectName("mainWindow" )
  12.         mainWindow.resize(QtCore.QSize(QtCore.QRect(0,0,402,421).size()).expandedTo(mainWindow.minimumSizeHint()))
  13.         self.centralwidget = QtGui.QWidget(mainWindow)
  14.         self.centralwidget.setObjectName("centralwidget" )
  15.         self.verticalLayout = QtGui.QWidget(self.centralwidget)
  16.         self.verticalLayout.setGeometry(QtCore.QRect(0,0,401,311))
  17.         self.verticalLayout.setObjectName("verticalLayout" )
  18.         self.vboxlayout = QtGui.QVBoxLayout(self.verticalLayout)
  19.         self.vboxlayout.setObjectName("vboxlayout" )
  20.         self.verticalLayout_2 = QtGui.QWidget(self.centralwidget)
  21.         self.verticalLayout_2.setGeometry(QtCore.QRect(0,310,401,71))
  22.         self.verticalLayout_2.setObjectName("verticalLayout_2" )
  23.         self.vboxlayout1 = QtGui.QVBoxLayout(self.verticalLayout_2)
  24.         self.vboxlayout1.setObjectName("vboxlayout1" )
  25.         mainWindow.setCentralWidget(self.centralwidget)
  26.         self.statusbar = QtGui.QStatusBar(mainWindow)
  27.         self.statusbar.setObjectName("statusbar" )
  28.         mainWindow.setStatusBar(self.statusbar)
  29.         self.retranslateUi(mainWindow)
  30.         QtCore.QMetaObject.connectSlotsByName(mainWindow)
  31.     def retranslateUi(self, mainWindow):
  32.         mainWindow.setWindowTitle(QtGui.QApplication.translate("mainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
  33. if __name__ == "__main__":
  34.     import sys
  35.     app = QtGui.QApplication(sys.argv)
  36.     mainWindow = QtGui.QMainWindow()
  37.     ui = Ui_mainWindow()
  38.     ui.setupUi(mainWindow)
  39.     mainWindow.show()
  40.     sys.exit(app.exec_())


 
Dans ce deuxième fichier, j'utilise un vboxlayout pour afficher la courbe et un vboxlayout pour afficher la barre de gestion Matplotlib.
Pour l'instant, les évènements récupérés permettent de gérer l'affichage des coordonnées du curseur dans la status bar.
Le gestionnaire d'évènement est celui de Matplotlib au travers de la commande suivante:

Code :
  1. self.can.mpl_connect('motion_notify_event', self.UpdateStatusBar)


 
Listing du fichier principal:

Code :
  1. # -*- coding: utf-8 -*-
  2. """
  3. Module implementing qtCursorDemo.
  4. """
  5. from PyQt4 import QtCore, QtGui
  6. from PyQt4.QtGui import QMainWindow
  7. from Ui_mainWindow import Ui_mainWindow
  8. from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
  9. from matplotlib.backends.backend_qt4 import NavigationToolbar2QT
  10. from matplotlib.figure import Figure
  11. from pylab import arange, sin
  12. class qtCursorDemo(QMainWindow, Ui_mainWindow):
  13.     """
  14.     Class documentation goes here.
  15.     """
  16.     def __init__(self, parent = None):
  17.         """
  18.         Constructor
  19.         """
  20.         QMainWindow.__init__(self, parent)
  21.         Ui_mainWindow.__init__(self)
  22.         self.setupUi(self)
  23.         self.fig = Figure()
  24.         self.axes=self.fig.add_subplot(111)
  25.         t=arange(0,100,0.1)
  26.         y=sin(t)
  27.        
  28.         self.axes.plot(t,y)
  29.         self.axes.set_xlabel('t')
  30.         self.axes.set_ylabel('sin(t)') 
  31.        
  32.         self.can=FigureCanvas(self.fig)
  33.         self.vboxlayout.addWidget(self.can)
  34.         self.axes.draw
  35.        
  36.         self.toolbar=NavigationToolbar2QT(self.can, self)
  37.         self.vboxlayout1.addWidget(self.toolbar)
  38.        
  39.         self.can.mpl_connect('motion_notify_event', self.UpdateStatusBar)
  40.        
  41.     def UpdateStatusBar(self, event):
  42.         if event.inaxes:
  43.             x, y = event.xdata, event.ydata
  44.             self.statusBar().showMessage(( "x= " + str(x) + "  y=" +str(y) ),0)
  45.             #print "x= " + str(x) + "  y=" +str(y)
  46. if __name__ == "__main__":
  47.      import sys
  48.      app = QtGui.QApplication(sys.argv)
  49.      window = qtCursorDemo()
  50.      window.show()
  51.      sys.exit(app.exec_())


 
La suite sera de m'inspirer de la bibliothèque wxmpl pour gérer de manière autonome le zoom. Mais je suis débutant en python wxPython et pyQt donc cela risque de me prendre un peu de temps.


Message édité par freekolok le 13-03-2008 à 14:12:11

---------------
http://freekolok.free.fr/blog
Reply

Marsh Posté le 05-04-2008 à 20:44:05    

PRayb a écrit :

Bonjour,
 
Je ne suis pas en mesure d'apporter une solution à ton problème (il est de toute façon certainement trop tard !), mais je serai très intéressé que tu nous exposes brièvement ton retour d'expérience sur l'utilisation de PyQwt pour afficher des graphes (2D ou 3D avec PyQwt3D ?) dans une IHM programmée avec la librairie Qt.
 
En effet, de mon côté, je découvre à peine le développement d'applications scientifiques avec Python (que je souhaite utiliser pour remplacer MATLAB et IDL). Et d'après mes recherches sur le net, PyQt semble la meilleure librairie d'IHM actuellement (juste devant wxPython, qui est paraît-il moins performante, moins complète et moins documentée). Je comptais donc beaucoup sur l'utilisation de matplotlib avec PyQt pour intégré des graphes 2D et 3D dans des IHM.
 
Merci d'avance, et bonne continuation,
PR


 
Désolé de répondre si tard, je n'étais pas revenu ici depuis un bon bout de temps. Mais un MP m'aurait rappelé à mes obligations
Pour résumer ben l'implémentation de Qwt est hyper-simple. Un objet Qwt est vu comme un widget donc il suffit en final d'intégrer la widget Qwt dans l'élément Qt (généralement dans un layer quelconque) et puis roule.
D'ailleurs Qwt est tellement lié à Qt que la version windows offre PyQt + PyQwt ensemble => http://www.riverbankcomputing.com/ [...] .3.3-2.exe
 
Si ça intéresse quelqu'un, je peux lui passer le source de mon projet. Je l'ai d'ailleurs déjà passé à Harkonen et à d'autres du fofo Qtfr http://forum.qtfr.org


Message édité par Sve@r le 05-04-2008 à 20:52:04

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 14-01-2009 à 13:21:17    

Je serais intéressé par ton projet voir d'autres si tu en as qui tournent autour des représentations graphiques en Math.
 
Sais-tu s'il est possible d'utiliser la souris avec PyQwt ?

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed