РЕДАКТИРОВАТЬ:
Я решил переписать это, чтобы включить рабочий пример моей проблемы. Хотя это довольно длинно, я надеюсь, что это окажется полезным для многих в будущем.
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
.
Когда пользователь перемещает мышь по холсту, сначала загружается фон. Я хотел сохранить и загрузить статический фон, чтобы фигура рисовалась быстрее. После этого последние три графика получают свои данные динамически и отображаются в виде трех вертикальных линий, которые перемещаются вместе с курсором мыши.
Проблема
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 дюйма, и у нас получается беспорядок. То есть в основном фон сохранялся не в том размере, в котором была нарисована фигура, а в том размере, в котором она была создана.
Однако, если я изменяю размер окна, все работает хорошо. Но в следующий раз, когда я нажимаю кнопку «показать», проблема появляется снова, и мне нужно снова изменить размер окна.
Что мне нужно
Мне нужно, чтобы эта штука работала плавно и выглядела так, как должна, независимо от того, сколько раз была нажата кнопка «показать». Кроме того, я бы предпочел, чтобы фигура не отображалась до тех пор, пока кнопка «показать» не будет нажата в первый раз, и с этого момента будет видна до закрытия программы.
Мне приходят в голову несколько приемов, например, изменение размера окна на один пиксель при нажатии кнопки «Показать», но это неправильный подход, не так ли?
Любые идеи и предложения более чем приветствуются. Спасибо.
pyplot
. См. matplotlib.org/examples/user_interfaces/embedding_in_qt4.html. посколькуpyplot
устанавливает собственный графический интерфейс, основной цикл и холст. - person tacaswell   schedule 01.08.2013