我正在使用matplotlib backend_qt5agg
来处理将matplotlib画布绘制到qt窗口中。用户可以在绘图上绘制矩形(matplotlib.patches.Rectangle
类型),并通过调用canvas.draw()
方法显示矩形。如果画布包含大量数据,此方法可能会非常慢,我想加快速度。
寻找我在backend_qt5agg
手册中找到的解决方案,称为drawRectangle(rect)
的方法存在。希望这个方法只能绘制补丁而不重绘整个画布,我试图使用Rectangle补丁作为输入调用此方法。所以我打电话给canvas.drawRectangle(my_rect)
而不是叫canvas.draw()
。这没有任何吸引力。
不幸的是,backend_qt5agg
手册纯粹是文件记录。所以我的问题是:drawRectangle
方法如何工作,它应该比重绘整个画布表现更好?
最小的例子(单击鼠标并在画布内移动时显示一个矩形)(只需在self.canvas.draw()
中使用self.canvas.drawRectangle(self.rect)
更改on_motion
以查看测试drawRectangle
方法):
import sys
import matplotlib
from PyQt5 import QtCore
import PyQt5.QtWidgets as QtW
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.patches import Rectangle
class MainWindow(QtW.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('MyWindow')
self._main = QtW.QWidget()
self.setCentralWidget(self._main)
# Set canvas properties
self.fig = matplotlib.figure.Figure(figsize=(5,5))
self.canvas = FigureCanvasQTAgg(self.fig)
self.ax = self.fig.add_subplot(1,1,1)
self.rect = Rectangle((0,0), 0.2, 0.2, color='k', fill=None, alpha=1)
self.ax.add_patch(self.rect); self.rect.set_visible(False)
self.canvas.draw()
# set Qlayout properties and show window
self.gridLayout = QtW.QGridLayout(self._main)
self.gridLayout.addWidget(self.canvas)
self.setLayout(self.gridLayout)
self.show()
# connect mouse events to canvas
self.fig.canvas.mpl_connect('button_press_event', self.on_click)
self.fig.canvas.mpl_connect('motion_notify_event', self.on_motion)
def on_click(self, event):
if event.button == 1 or event.button == 3:
# left or right click: get the x and y coordinates
if event.inaxes is not None:
self.xclick = event.xdata
self.yclick = event.ydata
self.on_press = True
def on_motion(self, event):
# draw the square
if event.button == 1 or event.button == 3 and self.on_press == True:
if (self.xclick is not None and self.yclick is not None):
x0, y0 = self.xclick, self.yclick
x1, y1 = event.xdata, event.ydata
if (x1 is not None or y1 is not None):
self.rect.set_width(x1 - x0)
self.rect.set_height(y1 - y0)
self.rect.set_xy((x0, y0))
self.rect.set_visible(True)
self.canvas.draw() # self.canvas.drawRectangle(self.rect)
if __name__ == '__main__':
app = QtCore.QCoreApplication.instance()
if app is None: app = QtW.QApplication(sys.argv)
win = MainWindow()
app.aboutToQuit.connect(app.deleteLater)
app.exec_()
您可以使用已作为matplotlib.widgets的一部分包含的RectangleSelector
小部件,而不是自己添加矩形。
这是一个例子,你需要对它进行修改并使其适应你的需求,但我希望它会让你前进:
import sys
import matplotlib
from PyQt5 import QtCore
import PyQt5.QtWidgets as QtW
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.widgets import RectangleSelector
class MainWindow(QtW.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('MyWindow')
self._main = QtW.QWidget()
self.setCentralWidget(self._main)
# Set canvas properties
self.fig = matplotlib.figure.Figure(figsize=(5,5))
self.canvas = FigureCanvasQTAgg(self.fig)
self.ax = self.fig.add_subplot(1,1,1)
self.canvas.draw()
self.rs = RectangleSelector(self.ax, self.line_select_callback,
drawtype='box', useblit=True,
button=[1, 3], # don't use middle button
minspanx=5, minspany=5,
spancoords='pixels',
interactive=True)
# set Qlayout properties and show window
self.gridLayout = QtW.QGridLayout(self._main)
self.gridLayout.addWidget(self.canvas)
self.setLayout(self.gridLayout)
self.show()
# connect mouse events to canvas
self.fig.canvas.mpl_connect('button_press_event', self.on_click)
def on_click(self, event):
if event.button == 1 or event.button == 3 and not self.rs.active:
self.rs.set_active(True)
else:
self.rs.set_active(False)
def line_select_callback(self, eclick, erelease):
x1, y1 = eclick.xdata, eclick.ydata
x2, y2 = erelease.xdata, erelease.ydata
print("(%3.2f, %3.2f) --> (%3.2f, %3.2f)" % (x1, y1, x2, y2))
print(" The button you used were: %s %s" % (eclick.button, erelease.button))
if __name__ == '__main__':
app = QtCore.QCoreApplication.instance()
if app is None: app = QtW.QApplication(sys.argv)
win = MainWindow()
app.aboutToQuit.connect(app.deleteLater)
app.exec_()
参考:https://matplotlib.org/examples/widgets/rectangle_selector.html