Los escuchadores de eventos matplotlib no funcionan en el widget PyQT

Tengo una biblioteca de objetos matplotlib que se pueden arrastrar y que estoy intentando utilizar con una GUI de PyQt5. Los detectores de eventos de los objetos funcionan correctamente en una ventana de figura de matplotlib independiente, pero no funcionan cuando la figura está incrustada en un widget QT. Ambas gráficas se procesan correctamente y no hay mensajes de error cuando bash arrastrar el parche en el widget QT.

Objeto MCVE:

import matplotlib.patches as patches class _DragObj: def __init__(self, ax): self.parentcanvas = ax.figure.canvas self.parentax = ax self.clickpress = self.parentcanvas.mpl_connect('button_press_event', self.on_click) self.clicked = False def on_click(self, event): if event.inaxes != self.parentax: return self.mousemotion = self.parentcanvas.mpl_connect('motion_notify_event', self.on_motion) self.clickrelease = self.parentcanvas.mpl_connect('button_release_event', self.on_release) self.clickx = event.xdata self.clicky = event.ydata self.clicked = True def on_release(self, event): self.clicked = False self.disconnect() def disconnect(self): self.parentcanvas.mpl_disconnect(self.mousemotion) self.parentcanvas.mpl_disconnect(self.clickrelease) self.parentcanvas.draw() def stopdrag(self): self.myobj.set_url('') self.parentcanvas.mpl_disconnect(self.clickpress) class _DragPatch(_DragObj): def __init__(self, ax, xy): super().__init__(ax) self.oldxy = xy def on_motion(self, event): if not self.clicked: return if event.inaxes != self.parentax: return oldx, oldy = self.oldxy dx = event.xdata - self.clickx dy = event.ydata - self.clicky newxy = [oldx + dx, oldy + dy] self.myobj.xy = newxy self.parentcanvas.draw() def on_release(self, event): self.clicked = False self.oldxy = self.myobj.xy self.disconnect() class DragRectangle(_DragPatch): def __init__(self, ax, xy, width, height, angle=0.0, **kwargs): self.myobj = patches.Rectangle(xy, width, height, angle, **kwargs) ax.add_artist(self.myobj) super().__init__(ax, xy) 

El ejemplo de matplotlib en funcionamiento:

 import minidrag import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(111) rect = minidrag.DragRectangle(ax, (0, 0), 2, 1) ax.set_xlim(-5, 5) ax.set_ylim(-5, 5) plt.show() 

El ejemplo no funcional de PyQT:

 import sys from PyQt5 import QtWidgets as QtW from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar from matplotlib.figure import Figure import minidrag class windowGUI(QtW.QDialog): def __init__(self): super().__init__() # Set up figure width_px = 800 height_px = 600 rect = QtW.QDesktopWidget().availableGeometry() screenrez = (rect.width(), rect.height()) left_px = (screenrez[0] - width_px)/2 top_px = (screenrez[1] - height_px)/2 self.setGeometry(left_px, top_px, width_px, height_px) self.canvas = PlotCanvas() layout = QtW.QVBoxLayout() layout.addWidget(NavigationToolbar(self.canvas, self)) layout.addWidget(self.canvas) self.setLayout(layout) class PlotCanvas(FigureCanvas): def __init__(self): fig = Figure(frameon=False) super().__init__(fig) super().setSizePolicy(QtW.QSizePolicy.Expanding, QtW.QSizePolicy.Expanding) super().updateGeometry() ax = fig.add_subplot(111) rect = minidrag.DragRectangle(ax, (0, 0), 2, 1) ax.set_xlim(-5, 5) ax.set_ylim(-5, 5) app = QtW.QApplication(sys.argv) window = windowGUI() window.show() sys.exit(app.exec_()) 

Estoy usando Python 3.6.0, matplotlib (2.0.0) y PyQt5 (5.8)

¿Qué me estoy perdiendo?

Resulta que el problema no son los eventos de arrastre, sino la instancia de minidrag.DragRectangle solo se recolecta como basura (mientras que el canvas sigue mostrando el rectángulo en su posición original).

Como solución, puede establecer el rectángulo como una variable de instancia:

 self.rect = minidrag.DragRectangle(ax, (0, 0), 2, 1) 

(Probado con Python2.7 y PyQt4.)