我在使用canvas.update()时遇到麻烦,除了只在canvas.draw()上删除之前的draw_artist。我想要做的是及时地在30多个子图上绘制一条垂直线(即鼠标和垂直线位置之间没有明显的延迟)。如果我使用canvas.draw()而不是canvas.update(),则由于正在重绘的子图的数量而存在显着的延迟。我为实现垂直线的鼠标鼠标实现的代码如下所示。当用户双击时,已经初始化跨越所有子图的悬停线。如果我使用canvas.draw(),有没有办法删除延迟,或者如果我使用canvas.update(),则删除先前绘制的垂直线。
def onMove(self, event):
if (dblclicked):
self.hoveringLine.set_xdata(event.xdata)
self.canvas.axis1.draw_artist(self.hoveringLine)
self.canvas.update()
编辑#2:这是完整的代码,我为不完整的评论道歉。
from PyQt4 import QtGui, QtCore
import sys
import matplotlib
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
from matplotlib.figure import Figure
class Canvas(FigureCanvasQTAgg):
def __init__(self, parent=None):
self.figure = Figure()
super(Canvas, self).__init__(self.figure)
self.ax1 = self.figure.add_subplot(1,1,1)
self.figure.subplots_adjust(left = 0.05, bottom = 0.02, right = 0.98, top = 0.99)
self.setMinimumWidth(1000)
self.ax1.plot([1,2,3])
self.draw()
def add_subplot(self, data=[]):
rows = len(self.figure.axes) + 1
for index, axes in enumerate(self.figure.axes, start=1):
axes.change_geometry(rows, 1, index)
ax = self.figure.add_subplot(rows, 1, index+1)
ax.plot(data)
ax.patch.set_facecolor('None')
self.figure.set_figheight(self.figure.get_figheight()*1.1)
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.showMaximized()
self.widget = QtGui.QWidget()
self.setCentralWidget(self.widget)
self.widget.setLayout(QtGui.QVBoxLayout())
self.widget.layout().setContentsMargins(0,0,0,0)
self.widget.layout().setSpacing(5)
self.canvas = Canvas(self)
self.scroll = QtGui.QScrollArea(self.widget)
self.scroll.setWidget(self.canvas)
self.scroll.setWidgetResizable(False)
self.numSubplots = 15
for x in range(self.numSubplots):
self.canvas.add_subplot()
self.canvas.adjustSize()
self.canvas.draw()
self.widget.layout().addWidget(self.scroll)
self.showVline = False
self.hoveringLine = None
self.canvas.mpl_connect("button_press_event", self.onClick)
self.canvas.mpl_connect("motion_notify_event", self.onMove)
def onClick(self, event):
if event.dblclick and self.showVline == False:
self.showVline = True
self.hoveringLine = self.canvas.ax1.axvline(x=event.xdata, ymin=-1.2*self.numSubplots, ymax=1.2,
lw=2, zorder=0, clip_on=False)
elif event.dblclick and self.showVline:
self.showVline = False
self.hoveringLine = None
self.canvas.ax1.axvline(x=event.xdata, ymin=-1.2*self.numSubplots, ymax=1.2,
lw=2, zorder=0, clip_on=False)
self.canvas.draw()
else:
pass
def onMove(self, event):
if (self.showVline):
self.hoveringLine.set_xdata(event.xdata)
self.canvas.ax1.draw_artist(self.hoveringLine)
self.canvas.update()
#self.canvas.draw() works as desired but there is a delay due to redrawing
#self.canvas.draw()
def main():
app = QtGui.QApplication(sys.argv)
app.aboutToQuit.connect(app.deleteLater)
GUI = Window()
GUI.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
答案 0 :(得分:1)
首先,您可以使用self.canvas.draw_idle()
代替self.canvas.draw()
获得一些收益。 draw_idle
仅在程序不忙于执行其他操作时才绘制画布。这似乎有点违反直觉,因为它应该更少地绘制画布,但这正是重点:它不会尝试在已经重绘画布的实例中重绘它,从而限制了重绘事件的数量否则会排队并限制性能。
如果上述情况仍无法给出满意的结果,您可以使用名为 blitting 的技术。在SO上有一个非常好的答案:Efficient Matplotlib Redrawing
这个想法主要是拍摄画布的快照并存储它。在该事件中,可以将该存储的区域放回到画布中,并且仅需要重新绘制更新的艺术家。
在这个案例中,问题如下:
def onClick(self, event):
if event.dblclick and self.showVline == False:
self.background = self.canvas.copy_from_bbox(self.canvas.figure.bbox)
self.showVline = True
self.hoveringLine = self.canvas.ax1.axvline(x=event.xdata, ymin=-1.2*self.numSubplots, ymax=1.2,
lw=2, zorder=0, clip_on=False)
elif event.dblclick and self.showVline:
self.showVline = False
self.hoveringLine = None
self.canvas.ax1.axvline(x=event.xdata, ymin=-1.2*self.numSubplots, ymax=1.2,
lw=2, zorder=0, clip_on=False)
self.canvas.draw()
else:
pass
def onMove(self, event):
if (self.showVline):
self.canvas.restore_region(self.background)
self.hoveringLine.set_xdata(event.xdata)
self.canvas.ax1.draw_artist(self.hoveringLine)
self.canvas.blit(self.canvas.figure.bbox)