matplotlib draw_artist和canvas更新,删除以前的avxline [英] matplotlib draw_artist and canvas update removing previous avxline

查看:101
本文介绍了matplotlib draw_artist和canvas更新,删除以前的avxline的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用canvas.update()时遇到麻烦,除了只在canvas.draw()上,它没有删除以前的draw_artist。我想做的是及时在30多个子图中绘制一条垂直线(即,鼠标和垂直线位置之间没有明显的延迟)。如果我使用canvas.draw()而不是canvas.update(),则由于要重绘的子图的数量,会有很大的延迟。我为绘制垂直线的鼠标实现的代码如下所示。用户双击时,跨越所有子图的悬停线已经初始化。如果我使用canvas.draw()有什么方法可以消除延迟,或者如果我使用canvas.update()有什么方法可以消除之前绘制的垂直线。

I'm having trouble with canvas.update() not removing the previous draw_artist except only on canvas.draw(). What I'm trying to do is draw a verticle line across 30+ subplots in a timely fashion (i.e no noticeable delay between mouse and verticle line position). If I use canvas.draw() instead of canvas.update(), there is a significant delay due to the number of subplots that are being redrawn. The code I've implemented for the mouse mouse which draws the verticle line is shown below. The hovering line which spans across all subplots is initialized already when the user double click. Is there any way to remove the delay if I use canvas.draw(), or remove the previous drawn vertical line if I use 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()


推荐答案

A 。 draw_idle()


首先,使用 self.canvas.draw_idle()代替 self.canvas.draw() draw_idle 仅在程序不忙于做其他事情时才绘制画布。这样做可能会更好,因为它绘制画布的频率降低了,这似乎是违反直觉的,但这恰恰是要点:在画布已经被重绘的情况下,它不会尝试重绘它,因此会限制重绘事件的数量。 ,否则将会排队并限制性能。

A. draw_idle()

First, you would already gain a bit by using self.canvas.draw_idle() instead of self.canvas.draw(). draw_idle only draws the canvas if the program is not busy doing other stuff. It may seem counterintuitive that this should perform better, as it draws the canvas less often, but that is exactly the point: It will not try to redraw it in an instance where the canvas is already being redrawn and thus limit the number of redraw events, which would otherwise queue up and limit the performance.

如果上述方法仍然不能令人满意,您可以使用 blitting 技术。在SO上对此有一个很好的答案:高效Matplotlib重绘

If the above still does not give satisfactory results, you may use a technique called blitting. There is a very good answer about this here on SO: Efficient Matplotlib Redrawing

该想法本质上是为画布拍摄快照并将其存储。在这种情况下,可以将此存储的区域放回画布中,并且只需要重画更新的艺术家。

The idea is essentially to take a snapshot of the canvas and store it. On the event, this stored region may be put back into the canvas and only the updated artist needs to be redrawn.

在这种情况下,问题如下: p>

In this case from the question, it would look as follows:

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)

这篇关于matplotlib draw_artist和canvas更新,删除以前的avxline的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆