数式のグラフ化プログラム(5)

完結編。いただいたコメントをもとにして、2次元プロットと3次元プロットができるようにした。

  • 使い方
    • xとyの関数形を媒介変数tで表わす。その形を入力する。
    • yをxの関数で与える場合にはx=tとしてyをtで表わす。
    • 表示するtの範囲(最大値と最小値)と刻み幅を与える。
    • 2次元プロットか3次元プロットかをラジオボタンで選ぶ。
  • 2次元と3次元の表示例



以下、ソース。

# coding: utf-8
# -------------------------------------------------------------------
# PlotTool3                               ver.1.2 (2008/12/08)
#                                               
# -------------------------------------------------------------------
import wx
import os
from pylab import *
import matplotlib.axes3d as p3

class MainFrame(wx.Frame):
    def __init__(self, id, title):
        width, height = 600, 540
        wx.Frame.__init__(self, id, title=u"Plot Tool",
                          size=wx.Size(width, height))
        
        self.current = "  "
        self.sb = self.CreateStatusBar(2)
        self.sb.SetStatusWidths([-1, 150])
        self.sb.SetStatusText(self.current)

        Sizer0 = wx.BoxSizer(wx.VERTICAL)
        Sizer1 = wx.BoxSizer(wx.HORIZONTAL)
        Sizer2 = wx.BoxSizer(wx.HORIZONTAL)
        Sizer4 = wx.BoxSizer(wx.HORIZONTAL)
        
        Pan = wx.Panel(self, -1)
        StTxt1 = wx.StaticText(Pan, -1, u"xの数式 x=f(t):")
        StTxt6 = wx.StaticText(Pan, -1, u"yの数式 y=g(t):")
        self.TxtCtl1 = wx.TextCtrl(Pan, -1, "", size=(300,-1))
        self.TxtCtl6 = wx.TextCtrl(Pan, -1, "", size=(300,-1))
        self.TxtCtl2 = wx.TextCtrl(Pan, -1, "", size=(60,-1))
        self.TxtCtl3 = wx.TextCtrl(Pan, -1, "", size=(60,-1))
        self.TxtCtl7 = wx.TextCtrl(Pan, -1, "", size=(60,-1))
        StTxt2 = wx.StaticText(Pan, -1, u"【数式の入力はPythonでの記法に従ってください】")
        BtnPlt = wx.Button(Pan, -1, u"で数式をプロットする")
        StTxt3 = wx.StaticText(Pan, -1, u"tの表示範囲:")
        StTxt4 = wx.StaticText(Pan, -1, u"から")
        StTxt5 = wx.StaticText(Pan, -1, u"までを刻み幅")
        self.RBtn1 = wx.RadioButton(Pan, -1, "2D", style=wx.RB_GROUP)
        self.RBtn2 = wx.RadioButton(Pan, -1, "3D")
        self.RBtn1.SetValue(True)

        self.fig = figure()
        bmp = wx.EmptyBitmap(450,350)
        self.bmpFlag = wx.StaticBitmap(Pan, -1, bmp, (0,0))
#        self.bmpFlag.SetBitmap(bmp)   
        
        BtnPlt.Bind(wx.EVT_BUTTON, self.OnPlot)
#        self.Bind(wx.EVT_RADIOBUTTON, self.OnRadio)

        Sizer1.Add(StTxt1, 0, wx.ALL, 2)
        Sizer1.Add(self.TxtCtl1, 0, wx.ALL, 2)
        Sizer4.Add(StTxt6, 0, wx.ALL, 2)
        Sizer4.Add(self.TxtCtl6, 0, wx.ALL, 2)
        Sizer2.Add(StTxt3, 0, wx.ALL, 2)
        Sizer2.Add(self.TxtCtl2, 0, wx.ALL, 2)
        Sizer2.Add(StTxt4, 0, wx.ALL, 2)
        Sizer2.Add(self.TxtCtl3, 0, wx.ALL, 2)
        Sizer2.Add(StTxt5, 0, wx.ALL, 2)
        Sizer2.Add(self.TxtCtl7, 0, wx.ALL, 2)
        Sizer2.Add(self.RBtn1, 0, wx.ALL, 2)
        Sizer2.Add(self.RBtn2, 0, wx.ALL, 2)
        Sizer2.Add(BtnPlt, 0, wx.RIGHT, 2)
        
        Sizer0.Add(StTxt2,  0, wx.ALL, 2)
        Sizer0.Add(Sizer1, 0, wx.ALL, 2)
        Sizer0.Add(Sizer4, 0, wx.ALL, 2)
        Sizer0.Add(Sizer2,  0, wx.ALL, 2)
        Sizer0.Add(self.bmpFlag,  0, wx.ALL, 5)

        Pan.SetSizer(Sizer0)
#        Sizer0.Fit(self)
        
    def OnPlot(self, event):
        susikix = self.TxtCtl1.GetValue()
        susikiy = self.TxtCtl6.GetValue()
        tmin = self.TxtCtl2.GetValue()
        tmax = self.TxtCtl3.GetValue()
        plot3d = self.RBtn2.GetValue()
        
        if len(susikix) == 0 or len(susikiy) == 0:   # input error
            self.sb.SetStatusText(u"ERR: 数式が入力されていません.")        
        else:
            dt = float(self.TxtCtl7.GetValue())
            vtmin = float(tmin)
            vtmax = float(tmax)
            vdt   = float(dt)
            
            t = arange(vtmin, vtmax, vdt)
            x = eval(susikix)
            y = eval(susikiy)
            if plot3d:
                clf()
                ax = p3.Axes3D(self.fig)
                ax.plot3D(x, y, t)
            else:
                clf()
                ax = self.fig.add_subplot(111)
                ax.plot(x, y, 'k', color='r', linewidth=2.0)
                ax.autoscale_view()
            xlabel('x')
            ylabel('y')
            tname = susikix + ", "+susikiy
            title(tname)
            filen = os.path.join(os.getcwd(), "tempfig")
            self.fig.savefig(filen, dpi=60)

            bmp = wx.Bitmap("tempfig.png")
            self.bmpFlag.SetBitmap(bmp)
            self.sb.SetStatusText(u"%sと%sが読み込まれました."
                                  % (susikix, susikiy))
            
    def OnRadio(self, event):
        pass
        
class Application(wx.App):
    def OnInit(self):
        frame = MainFrame(None, -1)
        frame.Show(True)
        self.SetTopWindow(frame)
        return True

def main():
    import time
    
    app = Application(0)
    print u"info> 起動時刻: %s." % time.ctime(time.time())
    appl_boot_path = os.getcwd()
    print u"info> 起動ディレクトリ: %s." % appl_boot_path
    app.MainLoop()

if __name__ == '__main__':
    main()
#eof