From 85f20ef491cb2bbfaeab4c35e405c60c6e6dc22e Mon Sep 17 00:00:00 2001 From: Thierry Zamofing Date: Tue, 3 Jan 2017 10:20:29 +0100 Subject: [PATCH] add MAVelocity.py --- .gitignore | 2 + python/MAError.py | 9 +- python/MAVelocity.py | 269 +++++++++++++++++++++++++++++++++++++ python/MAxyPlot.py | 2 +- python/PBMotionAnalyzer.py | 15 ++- 5 files changed, 290 insertions(+), 7 deletions(-) create mode 100644 .gitignore create mode 100644 python/MAVelocity.py mode change 100644 => 100755 python/PBMotionAnalyzer.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f836aa --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*~ +*.pyc diff --git a/python/MAError.py b/python/MAError.py index 2e6ca76..9a44f37 100644 --- a/python/MAError.py +++ b/python/MAError.py @@ -51,12 +51,13 @@ class MPLCanvasErr(FigureCanvas): ax=self.ax errx,erry,err=err hl = [] - hl = ax.plot(errx, 'g-',label='x-error') - hl = ax.plot(erry, 'y-',label='y-error') - hl = ax.plot(err, 'r-',label='error') + hl += ax.plot(errx, 'g-',label='x-error') + hl += ax.plot(erry, 'y-',label='y-error') + hl += ax.plot(err, 'r-',label='error') ax.xaxis.set_label_text('time (10x servo cycle)') ax.yaxis.set_label_text('pos-error um') legend = ax.legend(loc='upper right', shadow=True) + ax.plot([.5,.5],[0.01, 0.99],'k',transform=ax.transAxes) self.ax = ax self.hl = hl @@ -168,7 +169,7 @@ class MAErrorFrame(wx.Frame): def OnUpdate(self, msg, usrData): # this is the model-view-control update function - print 'OnUpdate',self, msg, usrData + #print 'OnUpdate',self, msg, usrData # for message description s.a. class MADoc if msg == 0: canvas = self.canvas diff --git a/python/MAVelocity.py b/python/MAVelocity.py new file mode 100644 index 0000000..336546d --- /dev/null +++ b/python/MAVelocity.py @@ -0,0 +1,269 @@ +#!/usr/bin/env python +#*-----------------------------------------------------------------------* +#| | +#| Copyright (c) 2013 by Paul Scherrer Institute (http://www.psi.ch) | +#| | +#| Author Thierry Zamofing (thierry.zamofing@psi.ch) | +#*-----------------------------------------------------------------------* +''' +implements an image view to show a colored image of a hdf5 dataset. +''' + +if __name__ == '__main__': + #Used to guarantee to use at least Wx2.8 + import wxversion + wxversion.ensureMinimal('2.8') +import wx +import matplotlib as mpl +if __name__ == '__main__': + mpl.use('WXAgg') + #or mpl.use('WX') + #matplotlib.get_backend() + +import wxutils as ut +import os +import numpy as np +from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas +import pylab as plt #used for the colormaps + +#or from matplotlib.backends.backend_wx import FigureCanvasWx as FigureCanvas +#The source of the DraggableColorbar is from: +#http://www.ster.kuleuven.be/~pieterd/python/html/plotting/interactive_colorbar.html + +class MPLCanvasVelo(FigureCanvas): + def __init__(self,parent,SetStatusCB=None): + if SetStatusCB: + self.SetStatusCB=SetStatusCB + fig = mpl.figure.Figure() + ax = fig.add_axes([0.075,0.075,0.85,0.85]) + FigureCanvas.__init__(self,parent, -1, fig) + self.mpl_connect('motion_notify_event', self.OnMotion) + self.mpl_connect('button_press_event', self.OnBtnPress) + self.mpl_connect('button_release_event', self.OnBtnRelease) + self.mpl_connect('scroll_event', self.OnBtnScroll) + self.mpl_connect('key_press_event',self.OnKeyPress) + self.fig=fig + self.ax=ax + + def InitChild(self,vel): + + fig=self.fig + ax=self.ax + + velxAct,velxDes,velyAct,velyDes=vel + hl = [] + hl += ax.plot(velxAct, 'g-',label='vel x act') + hl += ax.plot(velxDes, 'g--',label='vel x des') + hl += ax.plot(velyAct, 'b-',label='vel y act') + hl += ax.plot(velyDes, 'b--',label='vel y des') + ax.xaxis.set_label_text('time (10x servo cycle)') + ax.yaxis.set_label_text('pos-error um') + legend = ax.legend(loc='upper right', shadow=True) + #axvline(linewidth=4, color='r') + #mpl.axvline(linewidth=4, color='r') + #l = plt.axhline(y=.5, xmin=0.25, xmax=0.75) + #circ = mpl.patches.Circle((0.5, 0.5), 0.25, transform=ax.transAxes, + # facecolor='yellow', alpha=0.5) + #ax.add_patch(circ) + ax.plot([.5,.5],[0.01, 0.99],'k',transform=ax.transAxes) + self.ax = ax + self.hl = hl + + def OnMotion(self, event): + # print event,event.x,event.y,event.inaxes,event.xdata,event.ydata + + if event.inaxes == self.ax: + + x = int(round(event.xdata)) + #y = int(round(event.ydata)) + y = event.ydata + s = [] + for h in self.ax.get_lines(): # to get also the ellipses: self.ax.get_children() + c = h.contains(event) + if c[0]: + # s = str(h)+str(c[1]) + # print "over %s" % s + if type(h) == mpl.lines.Line2D: + lbl = h.get_label() + arr = h.get_data() + idx = c[1]['ind'][0] + #s += '%s[%d] = [%.2f, %.2f]' % (lbl, idx, arr[0][idx], arr[1][idx]) + s.append('%s=%.2f' % (lbl, arr[1][idx])) + else: + s += str(h) + str(c[1]) + s=', '.join(s) + + self.SetStatusCB(self.Parent, 0, (x, y, s)) + + def OnBtnPress(self, event): + """on button press we will see if the mouse is over us and store some data""" + print dir(event.guiEvent) + return + + def OnBtnRelease(self, event): + """on release we reset the press data""" + print dir(event.guiEvent) + #self.OnMouse(event) + return + + def OnBtnScroll(self, event): + return + + def OnKeyPress(self, event): + return + + def OnMouse(self, event): + return + + +class MAVelocityFrame(wx.Frame): + + def __del__(self): + self.doc.view.remove(self) + + def __init__(self, parent,doc): + wx.Frame.__init__(self, parent, title='velocity-Plot', size=wx.Size(850, 650)) + 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) + + canvas = MPLCanvasVelo(self,self.SetStatusCB) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(canvas, 1, wx.LEFT | wx.TOP | wx.GROW) + self.SetSizer(sizer) + + toolbar=ut.AddToolbar(canvas,sizer) + + try: + vel=doc.vel + except AttributeError: + rec=doc.fh['rec'] + velxAct = np.diff(rec[:, 1]) + velxDes = np.diff(rec[:, 4]) + velyAct = np.diff(rec[:, 2]) + velyDes = np.diff(rec[:, 5]) + doc.vel = vel = (velxAct,velxDes,velyAct,velyDes) + canvas.InitChild(vel) + + self.Centre() + + self.BuildMenu() + self.canvas=canvas + self.sizer=sizer + self.toolbar=toolbar + + def BuildMenu(self): + mnBar = wx.MenuBar() + + #-------- Edit Menu -------- + mn = wx.Menu() + #mnItem=mn.Append(wx.ID_ANY, 'Setup Colormap', 'Setup the color mapping ');self.Bind(wx.EVT_MENU, self.OnColmapSetup, mnItem) + #mnItem=mn.Append(wx.ID_ANY, 'Invert X-Axis', kind=wx.ITEM_CHECK);self.Bind(wx.EVT_MENU, self.OnInvertAxis, mnItem) + #self.mnIDxAxis=mnItem.GetId() + #mnItem=mn.Append(wx.ID_ANY, 'Invert Y-Axis', kind=wx.ITEM_CHECK);self.Bind(wx.EVT_MENU, self.OnInvertAxis, mnItem) + #mnItem=mn.Append(wx.ID_ANY, 'Show Moments', 'Show image moments ', kind=wx.ITEM_CHECK);self.Bind(wx.EVT_MENU, self.OnShowMoments, mnItem) + #self.mnItemShowMoment=mnItem + #mnItem=mn.Append(wx.ID_ANY, 'Tomo Normalize', 'Multiplies each pixel with a normalization factor. Assumes there exist an array exchange/data_white', kind=wx.ITEM_CHECK);self.Bind(wx.EVT_MENU, self.OnTomoNormalize, mnItem) + #self.mnItemTomoNormalize=mnItem + + mnBar.Append(mn, '&Edit') + mn = wx.Menu() + mnItem=mn.Append(wx.ID_ANY, 'Help', 'How to use the image viewer');self.Bind(wx.EVT_MENU, self.OnHelp, mnItem) + mnBar.Append(mn, '&Help') + + self.SetMenuBar(mnBar) + self.CreateStatusBar() + + def OnUpdate(self, msg, usrData): + # this is the model-view-control update function + #print 'OnUpdate',self, msg, usrData + # for message description s.a. class MADoc + if msg == 0: + canvas = self.canvas + ax = canvas.ax + len = usrData + err = self.doc.err + hl = canvas.hl + #hl[0].set_data(rec[:len, 4], rec[:len, 5]) + #hl[3].set_data(rec[:len, 1], rec[:len, 2]) + # ax.draw_artist(hl[2]) + x = ax.get_xlim(); + x = (x[1] - x[0]) / 2; + #y = ax.get_ylim(); + #y = (y[1] - y[0]) / 2; + ax.set_xlim(len-x, len + x,emit=True) + #ax.set_ylim(rec[len, 2] - y, rec[len, 2] + y) + canvas.draw() + + @staticmethod + def SetStatusCB(obj,mode,v): + if mode==0: + #obj.SetStatusText( "x= %d y=%d val=%s"%v,0) + obj.SetStatusText("x(%d,%.2f): %s" % v, 0) + else: + raise KeyError('wrong mode') + + + def OnHelp(self,event): + msg='''to change the image selection: +use the toolbar at the bottom to pan and zoom the image +use the scrollbars at the bottom (if present) to select an other slice + +to change the colorscale: +drag with left mouse button to move the colorbar up and down +drag with right mouse button to zoom in/out the colorbar at a given point +use mouse weel to zoom in/out the colorbar at a given point +double click left mouse button to set maximum and minimun colorbar values +use cursor up and down to use a different colormap''' + dlg = wx.MessageDialog(self, msg, 'Help', wx.OK|wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + +if __name__ == '__main__': + import os,sys,argparse #since python 2.7 + def GetParser(required=True): + fnHDF='/scratch/detectorData/e14472_00033.hdf5' + #lbl='mcs' + lbl='pilatus_1' + #lbl='spec' + elem='/entry/dataScan00033/'+lbl + exampleCmd='--hdfFile='+fnHDF+' --elem='+elem + parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, + description=__doc__, + epilog='Example:\n'+os.path.basename(sys.argv[0])+' '+exampleCmd+'\n ') + parser.add_argument('--hdfFile', required=required, default=fnHDF, help='the hdf5 to show') + parser.add_argument('--elem', required=required, default=elem, help='the path to the element in the hdf5 file') + return parser + args = parser.parse_args() + return args + + class App(wx.App): + def OnInit(self): + parser=GetParser() + #parser=GetParser(False) # debug with exampleCmd + args = parser.parse_args() + try: + self.fid=fid=h5py.h5f.open(args.hdfFile) + except IOError as e: + sys.stderr.write('Unable to open File: '+args.hdfFile+'\n') + parser.print_usage(sys.stderr) + return True + try: + hid = h5py.h5o.open(fid,args.elem) + except KeyError as e: + sys.stderr.write('Unable to open Object: '+args.elem+'\n') + parser.print_usage(sys.stderr) + return True + frame = HdfImageFrame(None,args.elem,hid) + frame.Show() + self.SetTopWindow(frame) + return True + + def OnExit(self): + self.fid.close() + + ut.StopWatch.Start() + app = App() + app.MainLoop() diff --git a/python/MAxyPlot.py b/python/MAxyPlot.py index 0ccf4d3..1f58cbd 100644 --- a/python/MAxyPlot.py +++ b/python/MAxyPlot.py @@ -260,7 +260,7 @@ class MAxyPlotFrame(wx.Frame): def OnUpdate(self, msg, usrData): # this is the model-view-control update function - print 'OnUpdate',self, msg, usrData + #print 'OnUpdate',self, msg, usrData if msg==0: canvas=self.canvas ax=canvas.ax diff --git a/python/PBMotionAnalyzer.py b/python/PBMotionAnalyzer.py old mode 100644 new mode 100755 index 5a8c602..85553d2 --- a/python/PBMotionAnalyzer.py +++ b/python/PBMotionAnalyzer.py @@ -1,9 +1,18 @@ +#!/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 * @@ -187,7 +196,8 @@ class MAMainFrame(wx.Frame): frame.Show(True) def OnShowVelocity(self, event): - pass + frame=MAVelocityFrame(self,self.doc) + frame.Show(True) def OnShell(self, event): frame = wx.Frame(self, -1, "wxPyShell",size=wx.Size(800, 500)) @@ -229,7 +239,8 @@ rec def OnUpdate(self,msg,usrData): #this is the model-view-control update function - print self,msg,usrData + #print self,msg,usrData + pass @staticmethod def OnSetTime(usrData, value, msg):