#!/usr/bin/env python # *-----------------------------------------------------------------------* # | | # | Copyright (c) 2016 by Paul Scherrer Institute (http://www.psi.ch) | # | | # | Author Thierry Zamofing (thierry.zamofing@psi.ch) | # *-----------------------------------------------------------------------* import os,sys import wx import wx.py import numpy as np from MAxyPlot import * from MAError import * from MAVelocity import * #from hdfTree import * #from hdfGrid import * #from hdfAttrib import * #from hdfImage import * import wxutils as ut class MADoc(): ''' lenRec=fh['rec'] lenPts=fh['pts'] pts= X,Y array idx 0 1 2 3 4 5 6 OLD Motor[3].ActPos Motor[2].ActPos Motor[1].ActPos Motor[3].DesPos Motor[2].DesPos Motor[1].DesPos Gate3[1].Chan[1].UserFlag NEW Motor[1].ActPos Motor[2].ActPos Motor[1].DesPos Motor[2].DesPos Gate3[1].Chan[1].UserFlag NEW y.ActPos x.ActPos y.DesPos x.DesPos Gate3[1].Chan[1].UserFlag OLD->NEW 0->none 1->1 2->0 3->none 4->3 5->2 Implemented messages 0: The time slider has changed. usrData=index 1: The position slider has changed. usrData=index ''' def __init__(self): self.view=[] #list of object that have view on this document pass def Update(self,skipView,msg,usrData): for v in self.view: if v==skipView: continue v.OnUpdate(msg,usrData) class AboutFrame(wx.Frame): def __init__(self,parent): wx.Frame.__init__(self,parent,-1,'About MotionAnalyzer',size=(300,330)) imgDir=ut.Path.GetImage() icon = wx.Icon(os.path.join(imgDir,'PBMA.ico'), wx.BITMAP_TYPE_ICO) self.SetIcon(icon) self.Centre() panel=wx.Panel(self,-1) #import pkg_resources #v=pkg_resources.get_distribution("h5pyViewer") v='my version info' s='Version:'+str(v)+'\n(c) www.psi.ch\n Author: Thierry Zamofing\n thierry.zamofing@psi.ch' st0=wx.StaticText(panel,-1,s,(30,10)) bmp = wx.StaticBitmap(panel,-1,wx.Bitmap(os.path.join(imgDir,'PBMA.png'), wx.BITMAP_TYPE_ANY ), (30,st0.Position[1]+st0.Size[1]+10)) for k,v in os.environ.iteritems(): print k,'=',v class MAMainFrame(wx.Frame): def OpenFile(self,fn_npz): doc=self.doc try: doc.fh=fh=np.load(fn_npz) except IOError as e: sys.stderr.write('Unable to open File: '+fn_npz+'\n') else: pass s='content of numpy file: '+fn_npz+'\n' for k,v in fh.iteritems(): s+=' '+k+': '+str(v.dtype)+' '+str(v.shape)+'\n' self.wxTxt.SetLabel(s) lenRec=fh['rec'].shape[0] lenPts=fh['pts'].shape[0] self.wxTimeCtrl.slider.SetRange(0,lenRec-1) self.wxTimeCtrl.slider.SetPageSize(lenRec/lenPts) self.xPosCtrl.slider.SetRange(0,lenPts-1) #self.wxTimeCtrl.slider.SetPageSize(100) #self.wxTree.ShowHirarchy(self.fid) def CloseFile(self): #http://docs.wxwidgets.org/2.8/wx_windowdeletionoverview.html#windowdeletionoverview #print 'CloseFile' try: self.fh.close() del self.fh except AttributeError as e: pass def __init__(self, parent, title,doc): wx.Frame.__init__(self, parent, title=title, size=wx.Size(650, 350)) self.doc=doc;doc.view.append(self) imgDir=ut.Path.GetImage() icon = wx.Icon(os.path.join(imgDir,'PBMA.ico'), wx.BITMAP_TYPE_ICO) self.SetIcon(icon) #wxSplt = wx.SplitterWindow(self, -1) #wxTree = HdfTreeCtrl(wxSplt, 1, wx.DefaultPosition, (-1,-1), wx.TR_HAS_BUTTONS) #wxTree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged, id=1) #wxTree.Bind(wx.EVT_TREE_ITEM_MENU, self.OnMenu, id=1) #wx.EVT_TREE_ITEM_MENU(id, func) #wxTxt = wx.StaticText(wxSplt, -1, '',(10,10) )#, style=wx.ALIGN_CENTRE) sizer = wx.BoxSizer(wx.VERTICAL) self.SetSizer(sizer) wxTxt = wx.StaticText(self, wx.ID_ANY, "MyLabel", wx.DefaultPosition, wx.DefaultSize, 0 ) sizer.Add(wxTxt, 1, wx.LEFT | wx.TOP | wx.GROW) wxTimeCtrl=ut.SliderGroup(self, label='DataPoint', range=(0, 1000)) wxTimeCtrl.SetCallback(MAMainFrame.OnSetTime, wxTimeCtrl) sizer.Add(wxTimeCtrl.sizer, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=5) #wxSplt.SplitVertically(wxTree, wxTxt) wxPosCtrl=ut.SliderGroup(self, label='Position', range=(0, 1000)) wxPosCtrl.SetCallback(MAMainFrame.OnSetPosition, wxPosCtrl) sizer.Add(wxPosCtrl.sizer, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=5) #wxSplt.SplitVertically(wxTree, wxTxt) #wxSplt.SetMinimumPaneSize(320) #wxLstCtrl=HdfAttrListCtrl(wxSplt) #wxSplt.SplitVertically(wxTree, wxLstCtrl) self.BuildMenu() self.Centre() self.wxTimeCtrl=wxTimeCtrl self.xPosCtrl=wxPosCtrl self.wxTxt=wxTxt #self.wxTree=wxTree #self.display=wxTxt def __del__(self): self.CloseFile() def OnOpen(self, event): dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), '','numpy files (*.npz;*.npy)|*.npz;*.npy|all (*.*)|*.*', wx.OPEN|wx.FD_CHANGE_DIR) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() #mypath = os.path.basename(path) #self.SetStatusText("You selected: %s" % mypath) self.CloseFile() self.OpenFile(path) #print 'OnOpen',path dlg.Destroy() def OnCloseWindow(self, event): #print 'OnCloseWindow' self.Destroy() def OnAbout(self,event): frame=AboutFrame(self) frame.Show() def BuildMenu(self): #http://wiki.wxpython.org/AnotherTutorial#wx.MenuBar mnBar = wx.MenuBar() #-------- File Menu -------- mn = wx.Menu() mnItem=mn.Append(wx.ID_OPEN, '&Open', 'Open a new document');self.Bind(wx.EVT_MENU, self.OnOpen, mnItem) #mnSub = wx.Menu() #mnItem=mnSub.Append(wx.ID_ANY, 'SubMenuEntry', 'My SubMenuEntry') #mn.AppendMenu(wx.ID_ANY, 'SubMenu', mnSub) mn.AppendSeparator() mnItem=mn.Append(wx.ID_EXIT, '&Quit', 'Quit the Application');self.Bind(wx.EVT_MENU, self.OnCloseWindow, mnItem) mnBar.Append(mn, '&File') self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) #-------- Edit Menu -------- mn = wx.Menu() mnItem = mn.Append(wx.ID_ANY, 'Show &XY-Path', 'Show XY-path motion path');self.Bind(wx.EVT_MENU, self.OnShowXYPath, mnItem) mnItem = mn.Append(wx.ID_ANY, 'Show &Error', 'Show error of motion path');self.Bind(wx.EVT_MENU, self.OnShowError, mnItem) mnItem = mn.Append(wx.ID_ANY, 'Show &Velocity', 'Show velocity of motion path');self.Bind(wx.EVT_MENU, self.OnShowVelocity, mnItem) mnItem = mn.Append(wx.ID_ANY, '&Python Shell', 'Opens an interactive python shell"');self.Bind(wx.EVT_MENU, self.OnShell, mnItem) mnBar.Append(mn, '&Window') #-------- Help Menu -------- mn = wx.Menu() #mnItem=mn.Append(wx.ID_HELP,'Help','Application Help') mnItem=mn.Append(wx.ID_ABOUT,'About','Application About');self.Bind(wx.EVT_MENU, self.OnAbout, mnItem) mnBar.Append(mn, '&Help') #mn.AppendSeparator() #mnItem = wx.MenuItem(mn, 105, '&Quit\tCtrl+Q', 'Quit the Application') #mnItem.SetBitmap(wx.Image('stock_exit-16.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap()) #mn.AppendItem(mnItem) self.SetMenuBar(mnBar) self.CreateStatusBar() self.SetStatusText("This is the status message") def OnShowXYPath(self, event): frame=MAxyPlotFrame(self,self.doc) frame.Show(True) def OnShowError(self, event): frame=MAErrorFrame(self,self.doc) frame.Show(True) def OnShowVelocity(self, event): frame=MAVelocityFrame(self,self.doc) frame.Show(True) def OnShell(self, event): frame = wx.Frame(self, -1, "wxPyShell",size=wx.Size(800, 500)) imgDir=Path.GetImage() icon = wx.Icon(os.path.join(imgDir,'PBMA.ico'), wx.BITMAP_TYPE_ICO) frame.SetIcon(icon) frame.Centre() fh=app.GetTopWindow().fh wnd=app.GetTopWindow() loc={'app' :app, 'fh' :fh, 'pts' :fh['pts'], 'rec' :fh['rec'] } introText='''Shell to the HDF5 objects app: application object fh: numpy file pts: desired motion points rec: recorded data #Examples: pts rec #using user defined modules #import userSample as us;reload(us);us.test1(hid) ''' shell=wx.py.shell.Shell(frame, introText=introText,locals=loc) frame.Show(True) #if loc is None, all variables are visible. the context is global #shell.push('wnd=app.GetTopWindow()') #for cmd in [ # 'wnd=app.GetTopWindow();wxTree=wnd.wxTree', # 'wxNode=wnd.wxTree.GetSelection()', # 'print wnd.fid', # 'lbl=wxTree.GetItemText(wxNode)', # 'hid=wxTree.GetPyData(wxNode)']: # shell.run(cmd, prompt=False) def OnUpdate(self,msg,usrData): #this is the model-view-control update function #print self,msg,usrData pass @staticmethod def OnSetTime(usrData, value, msg): 'called when the time slider has been changed' print 'OnSetTime', usrData, value, msg view=usrData.slider.Parent doc=view.doc doc.Update(view,0,value) # imgFrm=usrData.slider.Parent # imgFrm.img.set_array(imgFrm.data[usrData.value,...]) # data=imgFrm.data # sl=ut.GetSlice(imgFrm.idxXY,data.shape,imgFrm.wxAxCtrlLst) # try: # tomoNorm=imgFrm.tomoNorm # except AttributeError: # imgFrm.canvas.img.set_array(data[sl]) # else: # data=data[sl]*tomoNorm # imgFrm.canvas.img.set_array(data) # if imgFrm.mnItemShowMoment.IsChecked(): # imgFrm.PlotMoments() # imgFrm.canvas.draw() pass @staticmethod def OnSetPosition(usrData, value, msg): 'called when the time slider has been changed' print 'OnSetPosition', usrData, value, msg view = usrData.slider.Parent doc = view.doc doc.Update(view, 1, value) if __name__ == '__main__': def GetArgs(): import sys,argparse #since python 2.7 exampleCmd='/tmp/shapepath.npz' parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, description=__doc__, epilog='Example:\n'+os.path.basename(sys.argv[0])+' '+exampleCmd+'\n ') parser.add_argument('npzFile', nargs='?', help='the npz file with motion path data to show',default='/tmp/shapepath.npz') args = parser.parse_args() return args class MyApp(wx.App): def OnInit(self): args=GetArgs() doc=MADoc() frame = MAMainFrame(None,'PBMotionAnalyzer',doc) if args.npzFile: frame.OpenFile(args.npzFile) frame.Show(True) f1 = MAxyPlotFrame(frame, doc) f1.Show(True) f2= MAErrorFrame(frame, doc) f2.Show(True) f3= MAVelocityFrame(frame, doc) f3.Show(True) self.SetTopWindow(frame) return True #------------------ Main Code ---------------------------------- #redirect stdout/stderr: #http://www.blog.pythonlibrary.org/2009/01/01/wxpython-redirecting-stdout-stderr/ #https://groups.google.com/forum/#!topic/wxpython-users/S9uSKIYdYoo #https://17677433047266577941.googlegroups.com/attach/e4d343dc6a751906/REDIRECT.PY?part=2&view=1&vt=ANaJVrFeyCjCMydKnkyfFbYJM7ip07mE-ozUIBxJ5A1QuK1GhycJYJsPTxpAaNk5L2LpXvGhzRPInxDt8_WUcUyK2Ois28Dq8LNebfYoWG9Yxr-tujf5Jk4 #http://www.wxpython.org/docs/api/wx.PyOnDemandOutputWindow-class.html rd=not sys.stdout.isatty()#have a redirect window, if there is no console #rd=True #force to open a redirect window rd=False #avoid a redirect window app = MyApp(redirect=rd) app.MainLoop()