diff --git a/python/MAError.py b/python/MAError.py new file mode 100644 index 0000000..d1b0417 --- /dev/null +++ b/python/MAError.py @@ -0,0 +1,442 @@ +#!/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 MPLCanvasErr(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,pts,rec): + + fig=self.fig + ax=self.ax + + err=np.sqrt((rec[:,1]-rec[:,4])**2+(rec[:,1]-rec[:,4])**2) + hl = ax.plot(err, 'r-') + ax.xaxis.set_label_text('time (10x servo cycle)') + ax.yaxis.set_label_text('pos-error um') + self.ax = ax + self.hl = hl + + def OnMotion(self,event): + print event,event.x,event.y,event.inaxes,event.xdata,event.ydata + return + if event.inaxes==self.ax: + x=int(round(event.xdata)) + y=int(round(event.ydata)) + try: + v=self.img.get_array()[y,x] + except IndexError as e: + pass + else: + #print x,y,v + self.SetStatusCB(self.Parent,0,(x,y,v)) + elif event.inaxes==self.colBar.ax: + colBar=self.colBar + pt=colBar.ax.bbox.get_points()[:,1] + nrm=colBar.norm + vmin,vmax,p0,p1,pS = (nrm.vmin,nrm.vmax,pt[0],pt[1],event.y) + if isinstance(colBar.norm,mpl.colors.LogNorm):#type(colBar.norm)==mpl.colors.LogNorm does not work... + vS=0 + else:#scale around point + vS=vmin+(vmax-vmin)/(p1-p0)*(pS-p0) + self.SetStatusCB(self.Parent,1,vS) + try: + vmin,vmax,p0,p1,pS=self.colBarPressed + except AttributeError: + return + #if event.inaxes != self.cbar.ax: return + colBar=self.colBar + #print vmin,vmax,p0,p1,pS,type(colBar.norm) + #print 'x0=%f, xpress=%f, event.xdata=%f, dx=%f, x0+dx=%f'%(x0, xpress, event.xdata, dx, x0+dx) + + if isinstance(colBar.norm,mpl.colors.LogNorm):#type(colBar.norm)==mpl.colors.LogNorm does not work... + if event.button==1: + #colBar.norm.vmin=.1 + colBar.norm.vmax=vmax*np.exp((pS-event.y)/100) + #scale= np.exp((event.y-pS)/100) + elif event.button==1:#move top,bottom,both + pD = event.y - pS + vD=(vmax-vmin)/(p1-p0)*(pS-event.y) + colBar.norm.vmin = vmin+vD + colBar.norm.vmax = vmax+vD + elif event.button==3:#scale around point + scale= np.exp((pS-event.y)/100) + vS=vmin+(vmax-vmin)/(p1-p0)*(pS-p0) + #print scale,vS + colBar.norm.vmin = vS-scale*(vS-vmin) + colBar.norm.vmax = vS-scale*(vS-vmax) + self.img.set_norm(colBar.norm)#force image to redraw + colBar.patch.figure.canvas.draw() + + 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 + if event.inaxes == self.colBar.ax: + #if event.guiEvent.LeftDClick()==True: + # print dlg + pt=self.colBar.ax.bbox.get_points()[:,1] + nrm=self.colBar.norm + self.colBarPressed = (nrm.vmin,nrm.vmax,pt[0],pt[1],event.y) + #self.colBarPressed = event.x, event.y + #print self.colBarPressed + #self.OnMouse(event) + pass + + def OnBtnRelease(self, event): + """on release we reset the press data""" + #self.OnMouse(event) + return + try: del self.colBarPressed + except AttributeError: pass + + def OnBtnScroll(self, event): + return + #self.OnMouse(event) + colBar=self.colBar + if event.inaxes==colBar.ax: + pt=colBar.ax.bbox.get_points()[:,1] + nrm=colBar.norm + vmin,vmax,p0,p1,pS = (nrm.vmin,nrm.vmax,pt[0],pt[1],event.y) + if isinstance(colBar.norm,mpl.colors.LogNorm):#type(colBar.norm)==mpl.colors.LogNorm does not work... + scale= np.exp((-event.step)/10) + colBar.norm.vmax=vmax*scale + else:#scale around point + scale= np.exp((-event.step)/10) + vS=vmin+(vmax-vmin)/(p1-p0)*(pS-p0) + #print scale,vS + colBar.norm.vmin = vS-scale*(vS-vmin) + colBar.norm.vmax = vS-scale*(vS-vmax) + self.img.set_norm(colBar.norm)#force image to redraw + colBar.patch.figure.canvas.draw() + + def OnKeyPress(self, event): + return + colCycle=self.colCycle + colBar=self.colBar + if event.key=='down': + self.colIndex += 1 + elif event.key=='up': + self.colIndex -= 1 + self.colIndex%=len(colCycle) + cmap = colCycle[self.colIndex] + colBar.set_cmap(cmap) + colBar.draw_all() + self.img.set_cmap(cmap) + self.img.get_axes().set_title(cmap) + colBar.patch.figure.canvas.draw() + + def OnMouse(self, event): + return + for k in dir(event): + if k[0]!='_': + print k,getattr(event,k) + +class MAErrorFrame(wx.Frame): + def __init__(self, parent,doc): + wx.Frame.__init__(self, parent, title='xy-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 = MPLCanvasErr(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) + canvas.InitChild(doc.fh['pts'],doc.fh['rec']) + + 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 + + def SetIdxXY(self,x,y): + self.idxXY=(x,y) + + @staticmethod + def SetStatusCB(obj,mode,v): + if mode==0: + obj.SetStatusText( "x= %d y=%d val=%g"%v,0) + elif mode==1: + obj.SetStatusText( "Colormap Value %d (drag to scale)"%v,0) + else: + raise KeyError('wrong mode') + + + def OnShowMoments(self,event): + if event.IsChecked(): + dlg = wx.FileDialog(self, "Choose valid mask file (e.g. pilatus_valid_mask.mat)", os.getcwd(), '','MATLAB files (*.mat)|*.mat|all (*.*)|*.*', wx.OPEN|wx.FD_CHANGE_DIR) + if dlg.ShowModal() == wx.ID_OK: + fnMatMsk = dlg.GetPath() + print 'OnOpen',fnMatMsk + dlg.Destroy() + if not fnMatMsk: + return + #fnMatMsk='/scratch/detectorData/cSAXS_2013_10_e14608_georgiadis_3D_for_Marianne/analysis/data/pilatus_valid_mask.mat' + self.procMoment=pm=ProcMoment() + pm.SetMskMat(fnMatMsk,False) + #roi=[603, 826, 200, 200] + #pm.roi=(slice(roi[1],roi[1]+roi[3]),slice(roi[0],roi[0]+roi[2])) + #pm.shape=(roi[3],roi[2]) + + #pm.SetProcess('python') + #pm.SetProcess('pyFast') + pm.SetProcess('c') + self.PlotMoments() + #self.canvas.img.draw() + data=self.canvas.img.get_array() + self.canvas.img.set_array(data) + fig, ax = plt.subplots(2) + v=data.sum(axis=0); x=np.arange(v.size); x0=x.sum(); m0=v.sum(); m1=(v*x).sum(); m2=(v*x*x).sum() + ax[0].plot(v); + m=m1/m0 + s=np.sqrt( (m2-(m1**2/m0))/m0) + xx=1/(s*np.sqrt(2*np.pi))*np.exp(-.5*((x-m)/s)**2) + ax[0].set_title('%g | %g | %g | %g | %g'%(m0,m1,m2,m,s)) + ax[0].hold(True);ax[0].plot(xx*m0) + + v=data.sum(axis=1); + ax[1].plot(v); + + + plt.show() + #print pm.resArr[0:3],pm.resArr[1]/pm.resArr[0],pm.resArr[2]/pm.resArr[0] + else: + for o in self.goMoment: + o.remove() + del self.goMoment + del self.procMoment + self.canvas.draw() + + def PlotMoments(self): + data=self.canvas.img.get_array() + pm=self.procMoment + + #data=ndi.median_filter(data, 3) + try: + data.ravel()[pm.mskIdx]=0 + except AttributeError as e: + print e + try: + data=data[pm.roi] + except AttributeError as e: + print e + #data=np.log(data+1) + #data[100:110,500:510]=1000 #y,x + #data[650:850,700:850]=0 #y,x + #pm.Process(np.log(data+1)) + pm.Process(data) + xbar, ybar, cov=pm.GetIntertialAxis() + + m=pm.resArr + m00=m[0];m01=m[1];m10=m[2];m11=m[3];m02=m[4];m20=m[5] + + xm = m10 / m00 + ym = m01 / m00 + u11 = (m11 - xm * m01) / m00 + #u11[u11<0.]=0. #processing rounding error + u20 = (m20 - xm * m10) / m00 + u02 = (m02 - ym * m01) / m00 + a=(u20+u02)/2 + b=np.sqrt(4*u11**2+(u20-u02)**2)/2 + l0=a+b + l1=a-b + ang=0.5*np.arctan2(2*u11,(u20-u02))/(2*np.pi)*360. #orientation value 0..1 + exc=np.sqrt(1-l1/l0) #eccentricity :circle=0: http://en.wikipedia.org/wiki/Eccentricity_%28mathematics%29 + + print 'xb:%g yb:%g cov:%g %g %g %g ang:%g exc:%g'%((xm, ym)+tuple(cov.ravel())+(ang,exc)) + #fig, ax = plt.subplots() + #ax.imshow(data,vmax=100,interpolation='nearest') + #plt.show() + ax=self.canvas.img.get_axes() + try: + for o in self.goMoment: + o.remove() + except AttributeError: pass + + self.goMoment=ProcMoment.PlotMoments(ax, xbar, ybar, cov) + ax.axis('image') + + def OnTomoNormalize(self,event): + if event.IsChecked(): + #try to find white image + #calculate average + #show white normalize factors + white=self.data.parent['data_white'] + tomoNorm=white[1,:,:] + #tomoNorm=white[:,:,:].mean(axis=0) + #np.iinfo(tomoNorm.dtype).max + #tomoNorm=float(np.iinfo(tomoNorm.dtype).max/2)/tomoNorm + tomoNorm=tomoNorm.mean()/tomoNorm + #tomoNorm=tomoNorm/float(np.iinfo(tomoNorm.dtype).max) + data=self.canvas.img.get_array() + data*=tomoNorm + #data/=tomoNorm + self.tomoNorm=tomoNorm + self.canvas.img.set_array(data) + else: + tomoNorm=self.tomoNorm + data=self.canvas.img.get_array() + data/=tomoNorm + self.canvas.img.set_array(data) + del self.tomoNorm + self.canvas.draw() + + def OnSetComplexData(self, event): + if event.IsChecked(): + data=np.angle(self.canvas.dataRaw) + else: + data=np.absolute(self.canvas.dataRaw) + self.canvas.img.set_array(data) + self.canvas.draw() + + 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() + + def OnColmapSetup(self,event): + dlg=DlgColBarSetup(self) + if dlg.ShowModal()==wx.ID_OK: + pass + dlg.Destroy() + + def OnInvertAxis(self,event): + ax=self.canvas.ax + #event.Checked() + if self.mnIDxAxis==event.GetId(): + ax.invert_xaxis() + else: + ax.invert_yaxis() + self.canvas.draw() + pass + +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 new file mode 100644 index 0000000..0ccf4d3 --- /dev/null +++ b/python/MAxyPlot.py @@ -0,0 +1,347 @@ +#!/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 MPLCanvasImg(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.mpl_connect('pick_event',self.OnPick) #works but locks the screed if debugging + self.fig=fig + self.ax=ax + + def InitChild(self,pts,rec): + + fig=self.fig + ax=self.ax + + hl=[] + hl+=ax.plot(pts[:,0],pts[:,1],'r.',label='ptsDot') #,picker=5 default value + hl+=ax.plot(pts[:,0],pts[:,1],'y--',label='ptsLine') + + ec = mpl.collections.EllipseCollection(1, 1, 0, units='xy', offsets=pts,transOffset=ax.transData,edgecolors='g',facecolors=(1,1,0,0.3)) + ax.add_collection(ec) + + + hl+=ax.plot(rec[:, 4], rec[:, 5], 'b-',label='recDesPos') + hl+=ax.plot(rec[:,1],rec[:,2],'g-',label='recActPos') + ax.xaxis.set_label_text('x-pos um') + ax.yaxis.set_label_text('y-pos um') + + fig.obj=self + self.ax=ax + self.hl=hl + + def OnPick(self,event): + thisline = event.artist + xdata = thisline.get_xdata() + ydata = thisline.get_ydata() + ind = event.ind + points = tuple(zip(xdata[ind], ydata[ind])) + print('onpick points:', points) + pass + + + 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)) + 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]) + else: + s += str(h)+str(c[1]) + + self.SetStatusCB(self.Parent, 0, (x, y, s)) + + #try: + # #v=self.img.get_array()[y,x] + # v=0; + #except IndexError as e: + # pass + #else: + #print x,y,v + + #if event.button==1:#move top,bottom,both + # pD = event.y - pS + # vD=(vmax-vmin)/(p1-p0)*(pS-event.y) + # colBar.norm.vmin = vmin+vD + # colBar.norm.vmax = vmax+vD + #elif event.button==3:#scale around point + # scale= np.exp((pS-event.y)/100) + # vS=vmin+(vmax-vmin)/(p1-p0)*(pS-p0) + # #print scale,vS + # colBar.norm.vmin = vS-scale*(vS-vmin) + # colBar.norm.vmax = vS-scale*(vS-vmax) + + 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 + if event.inaxes == self.colBar.ax: + #if event.guiEvent.LeftDClick()==True: + # print dlg + pt=self.colBar.ax.bbox.get_points()[:,1] + nrm=self.colBar.norm + self.colBarPressed = (nrm.vmin,nrm.vmax,pt[0],pt[1],event.y) + #self.colBarPressed = event.x, event.y + #print self.colBarPressed + #self.OnMouse(event) + pass + + def OnBtnRelease(self, event): + """on release we reset the press data""" + #self.OnMouse(event) + return + try: del self.colBarPressed + except AttributeError: pass + + def OnBtnScroll(self, event): + return + #self.OnMouse(event) + colBar=self.colBar + if event.inaxes==colBar.ax: + pt=colBar.ax.bbox.get_points()[:,1] + nrm=colBar.norm + vmin,vmax,p0,p1,pS = (nrm.vmin,nrm.vmax,pt[0],pt[1],event.y) + if isinstance(colBar.norm,mpl.colors.LogNorm):#type(colBar.norm)==mpl.colors.LogNorm does not work... + scale= np.exp((-event.step)/10) + colBar.norm.vmax=vmax*scale + else:#scale around point + scale= np.exp((-event.step)/10) + vS=vmin+(vmax-vmin)/(p1-p0)*(pS-p0) + #print scale,vS + colBar.norm.vmin = vS-scale*(vS-vmin) + colBar.norm.vmax = vS-scale*(vS-vmax) + self.img.set_norm(colBar.norm)#force image to redraw + colBar.patch.figure.canvas.draw() + + def OnKeyPress(self, event): + return + colCycle=self.colCycle + colBar=self.colBar + if event.key=='down': + self.colIndex += 1 + elif event.key=='up': + self.colIndex -= 1 + self.colIndex%=len(colCycle) + cmap = colCycle[self.colIndex] + colBar.set_cmap(cmap) + colBar.draw_all() + self.img.set_cmap(cmap) + self.img.get_axes().set_title(cmap) + colBar.patch.figure.canvas.draw() + + def OnMouse(self, event): + return + for k in dir(event): + if k[0]!='_': + print k,getattr(event,k) + +class MAxyPlotFrame(wx.Frame): + def __del__(self): + self.doc.view.remove(self) + + def __init__(self, parent,doc): + wx.Frame.__init__(self, parent, title='xy-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 = MPLCanvasImg(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) + + wxAxCtrlLst=[] + #l=len(data.shape) + #idxXY=(l-2,l-1) + #for idx,l in enumerate(data.shape): + # if idx in idxXY: + # continue + # wxAxCtrl=ut.SliderGroup(self, label='Axis:%d'%idx,range=(0,l-1)) + # wxAxCtrl.idx=idx + # wxAxCtrlLst.append(wxAxCtrl) + # sizer.Add(wxAxCtrl.sizer, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=5) + # wxAxCtrl.SetCallback(HdfImageFrame.OnSetView,wxAxCtrl) + + #sl=ut.GetSlice(idxXY,data.shape,wxAxCtrlLst) + #wxAxCtrl=ut.SliderGroup(self, label='Axis:%d'%1,range=(0,1000)) + #wxAxCtrl.SetCallback(MAxyPlotFrame.OnSetView,wxAxCtrl) + #sizer.Add(wxAxCtrl.sizer, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=5) + + canvas.InitChild(doc.fh['pts'],doc.fh['rec']) + + #self.Fit() + self.Centre() + + self.BuildMenu() + self.canvas=canvas + self.sizer=sizer + self.toolbar=toolbar + #self.data=data + #self.idxXY=idxXY + #self.wxAxCtrlLst=wxAxCtrlLst + + 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') + #mnItem=mn.Append(wx.ID_ANY, 'Animate', 'Animate the motion');self.Bind(wx.EVT_MENU, self.OnAnimate, mnItem) + + 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 + if msg==0: + canvas=self.canvas + ax=canvas.ax + len=usrData + rec=self.doc.fh['rec'] + hl=canvas.hl + hl[2].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(rec[len, 1]-x,rec[len, 1]+x) + 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) + 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/PBMotionAnalyzer.py b/python/PBMotionAnalyzer.py index 8870948..5a8c602 100644 --- a/python/PBMotionAnalyzer.py +++ b/python/PBMotionAnalyzer.py @@ -2,30 +2,36 @@ import os,sys import wx import wx.py import numpy as np +from MAxyPlot import * +from MAError import * #from hdfTree import * #from hdfGrid import * #from hdfAttrib import * #from hdfImage import * -import utilities as ut +import wxutils as ut +class MADoc(): + ''' -class Path(): - @staticmethod - def GetImage(): - path=__file__ - try:symPath=os.readlink(path) #follow symbolic link - except (AttributeError,OSError) as e:pass - else: - path=symPath - path=os.path.abspath(path) - path=os.path.dirname(path) - return os.path.join(path,'images') +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=Path.GetImage() + imgDir=ut.Path.GetImage() icon = wx.Icon(os.path.join(imgDir,'PBMA.ico'), wx.BITMAP_TYPE_ICO) self.SetIcon(icon) self.Centre() @@ -43,8 +49,9 @@ class AboutFrame(wx.Frame): class MAMainFrame(wx.Frame): def OpenFile(self,fn_npz): + doc=self.doc try: - self.fh=fh=np.load(fn_npz) + doc.fh=fh=np.load(fn_npz) except IOError as e: sys.stderr.write('Unable to open File: '+fn_npz+'\n') else: @@ -53,7 +60,16 @@ class MAMainFrame(wx.Frame): for k,v in fh.iteritems(): s+=' '+k+': '+str(v.dtype)+' '+str(v.shape)+'\n' self.wxTxt.SetLabel(s) - #self.wxTree.ShowHirarchy(self.fid) + + 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 @@ -64,9 +80,10 @@ class MAMainFrame(wx.Frame): except AttributeError as e: pass - def __init__(self, parent, title): + def __init__(self, parent, title,doc): wx.Frame.__init__(self, parent, title=title, size=wx.Size(650, 350)) - imgDir=Path.GetImage() + 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) @@ -75,16 +92,29 @@ class MAMainFrame(wx.Frame): #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) - self.wxTxt = wx.StaticText(self, wx.ID_ANY, "MyLabel", wx.DefaultPosition, wx.DefaultSize, 0 ) - #wxSplt.SplitVertically(wxTree, wxTxt) + + 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='Time', 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): @@ -146,11 +176,16 @@ class MAMainFrame(wx.Frame): #mn.AppendItem(mnItem) self.SetMenuBar(mnBar) self.CreateStatusBar() + self.SetStatusText("This is the status message") def OnShowXYPath(self, event): - pass + frame=MAxyPlotFrame(self,self.doc) + frame.Show(True) + def OnShowError(self, event): - pass + frame=MAErrorFrame(self,self.doc) + frame.Show(True) + def OnShowVelocity(self, event): pass @@ -192,7 +227,43 @@ rec # '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 + @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(): @@ -211,7 +282,8 @@ if __name__ == '__main__': def OnInit(self): args=GetArgs() - frame = MAMainFrame(None, 'PBMotionAnalyzer') + doc=MADoc() + frame = MAMainFrame(None,'PBMotionAnalyzer',doc) if args.npzFile: frame.OpenFile(args.npzFile) frame.Show(True) diff --git a/python/data/shapepath.npz b/python/data/shapepath.npz new file mode 100644 index 0000000..1887abf Binary files /dev/null and b/python/data/shapepath.npz differ diff --git a/python/data/shapepath.prg b/python/data/shapepath.prg new file mode 100644 index 0000000..2e457c2 --- /dev/null +++ b/python/data/shapepath.prg @@ -0,0 +1,418 @@ +Gather.Enable=0 +Gather.Items=6 +Gather.MaxSamples=100000 +Gather.Period=10 +Gather.Addr[0]=Motor[1].ActPos.a +Gather.Addr[1]=Motor[2].ActPos.a +Gather.Addr[2]=Motor[3].ActPos.a +Gather.Addr[3]=Motor[1].DesPos.a +Gather.Addr[4]=Motor[2].DesPos.a +Gather.Addr[5]=Motor[3].DesPos.a +open prog 2 +Gather.Enable=2 + linear abs +X(5.488135) Y(7.151894) +X(56.027634) Y(5.448832) +X(104.236548) Y(6.458941) +X(154.375872) Y(8.917730) +X(209.636628) Y(3.834415) +X(257.917250) Y(5.288949) +X(305.680446) Y(9.255966) +X(350.710361) Y(0.871293) +X(400.202184) Y(8.326198) +X(457.781568) Y(8.700121) +X(509.786183) Y(7.991586) +X(554.614794) Y(7.805292) +X(601.182744) Y(6.399210) +X(651.433533) Y(9.446689) +X(705.218483) Y(4.146619) +X(752.645556) Y(7.742337) +X(804.561503) Y(5.684339) +X(850.187898) Y(6.176355) +X(906.120957) Y(6.169340) +X(959.437481) Y(6.818203) +X(952.961402) Y(51.187277) +X(902.828070) Y(51.201966) +X(857.392636) Y(50.391878) +X(809.767611) Y(56.048455) +X(759.764595) Y(54.686512) +X(708.379449) Y(50.960984) +X(658.209932) Y(50.971013) +X(601.965824) Y(53.687252) +X(556.563296) Y(51.381830) +X(501.589696) Y(51.103751) +X(454.663108) Y(52.444256) +X(406.531083) Y(52.532916) +X(352.088768) Y(51.613095) +X(309.883738) Y(51.020448) +X(255.701968) Y(54.386015) +X(203.154284) Y(53.637108) +X(152.103826) Y(51.289263) +X(106.667667) Y(56.706379) +X(56.976312) Y(50.602255) +X(3.595079) Y(54.370320) +X(3.179832) Y(104.142630) +X(50.641475) Y(106.924721) +X(105.666015) Y(102.653895) +X(155.232481) Y(100.939405) +X(205.759465) Y(109.292962) +X(253.185690) Y(106.674104) +X(301.317979) Y(107.163272) +X(352.894061) Y(101.831914) +X(405.865129) Y(100.201075) +X(458.289400) Y(100.046955) +X(506.778165) Y(102.700080) +X(557.351940) Y(109.621885) +X(602.487531) Y(105.761573) +X(655.920419) Y(105.722519) +X(702.230816) Y(109.527490) +X(754.471254) Y(108.464087) +X(806.994793) Y(102.974370) +X(858.137978) Y(103.965057) +X(908.811032) Y(105.812729) +X(958.817354) Y(106.925316) +X(954.071833) Y(150.691670) +X(908.073190) Y(155.691007) +X(851.238200) Y(158.480082) +X(801.624929) Y(156.155596) +X(751.494483) Y(158.681261) +X(707.142413) Y(159.988470) +X(651.002269) Y(159.194826) +X(608.061940) Y(157.038886) +X(554.358649) Y(158.919234) +X(508.965466) Y(153.675619) +X(456.521033) Y(154.314184) +X(405.743252) Y(156.532008) +X(355.699649) Y(155.908728) +X(301.354741) Y(152.982823) +X(256.180154) Y(154.287687) +X(206.601735) Y(152.900776) +X(150.191932) Y(153.015748) +X(104.238550) Y(156.063932) +X(59.560836) Y(156.439902) +X(7.252543) Y(155.013244) +X(6.974288) Y(204.535427) +X(57.220556) Y(208.663823) +X(109.755215) Y(208.558033) +X(150.117141) Y(203.599781) +X(207.299906) Y(201.716297) +X(255.210366) Y(200.543380) +X(301.999965) Y(200.185218) +X(357.936977) Y(202.239247) +X(403.453517) Y(209.280813) +X(457.044144) Y(200.318389) +X(501.646942) Y(206.214784) +X(555.772286) Y(202.378928) +X(609.342140) Y(206.139660) +X(655.356328) Y(205.899100) +X(707.301220) Y(203.119450) +X(753.982211) Y(202.098437) +X(801.861930) Y(209.443724) +X(857.395508) Y(204.904588) +X(902.274146) Y(202.543565) +X(950.580292) Y(204.344166) +X(952.776287) Y(255.867843) +X(903.741700) Y(254.635754) +X(852.074701) Y(254.246855) +X(805.182007) Y(250.256627) +X(752.539416) Y(252.133120) +X(709.473706) Y(257.308558) +X(656.874883) Y(252.155077) +X(601.856359) Y(259.527917) +X(552.735420) Y(257.980468) +X(506.289818) Y(258.726507) +X(455.883171) Y(258.310485) +X(403.200172) Y(253.834639) +X(350.206510) Y(257.583787) +X(306.630782) Y(252.633224) +X(259.903389) Y(252.168970) +X(205.365792) Y(258.966713) +X(156.793928) Y(254.536968) +X(100.246787) Y(250.672496) +X(53.777518) Y(251.796037) +X(3.117959) Y(256.963435) +X(8.638556) Y(301.175319) +X(55.173791) Y(301.320681) +X(107.168597) Y(303.960597) +X(155.654213) Y(301.832798) +X(201.448478) Y(304.880563) +X(253.556127) Y(309.404319) +X(307.653253) Y(307.486636) +X(359.037197) Y(300.834224) +X(405.521925) Y(305.844761) +X(459.619364) Y(302.921475) +X(502.408288) Y(301.002939) +X(550.164296) Y(309.295293) +X(606.699165) Y(307.851529) +X(652.817301) Y(305.864102) +X(700.639553) Y(304.856276) +X(759.774951) Y(308.765052) +X(803.381590) Y(309.615702) +X(852.317016) Y(309.493188) +X(909.413777) Y(307.992026) +X(956.304479) Y(308.742880) +X(958.605512) Y(357.270443) +X(904.205395) Y(355.573688) +X(856.720478) Y(352.453672) +X(800.795221) Y(350.896030) +X(757.705807) Y(351.469466) +X(707.255944) Y(350.114275) +X(651.324876) Y(350.534272) +X(604.072412) Y(352.322341) +X(553.331452) Y(350.811014) +X(509.065555) Y(357.740473) +X(459.729195) Y(359.608347) +X(400.978445) Y(358.621915) +X(355.113190) Y(352.243170) +X(308.221177) Y(351.898479) +X(253.685846) Y(351.369003) +X(204.973914) Y(356.394725) +X(159.818294) Y(354.783703) +X(103.472335) Y(351.481409) +X(56.178767) Y(350.132369) +X(2.930203) Y(358.489436) +X(2.703279) Y(401.314828) +X(50.553743) Y(403.015986) +X(102.621181) Y(404.561406) +X(156.832813) Y(406.956254) +X(202.835188) Y(403.799270) +X(251.811510) Y(407.885455) +X(300.568481) Y(406.969972) +X(357.786954) Y(407.774076) +X(402.594226) Y(403.738131) +X(455.875996) Y(402.728219) +X(503.708528) Y(401.970543) +X(554.598559) Y(400.446123) +X(607.997959) Y(400.769564) +X(655.188351) Y(403.068101) +X(705.775429) Y(409.594333) +X(756.455702) Y(400.353624) +X(804.304024) Y(405.100169) +X(855.361775) Y(406.813925) +X(902.775961) Y(401.288606) +X(953.926757) Y(409.564057) +X(950.163285) Y(451.852323) +X(903.553688) Y(453.567069) +X(850.333046) Y(459.589827) +X(802.586841) Y(458.490383) +X(750.627130) Y(454.240323) +X(706.288984) Y(453.984343) +X(658.155238) Y(451.594145) +X(608.207671) Y(459.088437) +X(559.518745) Y(455.757512) +X(508.577226) Y(454.572235) +X(454.581388) Y(455.909842) +X(407.963915) Y(459.591666) +X(352.400203) Y(451.605388) +X(307.567786) Y(456.360611) +X(256.996221) Y(453.277204) +X(209.040444) Y(456.900250) +X(157.241676) Y(453.990253) +X(108.820414) Y(454.586040) +X(55.438060) Y(454.569114) +X(1.871309) Y(459.039840) +X(4.012595) Y(509.292914) +X(50.996149) Y(509.453015) +X(108.694885) Y(504.541624) +X(153.267009) Y(502.327441) +X(206.144647) Y(500.330746) +X(250.156061) Y(504.287957) +X(300.680741) Y(502.519410) +X(352.211609) Y(502.531912) +X(401.310552) Y(500.120362) +X(451.154843) Y(506.184803) +X(509.742562) Y(509.903450) +X(554.090541) Y(501.629544) +X(606.387618) Y(504.903053) +X(659.894098) Y(500.653042) +X(707.832344) Y(502.883985) +X(752.414186) Y(506.625046) +X(802.460632) Y(506.658591) +X(855.173085) Y(504.240890) +X(905.546878) Y(502.870515) +X(957.065747) Y(504.148569) +X(959.944008) Y(554.518217) +X(906.995751) Y(559.679656) +X(859.402097) Y(557.507649) +X(806.339977) Y(558.672894) +X(755.023895) Y(559.425836) +X(708.391891) Y(552.377418) +X(654.492916) Y(553.044684) +X(602.378072) Y(551.718531) +X(553.742962) Y(557.487883) +X(502.724369) Y(553.790569) +X(457.307091) Y(558.817202) +X(406.897683) Y(550.583564) +X(359.509526) Y(552.334203) +X(302.494200) Y(551.059062) +X(252.965563) Y(559.920112) +X(209.689717) Y(559.049483) +X(158.149665) Y(559.854914) +X(102.326270) Y(553.485194) +X(59.249669) Y(550.460073) +X(3.605456) Y(558.286569) +X(0.708698) Y(602.927940) +X(51.523547) Y(604.174864) +X(101.312893) Y(606.041178) +X(153.828081) Y(608.953859) +X(209.677947) Y(605.468849) +X(252.748236) Y(605.922304) +X(308.967612) Y(604.067333) +X(355.520783) Y(602.716528) +X(404.554441) Y(604.017135) +X(452.484135) Y(605.058664) +X(503.103808) Y(603.730349) +X(555.249704) Y(607.505950) +X(603.335075) Y(609.241588) +X(658.623185) Y(600.486903) +X(702.536425) Y(604.461355) +X(751.046279) Y(603.484760) +X(807.400975) Y(606.805145) +X(856.223844) Y(607.105284) +X(902.049237) Y(603.416981) +X(956.762425) Y(608.792348) +X(956.232947) Y(658.869608) +X(902.277595) Y(654.103016) +X(856.939564) Y(650.908857) +X(804.420356) Y(655.199524) +X(757.908402) Y(650.972429) +X(705.098072) Y(653.339649) +X(656.964824) Y(658.136786) +X(609.627703) Y(650.168717) +X(556.003922) Y(655.887396) +X(500.027032) Y(656.471967) +X(456.719571) Y(659.488610) +X(405.771402) Y(656.952700) +X(352.097499) Y(651.157032) +X(306.222311) Y(652.790679) +X(250.243132) Y(653.426110) +X(200.894945) Y(654.059423) +X(155.305372) Y(659.221115) +X(100.078841) Y(653.726791) +X(50.302353) Y(657.103368) +X(5.436781) Y(652.826997) +X(6.188262) Y(701.334615) +X(59.805801) Y(708.717857) +X(105.027208) Y(709.223480) +X(155.413808) Y(709.233061) +X(208.298974) Y(709.682864) +X(259.197828) Y(700.360338) +X(301.747720) Y(703.891347) +X(359.521427) Y(703.000289) +X(401.604676) Y(708.863047) +X(454.463944) Y(709.078756) +X(501.602305) Y(706.611175) +X(554.402638) Y(700.764868) +X(606.964631) Y(702.473988) +X(650.396155) Y(700.599443) +X(700.610785) Y(709.077330) +X(757.398839) Y(708.980624) +X(806.725823) Y(705.289399) +X(853.044464) Y(709.979623) +X(903.621891) Y(704.706489) +X(953.782452) Y(709.795269) +X(955.896947) Y(757.453981) +X(901.173205) Y(751.070041) +X(857.730836) Y(759.587409) +X(804.322815) Y(755.219963) +X(750.626360) Y(752.419017) +X(703.354982) Y(751.476856) +X(657.645620) Y(756.982485) +X(609.762257) Y(758.897937) +X(556.375827) Y(758.130539) +X(503.518930) Y(757.214067) +X(453.972567) Y(759.992780) +X(405.910269) Y(756.591765) +X(350.968040) Y(753.433917) +X(309.704937) Y(751.334394) +X(254.565199) Y(753.374774) +X(205.145127) Y(753.679276) +X(152.840000) Y(752.384133) +X(106.072494) Y(754.776465) +X(56.803487) Y(750.632076) +X(1.746584) Y(753.279880) +X(8.481504) Y(809.358321) +X(59.834262) Y(803.998017) +X(103.803352) Y(801.478087) +X(156.849344) Y(806.567620) +X(208.620626) Y(800.972580) +X(254.977769) Y(805.810819) +X(302.415570) Y(801.690254) +X(358.595808) Y(800.585349) +X(404.706209) Y(801.158340) +X(454.570588) Y(809.799623) +X(504.237064) Y(808.571249) +X(551.173156) Y(802.712521) +X(604.037927) Y(803.998121) +X(656.713835) Y(803.447181) +X(707.137669) Y(806.391869) +X(753.991611) Y(804.317601) +X(806.145277) Y(800.700422) +X(858.224067) Y(806.534212) +X(907.263425) Y(805.369230) +X(951.104771) Y(804.050356) +X(953.494403) Y(857.814796) +X(904.329842) Y(855.282341) +X(851.533689) Y(851.995961) +X(807.734555) Y(854.564096) +X(751.621203) Y(855.596824) +X(700.656049) Y(858.562762) +X(652.650397) Y(850.661495) +X(602.213964) Y(851.000141) +X(550.805320) Y(850.853109) +X(503.732160) Y(852.228638) +X(455.181498) Y(858.427769) +X(401.905669) Y(850.191229) +X(355.241839) Y(853.650999) +X(305.349169) Y(854.042436) +X(258.671672) Y(850.291902) +X(209.591423) Y(851.032982) +X(157.032175) Y(856.347863) +X(101.097845) Y(856.063081) +X(50.299503) Y(857.372542) +X(4.053736) Y(853.210430) +X(7.510216) Y(909.272118) +X(50.289525) Y(908.956913) +X(103.925688) Y(908.783725) +X(156.907848) Y(909.873488) +X(207.592825) Y(903.645446) +X(255.010632) Y(903.763892) +X(303.649118) Y(902.609045) +X(354.959703) Y(906.817399) +X(402.773403) Y(905.243798) +X(451.173803) Y(901.598453) +X(500.468064) Y(909.707314) +X(550.038604) Y(901.785800) +X(606.128668) Y(900.813696) +X(658.818965) Y(907.196202) +X(709.663900) Y(905.076355) +X(753.004037) Y(905.495006) +X(809.308187) Y(905.207614) +X(852.672070) Y(908.773988) +X(903.719187) Y(900.013833) +X(952.476850) Y(903.182335) +X(952.503982) Y(954.833935) +X(903.917969) Y(952.421786) +X(859.758839) Y(959.325612) +X(805.964331) Y(951.175256) +X(755.682176) Y(952.465569) +X(704.246630) Y(951.076177) +X(653.041987) Y(950.753591) +X(601.024138) Y(951.563833) +X(558.428549) Y(958.180333) +X(501.390727) Y(954.269044) +X(457.781716) Y(958.442350) +X(404.530942) Y(954.939578) +X(359.227566) Y(952.940767) +X(302.164573) Y(951.660478) +X(256.756891) Y(952.448895) +X(209.661474) Y(957.918796) +X(159.918903) Y(953.767413) +X(108.806781) Y(959.450268) +X(54.445873) Y(953.361023) +X(8.587775) Y(954.585032) +dwell 100 +Gather.Enable=0 +close +&1 +b2r diff --git a/python/utilities.py b/python/utilities.py index fffbd34..320ee31 100755 --- a/python/utilities.py +++ b/python/utilities.py @@ -8,10 +8,9 @@ ''' utilities classes ''' -import logging, h5py, re, zlib, zmq, json +import json import numpy as np -from libDetXR import * -import time +import time,os class dotdict(dict): @@ -90,4 +89,3 @@ class GpasciiCommunicator(): p.write('gpascii -2\n') # execute gpascii command print p.read_until(self.gpascii_inp) return p - diff --git a/python/wxutils.py b/python/wxutils.py new file mode 100755 index 0000000..bfde205 --- /dev/null +++ b/python/wxutils.py @@ -0,0 +1,113 @@ +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') + +from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as NavigationToolbar +import time,os + +class Path(): + @staticmethod + def GetImage(): + path=__file__ + try:symPath=os.readlink(path) #follow symbolic link + except (AttributeError,OSError) as e:pass + else: + path=symPath + path=os.path.abspath(path) + path=os.path.dirname(path) + return os.path.join(path,'images') + +class StopWatch(): + @classmethod + def Start(cls): + cls.ts=time.time() + @classmethod + def Log(cls,str=None,restart=True): + ts=time.time() + print '%.6f'%(ts-cls.ts),str + if restart: + cls.ts=ts + +class SliderGroup(): + def __init__(self, parent, label, range=(0,100),val=0): + self.sliderLabel = wx.StaticText(parent, label=label) + self.sliderText = wx.TextCtrl(parent, -1, style=wx.TE_PROCESS_ENTER) + self.slider = wx.Slider(parent, -1) + self.slider.SetRange(range[0],range[1]) + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(self.sliderLabel, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=2) + sizer.Add(self.sliderText, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=2) + sizer.Add(self.slider, 1, wx.EXPAND) + self.sizer = sizer + self.slider.Bind(wx.EVT_SLIDER, self.sliderHandler) + self.sliderText.Bind(wx.EVT_TEXT_ENTER, self.sliderTextHandler) + self.SetValue(val) + + def SetValue(self, value): + self.value = value + self.slider.SetValue(value) + self.sliderText.SetValue(str(value)) + + def SetCallback(self,funcCB,usrData): + self.cbFuncData=(funcCB,usrData) + + def Callback(self,value,msg): + try: + (funcCB,usrData)=self.cbFuncData + except BaseException as e: + pass + else: + funcCB(usrData,value,msg) + + def sliderHandler(self, evt): + value = evt.GetInt() + self.sliderText.SetValue(str(value)) + self.value=value + self.Callback(value,0) + + def sliderTextHandler(self, evt): + value = int(self.sliderText.GetValue()) + self.slider.SetValue(value) + value = self.slider.Value + self.sliderText.SetValue(str(value)) + self.value=value + self.Callback(value,1) + +def GetSlice(idxXY,shp,wxAxCtrlLst): + '''returns a slice list to select data''' + sl=[None]*len(shp) + for ax in wxAxCtrlLst: + sl[ax.idx]=ax.value + for i in idxXY: + sl[i]=slice(None) + sl=tuple(sl) + return sl + + +def AddToolbar(parent,sizer): + toolbar = NavigationToolbar(parent) + toolbar.Realize() + if wx.Platform == '__WXMAC__': + # Mac platform (OSX 10.3, MacPython) does not seem to cope with + # having a toolbar in a sizer. This work-around gets the buttons + # back, but at the expense of having the toolbar at the top + parent.SetToolBar(toolbar) + else: + # On Windows platform, default window size is incorrect, so set + # toolbar width to figure width. + tw, th = toolbar.GetSizeTuple() + fw, fh = parent.GetSizeTuple() + # By adding toolbar in sizer, we are able to put it at the bottom + # of the frame - so appearance is closer to GTK version. + # As noted above, doesn't work for Mac. + toolbar.SetSize(wx.Size(fw, th)) + sizer.Add(toolbar, 0, wx.LEFT | wx.EXPAND) + # update the axes menu on the toolbar + toolbar.update() + return toolbar +