編集:
私の問題の実例を含めるためにこれを書き直すことにしました。これはかなり長いですが、将来多くの人にとって役立つことを願っています.
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
「表示」ボタンのあるツールバーを備えた基本があります。メイン ウィンドウは、Figure のキャンバスも作成しmatplotlib
、中央のウィジェットに設定します。
ユーザーが「表示」ボタンを押すと、 のdrawGraph()
メソッドを呼び出すことによっていくつかのデータが表示されGraphCanvas
ます。実際のプログラムでは、ユーザーがボタンをクリックする前に表示するように選択した内容に応じてデータが変化します。このメソッドresizeEvent()
は基本的に、新しい中央ウィジェットのサイズに対応するために Figure を再度描画します。
このdrawGraph()
メソッドは 4 つのプロットを作成し、最初のプロットにはデータがあるため、表示されます。最後の 2 行は Figure を描画し、静的な背景を変数 に保存しますself.background
。
ユーザーがキャンバス上でマウスを動かすと、最初に背景が読み込まれます。フィギュアの描画を高速化するために、静的な背景を保存してロードしたかったのです。その後、最後の 3 つのプロットはデータを動的に取得し、マウス カーソルで移動する 3 つの垂直線として表示されます。
問題
1)「表示」ボタンを押し続けると、図が徐々に遅くなります。50回くらい叩いてマウスを動かしてみると、縦の線がずいぶん遅れているのがわかります。実際の図にもっと動的なプロットや注釈などが含まれている場合、数回クリックしただけでプログラムが使用できなくなります。
賢明な人なら、なぜこの速度低下が起こっているのかわかるかもしれませんが、以前に読み込まれた図はメモリのどこかに保持されており、新しく作成された図の下に描画される可能性があると思います。そして、スタックはますます大きくなり続けています。
2)プログラム起動直後の図が表示されます。大したことではありませんが、ボタンがクリックされるまで空白の領域があればいいのにと思います。
試した解決策
私が試したのは、これらの 2 行をdef __init__(self)
ofclass 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()
そのため、ボタンが押された後にのみ図を作成しました。これで速度低下の問題は解決しますが、別の問題が生じます。「表示」ボタンを押してキャンバス上でマウスを動かすと、保存された Figure の背景が読み込まれますが、元のサイズは 5 x 4 インチで、ごちゃごちゃしています。なので、背景は基本的にフィギュアを描いた時のサイズではなく、作った時のサイズで保存しました。
ただし、ウィンドウのサイズを変更すると、すべてがうまく機能します。しかし、次に「表示」ボタンをクリックすると、問題が再発し、ウィンドウのサイズを再度変更する必要があります。
必要なもの
これを流動的に動作させ、「表示」ボタンが何回クリックされても正常に見えるようにする必要があります。また、「表示」ボタンが初めてクリックされるまで図が表示されず、その時点からプログラムが閉じられるまで表示されることをお勧めします。
「表示」ボタンがクリックされたときにウィンドウのサイズを1ピクセル変更するなど、いくつかのハックが私に来ましたが、それは正しいアプローチではありませんか?
どんなアイデアや提案も大歓迎です。ありがとうございました。