matplotlib и PyQt: динамическая фигура работает медленно после нескольких загрузок или выглядит грязно

РЕДАКТИРОВАТЬ:

Я решил переписать это, чтобы включить рабочий пример моей проблемы. Хотя это довольно долго, я надеюсь, что это окажется полезным для многих в будущем.

import sys

from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from PyQt4.QtGui import *
from PyQt4.QtCore import *

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.setGeometry(100, 100, 640, 480)
        showButton = QPushButton('Show')

        toolbarShowButton = self.addToolBar('Show button toolbar')

        toolbarShowButton.addWidget(showButton)

        self.connect(showButton, SIGNAL('clicked()'), self.showButtonClicked)
        self.graphLabel = GraphCanvas(self);
        self.setCentralWidget(self.graphLabel)

    def showButtonClicked(self):  
        self.graphLabel.drawGraph()

    def resizeEvent(self, event):
        try:
            self.graphLabel.setFig()
        except AttributeError:
            pass

class GraphCanvas(FigureCanvas):

    def __init__(self, parent=None, width=5, height=4, dpi=100):

        self.fig = Figure(figsize=(width, height), dpi=dpi)

        self.axes = self.fig.add_subplot(111)

        FigureCanvas.__init__(self, self.fig)
        self.setParent(parent)

        FigureCanvas.setSizePolicy(self,
                                   QSizePolicy.Expanding,
                                   QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)

        self.background = None

    def drawGraph(self):
        self.axes.cla()
        self.someplot = self.axes.plot(range(1,5), range(1,5))
        self.redVert, = self.axes.plot(None, None, 'r--')
        self.greenVert, = self.axes.plot(None, None, 'g--')
        self.yellowVert, = self.axes.plot(None, None, 'y--')

        self.verticalLines = (self.redVert, self.greenVert, self.yellowVert)

        self.fig.canvas.mpl_connect('motion_notify_event', self.onMove)

        self.draw()
        self.background = self.fig.canvas.copy_from_bbox(self.axes.bbox)

    def onMove(self, event):

        # cursor moves on the canvas
        if event.inaxes:

            # restore the clean background
            self.fig.canvas.restore_region(self.background)
            ymin, ymax = self.axes.get_ylim()
            x = event.xdata - 1

            # draw each vertical line
            for line in self.verticalLines:
                line.set_xdata((x,))
                line.set_ydata((ymin, ymax))
                self.axes.draw_artist(line)
                x += 1

            self.fig.canvas.blit(self.axes.bbox)

    def setFig(self):
        '''
        Draws the canvas again after the main window
        has been resized.
        '''

        try:
            # hide all vertical lines
            for line in self.verticalLines:
                line.set_visible(False)

        except AttributeError:
            pass

        else:
            # draw canvas again and capture the background
            self.draw()
            self.background = self.fig.canvas.copy_from_bbox(self.axes.bbox)

            # set all vertical lines visible again
            for line in self.verticalLines:
                line.set_visible(True)

def main():
    app = QApplication(sys.argv)
    mainWindow = MainWindow()
    mainWindow.show()
    sys.exit(app.exec_())

if __name__ == '__main__': main()

Описание кода

У меня есть базовыйQMainWindow с панелью инструментов, которая имеет "шоу" кнопка. Главное окно также создает холст дляmatplotlib рисунок и устанавливает его в качестве центрального виджета.

Когда пользователь нажимает "шоу" некоторые данные отображаются при вызовеdrawGraph() методGraphCanvas, В реальной программе эти данные изменяются в зависимости от того, что пользователь выбрал для показа до нажатия кнопки. МетодresizeEvent() в основном рисует фигуру снова, чтобы разместить новый центральный размер виджета.

drawGraph() Метод создает четыре участка, из которых первый имеет данные, поэтому онвидны Последние две линии рисуют фигуру и сохраняют статический фон в переменной.self.background

Когда пользователь перемещает мышь на холсте, фон сначала загружается. Я хотел сохранить и загрузить статический фон, чтобы фигура рисовалась быстрее. После этого последние три графика получают свои данные динамически и отображаются в виде 3 вертикальных линий, которые перемещаются курсором мыши.

Эта проблема

1) Фигура становится постепенно медленнее, когда вы продолжаете нажиматьшоу" кнопка. Если вы попытаетесь ударить его как-то 50 раз и наведете указатель мыши на фигуру, вы увидите, что вертикальные линии гораздо более медленные. Когда там'Благодаря гораздо большему количеству динамических графиков, аннотаций и т. д. на реальном рисунке, программа становится непригодной для использования после нескольких щелчков мышью.

Кто-то умнее может, вероятно, сказать, почему происходит это замедление, но я предполагаю, что ранее загруженные фигуры хранятся где-то в памяти и могут быть нарисованы под вновь созданной фигурой. И стек становится все больше и больше.

2) Рисунок показан сразу после запуска программы. Ничего страшного, но я бы предпочел просто пустую область, пока кнопка не нажата.

Решение попыталось

Я попробовал переместить эти две строки изdef __init__(self) изclass MainWindow к:def showButtonClicked(self)

self.graphLabel = GraphCanvas(self);
self.setCentralWidget(self.graphLabel)

Так это выглядит сейчас так:

def showButtonClicked(self):  
    self.graphLabel = GraphCanvas(self);
    self.setCentralWidget(self.graphLabel)
    self.graphLabel.drawGraph()

Поэтому я создал фигуру только после нажатия кнопки. Это решает проблему замедления, но приводит к другой проблеме. Теперь, когда вы нажметешоу" Нажмите кнопку и переместите мышь на холст, загруженный фон рисунка будет загружен, но в исходном размере 5 на 4 дюйма, и у нас будет беспорядок. Таким образом, в основном фон был сохранен не в том размере, в котором нарисована фигура, а в том размере, в котором он был создан.

Если я изменю размер окна, все работает хорошо. Но в следующий раз я нажму "шоу" Кнопка, проблема появляется снова, и мне нужно снова изменить размер окна.

Что мне нужно

Мне нужно, чтобы эта штука работала плавно и выглядела так, как должна, независимо от того, сколько раз "шоу" кнопка нажата. Кроме того, я бы предпочел, чтобы фигура непокажи "шоу" кнопка нажата в первый раз и с этого момента будет видна до закрытия программы.

Несколько хаков приходят ко мне, как изменение размера окна на один пиксель, когда "шоу" кнопка нажата, но этоне правильный подход, не так ли?

Любые идеи и предложения приветствуются. Спасибо.

Ответы на вопрос(1)

Ваш ответ на вопрос