Partage
  • Partager sur Facebook
  • Partager sur Twitter

[PyQt5 - MPL] Suppression d'un ancien objet artist

Patches, blit, artiste et PyQt5

    14 février 2017 à 13:26:49

    Salut, je ne sais pas si on pourra m'aider ici mais je tente quand même. J'ai envie de faire un app en PyQt5 utilisant le backend de matplotlib pour faire des graphs (plus précisément je souhaite faire un graph de type parallel coordinates mais ce n'est pas le sujet). Le graph en tant que tel n'est pas un problème, mon ennuie se situe au niveau de la création de patch et surtout de rafraichir l'image au fur et à mesure. Plus concrètement j'ai fait cet exemple rapide sur mpl qui fonctionne comme je le souhaite (il est bugué sur certains points mais osef) :

    import matplotlib.pyplot as plt
    import matplotlib.patches as patches
    
    class Test() :
    
        def __init__(self) :
            self.fig = plt.figure()
            self.ax = self.fig.add_subplot(111)
    
            self.fig.canvas.mpl_connect('button_press_event', self.button_pressed)
            self.fig.canvas.mpl_connect('button_release_event', self.button_released)
            self.fig.canvas.mpl_connect('motion_notify_event', self.notif)
    
            self.drawing = False
            self.patch = None
            self.spos = None
    
    
        def draw_rect(self, pos) :
            spos = (min(self.spos[0], pos[0]), min(self.spos[1], pos[1]))
            width = abs(self.spos[0] - pos[0])
            height = abs(self.spos[1] - pos[1])
            patch = patches.Rectangle(spos, width, height, color="black", alpha=.2)
    
            if self.patch : self.patch.remove()
            self.patch = patch
            self.ax.add_artist(patch)
            self.ax.draw_artist(patch)
            self.fig.canvas.blit(self.patch.get_window_extent())
    
        def button_pressed(self, event) :
            self.drawing = True
            self.spos = (event.xdata, event.ydata)
    
        def button_released(self, event) :
            self.drawing = False
            pos = (event.xdata, event.ydata)
            self.draw_rect(pos)
    
        def notif(self, event) :
            if self.drawing :
                pos = (event.xdata, event.ydata)
                self.draw_rect(pos)
    
    t = Test()
    plt.show()
    

    J'ai tenté de le transposer sur PyQt5 :

    from PyQt5 import QtGui, QtCore, QtWidgets
    import sys
    
    import matplotlib.pyplot as plt
    import matplotlib.patches as patches
    from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
    
    class ApplicationWindow(QtWidgets.QMainWindow) :
        def __init__(self):
            QtWidgets.QMainWindow.__init__(self)
            self.window = QtWidgets.QWidget()
            self.layout = QtWidgets.QHBoxLayout()
            self.graph = TestQt()
            self.layout.addWidget(self.graph)
            self.window.setLayout(self.layout)
    
            self.setCentralWidget(self.window)
            self.showMaximized()
    
    class TestQt(FigureCanvas) :
    
        def __init__(self) :
            self.fig = plt.figure()
            self.ax = self.fig.add_subplot(111)
    
            FigureCanvas.__init__(self, self.fig)
            self.setFocusPolicy(QtCore.Qt.ClickFocus)
    
            self.fig.canvas.mpl_connect('button_press_event', self.button_pressed)
            self.fig.canvas.mpl_connect('button_release_event', self.button_released)
            self.fig.canvas.mpl_connect('motion_notify_event', self.notif)
    
            self.drawing = False
            self.patch = None
            self.spos = None
    
        def draw_rect(self, pos) :
            spos = (min(self.spos[0], pos[0]), min(self.spos[1], pos[1]))
            width = abs(self.spos[0] - pos[0])
            height = abs(self.spos[1] - pos[1])
            patch = patches.Rectangle(spos, width, height, color="black", alpha=.2)
    
            if self.patch : self.patch.remove()
            self.patch = patch
            self.ax.add_artist(patch)
            self.ax.draw_artist(patch)
            self.fig.canvas.blit(self.patch.get_window_extent())
            #self.draw()
    
        def button_pressed(self, event) :
            self.drawing = True
            if not event.inaxes : return
            self.spos = (event.xdata, event.ydata)
    
        def button_released(self, event) :
            self.drawing = False
            pos = (event.xdata, event.ydata)
            self.draw_rect(pos)
    
        def notif(self, event) :
            if self.drawing and event.inaxes :
                pos = (event.xdata, event.ydata)
                self.draw_rect(pos)
    
    qApp = QtWidgets.QApplication(sys.argv)
    qApp.setStyle('cleanlooks')
    aw = ApplicationWindow()
    aw.show()
    sys.exit(qApp.exec_())
    

    Mais là c'est le foirage complet, quand je blit() l'ancien patch n'est jamais supprimé. J'ai passé ma matinée à chercher une solution mais pour l'instant rien n'a été concluant. Une solution reste d'utiliser draw() cependant ça enlève tout l'intérêt du blit() et comme il doit redessiner toute la surface, la fluidité de l'app devient pourrie.

    Merci d'avance !

    -
    Edité par Jevanni 14 février 2017 à 13:27:54

    • Partager sur Facebook
    • Partager sur Twitter
    Anonyme
      14 février 2017 à 16:52:39

      Difficile de t'aider effectivement... Je peux te proposer un exemple ICI, afin que tu puisses voir les points manquants peut-être.
      • Partager sur Facebook
      • Partager sur Twitter
        14 février 2017 à 17:16:01

        J'avais déjà vu cet exemple quelque part, mais je commence à me demander s'il ne s'agit pas d'un problème lié à ma machine et/ou au backend de mpl. Ce qui est étrange, c'est que sur PyQt4 j'avais déjà fait des choses similaires, comme l'utilisation dynamique de axhspan, qui au fond doit être similaire à la gestion d'artistes pour mpl.
        • Partager sur Facebook
        • Partager sur Twitter

        [PyQt5 - MPL] Suppression d'un ancien objet artist

        × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
        × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
        • Editeur
        • Markdown