wxPythonでMatplotlibを使う

wxFormBuilderでデスクトップアプリ作成の基礎 - メグタンの何でもブログの続き

起動用mainファイル

main.py

# -*- coding: utf-8 -*-
import wx
import win32gui
import ctypes
import o3dMain

class MyApp(wx.App):
    def OnInit(self):
        frame = o3dMain.o3dMain(None)
        self.SetTopWindow(frame)
        frame.Show(True)
        return True

try:
    ctypes.windll.shcore.SetProcessDpiAwareness(True)
except:
    pass

if __name__ == '__main__':
    if win32gui.FindWindow(None,"Open3Dtest") == 0:
        app = MyApp(False)
        app.MainLoop()

wxFormBuilder で作成された画面ファイル

このファイルは手修正してはいけない。
o3dtest.py

# -*- coding: utf-8 -*-

###########################################################################
## Python code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
## http://www.wxformbuilder.org/
##
## PLEASE DO *NOT* EDIT THIS FILE!
###########################################################################

import wx
import wx.xrc

###########################################################################
## Class Main
###########################################################################

class Main ( wx.Frame ):

    def __init__( self, parent ):
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"Open3Dtest", pos = wx.DefaultPosition, size = wx.Size( 800,600 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )

        self.SetSizeHints( wx.Size( 600,400 ), wx.DefaultSize )
        self.SetFont( wx.Font( 10, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "メイリオ" ) )

        self.m_menubar1 = wx.MenuBar( 0 )
        self.m_menu1 = wx.Menu()
        self.m_menuOpen = wx.MenuItem( self.m_menu1, wx.ID_ANY, u"Open", wx.EmptyString, wx.ITEM_NORMAL )
        self.m_menu1.Append( self.m_menuOpen )

        self.m_menuClose = wx.MenuItem( self.m_menu1, wx.ID_ANY, u"Close", wx.EmptyString, wx.ITEM_NORMAL )
        self.m_menu1.Append( self.m_menuClose )

        self.m_menubar1.Append( self.m_menu1, u"File" )

        self.SetMenuBar( self.m_menubar1 )

        self.m_statusBar1 = self.CreateStatusBar( 1, wx.STB_SIZEGRIP, wx.ID_ANY )
        bSizer1 = wx.BoxSizer( wx.HORIZONTAL )

        self.m_panel2 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        self.m_panel2.SetBackgroundColour( wx.Colour( 200, 255, 200 ) )

        bSizer6 = wx.BoxSizer( wx.VERTICAL )

        self.m_button1 = wx.Button( self.m_panel2, wx.ID_ANY, u"MyButton", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer6.Add( self.m_button1, 0, wx.ALL, 5 )


        self.m_panel2.SetSizer( bSizer6 )
        self.m_panel2.Layout()
        bSizer6.Fit( self.m_panel2 )
        bSizer1.Add( self.m_panel2, 0, wx.EXPAND |wx.ALL, 5 )

        self.m_panel4 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        self.m_panel4.SetBackgroundColour( wx.Colour( 255, 255, 225 ) )

        bSizer1.Add( self.m_panel4, 1, wx.EXPAND |wx.ALL, 5 )


        self.SetSizer( bSizer1 )
        self.Layout()

        self.Centre( wx.BOTH )

        # Connect Events
        self.Bind( wx.EVT_CLOSE, self.MainOnClose )
        self.Bind( wx.EVT_MENU, self.m_menuOpenOnMenuSelection, id = self.m_menuOpen.GetId() )
        self.Bind( wx.EVT_MENU, self.m_menuCloseOnMenuSelection, id = self.m_menuClose.GetId() )
        self.m_button1.Bind( wx.EVT_BUTTON, self.m_button1OnButtonClick )

    def __del__( self ):
        pass


    # Virtual event handlers, override them in your derived class
    def MainOnClose( self, event ):
        event.Skip()

    def m_menuOpenOnMenuSelection( self, event ):
        event.Skip()

    def m_menuCloseOnMenuSelection( self, event ):
        event.Skip()

    def m_button1OnButtonClick( self, event ):
        event.Skip()

自動生成された画面クラスを継承したクラスファイル

このファイルを自動生成するのは1度のみ。
このファイルを修正してプログラムを作るので、途中で自動生成すると上書きされて修正箇所が消えてしまう。
event.skipはそのイベントを下位の層に伝える事を意味する。
passは何もしない。
下記のようにmatplotlibを組み込むことで、wxpythonでmatplotlibが表示できる

o3dmain.py

"""Subclass of Main, which is generated by wxFormBuilder."""

import wx
import o3dtest
import numpy as np
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as NavigationToolbar
import matplotlib.pyplot as plt

# Implementing Main
class o3dMain( o3dtest.Main ):
    def __init__( self, parent ):
        o3dtest.Main.__init__( self, parent )

        # BoxSizerにmatplotlibのFigureCanvasを配置しm_panel4にセットする
        self.fig, self.ax = plt.subplots()
        self.figcan = FigureCanvas(self.m_panel4, -1, self.fig)
        self.CSizer = wx.BoxSizer( wx.VERTICAL )
        self.CSizer.Add(self.figcan, 1, wx.EXPAND |wx.ALL, 0)
        self.m_panel4.SetSizer( self.CSizer )
        self.m_panel4.Layout()

        # fig内のaxの位置を調整したい時
        # self.fig.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9)

        # 背景に色を付ける時
        # self.ax.set_facecolor([0.6,0.6,0.8])
        # self.fig.set_facecolor([0.6,0.6,0.8])

        # 縦横比を1にする(円が円として表示される)時
        # self.ax.set_aspect('equal')

        # FigureCanvasのNavigationToolbarを有効化して
        # マウス操作で拡大縮小移動が出来るようにする
        # ツールバー自体は邪魔なので隠す
        # pキーでマウスドラッグで拡大縮小移動モード(トグル)
        #   左ボタンドラッグで移動
        #   右ボタンドラッグで拡大縮小
        # sキーで保存
        # oキーでマウスドラッグエリアで拡大縮小モード(トグル)
        #   左ボタンエリア選択 拡大
        #   右ボタンエリア選択 縮小
        # rキーで初期表示状態
        self.ntoolbar = NavigationToolbar(self.figcan)
        self.ntoolbar.Realize()
        self.ntoolbar.Hide()

        # FigureCanvas上のマウスイベントで独自の機能を持たせたい時には
        # 下記のようにイベント処理を追加すればいい
        # self.fig.canvas.mpl_connect('button_release_event', self.on_button_release)
        # self.fig.canvas.mpl_connect('button_press_event', self.on_button_press)
        # self.fig.canvas.mpl_connect('pick_event', self.on_pick)
        # self.fig.canvas.mpl_connect('motion_notify_event', self.on_motion)
        # self.fig.canvas.mpl_connect('key_press_event', self.on_key_press)

        # サンプルデータ作成
        self.SampleData()

        # 描画
        self.fig.canvas.draw()

    # Handlers for Main events.
    def MainOnClose( self, event ):
        print("close process")
        #通常のクローズ処理へ
        event.Skip()

    def m_menuOpenOnMenuSelection( self, event ):
        pass

    def m_menuCloseOnMenuSelection( self, event ):
        print("Close menu selected")
        self.Close()

    def m_button1OnButtonClick( self, event ):
        print("button pushed")

    # SampleData 作成
    def SampleData(self):
        x = np.linspace(0,10,100)
        y = np.random.randn(100)
        self.ax.plot(x,y,color ="red", linewidth=2, linestyle = "dashed")