月曜日, 10月 18, 2010

Macでmatplotlibを埋め込んだPyQt4のコードが上手く動かなかった件について

やっぱり先のエントリこのコードを動かすとmatplotlibのウィンドウが余計に出てしまうのは未解決と書きました。

そもそも、これは解決容易な問題かどうかです。これまで出回っているサンプルコードが自分のMac環境で正常に動作するか確認してみました。コードはこちらこちらから使用しました。結論だけいうと、何の問題はありません。極めて正常に動作しています。つまりは、自分のコードが悪いという事です。

実は気になる心当たりがありました。

    fig = matplotlib.pyplot.figure()
実はこれはここのオリジナルのコードと意図的に変えています。
    fig = matplotlib.figure.Figure()
これを変えた理由は、作成したグラフをPyQtに埋め込んで表示すると同時に、グラフの画像ファイルを生成して保存する機能を盛り込みたかったからです。自分が修正したコードでは、figから画像ファイルを生成することができます。
fig.savefig(filename)
ところが、ここをオリジナルのコードに戻しますと、matplotlibのウィンドウ複数表示がなくなり、目下の問題は解決します。要するに原因はココだったわけです。しかし、オリジナルに戻しますとfig.savefig()が使えなくなります。これでは元の木阿弥です。

解決する方法はありました。画像を生成する方法を変えればいいのです。以前から目にはなんとなく入っていたprint_figure()というものを使ってみます。こちらを参考にして修正してみます。グラフの画像ファイルを生成する部分はPyQtで表示するのとは別のバックエンド用canvasオブジェクトを生成するようにすればいいようです。

canvas = matplotlib.backends.backend_agg.FigureCanvasAgg(fig)
canvas.print_figure(filename)
以前のサンプルコードを修正したフルコードは以下のようになります。
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# for command-line arguments
import sys

# Numpy functions for image creation
import numpy

# Matplotlib Figure object
import matplotlib
import matplotlib.pyplot

# Python Qt4 bindings for GUI objects
import PyQt4.QtGui

# import the Qt4Agg FigureCanvas object, that binds Figure to
# Qt4Agg backend. It also inherits from QWidget
#from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.backends.backend_qt4agg
import matplotlib.backends.backend_agg

# import the NavigationToolbar Qt4Agg widget
#from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar

class ApplicationWindow(PyQt4.QtGui.QMainWindow):
    """Example main window"""
    def __init__(self,figs):
        # initialization of Qt MainWindow widget
        PyQt4.QtGui.QMainWindow.__init__(self)
        # set window title
        self.setWindowTitle("Matplotlib Figure in a Qt4 Window With NavigationToolbar")
        # create a tab widget
        self.tab_widget = PyQt4.QtGui.QTabWidget(self)

        for fig, label in figs:
            # instantiate a widget, it will be the main one
            self.main_widget = PyQt4.QtGui.QWidget(self)
            self.tab_widget.addTab(self.main_widget, label)
            # create a vertical box layout widget
            vbl = PyQt4.QtGui.QVBoxLayout(self.main_widget)
            # instantiate our Matplotlib canvas widget
            qmc = matplotlib.backends.backend_qt4agg.FigureCanvasQTAgg(fig)
            # instantiate the navigation toolbar
            ntb = matplotlib.backends.backend_qt4agg.NavigationToolbar2QTAgg(
                qmc, self.main_widget)
            # pack these widget into the vertical box
            vbl.addWidget(qmc)
            vbl.addWidget(ntb)
            # # set the focus on the main widget
            # self.tab_widget.setFocus()
            # set the central widget of MainWindow to main_widget
            self.setCentralWidget(self.tab_widget)

def draw():
    figs = []

    # Standard Matplotlib code to generate the plot
    # fig = matplotlib.pyplot.figure()
    fig = matplotlib.figure.Figure()
    axes = fig.add_subplot(111)
    x = numpy.arange(0.0, 3.0, 0.01)
    y = numpy.cos(1*numpy.pi*x)
    axes.plot(x, y)
    figs.append((fig,"tab 1"))

    # fig = matplotlib.pyplot.figure()
    fig = matplotlib.figure.Figure()
    axes = fig.add_subplot(111)
    x = numpy.arange(0.0, 3.0, 0.01)
    y = numpy.cos(2*numpy.pi*x)
    axes.plot(x, y)
    figs.append((fig,"tab 2"))

    # fig = matplotlib.pyplot.figure()
    fig = matplotlib.figure.Figure()
    axes = fig.add_subplot(111)
    x = numpy.arange(0.0, 3.0, 0.01)
    y = numpy.cos(3*numpy.pi*x)
    axes.plot(x, y)
    figs.append((fig,"tab 3"))

    return figs

# Create the GUI application
qApp = PyQt4.QtGui.QApplication(sys.argv)

figs = draw()

# save image file of matplotlib graph
canvas = matplotlib.backends.backend_agg.FigureCanvasAgg(figs[0][0])
canvas.print_figure("qt4mpl.png")

# Create the Matplotlib widget
mpl = ApplicationWindow(figs)
# show the widget
mpl.show()

# start the Qt main loop execution, exiting from this script
# with the same return code of Qt application
sys.exit(qApp.exec_())
多分これで良さそうです。

0 件のコメント: